aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-01-07 14:50:53 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:25 -0400
commita9cc257a8016df80d8bbfdc3ffc6dd2193280c0a (patch)
tree30593a304fc18da6479c71c994e4625b0c27b72d
parenteb54995bc4b5a31293b1cd153d1460570f32125d (diff)
downloadarchive-a9cc257a8016df80d8bbfdc3ffc6dd2193280c0a.tar.gz
ALPHA-pl14n
-rw-r--r--Makefile2
-rw-r--r--drivers/char/console.c26
-rw-r--r--drivers/char/defkeymap.c212
-rw-r--r--drivers/char/defkeymap.map93
-rw-r--r--drivers/char/diacr.h8
-rw-r--r--drivers/char/keyboard.c419
-rw-r--r--drivers/char/tty_io.c40
-rw-r--r--drivers/char/vt.c54
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/slip.c41
-rw-r--r--drivers/net/slip.h3
-rw-r--r--drivers/scsi/sr_ioctl.c1
-rw-r--r--drivers/sound/Makefile2
-rw-r--r--drivers/sound/sb_dsp.c2
-rw-r--r--fs/ext2/CHANGES92
-rw-r--r--fs/ext2/balloc.c6
-rw-r--r--fs/ext2/ialloc.c21
-rw-r--r--fs/ext2/inode.c2
-rw-r--r--fs/ext2/super.c21
-rw-r--r--fs/ext2/truncate.c32
-rw-r--r--fs/super.c1
-rw-r--r--include/linux/ext2_fs.h4
-rw-r--r--include/linux/ip.h2
-rw-r--r--include/linux/kd.h10
-rw-r--r--include/linux/keyboard.h42
-rw-r--r--include/linux/socket.h21
-rw-r--r--include/linux/sockios.h10
-rw-r--r--kernel/module.c4
-rw-r--r--net/Makefile13
-rw-r--r--net/Space.c44
-rw-r--r--net/ddi.c73
-rw-r--r--net/inet/Makefile9
-rw-r--r--net/inet/README23
-rw-r--r--net/inet/arp.c1321
-rw-r--r--net/inet/arp.h36
-rw-r--r--net/inet/datagram.c200
-rw-r--r--net/inet/dev.c1
-rw-r--r--net/inet/devinet.c266
-rw-r--r--net/inet/devinet.h22
-rw-r--r--net/inet/eth.c228
-rw-r--r--net/inet/icmp.c666
-rw-r--r--net/inet/ip.c2412
-rw-r--r--net/inet/ip.h8
-rw-r--r--net/inet/loopback.c130
-rw-r--r--net/inet/packet.c379
-rw-r--r--net/inet/proc.c119
-rw-r--r--net/inet/protocol.c210
-rw-r--r--net/inet/raw.c585
-rw-r--r--net/inet/route.c101
-rw-r--r--net/inet/route.h18
-rw-r--r--net/inet/skbuff.c454
-rw-r--r--net/inet/skbuff.h107
-rw-r--r--net/inet/sockinet.c1636
-rw-r--r--net/inet/sockinet.h118
-rw-r--r--net/inet/tcp.c6004
-rw-r--r--net/inet/tcp.h64
-rw-r--r--net/inet/timer.c340
-rw-r--r--net/inet/udp.c855
-rw-r--r--net/inet/utils.c188
-rw-r--r--net/socket/Makefile37
-rw-r--r--net/socket/datagram.c213
-rw-r--r--net/socket/dev.c980
-rw-r--r--net/socket/dev.h187
-rw-r--r--net/socket/skbuff.c461
-rw-r--r--net/socket/skbuff.h111
-rw-r--r--net/socket/sock.c418
-rw-r--r--net/socket/sock.h191
-rw-r--r--net/unix/proc.c84
-rw-r--r--net/unix/sock.c1373
69 files changed, 13645 insertions, 8215 deletions
diff --git a/Makefile b/Makefile
index b212590..3b14313 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = m
+ALPHA = n
all: Version zImage
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 0823dc7..c153a74 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -10,7 +10,7 @@
* This module exports the console io functions:
*
* 'long con_init(long)'
- * 'void con_open(struct tty_queue * queue, struct )'
+ * 'int con_open(struct tty_struct *tty, struct file * filp)'
* 'void update_screen(int new_console)'
* 'void blank_screen(void)'
* 'void unblank_screen(void)'
@@ -73,9 +73,10 @@ static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
extern void vt_init(void);
extern void register_console(void (*proc)(const char *));
+extern void compute_shiftstate(void);
unsigned long video_num_columns; /* Number of text columns */
-unsigned long video_num_lines; /* Number of test lines */
+unsigned long video_num_lines; /* Number of text lines */
static unsigned char video_type; /* Type of display being used */
static unsigned long video_mem_base; /* Base of video memory */
@@ -215,29 +216,29 @@ static unsigned char * translations[] = {
/* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
+ "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
"\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
- "\376\245\376\376\376\376\231\376\235\376\376\376\232\376\376\341"
+ "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
- "\376\244\225\242\223\376\224\366\233\227\243\226\201\376\376\230",
+ "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
/* vt100 graphics */
(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
"\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
"\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- "\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
+ "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
"\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
@@ -498,12 +499,16 @@ static inline void bs(int currcons)
static inline void del(int currcons)
{
+#if 0
if (x) {
- pos -= 2;
- x--;
+ if (!need_wrap) { /* this is not the right condition */
+ pos -= 2;
+ x--;
+ }
*(unsigned short *)pos = video_erase_char;
need_wrap = 0;
}
+#endif
}
static void csi_J(int currcons, int vpar)
@@ -1547,6 +1552,7 @@ void update_screen(int new_console)
set_origin(fg_console);
set_cursor(new_console);
set_leds();
+ compute_shiftstate();
lock = 0;
}
diff --git a/drivers/char/defkeymap.c b/drivers/char/defkeymap.c
index 3193e1f..171931e 100644
--- a/drivers/char/defkeymap.c
+++ b/drivers/char/defkeymap.c
@@ -3,6 +3,7 @@
#include <linux/types.h>
#include <linux/keyboard.h>
+#include <linux/kd.h>
u_short key_map[NR_KEYMAPS][NR_KEYS] = {
{
@@ -20,7 +21,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
@@ -37,16 +38,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200,
0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x007e, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069,
+ 0x006f, 0x0070, 0x0200, 0x007e, 0x0201, 0x0702, 0x0061, 0x0073,
+ 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x007a, 0x0078, 0x0063, 0x0076,
+ 0x0062, 0x006e, 0x006d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -54,16 +55,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0517, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0051, 0x0057, 0x0045, 0x0052, 0x0054, 0x0059, 0x0055, 0x0049,
+ 0x004f, 0x0050, 0x0200, 0x0200, 0x0201, 0x0702, 0x0041, 0x0053,
+ 0x0044, 0x0046, 0x0047, 0x0048, 0x004a, 0x004b, 0x004c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x005a, 0x0058, 0x0043, 0x0056,
+ 0x0042, 0x004e, 0x004d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -71,7 +72,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e,
@@ -80,7 +81,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x000f, 0x0010, 0x001b, 0x001d, 0x0201, 0x0702, 0x0001, 0x0013,
0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
0x0007, 0x0000, 0x0700, 0x001c, 0x001a, 0x0018, 0x0003, 0x0016,
- 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x007f, 0x0700, 0x030c,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x020e, 0x007f, 0x0700, 0x030c,
0x0703, 0x0000, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0204, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -88,16 +89,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0200, 0x0200, 0x0200, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0200, 0x0200, 0x0200, 0x0200, 0x001f, 0x0200, 0x0200, 0x0200,
+ 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
+ 0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
+ 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -105,16 +106,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
+ 0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
+ 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -122,16 +123,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
+ 0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
+ 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -139,7 +140,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x081b, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836,
@@ -156,16 +157,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x050b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0851, 0x0857, 0x0845, 0x0852, 0x0854, 0x0859, 0x0855, 0x0849,
+ 0x084f, 0x0850, 0x0200, 0x0200, 0x0201, 0x0702, 0x0841, 0x0853,
+ 0x0844, 0x0846, 0x0847, 0x0848, 0x084a, 0x084b, 0x084c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x085a, 0x0858, 0x0843, 0x0856,
+ 0x0842, 0x084e, 0x084d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -173,16 +174,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0871, 0x0877, 0x0865, 0x0872, 0x0874, 0x0879, 0x0875, 0x0869,
+ 0x086f, 0x0870, 0x0200, 0x0200, 0x0201, 0x0702, 0x0861, 0x0873,
+ 0x0864, 0x0866, 0x0867, 0x0868, 0x086a, 0x086b, 0x086c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x087a, 0x0878, 0x0863, 0x0876,
+ 0x0862, 0x086e, 0x086d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -190,16 +191,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0851, 0x0857, 0x0845, 0x0852, 0x0854, 0x0859, 0x0855, 0x0849,
+ 0x084f, 0x0850, 0x0200, 0x0200, 0x0201, 0x0702, 0x0841, 0x0853,
+ 0x0844, 0x0846, 0x0847, 0x0848, 0x084a, 0x084b, 0x084c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x085a, 0x0858, 0x0843, 0x0856,
+ 0x0842, 0x084e, 0x084d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -207,16 +208,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -224,16 +225,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -241,16 +242,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -258,16 +259,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -275,7 +276,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
},
};
@@ -307,6 +308,10 @@ char func_buf[FUNC_BUFSIZE] = {
'\033', '[', '4', '~', 0,
'\033', '[', '5', '~', 0,
'\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ 0,
+ 0,
+ '\033', '[', 'P', 0,
0,
0,
0,
@@ -343,9 +348,52 @@ char *func_table[NR_FUNC] = {
func_buf + 135,
func_buf + 140,
func_buf + 145,
- func_buf + 146,
- func_buf + 147,
- func_buf + 148,
func_buf + 149,
func_buf + 150,
+ func_buf + 151,
+ func_buf + 155,
+ func_buf + 156,
+ func_buf + 157,
+ func_buf + 158,
+ func_buf + 159,
+ func_buf + 160,
};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', '\300'}, {'`', 'a', '\340'},
+ {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
+ {'^', 'A', '\302'}, {'^', 'a', '\342'},
+ {'~', 'A', '\303'}, {'~', 'a', '\343'},
+ {'"', 'A', '\304'}, {'"', 'a', '\344'},
+ {'O', 'A', '\305'}, {'o', 'a', '\345'},
+ {'0', 'A', '\305'}, {'0', 'a', '\345'},
+ {'A', 'A', '\305'}, {'a', 'a', '\345'},
+ {'A', 'E', '\306'}, {'a', 'e', '\346'},
+ {',', 'C', '\307'}, {',', 'c', '\347'},
+ {'`', 'E', '\310'}, {'`', 'e', '\350'},
+ {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
+ {'^', 'E', '\312'}, {'^', 'e', '\352'},
+ {'"', 'E', '\313'}, {'"', 'e', '\353'},
+ {'`', 'I', '\314'}, {'`', 'i', '\354'},
+ {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
+ {'^', 'I', '\316'}, {'^', 'i', '\356'},
+ {'"', 'I', '\317'}, {'"', 'i', '\357'},
+ {'-', 'D', '\320'}, {'-', 'd', '\360'},
+ {'~', 'N', '\321'}, {'~', 'n', '\361'},
+ {'`', 'O', '\322'}, {'`', 'o', '\362'},
+ {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
+ {'^', 'O', '\324'}, {'^', 'o', '\364'},
+ {'~', 'O', '\325'}, {'~', 'o', '\365'},
+ {'"', 'O', '\326'}, {'"', 'o', '\366'},
+ {'/', 'O', '\330'}, {'/', 'o', '\370'},
+ {'`', 'U', '\331'}, {'`', 'u', '\371'},
+ {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
+ {'^', 'U', '\333'}, {'^', 'u', '\373'},
+ {'"', 'U', '\334'}, {'"', 'u', '\374'},
+ {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
+ {'T', 'H', '\336'}, {'t', 'h', '\376'},
+ {'s', 's', '\337'}, {'"', 'y', '\377'},
+ {'s', 'z', '\337'}, {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/char/defkeymap.map b/drivers/char/defkeymap.map
index cf43e69..47d39ab 100644
--- a/drivers/char/defkeymap.map
+++ b/drivers/char/defkeymap.map
@@ -5,6 +5,7 @@ keycode 2 = one exclam
alt keycode 2 = Meta_one
keycode 3 = two at at
control keycode 3 = nul
+ shift control keycode 3 = nul
alt keycode 3 = Meta_two
keycode 4 = three numbersign
control keycode 4 = Escape
@@ -30,6 +31,7 @@ keycode 11 = zero parenright braceright
alt keycode 11 = Meta_zero
keycode 12 = minus underscore backslash
control keycode 12 = Control_underscore
+ shift control keycode 12 = Control_underscore
alt keycode 12 = Meta_minus
keycode 13 = equal plus
alt keycode 13 = Meta_equal
@@ -54,7 +56,7 @@ keycode 27 = bracketright braceright asciitilde
control keycode 27 = Control_bracketright
alt keycode 27 = Meta_bracketright
keycode 28 = Return
- alt keycode 28 = 0x080d
+ alt keycode 28 = Meta_Control_m
keycode 29 = Control
keycode 30 = a
keycode 31 = s
@@ -87,6 +89,7 @@ keycode 50 = m
keycode 51 = comma less
alt keycode 51 = Meta_comma
keycode 52 = period greater
+ control keycode 52 = Compose
alt keycode 52 = Meta_period
keycode 53 = slash question
control keycode 53 = Delete
@@ -196,14 +199,14 @@ keycode 110 = Insert
keycode 111 = Remove
altgr control keycode 111 = Boot
control alt keycode 111 = Boot
-keycode 112 =
-keycode 113 =
-keycode 114 =
-keycode 115 =
-keycode 116 =
-keycode 117 =
-keycode 118 =
-keycode 119 =
+keycode 112 = Macro
+keycode 113 = F13
+keycode 114 = F14
+keycode 115 = Help
+keycode 116 = Do
+keycode 117 = F17
+keycode 118 = KP_MinPlus
+keycode 119 = Pause
keycode 120 =
keycode 121 =
keycode 122 =
@@ -238,9 +241,81 @@ string Remove = "\033[3~"
string Select = "\033[4~"
string Prior = "\033[5~"
string Next = "\033[6~"
+string Help = ""
+string Do = ""
+string Macro = "\033[M"
+string Pause = "\033[P"
string F21 = ""
string F22 = ""
string F23 = ""
string F24 = ""
string F25 = ""
string F26 = ""
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/char/diacr.h b/drivers/char/diacr.h
new file mode 100644
index 0000000..1c1a3ff
--- /dev/null
+++ b/drivers/char/diacr.h
@@ -0,0 +1,8 @@
+#ifndef _DIACR_H
+#define _DIACR_H
+#include <linux/kd.h>
+
+extern struct kbdiacr accent_table[];
+extern unsigned int accent_table_size;
+
+#endif /* _DIACR_H */
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 0b1ae66..c509482 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -7,8 +7,8 @@
* the assembly version by Linus (with diacriticals added)
*
* Some additional features added by Christoph Niemann (ChN), March 1993
- *
* Loadable keymaps by Risto Kankkunen, May 1993
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
*/
#define KEYBOARD_IRQ 1
@@ -25,6 +25,10 @@
#include <asm/bitops.h>
+#include "diacr.h"
+
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
#ifndef KBD_DEFFLAGS
#ifdef CONFIG_KBD_META
@@ -64,8 +68,11 @@ __asm__ __volatile__("int $0x21")
unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
-unsigned long kbd_dead_keys = 0;
-unsigned long kbd_prev_dead_keys = 0;
+/*
+ * global state includes the following, and various static variables
+ * in this module: prev_scancode, shift_state, diacr, npadch,
+ * dead_key_next, last_console
+ */
/* shift state counters.. */
static unsigned char k_down[NR_SHIFT] = {0, };
@@ -74,6 +81,10 @@ static unsigned long key_down[8] = { 0, };
static int want_console = -1;
static int last_console = 0; /* last used VC */
+static int dead_key_next = 0;
+static int shift_state = 0;
+static int npadch = -1; /* -1 or number assembled on pad */
+static unsigned char diacr = 0;
static char rep = 0; /* flag telling character repeat */
struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table;
@@ -103,25 +114,18 @@ static k_hand key_handler[] = {
/* maximum values each key_handler can handle */
const int max_vals[] = {
- 255, NR_FUNC - 1, 13, 16, 4, 255, 3, NR_SHIFT,
+ 255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT,
255, 9, 3
};
-const int NR_TYPES = (sizeof(max_vals) / sizeof(int));
-
-#define E0_BASE 96
-
-static int shift_state = 0;
-static int diacr = -1;
-static int npadch = 0;
+const int NR_TYPES = SIZE(max_vals);
static void put_queue(int);
-static unsigned int handle_diacr(unsigned int);
+static unsigned char handle_diacr(unsigned char);
+/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
static struct pt_regs * pt_regs;
-static inline void translate(unsigned char scancode);
-
static inline void kb_wait(void)
{
int i;
@@ -137,15 +141,67 @@ static inline void send_cmd(unsigned char c)
outb(c,0x64);
}
+/*
+ * Translation of escaped scancodes to keysyms.
+ * This should be user-settable.
+ */
+#define E0_BASE 96
+
+#define E0_KPENTER (E0_BASE+0)
+#define E0_RCTRL (E0_BASE+1)
+#define E0_KPSLASH (E0_BASE+2)
+#define E0_PRSCR (E0_BASE+3)
+#define E0_RALT (E0_BASE+4)
+#define E0_BREAK (E0_BASE+5) /* (control-pause) */
+#define E0_HOME (E0_BASE+6)
+#define E0_UP (E0_BASE+7)
+#define E0_PGUP (E0_BASE+8)
+#define E0_LEFT (E0_BASE+9)
+#define E0_RIGHT (E0_BASE+10)
+#define E0_END (E0_BASE+11)
+#define E0_DOWN (E0_BASE+12)
+#define E0_PGDN (E0_BASE+13)
+#define E0_INS (E0_BASE+14)
+#define E0_DEL (E0_BASE+15)
+/* BTC */
+#define E0_MACRO (E0_BASE+16)
+/* LK450 */
+#define E0_F13 (E0_BASE+17)
+#define E0_F14 (E0_BASE+18)
+#define E0_HELP (E0_BASE+19)
+#define E0_DO (E0_BASE+20)
+#define E0_F17 (E0_BASE+21)
+#define E0_KPMINPLUS (E0_BASE+22)
+
+#define E1_PAUSE (E0_BASE+23)
+
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
+ E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
static void keyboard_interrupt(int int_pt_regs)
{
unsigned char scancode;
+ static unsigned int prev_scancode = 0; /* remember E0, E1 */
+ char up_flag; /* 0 or 0200 */
+ char raw_mode;
pt_regs = (struct pt_regs *) int_pt_regs;
- kbd_prev_dead_keys |= kbd_dead_keys;
- if (!kbd_dead_keys)
- kbd_prev_dead_keys = 0;
- kbd_dead_keys = 0;
send_cmd(0xAD); /* disable keyboard */
kb_wait();
if ((inb_p(0x64) & kbd_read_mask) != 0x01)
@@ -160,113 +216,106 @@ static void keyboard_interrupt(int int_pt_regs)
goto end_kbd_intr;
}
tty = TTY_TABLE(0);
- kbd = kbd_table + fg_console;
- if (vc_kbd_flag(kbd,VC_RAW)) {
- memset(k_down, 0, sizeof(k_down));
- memset(key_down, 0, sizeof(key_down));
- shift_state = 0;
- put_queue(scancode);
+ kbd = kbd_table + fg_console;
+ if ((raw_mode = vc_kbd_flag(kbd,VC_RAW))) {
+ put_queue(scancode);
+ /* we do not return yet, because we want to maintain
+ the key_down array, so that we have the correct
+ values when finishing RAW mode or when changing VT's */
+ }
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
goto end_kbd_intr;
- } else
- translate(scancode);
-end_kbd_intr:
- send_cmd(0xAE); /* enable keyboard */
- return;
-}
-
-static inline void translate(unsigned char scancode)
-{
- char break_flag;
- static unsigned char e0_keys[] = {
- 0x1c, /* keypad enter */
- 0x1d, /* right control */
- 0x35, /* keypad slash */
- 0x37, /* print screen */
- 0x38, /* right alt */
- 0x46, /* break (control-pause) */
- 0x47, /* editpad home */
- 0x48, /* editpad up */
- 0x49, /* editpad pgup */
- 0x4b, /* editpad left */
- 0x4d, /* editpad right */
- 0x4f, /* editpad end */
- 0x50, /* editpad dn */
- 0x51, /* editpad pgdn */
- 0x52, /* editpad ins */
- 0x53, /* editpad del */
-#ifdef LK450
- 0x3d, /* f13 */
- 0x3e, /* f14 */
- 0x3f, /* help */
- 0x40, /* do */
- 0x41, /* f17 */
- 0x4e /* keypad minus/plus */
-#endif
-#ifdef BTC
- 0x6f /* macro */
-#endif
- };
+ }
- if (scancode == 0xe0) {
- set_kbd_dead(KGD_E0);
- return;
- }
- if (scancode == 0xe1) {
- set_kbd_dead(KGD_E1);
- return;
- }
+ /*
+ * Convert scancode to keysym, using prev_scancode.
+ */
+ up_flag = (scancode & 0200);
+ scancode &= 0x7f;
+
+ if (prev_scancode) {
+ /*
+ * usually it will be 0xe0, but a Pause key generates
+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
+ */
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ goto end_kbd_intr;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ scancode = E1_PAUSE;
+ prev_scancode = 0;
+ } else {
+ printk("keyboard: unknown e1 escape sequence\n");
+ prev_scancode = 0;
+ goto end_kbd_intr;
+ }
+ } else {
+ prev_scancode = 0;
+ /*
+ * The keyboard maintains its own internal caps lock and
+ * num lock statuses. In caps lock mode E0 AA precedes make
+ * code and E0 2A follows break code. In num lock mode,
+ * E0 2A precedes make code and E0 AA follows break code.
+ * We do our own book-keeping, so we will just ignore these.
+ */
+ /*
+ * For my keyboard there is no caps lock mode, but there are
+ * both Shift-L and Shift-R modes. The former mode generates
+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+ * So, we should also ignore the latter. - aeb@cwi.nl
+ */
+ if (scancode == 0x2a || scancode == 0x36)
+ goto end_kbd_intr;
+
+ if (e0_keys[scancode])
+ scancode = e0_keys[scancode];
+ else if (!raw_mode) {
+ printk("keyboard: unknown scancode e0 %02x\n", scancode);
+ goto end_kbd_intr;
+ }
+ }
+ } else if (scancode >= E0_BASE && !raw_mode) {
+ printk("keyboard: scancode (%02x) not in range 00 - %2x\n",
+ scancode, E0_BASE - 1);
+ goto end_kbd_intr;
+ }
+
/*
- * The keyboard maintains its own internal caps lock and num lock
- * statuses. In caps lock mode E0 AA precedes make code and E0 2A
- * follows break code. In num lock mode, E0 2A precedes make
- * code and E0 AA follows break code. We do our own book-keeping,
- * so we will just ignore these.
+ * At this point the variable `scancode' contains the keysym.
+ * We keep track of the up/down status of the key, and
+ * return the keysym if in MEDIUMRAW mode.
+ * (Note: earlier kernels had a bug and did not pass the up/down
+ * bit to applications.)
*/
- if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa ||
- scancode == 0x36 || scancode == 0xb6))
- return;
-
- /* map two byte scancodes into one byte id's */
-
- break_flag = scancode > 0x7f;
- scancode &= 0x7f;
-
- if (kbd_dead(KGD_E0)) {
- int i;
- for (i = 0; i < sizeof(e0_keys); i++)
- if (scancode == e0_keys[i]) {
- scancode = E0_BASE + i;
- i = -1;
- break;
- }
- if (i != -1) {
-#if 0
- printk("keyboard: unknown scancode e0 %02x\n", scancode);
-#endif
- return;
- }
- } else if (scancode >= E0_BASE) {
-#if 0
- printk("keyboard: scancode (%02x) not in range 00 - %2x\n", scancode, E0_BASE - 1);
-#endif
- return;
- }
- rep = 0;
- if (break_flag)
- clear_bit(scancode, key_down);
- else
- rep = set_bit(scancode, key_down);
+ if (up_flag) {
+ clear_bit(scancode, key_down);
+ rep = 0;
+ } else
+ rep = set_bit(scancode, key_down);
+
+ if (raw_mode)
+ goto end_kbd_intr;
- if (vc_kbd_flag(kbd, VC_MEDIUMRAW)) {
- put_queue(scancode);
- return;
- }
+ if (vc_kbd_flag(kbd, VC_MEDIUMRAW)) {
+ put_queue(scancode + up_flag);
+ goto end_kbd_intr;
+ }
+
+ /*
+ * Small change in philosophy: earlier we defined repetition by
+ * rep = scancode == prev_keysym;
+ * prev_keysym = scancode;
+ * but now by the fact that the depressed key was down already.
+ * Does this ever make a difference?
+ */
/*
- * Repeat a key only if the input buffers are empty or the
- * characters get echoed locally. This makes key repeat usable
- * with slow applications and under heavy loads.
+ * Repeat a key only if the input buffers are empty or the
+ * characters get echoed locally. This makes key repeat usable
+ * with slow applications and under heavy loads.
*/
if (!rep ||
(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
@@ -275,8 +324,11 @@ static inline void translate(unsigned char scancode)
u_short key_code;
key_code = key_map[shift_state][scancode];
- (*key_handler[key_code >> 8])(key_code & 0xff, break_flag);
+ (*key_handler[key_code >> 8])(key_code & 0xff, up_flag);
}
+
+end_kbd_intr:
+ send_cmd(0xAE); /* enable keyboard */
}
static void put_queue(int ch)
@@ -371,7 +423,7 @@ static void hold(void)
/* pressing srcoll lock 2nd time sends ^Q, ChN */
put_queue(START_CHAR(tty));
else
- /* pressing srcoll lock 1st time sends ^S, ChN */
+ /* pressing scroll lock 1st time sends ^S, ChN */
put_queue(STOP_CHAR(tty));
chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
}
@@ -420,21 +472,25 @@ static void boot_it(void)
ctrl_alt_del();
}
+static void compose(void)
+{
+ dead_key_next = 1;
+}
static void do_spec(unsigned char value, char up_flag)
{
typedef void (*fnp)(void);
fnp fn_table[] = {
NULL, enter, show_ptregs, show_mem,
- show_state, send_intr, lastcons, caps_toggle,
+ show_state, send_intr, lastcons, caps_toggle,
num, hold, scrll_forw, scrll_back,
- boot_it, caps_on
+ boot_it, caps_on, compose
};
- if (value >= sizeof(fn_table)/sizeof(fnp))
- return;
if (up_flag)
return;
+ if (value >= SIZE(fn_table))
+ return;
if (!fn_table[value])
return;
fn_table[value]();
@@ -445,7 +501,14 @@ static void do_self(unsigned char value, char up_flag)
if (up_flag)
return; /* no action, if this is a key release */
- value = handle_diacr(value);
+ if (diacr)
+ value = handle_diacr(value);
+
+ if (dead_key_next) {
+ dead_key_next = 0;
+ diacr = value;
+ return;
+ }
/* kludge... but works for ISO 8859-1 */
if (vc_kbd_flag(kbd,VC_CAPSLOCK))
@@ -457,8 +520,13 @@ static void do_self(unsigned char value, char up_flag)
put_queue(value);
}
+#define A_GRAVE '`'
+#define A_ACUTE '\''
+#define A_CFLEX '^'
+#define A_TILDE '~'
+#define A_DIAER '"'
static unsigned char ret_diacr[] =
- {'`', '\'', '^', '~', '"' }; /* Must not end with 0 */
+ {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
/* If a dead key pressed twice, output a character corresponding to it, */
/* otherwise just remember the dead key. */
@@ -468,52 +536,34 @@ static void do_dead(unsigned char value, char up_flag)
if (up_flag)
return;
- if (diacr == value) { /* pressed twice */
- diacr = -1;
- put_queue(ret_diacr[value]);
- return;
- }
+ value = ret_diacr[value];
+ if (diacr == value) { /* pressed twice */
+ diacr = 0;
+ put_queue(value);
+ return;
+ }
diacr = value;
}
-/* If no pending dead key, return the character unchanged. Otherwise, */
-/* if space if pressed, return a character corresponding the pending */
+
+/* If space is pressed, return the character corresponding the pending */
/* dead key, otherwise try to combine the two. */
-unsigned int handle_diacr(unsigned int ch)
+unsigned char handle_diacr(unsigned char ch)
{
- static unsigned char accent_table[5][64] = {
- " \300BCD\310FGH\314JKLMN\322PQRST\331VWXYZ[\\]^_"
- "`\340bcd\350fgh\354jklmn\362pqrst\371vwxyz{|}~", /* accent grave */
-
- " \301BCD\311FGH\315JKLMN\323PQRST\332VWX\335Z[\\]^_"
- "`\341bcd\351fgh\355jklmn\363pqrst\372vwx\375z{|}~", /* accent acute */
-
- " \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_"
- "`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~", /* circumflex */
-
- " \303BCDEFGHIJKLM\321\325PQRSTUVWXYZ[\\]^_"
- "`\343bcdefghijklm\361\365pqrstuvwxyz{|}~", /* tilde */
-
- " \304BCD\313FGH\317JKLMN\326PQRST\334VWXYZ[\\]^_"
- "`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */
- };
- int d = diacr, e;
+ int d = diacr;
+ int i;
- if (diacr == -1)
- return ch;
+ diacr = 0;
+ if (ch == ' ')
+ return d;
- diacr = -1;
- if (ch == ' ')
- return ret_diacr[d];
+ for (i = 0; i < accent_table_size; i++)
+ if(accent_table[i].diacr == d && accent_table[i].base == ch)
+ return accent_table[i].result;
- if (ch >= 64 && ch <= 122) {
- e = accent_table[d][ch - 64];
- if (e != ch)
- return e;
- }
- put_queue(ret_diacr[d]);
- return ch;
+ put_queue(d);
+ return ch;
}
static void do_cons(unsigned char value, char up_flag)
@@ -527,13 +577,16 @@ static void do_fn(unsigned char value, char up_flag)
{
if (up_flag)
return;
- puts_queue(func_table[value]);
+ if (value < SIZE(func_table))
+ puts_queue(func_table[value]);
+ else
+ printk("do_fn called with value=%d\n", value);
}
static void do_pad(unsigned char value, char up_flag)
{
- static char *pad_chars = "0123456789+-*/\015,.";
- static char *app_map = "pqrstuvwxylSRQMnn";
+ static char *pad_chars = "0123456789+-*/\015,.?";
+ static char *app_map = "pqrstuvwxylSRQMnn?";
if (up_flag)
return; /* no action, if this is a key release */
@@ -610,6 +663,8 @@ static void do_shift(unsigned char value, char up_flag)
}
if (up_flag) {
+ /* handle the case that two shift or control
+ keys are depressed simultaneously */
if (k_down[value])
k_down[value]--;
} else
@@ -621,12 +676,37 @@ static void do_shift(unsigned char value, char up_flag)
shift_state &= ~ (1 << value);
/* kludge */
- if (up_flag && shift_state != old_state && npadch != 0) {
+ if (up_flag && shift_state != old_state && npadch != -1) {
put_queue(npadch);
- npadch = 0;
+ npadch = -1;
}
}
+/* called after returning from RAW mode or when changing consoles -
+ recompute k_down[] and shift_state from key_down[] */
+void compute_shiftstate(void)
+{
+ int i, j, k, sym, val;
+
+ shift_state = 0;
+ for(i=0; i < SIZE(k_down); i++)
+ k_down[i] = 0;
+
+ for(i=0; i < SIZE(key_down); i++)
+ if(key_down[i]) { /* skip this word if not a single bit on */
+ k = (i<<5);
+ for(j=0; j<32; j++,k++)
+ if(test_bit(k, key_down)) {
+ sym = key_map[0][k];
+ if(KTYP(sym) == KT_SHIFT) {
+ val = KVAL(sym);
+ k_down[val]++;
+ shift_state |= (1<<val);
+ }
+ }
+ }
+}
+
static void do_meta(unsigned char value, char up_flag)
{
if (up_flag)
@@ -644,7 +724,10 @@ static void do_ascii(unsigned char value, char up_flag)
if (up_flag)
return;
- npadch = (npadch * 10 + value) % 1000;
+ if (npadch == -1)
+ npadch = value;
+ else
+ npadch = (npadch * 10 + value) % 1000;
}
/* done stupidly to avoid coding in any dependencies of
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 44f094b..5422dcc 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -586,57 +586,41 @@ void copy_to_cooked(struct tty_struct * tty)
if (c == __DISABLED_CHAR)
tty->lnext = 1;
if (L_CANON(tty) && !tty->lnext) {
- if (c == KILL_CHAR(tty) || c == WERASE_CHAR(tty)) {
+ if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || c == WERASE_CHAR(tty)) {
int seen_alnums =
(c == WERASE_CHAR(tty)) ? 0 : -1;
+ int cc;
- /* deal with killing the input line */
+ /* deal with killing in the input line */
while(!(EMPTY(&tty->secondary) ||
- (c=LAST(&tty->secondary))==10 ||
+ (cc=LAST(&tty->secondary))==10 ||
((EOF_CHAR(tty) != __DISABLED_CHAR) &&
- (c==EOF_CHAR(tty))))) {
+ (cc==EOF_CHAR(tty))))) {
/* if killing just a word, kill all
non-alnum chars, then all alnum
chars. */
if (seen_alnums >= 0) {
- if (isalnum(c))
+ if (isalnum(cc))
seen_alnums++;
else if (seen_alnums)
break;
}
if (L_ECHO(tty)) {
- if (c<32) {
+ int ct = 1;
+ if (cc < 32)
+ ct = (L_ECHOCTL(tty) ? 2 : 0);
+ while(ct--) {
put_tty_queue('\b', &tty->write_q);
put_tty_queue(' ', &tty->write_q);
put_tty_queue('\b',&tty->write_q);
}
- put_tty_queue('\b',&tty->write_q);
- put_tty_queue(' ',&tty->write_q);
- put_tty_queue('\b',&tty->write_q);
}
DEC(tty->secondary.head);
+ if(c == ERASE_CHAR(tty))
+ break;
}
continue;
}
- if (c == ERASE_CHAR(tty)) {
- if (EMPTY(&tty->secondary) ||
- (c=LAST(&tty->secondary))==10 ||
- ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
- (c==EOF_CHAR(tty))))
- continue;
- if (L_ECHO(tty)) {
- if (c<32) {
- put_tty_queue('\b',&tty->write_q);
- put_tty_queue(' ',&tty->write_q);
- put_tty_queue('\b',&tty->write_q);
- }
- put_tty_queue('\b',&tty->write_q);
- put_tty_queue(' ',&tty->write_q);
- put_tty_queue('\b',&tty->write_q);
- }
- DEC(tty->secondary.head);
- continue;
- }
if (c == LNEXT_CHAR(tty)) {
tty->lnext = 1;
if (L_ECHO(tty)) {
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index d1069be..28b5e40 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2,6 +2,7 @@
* kernel/chr_drv/vt.c
*
* Copyright (C) 1992 obz under the linux copyright
+ * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
*/
#include <linux/types.h>
@@ -19,6 +20,7 @@
#include <asm/segment.h>
#include "vt_kern.h"
+#include "diacr.h"
/*
* Console (vt and kd) routines, as defined by USL SVR4 manual, and by
@@ -37,6 +39,7 @@ struct vt_struct vt_cons[NR_CONSOLES];
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern void compute_shiftstate(void);
extern void change_console(unsigned int new_console);
extern void complete_change_console(unsigned int new_console);
extern int vt_waitactive(void);
@@ -212,6 +215,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
} else if (arg == K_XLATE) {
clr_vc_kbd_flag(kbd, VC_RAW);
clr_vc_kbd_flag(kbd, VC_MEDIUMRAW);
+ compute_shiftstate();
} else if (arg == K_MEDIUMRAW) {
clr_vc_kbd_flag(kbd, VC_RAW);
set_vc_kbd_flag(kbd, VC_MEDIUMRAW);
@@ -278,10 +282,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
if (i)
return i;
- if ((i = get_fs_byte(&a->kb_func)) >= NR_FUNC)
+ if ((i = get_fs_byte(&a->kb_func)) >= NR_FUNC || i < 0)
return -EINVAL;
q = a->kb_string;
- for (p = func_table[i]; *p; p++)
+ p = func_table[i];
+ if(!p) {
+ /* beware of tables generated for a smaller NR_FUNC */
+ printk("KDGKBSENT error: func_table[%d] is nil.\n",
+ i);
+ return -EINVAL;
+ }
+ for ( ; *p; p++)
put_fs_byte(*p, q++);
put_fs_byte(0, q);
return 0;
@@ -301,7 +312,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return i;
if ((i = get_fs_byte(&a->kb_func)) >= NR_FUNC)
return -EINVAL;
- delta = -strlen(func_table[i]);
+ q = func_table[i];
+ if (!q) {
+ /* beware of tables generated for a smaller NR_FUNC */
+ printk("KDSKBSENT error: func_table[%d] is nil.\n",
+ i);
+ return -EINVAL;
+ }
+ delta = -strlen(q);
for (p = a->kb_string; get_fs_byte(p); p++)
delta++;
first_free = func_table[NR_FUNC - 1] +
@@ -317,6 +335,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
func_table[i + 1],
first_free - func_table[i + 1]);
for (k = i + 1; k < NR_FUNC; k++)
+ if (func_table[k]) /* just to be sure */
func_table[k] += delta;
}
for (p = a->kb_string, q = func_table[i]; ; p++, q++)
@@ -325,6 +344,35 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
+ case KDGKBDIACR:
+ {
+ struct kbdiacrs *a = (struct kbdiacrs *)arg;
+
+ i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
+ if (i)
+ return i;
+ put_fs_long(accent_table_size, &a->kb_cnt);
+ memcpy_tofs(a->kbdiacr, accent_table,
+ accent_table_size*sizeof(struct kbdiacr));
+ return 0;
+ }
+
+ case KDSKBDIACR:
+ {
+ struct kbdiacrs *a = (struct kbdiacrs *)arg;
+ unsigned int ct;
+
+ i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
+ if (i)
+ return i;
+ ct = get_fs_long(&a->kb_cnt);
+ if (ct >= MAX_DIACR)
+ return -EINVAL;
+ accent_table_size = ct;
+ memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
+ return 0;
+ }
+
case KDGETLED:
i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
if (i)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 51c1c8d..e6d1140 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,8 +8,8 @@
include CONFIG
NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o)
-CFLAGS := $(CFLAGS) -I../../net/inet
-CPP := $(CPP) -I../../net/inet
+CFLAGS := $(CFLAGS) -I../../net/inet -I../../net/socket -I../../net
+CPP := $(CPP) -I../../net/inet -I../../net/socket -I../../net
# The point of the makefile...
all: net.a
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index b900956..a3f2e1c 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -18,6 +18,7 @@
* Pauline Middelink : Slip driver fixes.
* Alan Cox : Honours the old SL_COMPRESSED flag
* Alan Cox : KISS AX.25 and AXUI IP support
+ * Michael Riepe : Automatic CSLIP recognition added
*/
#include <asm/segment.h>
@@ -39,9 +40,9 @@
#include <linux/tty.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#ifdef CONFIG_AX25
-#include "ax25.h"
+#include "ax25/ax25.h"
#endif
#include "eth.h"
#include "ip.h"
@@ -135,10 +136,14 @@ sl_initialize(struct slip *sl, struct device *dev)
sl->sending = 0;
sl->escape = 0;
sl->flags = 0;
+#ifdef SL_ADAPTIVE
+ sl->mode = SL_MODE_ADAPTIVE; /* automatic CSLIP recognition */
+#else
#ifdef SL_COMPRESSED
- sl->mode = SL_MODE_CSLIP; /* Default */
+ sl->mode = SL_MODE_CSLIP | SL_MODE_ADAPTIVE; /* Default */
#else
sl->mode = SL_MODE_SLIP; /* Default for non compressors */
+#endif
#endif
sl->line = dev->base_addr;
@@ -351,8 +356,15 @@ sl_bump(struct slip *sl)
int count;
count = sl->rcount;
- if (sl->mode & SL_MODE_CSLIP) {
+ if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
+#if 1
+ /* ignore compressed packets when CSLIP is off */
+ if (!(sl->mode & SL_MODE_CSLIP)) {
+ printk("SLIP: compressed packet ignored\n");
+ return;
+ }
+#endif
/* make sure we've reserved enough space for uncompress to use */
save_flags(flags);
cli();
@@ -374,6 +386,11 @@ sl_bump(struct slip *sl)
return;
}
} else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
+ if (!(sl->mode & SL_MODE_CSLIP)) {
+ /* turn on header compression */
+ sl->mode |= SL_MODE_CSLIP;
+ printk("SLIP: header compression turned on\n");
+ }
sl->rbuff[0] &= 0x4f;
if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {
sl->errors++;
@@ -485,6 +502,21 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
}
}
+/*static void sl_hex_dump(unsigned char *x,int l)
+{
+ int n=0;
+ printk("sl_xmit: (%d bytes)\n",l);
+ while(l)
+ {
+ printk("%2X ",(int)*x++);
+ l--;
+ n++;
+ if(n%32==0)
+ printk("\n");
+ }
+ if(n%32)
+ printk("\n");
+}*/
/* Encapsulate an IP datagram and kick it into a TTY queue. */
static int
@@ -525,6 +557,7 @@ sl_xmit(struct sk_buff *skb, struct device *dev)
}
#endif
sl_lock(sl);
+/* sl_hex_dump((unsigned char *)(skb+1),skb->len);*/
sl_encaps(sl, (unsigned char *) (skb + 1), skb->len);
if (skb->free) kfree_skb(skb, FREE_WRITE);
}
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index 7f04909..b0be292 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -66,8 +66,9 @@ struct slip {
#define SL_MODE_SLIP 0
#define SL_MODE_CSLIP 1
#define SL_MODE_SLIP6 2 /* Matt Dillon's printable slip */
-#define SL_MODE_CSLIP6 (SL_MODE_SLIP|SL_MODE_CSLIP)
+#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP)
#define SL_MODE_AX25 4
+#define SL_MODE_ADAPTIVE 8
int xdata,xbits; /* 6 bit slip controls */
};
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 4423188..c572fd0 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -315,6 +315,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
}
/* Now mask and substitute our own volume and reuse the rest */
+ buffer[0] = 0; /* Clear reserved field */
buffer[21] = volctrl.channel0 & mask[21];
buffer[23] = volctrl.channel1 & mask[23];
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 1f3760a..d8518d7 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -25,7 +25,7 @@ all: local.h sound.a
/usr/include/sys/soundcard.h:
@echo "WARNING! Your /usr/include/sys/soundcard.h not found."
- @echo "Please make a new /usr/include/sys/soundcard.h containing
+ @echo "Please make a new /usr/include/sys/soundcard.h containing"
@echo "just a line #include <linux/soundcard.h>"
sound.a: $(OBJS)
diff --git a/drivers/sound/sb_dsp.c b/drivers/sound/sb_dsp.c
index e66fe32..d6297e5 100644
--- a/drivers/sound/sb_dsp.c
+++ b/drivers/sound/sb_dsp.c
@@ -682,7 +682,7 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
sb_mixer_init(major);
#endif
-#ifndef EXCLUDE_YM8312
+#ifndef EXCLUDE_YM3812
if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */
{
enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
diff --git a/fs/ext2/CHANGES b/fs/ext2/CHANGES
new file mode 100644
index 0000000..258bf23
--- /dev/null
+++ b/fs/ext2/CHANGES
@@ -0,0 +1,92 @@
+Changes from version 0.4a to version 0.4b
+=========================================
+ - Copyrights changed to include the name of my laboratory.
+ - Clean up of balloc.c and ialloc.c.
+ - More consistency checks.
+ - Block preallocation added by Stephen Tweedie.
+ - Direct reads of directories disallowed if CONFIG_EXT2_FS_DIR_READ not
+ defined.
+ - Readahead implemented in readdir by Stephen Tweedie.
+ - Bugs in block and inodes allocation fixed.
+ - Readahead implemented in ext2_find_entry by Chip Salzenberg.
+ - New mount options:
+ `check=none|normal|strict'
+ `debug'
+ `errors=continue|remount-ro|panic'
+ `grpid', `bsdgroups'
+ `nocheck'
+ `nogrpid', `sysvgroups'
+ - truncate() now tries to deallocate contigous blocks in a single call
+ to ext2_free_blocks().
+ - lots of cosmetic changes.
+
+Changes from version 0.4 to version 0.4a
+========================================
+ - the `sync' option support is now complete. Version 0.4 was not
+ supporting it when truncating a file. I have tested the synchronous
+ writes and they work but they make the system very slow :-( I have
+ to work again on this to make it faster.
+ - when detecting an error on a mounted filesystem, version 0.4 used
+ to try to write a flag in the super block even if the filesystem had
+ been mounted read-only. This is fixed.
+ - the `sb=#' option now causes the kernel code to use the filesystem
+ descriptors located at block #+1. Version 0.4 used the superblock
+ backup located at block # but used the main copy of the descriptors.
+ - a new file attribute `S' is supported. This attribute causes
+ synchronous writes but is applied to a file not to the entire file
+ system (thanks to Michael Kraehe <kraehe@bakunin.north.de> for
+ suggesting it).
+ - the directory cache is inhibited by default. The cache management
+ code seems to be buggy and I have to look at it carefully before
+ using it again.
+ - deleting a file with the `s' attribute (secure deletion) causes its
+ blocks to be overwritten with random values not with zeros (thanks to
+ Michael A. Griffith <grif@cs.ucr.edu> for suggesting it).
+ - lots of cosmetic changes have been made.
+
+Changes from version 0.3 to version 0.4
+=======================================
+ - Three new mount options are supported: `check', `sync' and `sb=#'.
+ `check' tells the kernel code to make more consistency checks
+ when the file system is mounted. Currently, the kernel code checks
+ that the blocks and inodes bitmaps are consistent with the free
+ blocks and inodes counts. More checks will be added in future
+ releases.
+ `sync' tells the kernel code to use synchronous writes when updating
+ an inode, a bitmap, a directory entry or an indirect block. This
+ can make the file system much slower but can be a big win for files
+ recovery in case of a crash (and we can now say to the BSD folks
+ that Linux also supports synchronous updates :-).
+ `sb=#' tells the kernel code to use an alternate super block instead
+ of its master copy. `#' is the number of the block (counted in
+ 1024 bytes blocks) which contains the alternate super block.
+ An ext2 file system typically contains backups of the super block
+ at blocks 8193, 16385, and so on.
+ - I have change the meaning of the valid flag used by e2fsck. it
+ now contains the state of the file system. If the kernel code
+ detects an inconsistency while the file system is mounted, it flags
+ it as erroneous and e2fsck will detect that on next run.
+ - The super block now contains a mount counter. This counter is
+ incremented each time the file system is mounted read/write. When
+ this counter becomes bigger than a maximal mount counts (also stored
+ in the super block), e2fsck checks the file system, even if it had
+ been unmounted cleany, and resets this counter to 0.
+ - File attributes are now supported. One can associate a set of
+ attributes to a file. Three attributes are defined:
+ `c': the file is marked for automatic compression,
+ `s': the file is marked for secure deletion: when the file is
+ deleted, its blocks are zeroed and written back to the disk,
+ `u': the file is marked for undeletion: when the file is deleted,
+ its contents are saved to allow a future undeletion.
+ Currently, only the `s' attribute is implemented in the kernel
+ code. Support for the other attributes will be added in a future
+ release.
+ - a few bugs related to times updates have been fixed by Bruce
+ Evans and me.
+ - a bug related to the links count of deleted inodes has been fixed.
+ Previous versions used to keep the links count set to 1 when a file
+ was deleted. The new version now sets links_count to 0 when deleting
+ the last link.
+ - a race condition when deallocating an inode has been fixed by
+ Stephen Tweedie.
+
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 96d0ab1..984e574 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -462,7 +462,7 @@ repeat:
EXT2_BLOCKS_PER_GROUP(sb));
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
ext2_error (sb, "ext2_new_block",
- "Unable to locate free bit in block group %d", i);
+ "Free blocks count corrupted for block group %d", i);
unlock_super (sb);
return 0;
}
@@ -486,8 +486,8 @@ got_block:
tmp == gdp->bg_inode_bitmap ||
in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group)))
ext2_panic (sb, "ext2_new_block",
- "Allocating block in system zone\nblock = %u",
- tmp);
+ "Allocating block in system zone\n"
+ "block = %u", tmp);
if (set_bit (j, bh->b_data)) {
ext2_warning (sb, "ext2_new_block",
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index d44856b..de2144a 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -410,7 +410,7 @@ repeat:
/*
* That failed: try linear search for a free inode
*/
- i = dir->u.ext2_i.i_block_group + 2;
+ i = dir->u.ext2_i.i_block_group + 1;
for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
if (++i >= sb->u.ext2_sb.s_groups_count)
i = 0;
@@ -443,8 +443,17 @@ repeat:
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- } else
+ } else {
+ if (gdp->bg_free_inodes_count != 0) {
+ ext2_error (sb, "ext2_new_inode",
+ "Free inodes count corrupted in group %d",
+ i);
+ unlock_super (sb);
+ iput (inode);
+ return NULL;
+ }
goto repeat;
+ }
j += i * EXT2_INODES_PER_GROUP(sb) + 1;
if (j < EXT2_FIRST_INO || j > es->s_inodes_count) {
ext2_error (sb, "ext2_new_inode",
@@ -467,9 +476,13 @@ repeat:
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->euid;
- if ((dir->i_mode & S_ISGID) || test_opt (sb, GRPID))
+ if (test_opt (sb, GRPID))
+ inode->i_gid = dir->i_gid;
+ else if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
- else
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ } else
inode->i_gid = current->egid;
inode->i_dirt = 1;
inode->i_ino = j;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index bbc1e52..3f0230e 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -299,7 +299,7 @@ repeat:
}
}
if (!goal)
- goal = bh->b_blocknr + 1;
+ goal = bh->b_blocknr;
}
tmp = ext2_alloc_block (inode, goal);
if (!tmp) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 766179f..d04caea 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -233,13 +233,15 @@ static int parse_options (char * options, unsigned long * sb_block,
return 0;
}
}
- else if (!strcmp (this_char, "grpid"))
+ else if (!strcmp (this_char, "grpid") ||
+ !strcmp (this_char, "bsdgroups"))
set_opt (*mount_options, GRPID);
else if (!strcmp (this_char, "nocheck")) {
clear_opt (*mount_options, CHECK_NORMAL);
clear_opt (*mount_options, CHECK_STRICT);
}
- else if (!strcmp (this_char, "nogrpid"))
+ else if (!strcmp (this_char, "nogrpid") ||
+ !strcmp (this_char, "sysvgroups"))
clear_opt (*mount_options, GRPID);
else if (!strcmp (this_char, "sb")) {
if (!value || !*value) {
@@ -271,7 +273,8 @@ static void ext2_setup_super (struct super_block * sb,
else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
printk ("EXT2-fs warning: mounting fs with errors, "
"running e2fsck is recommended\n");
- else if (es->s_mnt_count >= es->s_max_mnt_count)
+ else if (es->s_max_mnt_count >= 0 &&
+ es->s_mnt_count >= es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n");
if (!(sb->s_flags & MS_RDONLY)) {
@@ -390,8 +393,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
unlock_super (sb);
brelse (bh);
if (!silent)
- printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
- dev);
+ printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n",
+ MAJOR(dev), MINOR(dev));
return NULL;
}
sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
@@ -477,8 +480,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
unlock_super (sb);
brelse (bh);
if (!silent)
- printk ("VFS: Can't find an ext2 filesystem on dev 0x%04x.\n",
- dev);
+ printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n",
+ MAJOR(dev), MINOR(dev));
return NULL;
}
if (sb->s_blocksize != bh->b_size) {
@@ -522,7 +525,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
sb->s_dev = 0;
unlock_super (sb);
for (j = 0; j < i; j++)
- brelse (sb->u.ext2_sb.s_group_desc[i]);
+ brelse (sb->u.ext2_sb.s_group_desc[j]);
brelse (bh);
printk ("EXT2-fs: unable to read group descriptors\n");
return NULL;
@@ -532,7 +535,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
sb->s_dev = 0;
unlock_super (sb);
for (j = 0; j < i; j++)
- brelse (sb->u.ext2_sb.s_group_desc[i]);
+ brelse (sb->u.ext2_sb.s_group_desc[j]);
brelse (bh);
printk ("EXT2-fs: group descriptors corrupted !\n");
return NULL;
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index aa366c7..cc28496 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -46,6 +46,8 @@ static int trunc_direct (struct inode * inode)
int i, tmp;
unsigned long * p;
struct buffer_head * bh;
+ unsigned long block_to_free = 0;
+ unsigned long free_count = 0;
int retry = 0;
int blocks = inode->i_sb->s_blocksize / 512;
#define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
@@ -82,8 +84,20 @@ repeat:
bh->b_dirt = 1;
}
brelse (bh);
- ext2_free_blocks (inode->i_sb, tmp, 1);
+ if (free_count == 0) {
+ block_to_free = tmp;
+ free_count++;
+ } else if (free_count > 0 && block_to_free == tmp - free_count)
+ free_count++;
+ else {
+ ext2_free_blocks (inode->i_sb, block_to_free, free_count);
+ block_to_free = tmp;
+ free_count = 1;
+ }
+/* ext2_free_blocks (inode->i_sb, tmp, 1); */
}
+ if (free_count > 0)
+ ext2_free_blocks (inode->i_sb, block_to_free, free_count);
return retry;
}
@@ -93,6 +107,8 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
struct buffer_head * bh;
struct buffer_head * ind_bh;
unsigned long * ind;
+ unsigned long block_to_free = 0;
+ unsigned long free_count = 0;
int retry = 0;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int blocks = inode->i_sb->s_blocksize / 512;
@@ -144,10 +160,22 @@ repeat:
bh->b_dirt = 1;
}
brelse (bh);
- ext2_free_blocks (inode->i_sb, tmp, 1);
+ if (free_count == 0) {
+ block_to_free = tmp;
+ free_count++;
+ } else if (free_count > 0 && block_to_free == tmp - free_count)
+ free_count++;
+ else {
+ ext2_free_blocks (inode->i_sb, block_to_free, free_count);
+ block_to_free = tmp;
+ free_count = 1;
+ }
+/* ext2_free_blocks (inode->i_sb, tmp, 1); */
inode->i_blocks -= blocks;
inode->i_dirt = 1;
}
+ if (free_count > 0)
+ ext2_free_blocks (inode->i_sb, block_to_free, free_count);
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(ind++))
diff --git a/fs/super.c b/fs/super.c
index dbbfb67..e0b23bc 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -486,6 +486,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
return retval;
}
}
+ page = 0;
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 2888383..3c384b1 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -52,7 +52,7 @@
/*
* The second extended file system version
*/
-#define EXT2FS_DATE "93/12/30"
+#define EXT2FS_DATE "94/01/05"
#define EXT2FS_VERSION "0.4b"
/*
@@ -289,7 +289,7 @@ struct ext2_super_block {
unsigned long s_mtime; /* Mount time */
unsigned long s_wtime; /* Write time */
unsigned short s_mnt_count; /* Mount count */
- unsigned short s_max_mnt_count; /* Maximal mount count */
+ short s_max_mnt_count; /* Maximal mount count */
unsigned short s_magic; /* Magic signature */
unsigned short s_state; /* File system state */
unsigned short s_errors; /* Behaviour when detecting errors */
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 26d4a59..887b2cb 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -59,6 +59,8 @@ struct options {
unsigned short handling;
unsigned short stream;
unsigned tcc;
+ int option_length;
+ void *option_data;
};
diff --git a/include/linux/kd.h b/include/linux/kd.h
index 5db5a5f..d751504 100644
--- a/include/linux/kd.h
+++ b/include/linux/kd.h
@@ -184,4 +184,14 @@ struct kbsentry {
#define KDGKBSENT 0x4B48 /* gets one function key string entry */
#define KDSKBSENT 0x4B49 /* sets one function key string entry */
+struct kbdiacr {
+ u_char diacr, base, result;
+};
+struct kbdiacrs {
+ unsigned int kb_cnt; /* number of entries in following array */
+ struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */
+};
+#define KDGKBDIACR 0x4B4A /* read kernel accent table */
+#define KDSKBDIACR 0x4B4B /* write kernel accent table */
+
#endif /* _LINUX_KD_H */
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 8b0fcab..9b34bcd 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -5,19 +5,6 @@
#define set_leds() mark_bh(KEYBOARD_BH)
/*
- * "dead" keys - prefix key values that are valid only for the next
- * character code (sticky shift, E0/E1 special scancodes, diacriticals)
- */
-extern unsigned long kbd_dead_keys;
-extern unsigned long kbd_prev_dead_keys;
-
-/*
- * these are the hardcoded dead key flags
- */
-#define KGD_E0 0
-#define KGD_E1 1
-
-/*
* kbd->xxx contains the VC-local things (flag settings etc..)
* The low 3 local flags are hardcoded to be the led setting..
*/
@@ -52,26 +39,6 @@ extern struct kbd_struct kbd_table[];
extern unsigned long kbd_init(unsigned long);
-extern inline int kbd_dead(int flag)
-{
- return kbd_prev_dead_keys & (1 << flag);
-}
-
-extern inline void set_kbd_dead(int flag)
-{
- kbd_dead_keys |= 1 << flag;
-}
-
-extern inline void clr_kbd_dead(int flag)
-{
- kbd_dead_keys &= ~(1 << flag);
-}
-
-extern inline void chg_kbd_dead(int flag)
-{
- kbd_dead_keys ^= 1 << flag;
-}
-
extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag)
{
return ((kbd->flags >> flag) & 1);
@@ -98,7 +65,7 @@ extern const int NR_TYPES;
extern const int max_vals[];
extern unsigned short key_map[NR_KEYMAPS][NR_KEYS];
-#define NR_FUNC 32
+#define NR_FUNC 36
#define FUNC_BUFSIZE 512
extern char func_buf[FUNC_BUFSIZE];
extern char *func_table[NR_FUNC];
@@ -145,6 +112,10 @@ extern char *func_table[NR_FUNC];
#define K_SELECT K(KT_FN,23)
#define K_PGUP K(KT_FN,24)
#define K_PGDN K(KT_FN,25)
+#define K_MACRO K(KT_FN,26)
+#define K_HELP K(KT_FN,27)
+#define K_DO K(KT_FN,28)
+#define K_PAUSE K(KT_FN,29)
#define K_HOLE K(KT_SPEC,0)
#define K_ENTER K(KT_SPEC,1)
@@ -160,6 +131,7 @@ extern char *func_table[NR_FUNC];
#define K_SCROLLBACK K(KT_SPEC,11)
#define K_BOOT K(KT_SPEC,12)
#define K_CAPSON K(KT_SPEC,13)
+#define K_COMPOSE K(KT_SPEC,14)
#define K_P0 K(KT_PAD,0)
#define K_P1 K(KT_PAD,1)
@@ -178,6 +150,7 @@ extern char *func_table[NR_FUNC];
#define K_PENTER K(KT_PAD,14) /* key-pad enter */
#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */
#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */
+#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */
#define K_DGRAVE K(KT_DEAD,0)
#define K_DACUTE K(KT_DEAD,1)
@@ -220,4 +193,5 @@ extern char *func_table[NR_FUNC];
#define K_ALTLOCK K(KT_LOCK,3)
#define K_ALTGRLOCK K(KT_LOCK,1)
+#define MAX_DIACR 256
#endif
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 4e5fdbd..e6a520b 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -30,10 +30,14 @@ struct linger {
#define AF_UNSPEC 0
#define AF_UNIX 1
#define AF_INET 2
+#define AF_AX25 3
+#define AF_IPX 4
/* Protocol families, same as address families. */
#define PF_UNIX AF_UNIX
#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
/* Flags we can use with send/ and recv. */
#define MSG_OOB 1
@@ -41,6 +45,10 @@ struct linger {
/* Setsockoptions(2) level. */
#define SOL_SOCKET 1
+#define SOL_IP 2
+#define SOL_IPX 3
+#define SOL_AX25 4
+#define SOL_TCP 5
/* For setsockoptions(2) */
#define SO_DEBUG 1
@@ -56,6 +64,19 @@ struct linger {
#define SO_NO_CHECK 11
#define SO_PRIORITY 12
#define SO_LINGER 13
+/* IP options */
+#define IP_TOS 1
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IP_TTL 2
+/* IPX options */
+#define IPX_TYPE 1
+/* AX.25 options */
+#define AX25_WINDOW 1
+/* TCP options */
+#define TCP_MSS 1
+#define TCP_NODELAY 2
/* The various priorities. */
#define SOPRI_INTERACTIVE 0
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index 499b219..4484b14 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -24,11 +24,11 @@
#define IP_SET_DEV 0x2401
struct ip_config {
- char name[MAX_IP_NAME];
- unsigned long paddr;
- unsigned long router;
- unsigned long net;
- unsigned int up:1,destroy:1;
+ char name[MAX_IP_NAME];
+ unsigned long paddr;
+ unsigned long router;
+ unsigned long net;
+ unsigned int up:1,destroy:1;
};
#endif /* FIXME: */
diff --git a/kernel/module.c b/kernel/module.c
index e949327..2e38de5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -149,7 +149,9 @@ sys_get_kernel_syms(struct kernel_sym *table)
if (table != NULL) {
from = symbol_table;
to = table;
- verify_area(VERIFY_WRITE, to, symbol_table_size * sizeof *table);
+ i = verify_area(VERIFY_WRITE, to, symbol_table_size * sizeof *table);
+ if (i)
+ return i;
for (i = symbol_table_size ; --i >= 0 ; ) {
sym.value = from->addr;
strncpy(sym.name, from->name, sizeof sym.name);
diff --git a/net/Makefile b/net/Makefile
index 6478d1e..8299a0e 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -7,10 +7,17 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-# only these two lines should need to be changed to remove inet sockets.
-# (and the inet/tcpip.o in net.o)
+SUBDIRS := unix socket
-SUBDIRS := unix inet
+ifdef CONFIG_INET
+SUBDIRS := $(SUBDIRS) inet
+endif
+ifdef CONFIG_IPX
+SUBDIRS := $(SUBDIRS) ipx
+endif
+ifdef CONFIG_AX25
+SUBDIRS := $(SUBDIRS) ax25
+endif
SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o)
diff --git a/net/Space.c b/net/Space.c
index b2cc011..5c90082 100644
--- a/net/Space.c
+++ b/net/Space.c
@@ -30,10 +30,10 @@
# include "inet/inet.h"
#endif
#ifdef CONFIG_IPX
-#include "inet/ipxcall.h"
+#include "ipx/ipxcall.h"
#endif
#ifdef CONFIG_AX25
-#include "inet/ax25call.h"
+#include "ax25/ax25call.h"
#endif
struct ddi_proto protocols[] = {
@@ -53,43 +53,3 @@ struct ddi_proto protocols[] = {
};
-/*
- * Section B: Device Driver Modules.
- * This section defines which network device drivers
- * get linked into the Linux kernel. It is currently
- * only used by the INET protocol. Any takers for the
- * other protocols like XNS or Novell?
- *
- * WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!!
- */
-/*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */
-/*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */
-/*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */
-
-
-struct ddi_device devices[] = {
-#if CONF_WE8003
- { "WD80x3[EBT]",
- "", 0, 1, we8003_init, NULL,
- 19, 0, DDI_FCHRDEV,
- { 0x280, 0, 15, 0, 32768, 0xD0000 } },
-#endif
-#if CONF_DP8390
- { "DP8390/WD80x3",
- "", 0, 1, dpwd8003_init, NULL,
- 20, 0, DDI_FCHRDEV,
- { 0, 0, 0, 0, 0, 0, } },
- { "DP8390/NE-x000",
- "", 0, 1, dpne2000_init, NULL,
- 20, 8, DDI_FCHRDEV,
- { 0, 0, 0, 0, 0, 0, } },
- { "DP8390/3C50x",
- "", 0, 1, dpec503_init, NULL,
- 20, 16, DDI_FCHRDEV,
- { 0, 0, 0, 0, 0, 0, } },
-#endif
- { NULL,
- "", 0, 0, NULL, NULL,
- 0, 0, 0,
- { 0, 0, 0, 0, 0, 0 } }
-};
diff --git a/net/ddi.c b/net/ddi.c
index 7ebd3bf..79bcb00 100644
--- a/net/ddi.c
+++ b/net/ddi.c
@@ -4,9 +4,11 @@
* but it eventually might move to an upper directory of
* the system.
*
- * Version: @(#)ddi.c 1.0.5 04/22/93
+ * Version: @(#)ddi.c 1.28 27/12/93
*
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * Unused pieces nobbled.
*/
#include <asm/segment.h>
#include <asm/system.h>
@@ -18,6 +20,9 @@
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/ddi.h>
+#include <linux/interrupt.h>
+
+#include "socket/dev.h"
#undef DDI_DEBUG
@@ -28,64 +33,32 @@
#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;
+ struct ddi_proto *pro;
- PRINTK (("DDI: Starting up!\n"));
+ PRINTK (("DDI: Starting up!\n"));
- /* First off, kick all configured protocols. */
- pro = protocols;
- while (pro->name != NULL) {
- (*pro->init)(pro);
- pro++;
- }
+ /* First off, kick all configured protocols. */
+ pro = protocols;
+ while (pro->name != NULL)
+ {
+ (*pro->init)(pro);
+ pro++;
+ }
- /* Done. Now kick all configured device drivers. */
- dev = devices;
- while (dev->title != NULL) {
- (*dev->init)(dev);
- dev++;
- }
-
- /* We're all done... */
-}
+ dev_init();
+ /* Initialize the "Buffer Head" pointers. */
+ bh_base[INET_BH].routine = inet_bh;
+
+ /* We're all done... */
+}
diff --git a/net/inet/Makefile b/net/inet/Makefile
index a10caa3..4c1aa76 100644
--- a/net/inet/Makefile
+++ b/net/inet/Makefile
@@ -7,6 +7,9 @@
#
# 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:
@@ -15,10 +18,8 @@
$(CC) $(CFLAGS) -S -o $*.s $<
-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
+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
ifdef CONFIG_INET
diff --git a/net/inet/README b/net/inet/README
index 79f957f..f216f16 100644
--- a/net/inet/README
+++ b/net/inet/README
@@ -1,27 +1,8 @@
-NET2Debugged 1.24 README
+NET2Debugged 1.28 README
------------------------
-Major Changes
-
-o PLIP driver sort of works
-o UDP and RAW have been partially rewritten for speed
-o Internals heavily cleaned up, and memory monitoring of network
- memory is now done. (On shift-scroll-lock)
-o ARP should now not generate garbage
-o Using MSG_PEEK can't cause race conditions and crashes
-o Support for bootp clients.
-o Supports RFC931 TAP authd
-o NFS problems with certain types of network configuration are
- fixed.
-o Doesn't forward packets for other subnet (can cause packet storms)
-o TCP won't ack rst frames causing packet storms (especially with
- Lan workplace for DOS).
-o Numerous fixes for solidity
-o Verify_area used properly.
-o MSG_PEEK is faster again
-o Minor TCP fixes. Hopefully no more TCP lockups (ha!)
-o Donald's promiscuous mode. Go forth and write protocol analysers...
+
-------------------------------------------------------------------------
NOTE:
Drivers for this stack set must be using alloc_skb() not just
diff --git a/net/inet/arp.c b/net/inet/arp.c
index 0b69e1f..c272817 100644
--- a/net/inet/arp.c
+++ b/net/inet/arp.c
@@ -13,7 +13,7 @@
* resolver, like it should be. It will be put in a separate
* directory under 'net', being a protocol of its own. -FvK
*
- * Version: @(#)arp.c 1.0.15 05/25/93
+ * Version: @(#)arp.c 1.28 20/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -36,6 +36,11 @@
* 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
@@ -64,52 +69,27 @@
#include <asm/segment.h>
#include <stdarg.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "eth.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.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
-
-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]))
-
-
+/*
+ * The ARP table itself
+ */
+
struct arp_table *arp_tables[ARP_TABLE_SIZE] = {
NULL,
};
@@ -118,103 +98,43 @@ 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);
-/* 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));
-}
-
+/*
+ * 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.
+ */
-/* This will try to retransmit everything on the queue. */
-static void
-arp_send_q(void)
+static void arp_send_q(void)
{
- struct sk_buff *skb;
- struct sk_buff *volatile work_q;
- cli();
- work_q = arp_q;
- skb_new_list_head(&work_q);
- arp_q = NULL;
- sti();
- while((skb=skb_dequeue(&work_q))!=NULL)
- {
- IS_SKB(skb);
- skb->magic = 0;
- skb->next = NULL;
- skb->prev = NULL;
-
- /* Decrement the 'tries' counter. */
+ struct sk_buff *skb;
+ struct sk_buff *volatile work_q;
cli();
- skb->tries--;
- if (skb->tries == 0) {
+ work_q = arp_q;
+ skb_new_list_head(&work_q);
+ arp_q = NULL;
+ sti();
+ while((skb=skb_dequeue(&work_q))!=NULL)
+ {
+ IS_SKB(skb);
+ skb->magic = 0; /* So everyone knows this is _NOT_ on the arp queue */
+
+ /* Decrement the 'tries' counter. */
+ cli();
+ skb->tries--;
+ if (skb->tries == 0)
+ {
/*
* Grmpf.
* We have tried ARP_MAX_TRIES to resolve the IP address
@@ -224,231 +144,270 @@ arp_send_q(void)
* In any case, trying further is useless. So, we kill
* this packet from the queue. (grinnik) -FvK
*/
- skb->sk = NULL;
- if(skb->free)
- kfree_skb(skb, FREE_WRITE);
+ skb->sk = NULL;
+ if(skb->free)
+ kfree_skb(skb, FREE_WRITE);
/* If free was 0, magic is now 0, next is 0 and
the write queue will notice and kill */
- sti();
- continue;
- }
+ sti();
+ continue;
+ }
- /* Can we now complete this packet? */
- sti();
- if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev)) {
- skb->arp = 1;
- skb->dev->queue_xmit(skb, skb->dev, 0);
- } else {
- /* Alas. Re-queue it... */
- skb->magic = ARP_QUEUE_MAGIC;
- skb_queue_head(&arp_q,skb);
- }
- }
+ /* Can we now complete this packet? */
+ sti();
+ if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev))
+ {
+ skb->arp = 1;
+ skb->dev->queue_xmit(skb, skb->dev, 0);
+ }
+ else
+ {
+ /* Alas. Re-queue it... */
+ skb->magic = ARP_QUEUE_MAGIC;
+ skb_queue_head(&arp_q,skb);
+ }
+ }
}
-/* Create and send our response to an ARP request. */
-static int
-arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
+/*
+ * Create and send our response to an ARP request.
+ */
+
+static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
{
- struct arphdr *arp2;
- struct sk_buff *skb;
- unsigned long src, dst;
- unsigned char *ptr1, *ptr2;
- int hlen;
- struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */
-
- /* Decode the source (REQUEST) message. */
- ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short);
- src = *((unsigned long *) (ptr1 + arp1->ar_hln));
- dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln));
+ struct arphdr *arp2;
+ struct sk_buff *skb;
+ unsigned long src, dst;
+ unsigned char *ptr1, *ptr2;
+ int hlen;
+ struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */
+
+ /* Decode the source (REQUEST) message. */
+ ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short);
+ src = *((unsigned long *) (ptr1 + arp1->ar_hln));
+ dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln));
- if(addrtype!=IS_MYADDR)
- {
- apt=arp_lookup_proxy(dst);
- if(apt==NULL)
- return(1);
- }
-
- /* Get some mem and initialize it for the return trip. */
- skb = alloc_skb(sizeof(struct sk_buff) +
+ if(addrtype!=IS_MYADDR)
+ {
+ apt=arp_lookup_proxy(dst);
+ if(apt==NULL)
+ return(1);
+ }
+
+ /* Get some mem and initialize it for the return trip. */
+ skb = alloc_skb(sizeof(struct sk_buff) +
sizeof(struct arphdr) +
(2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
dev->hard_header_len, GFP_ATOMIC);
- if (skb == NULL) {
- printk("ARP: no memory available for ARP REPLY!\n");
- return(1);
- }
-
- skb->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,
+
+ if (skb == NULL)
+ {
+ printk("ARP: no memory available for ARP REPLY!\n");
+ return(1);
+ }
+
+ skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
+ (2 * arp1->ar_pln) + dev->hard_header_len;
+ hlen = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, src, dst, skb->len);
- if (hlen < 0) {
- printk("ARP: cannot create HW frame header for REPLY !\n");
- kfree_skb(skb, FREE_WRITE);
- return(1);
- }
+ if (hlen < 0)
+ {
+ printk("ARP: cannot create HW frame header for REPLY !\n");
+ kfree_skb(skb, FREE_WRITE);
+ return(1);
+ }
/*
* Fill in the ARP REPLY packet.
* This looks ugly, but we have to deal with the variable-length
* ARP packets and such. It is not as bad as it looks- FvK
*/
- arp2 = (struct arphdr *) ((unsigned char *) (skb+1) + hlen);
- ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short);
- arp2->ar_hrd = arp1->ar_hrd;
- arp2->ar_pro = arp1->ar_pro;
- arp2->ar_hln = arp1->ar_hln;
- arp2->ar_pln = arp1->ar_pln;
- arp2->ar_op = htons(ARPOP_REPLY);
- if(addrtype==IS_MYADDR)
- memcpy(ptr2, dev->dev_addr, arp2->ar_hln);
- else /* Proxy arp, so pull from the table */
- memcpy(ptr2, apt->ha, arp2->ar_hln);
- ptr2 += arp2->ar_hln;
- memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);
- ptr2 += arp2->ar_pln;
- memcpy(ptr2, ptr1, arp2->ar_hln);
- ptr2 += arp2->ar_hln;
- memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln);
-
- skb->free = 1;
- skb->arp = 1;
- skb->sk = NULL;
- skb->next = NULL;
-
- DPRINTF((DBG_ARP, ">>"));
- arp_print(arp2);
-
- /* Queue the packet for transmission. */
- dev->queue_xmit(skb, dev, 0);
- return(0);
+ arp2 = (struct arphdr *) ((unsigned char *) (skb+1) + hlen);
+ ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short);
+ arp2->ar_hrd = arp1->ar_hrd;
+ arp2->ar_pro = arp1->ar_pro;
+ arp2->ar_hln = arp1->ar_hln;
+ arp2->ar_pln = arp1->ar_pln;
+ arp2->ar_op = htons(ARPOP_REPLY);
+
+ if(addrtype==IS_MYADDR)
+ memcpy(ptr2, dev->dev_addr, arp2->ar_hln);
+ else /* Proxy arp, so pull from the table */
+ memcpy(ptr2, apt->ha, arp2->ar_hln);
+
+ ptr2 += arp2->ar_hln;
+ memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);
+ ptr2 += arp2->ar_pln;
+ memcpy(ptr2, ptr1, arp2->ar_hln);
+ ptr2 += arp2->ar_hln;
+ memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln);
+
+ skb->free = 1;
+ skb->arp = 1;
+ skb->sk = NULL;
+ skb->next = NULL;
+
+ /* Queue the packet for transmission. */
+ dev->queue_xmit(skb, dev, 0);
+ return(0);
}
-/* This will find an entry in the ARP table by looking at the IP address. */
-static struct arp_table *
-arp_lookup(unsigned long paddr)
+/*
+ * This will find an entry in the ARP table by looking at the IP address.
+ */
+
+static struct arp_table *arp_lookup(unsigned long paddr)
{
- struct arp_table *apt;
- unsigned long hash;
-
- DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));
-
- /* We don't want to ARP ourselves. */
- if (chk_addr(paddr) == IS_MYADDR) {
- printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr));
- return(NULL);
- }
-
- /* Loop through the table for the desired address. */
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
- cli();
- apt = arp_tables[hash];
- while(apt != NULL) {
- if (apt->ip == paddr) {
- sti();
- return(apt);
- }
- apt = apt->next;
- }
- sti();
- return(NULL);
+ struct arp_table *apt;
+ unsigned long hash;
+
+ DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));
+
+ /* We don't want to ARP ourselves. */
+ if (chk_addr(paddr) == IS_MYADDR)
+ {
+ printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr));
+ return(NULL);
+ }
+
+ /* Loop through the table for the desired address. */
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+ cli();
+ apt = arp_tables[hash];
+ while(apt != NULL)
+ {
+ if (apt->ip == paddr)
+ {
+ sti();
+ return(apt);
+ }
+ apt = apt->next;
+ }
+ sti();
+ return(NULL);
}
-/* This will find a proxy in the ARP table by looking at the IP address. */
+/*
+ * This will find a proxy in the ARP table by looking at the IP address.
+ */
+
static struct arp_table *arp_lookup_proxy(unsigned long paddr)
{
- struct arp_table *apt;
- unsigned long hash;
+ struct arp_table *apt;
+ unsigned long hash;
- DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr)));
- /* Loop through the table for the desired address. */
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
- cli();
- apt = arp_tables[hash];
- while(apt != NULL) {
- if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) {
- sti();
- return(apt);
- }
- apt = apt->next;
- }
- sti();
- return(NULL);
+ /* Loop through the table for the desired address. */
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+ cli();
+ apt = arp_tables[hash];
+ while(apt != NULL)
+ {
+ if (apt->ip == paddr && (apt->flags & ATF_PUBL) )
+ {
+ sti();
+ return(apt);
+ }
+ apt = apt->next;
+ }
+ sti();
+ return(NULL);
}
-/* Delete an ARP mapping entry in the cache. */
-void
-arp_destroy(unsigned long paddr)
+/*
+ * Delete an ARP mapping entry in the cache.
+ */
+
+static void arp_destructor(unsigned long paddr, int force)
{
- struct arp_table *apt;
- struct arp_table **lapt;
- unsigned long hash;
+ struct arp_table *apt;
+ struct arp_table **lapt;
+ unsigned long hash;
- DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr)));
- /* We cannot destroy our own ARP entry. */
- if (chk_addr(paddr) == IS_MYADDR) {
- DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n",
+ /* We cannot destroy our own ARP entry. */
+ if (chk_addr(paddr) == IS_MYADDR)
+ {
+ DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n",
in_ntoa(paddr)));
- return;
- }
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
-
- cli();
- lapt = &arp_tables[hash];
- while ((apt = *lapt) != NULL) {
- if (apt->ip == paddr) {
- *lapt = apt->next;
- if(apt->flags&ATF_PUBL)
- arp_proxies--;
- kfree_s(apt, sizeof(struct arp_table));
- sti();
return;
}
- lapt = &apt->next;
- }
- sti();
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+
+ cli();
+ lapt = &arp_tables[hash];
+ while ((apt = *lapt) != NULL)
+ {
+ if (apt->ip == paddr)
+ {
+ if((apt->flags&ATF_PERM) && !force)
+ return;
+ *lapt = apt->next;
+ if(apt->flags&ATF_PUBL)
+ arp_proxies--;
+ kfree_s(apt, sizeof(struct arp_table));
+ sti();
+ return;
+ }
+ lapt = &apt->next;
+ }
+ sti();
}
+/*
+ * Kill an entry - eg for ioctl()
+ */
-/* 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)
+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)
{
- struct arp_table *apt;
- unsigned long hash;
-
- DPRINTF((DBG_ARP, "ARP: create(%s, ", in_ntoa(paddr)));
- DPRINTF((DBG_ARP, "%s, ", eth_print(addr)));
- DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype));
-
- apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
- if (apt == NULL) {
- printk("ARP: no memory available for new ARP entry!\n");
- return(NULL);
- }
-
- /* Fill in the allocated ARP cache entry. */
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
- apt->ip = paddr;
- apt->hlen = hlen;
- apt->htype = htype;
- apt->flags = (ATF_INUSE | ATF_COM); /* USED and COMPLETED entry */
- memcpy(apt->ha, addr, hlen);
- apt->last_used = jiffies;
- cli();
- apt->next = arp_tables[hash];
- arp_tables[hash] = apt;
- sti();
- return(apt);
+ arp_destructor(paddr,0);
+}
+
+/*
+ * Create an ARP entry. The caller should check for duplicates!
+ */
+
+static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
+{
+ struct arp_table *apt;
+ unsigned long hash;
+
+
+ apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
+ if (apt == NULL)
+ {
+ printk("ARP: no memory available for new ARP entry!\n");
+ return(NULL);
+ }
+
+ /* Fill in the allocated ARP cache entry. */
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+ apt->ip = paddr;
+ apt->hlen = hlen;
+ apt->htype = htype;
+ apt->flags = (ATF_INUSE | ATF_COM); /* USED and COMPLETED entry */
+ memcpy(apt->ha, addr, hlen);
+ apt->last_used = jiffies;
+ cli();
+ apt->next = arp_tables[hash];
+ arp_tables[hash] = apt;
+ sti();
+ return(apt);
}
@@ -461,281 +420,295 @@ arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
* one of our own IP addresses), we set up and send out an ARP REPLY
* packet to the sender.
*/
-int
-arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- struct arphdr *arp;
- struct arp_table *tbl;
- unsigned long src, dst;
- unsigned char *ptr;
- int ret;
- int addr_hint;
-
- DPRINTF((DBG_ARP, "<<\n"));
- arp = skb->h.arp;
- arp_print(arp);
-
- /* If this test doesn't pass, its not IP. Might be DECNET or friends */
- if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
- {
- DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name));
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- /* For now we will only deal with IP addresses. */
- if (((arp->ar_pro != NET16(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4)
- {
- if (arp->ar_op != NET16(ARPOP_REQUEST))
- DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name));
- kfree_skb(skb, FREE_READ);
- return(0);
- }
+ struct arphdr *arp;
+ struct arp_table *tbl;
+ unsigned long src, dst;
+ unsigned char *ptr;
+ int ret;
+ int addr_hint;
+
+ arp = skb->h.arp;
+
+ /* If this test doesn't pass, its not IP. Might be DECNET or friends */
+ if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
+ {
+ DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name));
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
- /*
- * As said before, we try to be smart by using the
- * info already present in the packet: the sender's
- * IP and hardware address.
- */
- ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
- memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);
- tbl = arp_lookup(src);
- if (tbl != NULL) {
- DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));
- memcpy(tbl->ha, ptr, arp->ar_hln);
- tbl->hlen = arp->ar_hln;
- tbl->flags |= ATF_COM;
- tbl->last_used = jiffies;
- } else {
- memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
- if (chk_addr(dst) != IS_MYADDR) {
+ /* For now we will only deal with IP addresses. */
+ if (((arp->ar_pro != NET16(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4)
+ {
+ if (arp->ar_op != NET16(ARPOP_REQUEST))
+ DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name));
kfree_skb(skb, FREE_READ);
return(0);
- } else {
- tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);
- if (tbl == NULL) {
+ }
+
+ /*
+ * As said before, we try to be smart by using the
+ * info already present in the packet: the sender's
+ * IP and hardware address.
+ */
+ ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
+ memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);
+ tbl = arp_lookup(src);
+ if (tbl != NULL)
+ {
+ DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));
+ memcpy(tbl->ha, ptr, arp->ar_hln);
+ tbl->hlen = arp->ar_hln;
+ tbl->flags |= ATF_COM;
+ tbl->last_used = jiffies;
+ }
+ else
+ {
+ memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
+ if (chk_addr(dst) != IS_MYADDR)
+ {
kfree_skb(skb, FREE_READ);
return(0);
+ }
+ else
+ {
+ tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);
+ if (tbl == NULL)
+ {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
}
- }
- }
+ }
/*
* Since we updated the ARP cache, we might have enough
* information to send out some previously queued IP
* datagrams....
*/
- arp_send_q();
+ arp_send_q();
/*
* OK, we used that part of the info. Now check if the
* request was an ARP REQUEST for one of our own addresses..
*/
- if (arp->ar_op != NET16(ARPOP_REQUEST)) {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
+ if (arp->ar_op != NET16(ARPOP_REQUEST))
+ {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
/*
* A broadcast arp, ignore it
*/
- if((dst&0xFF)==0xFF)
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
- if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
- DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
- kfree_skb(skb, FREE_READ);
- return(0);
- }
+ if(chk_addr(dst)==IS_BROADCAST)
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
- /*
- * Yes, it is for us.
- * Allocate, fill in and send an ARP REPLY packet.
- */
- ret = arp_response(arp, dev, addr_hint);
- kfree_skb(skb, FREE_READ);
- return(ret);
+ memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
+ if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0)
+ {
+ DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ /*
+ * Yes, it is for us.
+ * Allocate, fill in and send an ARP REPLY packet.
+ */
+ ret = arp_response(arp, dev, addr_hint);
+ kfree_skb(skb, FREE_READ);
+ return(ret);
}
-/* Create and send an ARP REQUEST packet. */
-void
-arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
+/*
+ * Create and send an ARP REQUEST packet.
+ */
+
+void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
{
- struct sk_buff *skb;
- struct arphdr *arp;
- unsigned char *ptr;
- int tmp;
+ struct sk_buff *skb;
+ struct arphdr *arp;
+ unsigned char *ptr;
+ int tmp;
- DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr)));
- DPRINTF((DBG_ARP, "dev=%s, ", dev->name));
- DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));
+ DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "dev=%s, ", dev->name));
+ DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));
- skb = alloc_skb(sizeof(struct sk_buff) +
+ skb = alloc_skb(sizeof(struct sk_buff) +
sizeof(struct arphdr) + (2 * dev->addr_len) +
dev->hard_header_len +
(2 * 4 /* arp->plen */), GFP_ATOMIC);
- if (skb == NULL) {
- printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
- return;
- }
+ if (skb == NULL)
+ {
+ printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
+ return;
+ }
- /* Fill in the request. */
- skb->sk = NULL;
- skb->mem_addr = skb;
- skb->len = sizeof(struct arphdr) +
+ /* Fill in the request. */
+ skb->sk = NULL;
+ 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,
+ skb->arp = 1;
+ skb->dev = dev;
+ skb->next = NULL;
+ skb->free = 1;
+ tmp = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, 0, saddr, skb->len);
- if (tmp < 0) {
- kfree_skb(skb,FREE_WRITE);
- return;
- }
- arp = (struct arphdr *) ((unsigned char *) (skb+1) + tmp);
- arp->ar_hrd = htons(dev->type);
- if(dev->type!=3) /* AX.25 */
- arp->ar_pro = htons(ETH_P_IP);
- else
- arp->ar_pro = htons(0xCC);
- arp->ar_hln = dev->addr_len;
- arp->ar_pln = 4;
- arp->ar_op = htons(ARPOP_REQUEST);
-
- ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
- memcpy(ptr, dev->dev_addr, arp->ar_hln);
- ptr += arp->ar_hln;
- memcpy(ptr, &saddr, arp->ar_pln);
- ptr += arp->ar_pln;
- /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/
- memset(ptr,0,arp->ar_hln);
- ptr += arp->ar_hln;
- memcpy(ptr, &paddr, arp->ar_pln);
-
- DPRINTF((DBG_ARP, ">>\n"));
- arp_print(arp);
- dev->queue_xmit(skb, dev, 0);
+ if (tmp < 0)
+ {
+ kfree_skb(skb,FREE_WRITE);
+ return;
+ }
+ arp = (struct arphdr *) ((unsigned char *) (skb+1) + tmp);
+ arp->ar_hrd = htons(dev->type);
+ if(dev->type!=3) /* AX.25 */
+ arp->ar_pro = htons(ETH_P_IP);
+ else
+ arp->ar_pro = htons(0xCC);
+ arp->ar_hln = dev->addr_len;
+ arp->ar_pln = 4;
+ arp->ar_op = htons(ARPOP_REQUEST);
+
+ ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
+ memcpy(ptr, dev->dev_addr, arp->ar_hln);
+ ptr += arp->ar_hln;
+ memcpy(ptr, &saddr, arp->ar_pln);
+ ptr += arp->ar_pln;
+ /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/
+ memset(ptr,0,arp->ar_hln);
+ ptr += arp->ar_hln;
+ memcpy(ptr, &paddr, arp->ar_pln);
+
+ dev->queue_xmit(skb, dev, 0);
}
-/* Find an ARP mapping in the cache. If not found, post a REQUEST. */
-int
-arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
- unsigned long saddr)
+/*
+ * Find an ARP mapping in the cache. If not found, post a REQUEST.
+ */
+
+int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
+ unsigned long saddr)
{
- struct arp_table *apt;
+ struct arp_table *apt;
- DPRINTF((DBG_ARP, "ARP: find(haddr=%s, ", eth_print(haddr)));
- DPRINTF((DBG_ARP, "paddr=%s, ", in_ntoa(paddr)));
- DPRINTF((DBG_ARP, "dev=%s, saddr=%s)\n", dev->name, in_ntoa(saddr)));
-
- switch(chk_addr(paddr)) {
- case IS_MYADDR:
- memcpy(haddr, dev->dev_addr, dev->addr_len);
- return(0);
- case IS_BROADCAST:
- memcpy(haddr, dev->broadcast, dev->addr_len);
- return(0);
- }
+ switch(chk_addr(paddr))
+ {
+ case IS_MYADDR:
+ memcpy(haddr, dev->dev_addr, dev->addr_len);
+ return(0);
+ case IS_BROADCAST:
+ memcpy(haddr, dev->broadcast, dev->addr_len);
+ return(0);
+ }
- apt = arp_lookup(paddr);
- if (apt != NULL) {
+ apt = arp_lookup(paddr);
+ if (apt != NULL)
+ {
/*
* Make sure it's not too old. If it is too old, we will
* just pretend we did not find it, and then arp_send will
* verify the address for us.
*/
- if ((!(apt->flags & ATF_PERM)) ||
- (!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
- apt->last_used = jiffies;
- memcpy(haddr, apt->ha, dev->addr_len);
- return(0);
- } else {
- DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",
- in_ntoa(apt->ip)));
- }
- }
+ if ((apt->flags & ATF_PERM) ||
+ (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0))
+ {
+ apt->last_used = jiffies;
+ memcpy(haddr, apt->ha, dev->addr_len);
+ return(0);
+ }
+ else
+ {
+ DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",
+ in_ntoa(apt->ip)));
+ }
+ }
/*
* This assume haddr are at least 4 bytes.
* If this isn't true we can use a lookup table, one for every dev.
- * NOTE: this bit of code still looks fishy to me- FvK
*/
- *(unsigned long *)haddr = paddr;
+
+ *(unsigned long *)haddr = paddr;
- /* If we didn't find an entry, we will try to send an ARP packet. */
- arp_send(paddr, dev, saddr);
+ /* If we didn't find an entry, we will try to send an ARP packet. */
+ arp_send(paddr, dev, saddr);
- return(1);
+ return(1);
}
-/* Add an entry to the ARP cache. Check for dupes! */
-void
-arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
+/*
+ * Add an entry to the ARP cache. Check for dupes!
+ */
+
+void arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
{
- struct arp_table *apt;
-
- DPRINTF((DBG_ARP, "ARP: add(%s, ", in_ntoa(addr)));
- DPRINTF((DBG_ARP, "%s, ", eth_print(haddr)));
- DPRINTF((DBG_ARP, "%d, %d)\n", dev->hard_header_len, dev->type));
-
- /* This is probably a good check... */
- if (addr == 0) {
- printk("ARP: add: will not add entry for 0.0.0.0 !\n");
- return;
- }
-
- /* First see if the address is already in the table. */
- apt = arp_lookup(addr);
- if (apt != NULL) {
- DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));
- apt->last_used = jiffies;
- memcpy(apt->ha, haddr , dev->addr_len);
- return;
- }
- arp_create(addr, haddr, dev->addr_len, dev->type);
+ struct arp_table *apt;
+
+ /* This is probably a good check... */
+ if (addr == 0)
+ {
+ printk("ARP: add: will not add entry for 0.0.0.0 !\n");
+ return;
+ }
+
+ /* First see if the address is already in the table. */
+ apt = arp_lookup(addr);
+ if (apt != NULL)
+ {
+ DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));
+ apt->last_used = jiffies;
+ memcpy(apt->ha, haddr , dev->addr_len);
+ return;
+ }
+ arp_create(addr, haddr, dev->addr_len, dev->type);
}
-/* Create an ARP entry for a device's broadcast address. */
-void
-arp_add_broad(unsigned long addr, struct device *dev)
-{
- struct arp_table *apt;
+/*
+ * Create an ARP entry for a device's broadcast address.
+ */
- arp_add(addr, dev->broadcast, dev);
- apt = arp_lookup(addr);
- if (apt != NULL) {
- apt->flags |= ATF_PERM;
- }
+void arp_add_broad(unsigned long addr, struct device *dev)
+{
+ struct arp_table *apt;
+
+ arp_add(addr, dev->broadcast, dev);
+ apt = arp_lookup(addr);
+ if (apt != NULL)
+ {
+ apt->flags |= ATF_PERM;
+ }
}
/* 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)
{
- cli();
- skb->tries = ARP_MAX_TRIES;
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ skb->tries = ARP_MAX_TRIES;
- if (skb->next != NULL) {
- sti();
- printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
- return;
- }
- skb_queue_tail(&arp_q,skb);
- skb->magic = ARP_QUEUE_MAGIC;
- sti();
+ 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);
}
@@ -754,172 +727,196 @@ arp_queue(struct sk_buff *skb)
*
* Perhaps we should redo PROCfs to handle larger buffers? Michael?
*/
-int
-arp_get_info(char *buffer)
+
+int arp_get_info(char *buffer)
{
- struct arpreq *req;
- struct arp_table *apt;
- int i;
- char *pos;
-
- /* Loop over the ARP table and copy structures to the buffer. */
- pos = buffer;
- i = 0;
- for (i = 0; i < ARP_TABLE_SIZE; i++) {
- cli();
- apt = arp_tables[i];
- sti();
- while (apt != NULL) {
- if (pos < (buffer + 4000)) {
- req = (struct arpreq *) pos;
- memset((char *) req, 0, sizeof(struct arpreq));
- req->arp_pa.sa_family = AF_INET;
- memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4);
- req->arp_ha.sa_family = apt->htype;
- memcpy((char *) req->arp_ha.sa_data,
- (char *) &apt->ha, apt->hlen);
- }
- pos += sizeof(struct arpreq);
+ struct arpreq *req;
+ struct arp_table *apt;
+ int i;
+ char *pos;
+
+ /* Loop over the ARP table and copy structures to the buffer. */
+ pos = buffer;
+ i = 0;
+ for (i = 0; i < ARP_TABLE_SIZE; i++)
+ {
cli();
- apt = apt->next;
+ apt = arp_tables[i];
sti();
- }
- }
- return(pos - buffer);
+ while (apt != NULL)
+ {
+ if (pos < (buffer + 4000))
+ {
+ req = (struct arpreq *) pos;
+ memset((char *) req, 0, sizeof(struct arpreq));
+ req->arp_pa.sa_family = AF_INET;
+ memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4);
+ req->arp_ha.sa_family = apt->htype;
+ memcpy((char *) req->arp_ha.sa_data,
+ (char *) &apt->ha, apt->hlen);
+ }
+ pos += sizeof(struct arpreq);
+ cli();
+ apt = apt->next;
+ sti();
+ }
+ }
+ return(pos - buffer);
}
-/* Set (create) an ARP cache entry. */
-static int
-arp_req_set(struct arpreq *req)
+/*
+ * Set (create) an ARP cache entry.
+ */
+
+static int arp_req_set(struct arpreq *req)
{
- struct arpreq r;
- struct arp_table *apt;
- struct sockaddr_in *si;
- int htype, hlen;
-
- /* We only understand about IP addresses... */
- memcpy_fromfs(&r, req, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
-
- /*
- * Find out about the hardware type.
- * We have to be compatible with BSD UNIX, so we have to
- * assume that a "not set" value (i.e. 0) means Ethernet.
- */
- si = (struct sockaddr_in *) &r.arp_pa;
- switch(r.arp_ha.sa_family) {
- case 0:
- case ARPHRD_ETHER:
- htype = ARPHRD_ETHER;
- hlen = ETH_ALEN;
- break;
- default:
- return(-EPFNOSUPPORT);
- }
-
- /* Is there an existing entry for this address? */
- if (si->sin_addr.s_addr == 0) {
- printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
- return(-EINVAL);
- }
- apt = arp_lookup(si->sin_addr.s_addr);
- if (apt == NULL) {
- apt = arp_create(si->sin_addr.s_addr,
- (unsigned char *) r.arp_ha.sa_data, hlen, htype);
- if (apt == NULL) return(-ENOMEM);
- }
-
- /* We now have a pointer to an ARP entry. Update it! */
- memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen);
- apt->last_used = jiffies;
- apt->flags = r.arp_flags;
- if(apt->flags&ATF_PUBL)
- arp_proxies++; /* Count proxy arps so we know if to use it */
-
- return(0);
+ struct arpreq r;
+ struct arp_table *apt;
+ struct sockaddr_in *si;
+ int htype, hlen;
+
+ /* We only understand about IP addresses... */
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (r.arp_pa.sa_family != AF_INET)
+ return(-EPFNOSUPPORT);
+
+ /*
+ * Find out about the hardware type.
+ * We have to be compatible with BSD UNIX, so we have to
+ * assume that a "not set" value (i.e. 0) means Ethernet.
+ */
+ si = (struct sockaddr_in *) &r.arp_pa;
+ switch(r.arp_ha.sa_family)
+ {
+ case 0:
+ case ARPHRD_ETHER:
+ htype = ARPHRD_ETHER;
+ hlen = ETH_ALEN;
+ break;
+ case ARPHRD_AX25:
+ htype = ARPHRD_AX25;
+ hlen = 7;
+ break;
+
+ default:
+ return(-EPFNOSUPPORT);
+ }
+
+ /* Is there an existing entry for this address? */
+ if (si->sin_addr.s_addr == 0)
+ {
+ printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
+ return(-EINVAL);
+ }
+ apt = arp_lookup(si->sin_addr.s_addr);
+ if (apt == NULL)
+ {
+ apt = arp_create(si->sin_addr.s_addr,
+ (unsigned char *) r.arp_ha.sa_data, hlen, htype);
+ if (apt == NULL)
+ return(-ENOMEM);
+ }
+
+ /* We now have a pointer to an ARP entry. Update it! */
+ memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen);
+ apt->last_used = jiffies;
+ apt->flags = r.arp_flags;
+ if(apt->flags&ATF_PUBL)
+ arp_proxies++; /* Count proxy arps so we know if to use it */
+
+ return(0);
}
-/* Get an ARP cache entry. */
-static int
-arp_req_get(struct arpreq *req)
+/*
+ * Get an ARP cache entry.
+ */
+
+static int arp_req_get(struct arpreq *req)
{
- struct arpreq r;
- struct arp_table *apt;
- struct sockaddr_in *si;
-
- /* We only understand about IP addresses... */
- memcpy_fromfs(&r, req, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
-
- /* Is there an existing entry for this address? */
- si = (struct sockaddr_in *) &r.arp_pa;
- apt = arp_lookup(si->sin_addr.s_addr);
- if (apt == NULL) return(-ENXIO);
-
- /* We found it; copy into structure. */
- memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);
- r.arp_ha.sa_family = apt->htype;
-
- /* Copy the information back */
- memcpy_tofs(req, &r, sizeof(r));
- return(0);
+ struct arpreq r;
+ struct arp_table *apt;
+ struct sockaddr_in *si;
+
+ /* We only understand about IP addresses... */
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (r.arp_pa.sa_family != AF_INET)
+ return(-EPFNOSUPPORT);
+
+ /* Is there an existing entry for this address? */
+ si = (struct sockaddr_in *) &r.arp_pa;
+ apt = arp_lookup(si->sin_addr.s_addr);
+ if (apt == NULL)
+ return(-ENXIO);
+
+ /* We found it; copy into structure. */
+ memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);
+ r.arp_ha.sa_family = apt->htype;
+
+ /* Copy the information back */
+ memcpy_tofs(req, &r, sizeof(r));
+ return(0);
}
-/* Delete an ARP cache entry. */
-static int
-arp_req_del(struct arpreq *req)
+/*
+ * Delete an ARP cache entry.
+ */
+
+static int arp_req_del(struct arpreq *req)
{
- struct arpreq r;
- struct sockaddr_in *si;
-
- /* We only understand about IP addresses... */
- memcpy_fromfs(&r, req, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
-
- si = (struct sockaddr_in *) &r.arp_pa;
+ struct arpreq r;
+ struct sockaddr_in *si;
+
+ /* We only understand about IP addresses... */
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (r.arp_pa.sa_family != AF_INET)
+ return(-EPFNOSUPPORT);
+ si = (struct sockaddr_in *) &r.arp_pa;
- /* The system cope with this but splats up a nasty kernel message
- We trap it beforehand and tell the user off */
- if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR)
- return -EINVAL;
+ /* The system cope with this but splats up a nasty kernel message
+ We trap it beforehand and tell the user off */
+ if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR)
+ return -EINVAL;
- arp_destroy(si->sin_addr.s_addr);
-
- return(0);
+ arp_destroy(si->sin_addr.s_addr);
+
+ return(0);
}
-/* Handle an ARP layer I/O control request. */
-int
-arp_ioctl(unsigned int cmd, void *arg)
+/*
+ * Handle an ARP layer I/O control request.
+ */
+
+int arp_ioctl(unsigned int cmd, void *arg)
{
- int err;
- switch(cmd) {
- case DDIOCSDBG:
- return(dbg_ioctl(arg, DBG_ARP));
- case SIOCDARP:
- if (!suser()) return(-EPERM);
- err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
- if(err)
- return err;
- return(arp_req_del((struct arpreq *)arg));
- case SIOCGARP:
- err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq));
- if(err)
- return err;
- return(arp_req_get((struct arpreq *)arg));
- case SIOCSARP:
- if (!suser()) return(-EPERM);
- err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
- if(err)
- return err;
- return(arp_req_set((struct arpreq *)arg));
- default:
- return(-EINVAL);
- }
- /*NOTREACHED*/
- return(0);
+ int err;
+ switch(cmd)
+ {
+ case DDIOCSDBG:
+ return(dbg_ioctl(arg, DBG_ARP));
+ case SIOCDARP:
+ if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
+ return(arp_req_del((struct arpreq *)arg));
+ case SIOCGARP:
+ err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
+ return(arp_req_get((struct arpreq *)arg));
+ case SIOCSARP:
+ if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
+ return(arp_req_set((struct arpreq *)arg));
+ default:
+ return(-EINVAL);
+ }
+ /*NOTREACHED*/
+ return(0);
}
diff --git a/net/inet/arp.h b/net/inet/arp.h
index c75c6cf..b18e0ae 100644
--- a/net/inet/arp.h
+++ b/net/inet/arp.h
@@ -5,7 +5,7 @@
*
* Definitions for the ARP protocol module.
*
- * Version: @(#)arp.h 1.0.6 05/21/93
+ * Version: @(#)arp.h 1.28 24/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -26,29 +26,31 @@
#define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */
-/* This structure defines the ARP mapping cache. */
-struct arp_table {
- struct arp_table *next;
- volatile unsigned long last_used;
- unsigned int flags;
-#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 structure defines the ARP mapping cache.
+ */
+
+struct arp_table
+{
+ struct arp_table *next;
+ volatile unsigned long last_used;
+ unsigned int flags;
+ unsigned long ip;
+ unsigned char ha[MAX_ADDR_LEN];
+ unsigned char hlen;
+ unsigned char htype;
};
-/* This is also used in "sock.c" and "tcp.c" - YUCK! - FvK */
+/*
+ * This is also used in "sock.c" and "tcp.c" - YUCK! - FvK
+ */
+
extern struct sk_buff *arp_q;
extern void arp_destroy(unsigned long paddr);
+extern void arp_destroy_maybe(unsigned long paddr);
extern int arp_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
extern int arp_find(unsigned char *haddr, unsigned long paddr,
diff --git a/net/inet/datagram.c b/net/inet/datagram.c
index 931d9f3..e69de29 100644
--- a/net/inet/datagram.c
+++ b/net/inet/datagram.c
@@ -1,200 +0,0 @@
-/*
- * SUCS NET2 Debugged.
- *
- * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
- * of these would make sense. Not tonight however 8-).
- * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
- * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
- *
- * Fixes:
- * Alan Cox : NULL return from skb_peek_copy() understood
- * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
- * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
- * AX.25 now works right, and SPX is feasible.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include "inet.h"
-#include "dev.h"
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include "skbuff.h"
-#include "sock.h"
-
-
-/*
- * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
- * races. This replaces identical code in packet,raw and udp, as well as the yet to
- * be released IPX support. It also finally fixes the long standing peek and read
- * race for datagram sockets. If you alter this routine remember it must be
- * re-entrant.
- */
-
-struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
-{
- struct sk_buff *skb;
-
- /* Socket is inuse - so the timer doesn't attack it */
-restart:
- sk->inuse = 1;
- while(sk->rqueue == NULL) /* No data */
- {
- /* If we are shutdown then no more data is going to appear. We are done */
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- *err=0;
- return NULL;
- }
-
- if(sk->err)
- {
- release_sock(sk);
- *err=-sk->err;
- sk->err=0;
- return NULL;
- }
-
- /* Sequenced packets can come disconnected. If so we report the problem */
- if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
- {
- release_sock(sk);
- *err=-ENOTCONN;
- return NULL;
- }
-
- /* User doesn't want to wait */
- if (noblock)
- {
- release_sock(sk);
- *err=-EAGAIN;
- return NULL;
- }
- release_sock(sk);
-
- /* Interrupts off so that no packet arrives before we begin sleeping.
- Otherwise we might miss our wake up */
- cli();
- if (sk->rqueue == NULL)
- {
- interruptible_sleep_on(sk->sleep);
- /* Signals may need a restart of the syscall */
- if (current->signal & ~current->blocked)
- {
- sti();
- *err=-ERESTARTSYS;
- return(NULL);
- }
- if(sk->err != 0) /* Error while waiting for packet
- eg an icmp sent earlier by the
- peer has finaly turned up now */
- {
- *err = -sk->err;
- sti();
- sk->err=0;
- return NULL;
- }
- }
- sk->inuse = 1;
- sti();
- }
- /* Again only user level code calls this function, so nothing interrupt level
- will suddenely eat the rqueue */
- if (!(flags & MSG_PEEK))
- {
- skb=skb_dequeue(&sk->rqueue);
- if(skb!=NULL)
- skb->users++;
- else
- goto restart; /* Avoid race if someone beats us to the data */
- }
- else
- {
- cli();
- skb=skb_peek(&sk->rqueue);
- if(skb!=NULL)
- skb->users++;
- sti();
- if(skb==NULL) /* shouldn't happen but .. */
- *err=-EAGAIN;
- }
- return skb;
-}
-
-void skb_free_datagram(struct sk_buff *skb)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb->users--;
- if(skb->users>0)
- {
- restore_flags(flags);
- return;
- }
- /* See if it needs destroying */
- if(skb->list == NULL) /* Been dequeued by someone - ie its read */
- kfree_skb(skb,FREE_READ);
- restore_flags(flags);
-}
-
-void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
-{
- /* We will know all about the fraglist options to allow >4K receives
- but not this release */
- memcpy_tofs(to,skb->h.raw+offset,size);
-}
-
-/*
- * Datagram select: Again totally generic. Moved from udp.c
- * Now does seqpacket.
- */
-
-int datagram_select(struct sock *sk, int sel_type, select_table *wait)
-{
- select_wait(sk->sleep, wait);
- switch(sel_type)
- {
- case SEL_IN:
- if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
- {
- /* Connection closed: Wake up */
- return(1);
- }
- if (sk->rqueue != NULL || sk->err != 0)
- { /* This appears to be consistent
- with other stacks */
- return(1);
- }
- return(0);
-
- case SEL_OUT:
- if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
- {
- return(1);
- }
- return(0);
-
- case SEL_EX:
- if (sk->err)
- return(1); /* Socket has gone into error state (eg icmp error) */
- return(0);
- }
- return(0);
-}
diff --git a/net/inet/dev.c b/net/inet/dev.c
index e867ae3..05c2db4 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -790,7 +790,6 @@ static inline int bad_mask(unsigned long mask, unsigned long addr)
return 0;
}
-
/* Perform the SIOCxIFxxx calls. */
static int
dev_ifsioc(void *arg, unsigned int getset)
diff --git a/net/inet/devinet.c b/net/inet/devinet.c
new file mode 100644
index 0000000..6b83134
--- /dev/null
+++ b/net/inet/devinet.c
@@ -0,0 +1,266 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Interface (streams) handling functions.
+ *
+ * Version: @(#)dev.c 1.28 20/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox: check_addr returns a value for a wrong subnet
+ * ie not us but don't forward this!
+ * Alan Cox: block timer if the inet_bh handler is running
+ * Alan Cox: generic queue code added. A lot neater now
+ * C.E.Hawkins: SIOCGIFCONF only reports 'upped' interfaces
+ * C.E.Hawkins: IFF_PROMISC support
+ * Alan Cox: Supports Donald Beckers new hardware
+ * multicast layer, but not yet multicast lists.
+ * Alan Cox: ip_addr_match problems with class A/B nets.
+ * C.E.Hawkins IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT]
+ * Alan Cox: Removed bogus subnet check now the subnet code
+ * a) actually works for all A/B nets
+ * b) doesn't forward off the same interface.
+ * Alan Cox: Multiple extra protocols
+ * Alan Cox: A Couple more escaped verify_area calls die
+ * Alan Cox: IP_SET_DEV is gone (forever) as per Fred's comment.
+ * Alan Cox: Grand tidy up ready for the big day.
+ * Alan Cox: Handles dev_open errors correctly.
+ * Alan Cox: IP and generic parts split
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include "inet.h"
+#include "devinet.h"
+#include "eth.h"
+#include "ip.h"
+#include "route.h"
+#include "protocol.h"
+#include "tcp.h"
+#include "skbuff.h"
+
+
+/*
+ * Determine a default network mask, based on the IP address.
+ */
+
+unsigned long ip_get_mask(unsigned long addr)
+{
+ unsigned long dst;
+
+ if (addr == 0L)
+ return(0L); /* special case */
+
+ dst = ntohl(addr);
+ if (IN_CLASSA(dst))
+ return(htonl(IN_CLASSA_NET));
+ if (IN_CLASSB(dst))
+ return(htonl(IN_CLASSB_NET));
+ if (IN_CLASSC(dst))
+ return(htonl(IN_CLASSC_NET));
+
+ /* Something else, probably a subnet. */
+ return(0);
+}
+
+/*
+ * See if a pair of addresses match.
+ */
+
+int ip_addr_match(unsigned long me, unsigned long him)
+{
+ int i;
+ unsigned long mask=0xFFFFFFFF;
+ DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me)));
+ DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him)));
+
+ /* Fast path for 99.9% of cases */
+ if (me == him)
+ return(1);
+
+ for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8)
+ {
+ if ((me & 0xFF) != (him & 0xFF))
+ {
+ /*
+ * The only way this could be a match is for
+ * the rest of addr1 to be 0 or 255.
+ */
+ if (me != 0 && me != mask)
+ return(0);
+ return(1);
+ }
+ }
+ return(1);
+}
+
+
+/*
+ * Check the address for our address, broadcasts, etc.
+ *
+ * This routine is used a lot, and in many time critical
+ * places. It's already _TOO_ slow so be careful how you
+ * alter it.
+ */
+
+int chk_addr(unsigned long addr)
+{
+ struct device *dev;
+ unsigned long dst;
+
+ DPRINTF((DBG_DEV, "chk_addr(%s) --> ", in_ntoa(addr)));
+ dst = ntohl(addr);
+
+ /*
+ * Accept both `all ones' and `all zeros' as BROADCAST.
+ * All 0's is the old BSD broadcast.
+ */
+
+ if (dst == INADDR_ANY || dst == INADDR_BROADCAST)
+ {
+ DPRINTF((DBG_DEV, "BROADCAST\n"));
+ return(IS_BROADCAST);
+ }
+
+ /* Accept all of the `loopback' class A net. */
+ if ((dst & IN_CLASSA_NET) == 0x7F000000L)
+ {
+ DPRINTF((DBG_DEV, "LOOPBACK\n"));
+
+ /*
+ * We force `loopback' to be equal to MY_ADDR.
+ */
+ return(IS_MYADDR);
+ /* return(IS_LOOPBACK); */
+ }
+
+ /* OK, now check the interface addresses. */
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (!(dev->flags&IFF_UP))
+ continue;
+ if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
+ return(IS_MYADDR);
+ /* Is it the exact IP address? */
+ if (addr == dev->pa_addr)
+ {
+ DPRINTF((DBG_DEV, "MYADDR\n"));
+ return(IS_MYADDR);
+ }
+
+ /* Nope. Check for a subnetwork broadcast. */
+ if ((addr & dev->pa_mask) == (dev->pa_addr & dev->pa_mask))
+ {
+ if ((addr & ~dev->pa_mask) == 0)
+ {
+ DPRINTF((DBG_DEV, "SUBBROADCAST-0\n"));
+ return(IS_BROADCAST);
+ }
+ if (((addr & ~dev->pa_mask) | dev->pa_mask)
+ == INADDR_BROADCAST)
+ {
+ DPRINTF((DBG_DEV, "SUBBROADCAST-1\n"));
+ return(IS_BROADCAST);
+ }
+ }
+
+ /* Nope. Check for Network broadcast. */
+ if(IN_CLASSA(dst))
+ {
+ if( addr == (dev->pa_addr | 0xffffff00))
+ {
+ DPRINTF((DBG_DEV, "CLASS A BROADCAST-1\n"));
+ return(IS_BROADCAST);
+ }
+ }
+ else if(IN_CLASSB(dst))
+ {
+ if( addr == (dev->pa_addr | 0xffff0000))
+ {
+ DPRINTF((DBG_DEV, "CLASS B BROADCAST-1\n"));
+ return(IS_BROADCAST);
+ }
+ }
+ else
+ { /* IN_CLASSC */
+ if( addr == (dev->pa_addr | 0xff000000))
+ {
+ DPRINTF((DBG_DEV, "CLASS C BROADCAST-1\n"));
+ return(IS_BROADCAST);
+ }
+ }
+ }
+
+ DPRINTF((DBG_DEV, "NONE\n"));
+
+ return(0); /* no match at all */
+}
+
+
+/*
+ * Retrieve our own address.
+ * Because the loopback address (127.0.0.1) is already recognized
+ * automatically, we can use the loopback interface's address as
+ * our "primary" interface. This is the addressed used by IP et
+ * al when it doesn't know which address to use (i.e. it does not
+ * yet know from or to which interface to go...).
+ */
+
+unsigned long my_addr(void)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (dev->flags & IFF_LOOPBACK)
+ return(dev->pa_addr);
+ }
+ return(0);
+}
+
+
+
+/*
+ * Find an interface that can handle addresses for a certain address.
+ */
+
+struct device *dev_check(unsigned long addr)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev; dev = dev->next)
+ if ((dev->flags & IFF_UP) && (dev->flags & IFF_POINTOPOINT) &&
+ (addr == dev->pa_dstaddr))
+ return dev;
+ for (dev = dev_base; dev; dev = dev->next)
+ if ((dev->flags & IFF_UP) && !(dev->flags & IFF_POINTOPOINT) &&
+ (dev->flags & IFF_LOOPBACK ? (addr == dev->pa_addr) :
+ (dev->pa_mask & addr) == (dev->pa_addr & dev->pa_mask)))
+ break;
+ /* no need to check broadcast addresses */
+ return dev;
+}
+
diff --git a/net/inet/devinet.h b/net/inet/devinet.h
new file mode 100644
index 0000000..c9fc5cc
--- /dev/null
+++ b/net/inet/devinet.h
@@ -0,0 +1,22 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the INET bits of the interfaces handler.
+ *
+ */
+
+#ifndef _DEVINET_H
+#define _DEVINET_H
+
+#ifndef _DEV_H
+#include "dev.h"
+#endif
+
+extern int ip_addr_match(unsigned long addr1, unsigned long addr2);
+extern int chk_addr(unsigned long addr);
+extern struct device *dev_check(unsigned long daddr);
+extern unsigned long my_addr(void);
+
+#endif /* _DEVINET_H */
diff --git a/net/inet/eth.c b/net/inet/eth.c
index 01e2f51..7bf2657 100644
--- a/net/inet/eth.c
+++ b/net/inet/eth.c
@@ -5,24 +5,27 @@
*
* Ethernet-type device handling.
*
- * Version: @(#)eth.c 1.0.7 05/25/93
+ * Version: @(#)eth.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:
- * 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>
@@ -33,18 +36,19 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "eth.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include <linux/errno.h>
#include "arp.h"
+#ifdef ETH_DEBUG
/* Display an Ethernet address in readable format. */
char *eth_print(unsigned char *ptr)
{
@@ -57,32 +61,16 @@ char *eth_print(unsigned char *ptr)
);
return(buff);
}
+#endif
-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;
- }
-}
-/* Display the contents of the Ethernet MAC header. */
-void
-eth_dump(struct ethhdr *eth)
+#ifdef ETH_DEBUG
+
+/*
+ * Display the contents of the Ethernet MAC header.
+ */
+
+void eth_dump(struct ethhdr *eth)
{
if (inet_debug != DBG_ETH) return;
@@ -91,96 +79,128 @@ eth_dump(struct ethhdr *eth)
printk("TYPE = %04X\n", ntohs(eth->h_proto));
}
+#endif
-/* Create the Ethernet MAC header. */
-int
-eth_header(unsigned char *buff, struct device *dev, unsigned short type,
+
+/*
+ * 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,
unsigned long daddr, unsigned long saddr, unsigned len)
{
- struct ethhdr *eth;
-
- DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr)));
- DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type));
-
- /* Fill in the basic Ethernet MAC header. */
- eth = (struct ethhdr *) buff;
- eth->h_proto = htons(type);
-
- /* We don't ARP for the LOOPBACK device... */
- if (dev->flags & IFF_LOOPBACK) {
- DPRINTF((DBG_DEV, "ETH: No header for loopback\n"));
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- memset(eth->h_dest, 0, dev->addr_len);
- return(dev->hard_header_len);
- }
-
- /* Check if we can use the MAC BROADCAST address. */
- if (chk_addr(daddr) == IS_BROADCAST) {
- DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
- return(dev->hard_header_len);
- }
- cli();
- memcpy(eth->h_source, &saddr, 4);
- /* No. Ask ARP to resolve the Ethernet address. */
- if (arp_find(eth->h_dest, daddr, dev, saddr))
- {
- sti();
- if(type!=ETH_P_IP)
- printk("Erk: protocol %X got into an arp request state!\n",type);
- return(-dev->hard_header_len);
- }
- else
- {
- memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the
- header built correctly! */
- sti();
- return(dev->hard_header_len);
- }
+ struct ethhdr *eth;
+
+ DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr)));
+ DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type));
+
+ /* Fill in the basic Ethernet MAC header. */
+ eth = (struct ethhdr *) buff;
+ eth->h_proto = htons(type);
+
+ /* We don't ARP for the LOOPBACK device... */
+ if (dev->flags & IFF_LOOPBACK)
+ {
+ DPRINTF((DBG_DEV, "ETH: No header for loopback\n"));
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ memset(eth->h_dest, 0, dev->addr_len);
+ return(dev->hard_header_len);
+ }
+
+ /* Check if we can use the MAC BROADCAST address. */
+ if (chk_addr(daddr) == IS_BROADCAST)
+ {
+ DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
+ return(dev->hard_header_len);
+ }
+ /*
+ * We disable interrupts here to avoid a race if the ARP
+ * reply is too quick.
+ */
+ cli();
+ memcpy(eth->h_source, &saddr, 4);
+ /* No. Ask ARP to resolve the Ethernet address. */
+ if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr/* saddr */))
+ {
+ sti();
+ if(type!=ETH_P_IP)
+ printk("Erk: protocol %X got into an arp request state!\n",type);
+ return(-dev->hard_header_len);
+ }
+ else
+ {
+ memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the
+ header built correctly! */
+ sti();
+ return(dev->hard_header_len);
+ }
}
-/* Rebuild the Ethernet MAC header. */
-int
-eth_rebuild_header(void *buff, struct device *dev)
+/*
+ * 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)
{
- struct ethhdr *eth;
- unsigned long src, dst;
-
- DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
- eth = (struct ethhdr *) buff;
- src = *(unsigned long *) eth->h_source;
- dst = *(unsigned long *) eth->h_dest;
- DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
- DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
- if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */
- if (arp_find(eth->h_dest, dst, dev, src)) return(1);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return(0);
+ struct ethhdr *eth;
+ unsigned long src, dst;
+
+ DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
+ eth = (struct ethhdr *) buff;
+ src = *(unsigned long *) eth->h_source;
+ dst = *(unsigned long *) eth->h_dest;
+ DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
+ DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
+ if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */
+ if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */))
+ /* Still not known */
+ return(1);
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ return(0);
}
-/* Add an ARP entry for a host on this interface. */
-void
-eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
+/*
+ * Add an ARP entry for a host on this interface.
+ */
+
+void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
{
- struct ethhdr *eth;
+ struct ethhdr *eth;
- eth = (struct ethhdr *) (skb + 1);
- arp_add(addr, eth->h_source, dev);
+ eth = (struct ethhdr *) (skb + 1);
+ arp_add(addr, eth->h_source, dev);
}
-/* Determine the packet's protocol ID. */
-unsigned short
-eth_type_trans(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)
{
- struct ethhdr *eth;
+ struct ethhdr *eth;
- eth = (struct ethhdr *) (skb + 1);
+ eth = (struct ethhdr *) (skb + 1);
- if(ntohs(eth->h_proto)<1536)
- return(htons(ETH_P_802_3));
- return(eth->h_proto);
+ if(ntohs(eth->h_proto)<1536)
+ return(htons(ETH_P_802_3));
+ return(eth->h_proto);
}
diff --git a/net/inet/icmp.c b/net/inet/icmp.c
index 7b953d4..467a119 100644
--- a/net/inet/icmp.c
+++ b/net/inet/icmp.c
@@ -5,7 +5,7 @@
*
* Internet Control Message Protocol (ICMP)
*
- * Version: @(#)icmp.c 1.0.11 06/02/93
+ * Version: @(#)icmp.c 1.28 20/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -14,6 +14,7 @@
* 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
@@ -21,6 +22,7 @@
* 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>
@@ -28,14 +30,14 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
@@ -63,379 +65,413 @@ struct icmp_err icmp_err_convert[] = {
};
+#ifdef ICMP_DEBUG
+
/* Display the contents of an ICMP header. */
static void
print_icmp(struct icmphdr *icmph)
{
- if (inet_debug != DBG_ICMP) return;
+ if (inet_debug != DBG_ICMP)
+ return;
- printk("ICMP: type = %d, code = %d, checksum = %X\n",
+ printk("ICMP: type = %d, code = %d, checksum = %X\n",
icmph->type, icmph->code, icmph->checksum);
- printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
+ printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
}
+#endif
+
+/*
+ * Send an ICMP message.
+ *
+ * ICMP is the control message protocol for error reporting in IP.
+ * A good document to start with for this stuff is RFC 791.
+ */
-/* Send an ICMP message. */
-void
-icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
+void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
{
- struct sk_buff *skb;
- struct iphdr *iph;
- int offset;
- struct icmphdr *icmph;
- int len;
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ int offset;
+ struct icmphdr *icmph;
+ int len;
- DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
+ DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
skb_in, type, code, dev));
- /* Get some memory for the reply. */
- len = sizeof(struct sk_buff) + dev->hard_header_len +
- sizeof(struct iphdr) + sizeof(struct icmphdr) +
- sizeof(struct iphdr) + 8; /* amount of header to return */
+ /* Get some memory for the reply. */
+ len = sizeof(struct sk_buff) + dev->hard_header_len +
+ sizeof(struct iphdr) + sizeof(struct icmphdr) +
+ sizeof(struct iphdr) + 8; /* amount of header to return */
- skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
- if (skb == NULL)
- return;
-
- skb->sk = NULL;
- skb->mem_addr = skb;
- skb->mem_len = len;
- len -= sizeof(struct sk_buff);
-
- /* Find the IP header. */
- iph = (struct iphdr *) (skb_in + 1);
- iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
-
- /* Build Layer 2-3 headers for message back to source. */
- offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
- &dev, IPPROTO_ICMP, NULL, len);
- if (offset < 0) {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /* Re-adjust length according to actual IP header size. */
- skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
- icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
- icmph->type = type;
- icmph->code = code;
- icmph->checksum = 0;
- icmph->un.gateway = 0;
- memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
-
- icmph->checksum = ip_compute_csum((unsigned char *)icmph,
- sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
-
- DPRINTF((DBG_ICMP, ">>\n"));
- print_icmp(icmph);
-
- /* Send it and free it. */
- ip_queue_xmit(NULL, dev, skb, 1);
+ skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
+ /* We just forget about failed ICMP messages. ICMP is unreliable anyway and
+ things will sort out in time */
+
+ if (skb == NULL)
+ return;
+
+ skb->sk = NULL;
+ len -= sizeof(struct sk_buff);
+
+ /* Find the IP header. */
+ iph = (struct iphdr *) (skb_in + 1);
+ iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
+
+ /* Build Layer 2-3 headers for message back to source. */
+ offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
+ &dev, IPPROTO_ICMP, NULL, len, 25, IPTOS_RELIABILITY);
+ if (offset < 0)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
+ icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
+ icmph->type = type;
+ icmph->code = code;
+ icmph->checksum = 0;
+ icmph->un.gateway = 0;
+ memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
+
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph,
+ sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
+
+#ifdef ICMP_DEBUG
+ DPRINTF((DBG_ICMP, ">>\n"));
+ print_icmp(icmph);
+#endif
+ /* Send it and free it. */
+ ip_queue_xmit(NULL, dev, skb, 1);
}
-/* Handle ICMP_UNREACH and ICMP_QUENCH. */
-static void
-icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
+/*
+ * Handle ICMP_UNREACH and ICMP_QUENCH.
+ */
+
+static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
{
- struct inet_protocol *ipprot;
- struct iphdr *iph;
- unsigned char hash;
- int err;
-
- err = (icmph->type << 8) | icmph->code;
- iph = (struct iphdr *) (icmph + 1);
- switch(icmph->code & 7) {
- case ICMP_NET_UNREACH:
- DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
+ struct inet_protocol *ipprot;
+ struct iphdr *iph;
+ unsigned char hash;
+ int err;
+
+ err = (icmph->type << 8) | icmph->code;
+ iph = (struct iphdr *) (icmph + 1);
+ switch(icmph->code & 7)
+ {
+ case ICMP_NET_UNREACH:
+ DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
in_ntoa(iph->daddr)));
- break;
- case ICMP_HOST_UNREACH:
- DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
- in_ntoa(iph->daddr)));
- break;
- case ICMP_PROT_UNREACH:
- printk("ICMP: %s:%d: protocol unreachable.\n",
- in_ntoa(iph->daddr), ntohs(iph->protocol));
- break;
- case ICMP_PORT_UNREACH:
- DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
- in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
- break;
- case ICMP_FRAG_NEEDED:
- printk("ICMP: %s: fragmentation needed and DF set.\n",
- in_ntoa(iph->daddr));
- break;
- case ICMP_SR_FAILED:
- printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
- break;
- default:
- DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
- (icmph->code & 7), in_ntoa(iph->daddr)));
- break;
- }
-
- /* Get the protocol(s). */
- hash = iph->protocol & (MAX_INET_PROTOS -1);
-
- /* This can change while we are doing it. */
- ipprot = (struct inet_protocol *) inet_protos[hash];
- while(ipprot != NULL) {
- struct inet_protocol *nextip;
-
- nextip = (struct inet_protocol *) ipprot->next;
-
- /* Pass it off to everyone who wants it. */
- if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
- ipprot->err_handler(err, (unsigned char *)(icmph + 1),
- iph->daddr, iph->saddr, ipprot);
+ break;
+ case ICMP_HOST_UNREACH:
+ DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
+ in_ntoa(iph->daddr)));
+ break;
+ case ICMP_PROT_UNREACH:
+ printk("ICMP: %s:%d: protocol unreachable.\n",
+ in_ntoa(iph->daddr), ntohs(iph->protocol));
+ break;
+ case ICMP_PORT_UNREACH:
+ DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
+ in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
+ break;
+ case ICMP_FRAG_NEEDED:
+ printk("ICMP: %s: fragmentation needed and DF set.\n",
+ in_ntoa(iph->daddr));
+ break;
+ case ICMP_SR_FAILED:
+ printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
+ break;
+ default:
+ DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
+ (icmph->code & 7), in_ntoa(iph->daddr)));
+ break;
}
+
+ /* Get the protocol(s). */
+ hash = iph->protocol & (MAX_INET_PROTOS -1);
+
+ /* This can change while we are doing it. */
+ ipprot = (struct inet_protocol *) inet_protos[hash];
+ while(ipprot != NULL)
+ {
+ struct inet_protocol *nextip;
+
+ nextip = (struct inet_protocol *) ipprot->next;
+
+ /* Pass it off to everyone who wants it. */
+ if (iph->protocol == ipprot->protocol && ipprot->err_handler)
+ {
+ ipprot->err_handler(err, (unsigned char *)(icmph + 1),
+ iph->daddr, iph->saddr, ipprot);
+ }
- ipprot = nextip;
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ ipprot = nextip;
+ }
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/* Handle ICMP_REDIRECT. */
-static void
-icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
+/*
+ * Handle ICMP_REDIRECT.
+ */
+
+static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
{
- struct iphdr *iph;
- unsigned long ip;
-
- iph = (struct iphdr *) (icmph + 1);
- ip = iph->daddr;
- switch(icmph->code & 7) {
- case ICMP_REDIR_NET:
- rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev);
- break;
- case ICMP_REDIR_HOST:
- rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev);
- break;
- case ICMP_REDIR_NETTOS:
- case ICMP_REDIR_HOSTTOS:
- printk("ICMP: cannot handle TOS redirects yet!\n");
+ struct iphdr *iph;
+ unsigned long ip;
+
+ iph = (struct iphdr *) (icmph + 1);
+ ip = iph->daddr;
+ switch(icmph->code & 7)
+ {
+ case ICMP_REDIR_NET:
+ rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
+ ip, 0, icmph->un.gateway, dev);
+ break;
+ case ICMP_REDIR_HOST:
+ rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
+ ip, 0, icmph->un.gateway, dev);
+ break;
+ case ICMP_REDIR_NETTOS:
+ case ICMP_REDIR_HOSTTOS:
+ printk("ICMP: cannot handle TOS redirects yet!\n");
+ break;
+ default:
+ DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
+ (icmph->code & 7)));
break;
- default:
- DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
- (icmph->code & 7)));
- break;
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ }
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
/* Handle ICMP_ECHO ("ping") requests. */
-static void
-icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
-
- size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
- if (skb2 == NULL) {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->sk = NULL;
- skb2->mem_addr = skb2;
- skb2->mem_len = size;
- skb2->free = 1;
-
- /* Build Layer 2-3 headers for message back to source */
- offset = ip_build_header(skb2, daddr, saddr, &dev,
- IPPROTO_ICMP, opt, len);
- if (offset < 0) {
- printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
- kfree_skb(skb2,FREE_WRITE);
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /* Re-adjust length according to actual IP header size. */
- skb2->len = offset + len;
-
- /* Build ICMP_ECHO Response message. */
- icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
- memcpy((char *) icmphr, (char *) icmph, len);
- icmphr->type = ICMP_ECHOREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /* Ship it out - free it when done */
- ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ struct icmphdr *icmphr;
+ struct sk_buff *skb2;
+ int size, offset;
+
+ size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
+ skb2 = alloc_skb(size, GFP_ATOMIC);
+ if (skb2 == NULL)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ skb2->sk = NULL;
+ skb2->free = 1;
+
+ /* Build Layer 2-3 headers for message back to source */
+ offset = ip_build_header(skb2, daddr, saddr, &dev,
+ IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
+ if (offset < 0)
+ {
+ printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
+ kfree_skb(skb2,FREE_WRITE);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb2->len = offset + len;
+
+ /* Build ICMP_ECHO Response message. */
+ icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
+ memcpy((char *) icmphr, (char *) icmph, len);
+ icmphr->type = ICMP_ECHOREPLY;
+ icmphr->code = 0;
+ icmphr->checksum = 0;
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
+
+ /* Ship it out - free it when done */
+ ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
+
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/* Handle the ICMP INFORMATION REQUEST. */
-static void
-icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+/*
+ * Handle the ICMP INFORMATION REQUEST.
+ */
+
+static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
- /* NOT YET */
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ /* NOT YET */
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/* Handle ICMP_ADRESS_MASK requests. */
-static void
-icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+/*
+ * Handle ICMP_ADRESS_MASK requests.
+ */
+
+static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
-
- size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
- if (skb2 == NULL) {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->sk = NULL;
- skb2->mem_addr = skb2;
- skb2->mem_len = size;
- skb2->free = 1;
-
- /* Build Layer 2-3 headers for message back to source */
- offset = ip_build_header(skb2, daddr, saddr, &dev,
- IPPROTO_ICMP, opt, len);
- if (offset < 0) {
- printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
- kfree_skb(skb2,FREE_WRITE);
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /* Re-adjust length according to actual IP header size. */
- skb2->len = offset + len;
-
- /* Build ICMP ADDRESS MASK Response message. */
- icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
- icmphr->type = ICMP_ADDRESSREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->un.echo.id = icmph->un.echo.id;
- icmphr->un.echo.sequence = icmph->un.echo.sequence;
- memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
-
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /* Ship it out - free it when done */
- ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ struct icmphdr *icmphr;
+ struct sk_buff *skb2;
+ int size, offset;
+
+ size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
+ skb2 = alloc_skb(size, GFP_ATOMIC);
+ if (skb2 == NULL)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ skb2->sk = NULL;
+ skb2->free = 1;
+
+ /* Build Layer 2-3 headers for message back to source */
+ offset = ip_build_header(skb2, daddr, saddr, &dev,
+ IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
+ if (offset < 0)
+ {
+ printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
+ kfree_skb(skb2,FREE_WRITE);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb2->len = offset + len;
+
+ /* Build ICMP ADDRESS MASK Response message. */
+ icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
+ icmphr->type = ICMP_ADDRESSREPLY;
+ icmphr->code = 0;
+ icmphr->checksum = 0;
+ icmphr->un.echo.id = icmph->un.echo.id;
+ icmphr->un.echo.sequence = icmph->un.echo.sequence;
+ memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
+
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
+
+ /* Ship it out - free it when done */
+ ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
+
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/* Deal with incoming ICMP packets. */
-int
-icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
+/*
+ * Deal with incoming ICMP packets.
+ */
+
+int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
- struct icmphdr *icmph;
- unsigned char *buff;
+ struct icmphdr *icmph;
+ unsigned char *buff;
- /* Drop broadcast packets. */
- if (chk_addr(daddr) == IS_BROADCAST) {
- DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
+ /* Drop broadcast packets. */
+ if (chk_addr(daddr) == IS_BROADCAST)
+ {
+ DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
in_ntoa(saddr)));
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
-
- buff = skb1->h.raw;
- icmph = (struct icmphdr *) buff;
-
- /* Validate the packet first */
- if (ip_compute_csum((unsigned char *) icmph, len)) {
- /* Failed checksum! */
- printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
- print_icmp(icmph);
-
- /* Parse the ICMP message */
- switch(icmph->type) {
- case ICMP_TIME_EXCEEDED:
- case ICMP_DEST_UNREACH:
- case ICMP_SOURCE_QUENCH:
- icmp_unreach(icmph, skb1);
- return(0);
- case ICMP_REDIRECT:
- icmp_redirect(icmph, skb1, dev);
- return(0);
- case ICMP_ECHO:
- icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ECHOREPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_INFO_REQUEST:
- icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_INFO_REPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_ADDRESS:
- icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ADDRESSREPLY:
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
- default:
- DPRINTF((DBG_ICMP,
- "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
- in_ntoa(saddr), icmph->type));
+ }
+
+ buff = skb1->h.raw;
+ icmph = (struct icmphdr *) buff;
+
+ /* Validate the packet first */
+ if (ip_compute_csum((unsigned char *) icmph, len))
+ {
+ /* Failed checksum! */
+ printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
- }
- /*NOTREACHED*/
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(-1);
+ }
+#ifdef ICMP_DEBUG
+ print_icmp(icmph);
+#endif
+ /* Parse the ICMP message */
+ switch(icmph->type)
+ {
+ case ICMP_TIME_EXCEEDED:
+ case ICMP_DEST_UNREACH:
+ case ICMP_SOURCE_QUENCH:
+ icmp_unreach(icmph, skb1);
+ return(0);
+ case ICMP_REDIRECT:
+ icmp_redirect(icmph, skb1, dev);
+ return(0);
+ case ICMP_ECHO:
+ icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_ECHOREPLY:
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ case ICMP_INFO_REQUEST:
+ icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_INFO_REPLY:
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ case ICMP_ADDRESS:
+ icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_ADDRESSREPLY:
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ default:
+ DPRINTF((DBG_ICMP,
+ "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
+ in_ntoa(saddr), icmph->type));
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ }
+ /*NOTREACHED*/
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(-1);
}
-/* Perform any ICMP-related I/O control requests. */
-int
-icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+/*
+ * 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)
{
- switch(cmd) {
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_ICMP));
- default:
- return(-EINVAL);
- }
- return(0);
+ switch(cmd)
+ {
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_ICMP));
+ default:
+ return(-EINVAL);
+ }
+ return(0);
}
diff --git a/net/inet/ip.c b/net/inet/ip.c
index 4c9f924..a3cc4ec 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) module.
*
- * Version: @(#)ip.c 1.0.16b 9/1/93
+ * Version: @(#)ip.c 1.28 20/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -31,10 +31,14 @@
* 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:
- * IP option processing is mostly not needed. ip_forward needs to know about routing rules
- * and time stamp but that's about all.
+ * RFC791 states that options are a 'required' feature of an
+ * IP implementation. We don't do options at all.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -52,141 +56,176 @@
#include <linux/sockios.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "route.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include "arp.h"
#include "icmp.h"
-#define CONFIG_IP_FORWARD
-#define CONFIG_IP_DEFRAG
+/*
+ * 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 ? */
+
extern int last_retran;
extern void sort_send(struct sock *sk);
-void
-ip_print(struct iphdr *ip)
+#ifdef IP_DEBUG
+
+void ip_print(struct iphdr *ip)
{
- unsigned char buff[32];
- unsigned char *ptr;
- int addr, len, i;
-
- if (inet_debug != DBG_IP) return;
-
- /* Dump the IP header. */
- printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
- ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len));
- printk(" id=%X, ttl=%d, prot=%d, check=%X\n",
- ip->id, ip->ttl, ip->protocol, ip->check);
- printk(" frag_off=%d\n", ip->frag_off);
- printk(" soucre=%s ", in_ntoa(ip->saddr));
- printk("dest=%s\n", in_ntoa(ip->daddr));
- printk(" ----\n");
-
- /* Dump the data. */
- ptr = (unsigned char *)(ip + 1);
- addr = 0;
- len = ntohs(ip->tot_len) - (4 * ip->ihl);
- while (len > 0) {
- printk(" %04X: ", addr);
- for(i = 0; i < 16; i++) {
- if (len > 0) {
- printk("%02X ", (*ptr & 0xFF));
- buff[i] = *ptr++;
- if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
- } else {
- printk(" ");
- buff[i] = ' ';
- }
- addr++;
- len--;
- };
- buff[i] = '\0';
- printk(" \"%s\"\n", buff);
- }
- printk(" ----\n\n");
+ unsigned char buff[32];
+ unsigned char *ptr;
+ int addr, len, i;
+
+ if (inet_debug != DBG_IP)
+ return;
+
+ /* Dump the IP header. */
+ printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
+ ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len));
+ printk(" id=%X, ttl=%d, prot=%d, check=%X\n",
+ ip->id, ip->ttl, ip->protocol, ip->check);
+ printk(" frag_off=%d\n", ip->frag_off);
+ printk(" soucre=%s ", in_ntoa(ip->saddr));
+ printk("dest=%s\n", in_ntoa(ip->daddr));
+ printk(" ----\n");
+
+ /* Dump the data. */
+ ptr = (unsigned char *)(ip + 1);
+ addr = 0;
+ len = ntohs(ip->tot_len) - (4 * ip->ihl);
+ while (len > 0)
+ {
+ printk(" %04X: ", addr);
+ for(i = 0; i < 16; i++)
+ {
+ if (len > 0)
+ {
+ printk("%02X ", (*ptr & 0xFF));
+ buff[i] = *ptr++;
+ if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
+ }
+ else
+ {
+ printk(" ");
+ buff[i] = ' ';
+ }
+ addr++;
+ len--;
+ };
+ buff[i] = '\0';
+ printk(" \"%s\"\n", buff);
+ }
+ printk(" ----\n\n");
}
+#endif
-int
-ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
+/*
+ * 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)
{
- switch(cmd) {
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_IP));
- default:
- return(-EINVAL);
- }
+ switch(cmd)
+ {
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_IP));
+ default:
+ return(-EINVAL);
+ }
}
-/* these two routines will do routining. */
-static void
-strict_route(struct iphdr *iph, struct options *opt)
+/*
+ * 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)
{
}
-static void
-loose_route(struct iphdr *iph, struct options *opt)
+static void loose_route(struct iphdr *iph, struct options *opt)
{
}
-static void
-print_ipprot(struct inet_protocol *ipprot)
+static void print_ipprot(struct inet_protocol *ipprot)
{
- DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
- ipprot->handler, ipprot->protocol, ipprot->copy));
+ DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
+ ipprot->handler, ipprot->protocol, ipprot->copy));
}
-/* This routine will check to see if we have lost a gateway. */
-void
-ip_route_check(unsigned long daddr)
+/*
+ * This routine will check to see if we have lost a gateway.
+ */
+
+void ip_route_check(unsigned long daddr)
{
}
-#if 0
-/* this routine puts the options at the end of an ip header. */
-static int
-build_options(struct iphdr *iph, struct options *opt)
+/*
+ * 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;
- /* currently we don't support any options. */
- ptr = (unsigned char *)(iph+1);
- *ptr = 0;
- return (4);
+ unsigned char *ptr;
+ ptr = (unsigned char *)(iph+1);
+ /* currently we don't support any options. */
+ if(opt==NULL)
+ {
+ *ptr = 0;
+ return (1);
+ }
+ else
+ {
+ memcpy(ptr,opt->option_data,opt->option_length);
+ return((opt->option_length+3)/4);
+ }
}
-#endif
-/* Take an skb, and fill in the MAC header. */
-static int
-ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
+/*
+ * Take an skb, and fill in the MAC header.
+ */
+
+static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
unsigned long saddr)
{
- unsigned char *ptr;
- int mac;
-
- ptr = (unsigned char *)(skb + 1);
- mac = 0;
- skb->arp = 1;
- if (dev->hard_header) {
- mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
- }
- if (mac < 0) {
- mac = -mac;
- skb->arp = 0;
- }
- skb->dev = dev;
- return(mac);
+ unsigned char *ptr;
+ int mac;
+
+ ptr = (unsigned char *)(skb + 1);
+ mac = 0;
+ skb->arp = 1;
+ if (dev->hard_header)
+ {
+ mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
+ }
+ if (mac < 0)
+ {
+ mac = -mac;
+ skb->arp = 0;
+ }
+ skb->dev = dev;
+ return(mac);
}
@@ -196,333 +235,419 @@ ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *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 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)
{
- static struct options optmem;
- struct iphdr *iph;
- struct rtable *rt;
- unsigned char *buff;
- unsigned long raddr;
- static int count = 0;
- int tmp;
-
- if (saddr == 0)
- saddr = my_addr();
-
- DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n"
- " type=%d, opt=%X, len = %d)\n",
- skb, saddr, daddr, *dev, type, opt, len));
+ static struct options optmem;
+ struct iphdr *iph;
+ struct rtable *rt;
+ unsigned char *buff;
+ unsigned long raddr;
+ static int count = 0;
+ int tmp;
+ int optlen;
+
+ if (saddr == 0)
+ saddr = my_addr();
+
+ DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n"
+ " type=%d, opt=%X, len = %d)\n",
+ skb, saddr, daddr, *dev, type, opt, len));
- buff = (unsigned char *)(skb + 1);
+ buff = (unsigned char *)(skb + 1);
- /* See if we need to look up the device. */
- if (*dev == NULL) {
- rt = rt_route(daddr, &optmem);
- if (rt == NULL)
- return(-ENETUNREACH);
+ /* See if we need to look up the device. */
+ if (*dev == NULL)
+ {
+ rt = rt_route(daddr, &optmem);
+ if (rt == NULL)
+ return(-ENETUNREACH);
- *dev = rt->rt_dev;
- if (saddr == 0x0100007FL && daddr != 0x0100007FL)
- saddr = rt->rt_dev->pa_addr;
- raddr = rt->rt_gateway;
+ *dev = rt->rt_dev;
+ if (saddr == 0x0100007FL && daddr != 0x0100007FL)
+ saddr = rt->rt_dev->pa_addr;
+ raddr = rt->rt_gateway;
- DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
- opt = &optmem;
- } else {
- /* We still need the address of the first hop. */
- rt = rt_route(daddr, &optmem);
- raddr = (rt == NULL) ? 0 : rt->rt_gateway;
- }
- if (raddr == 0)
- raddr = daddr;
-
- /* Now build the MAC header. */
- tmp = ip_send(skb, raddr, len, *dev, saddr);
- buff += tmp;
- len -= tmp;
-
- skb->dev = *dev;
- skb->saddr = saddr;
- if (skb->sk) skb->sk->saddr = saddr;
-
- /* Now build the IP header. */
-
- /* If we are using IPPROTO_RAW, then we don't need an IP header, since
- one is being supplied to us by the user */
-
- if(type == IPPROTO_RAW) return (tmp);
-
- iph = (struct iphdr *)buff;
- iph->version = 4;
- iph->tos = 0;
- iph->frag_off = 0;
- iph->ttl = 32;
- iph->daddr = daddr;
- iph->saddr = saddr;
- iph->protocol = type;
- iph->ihl = 5;
- iph->id = htons(count++);
-
- /* Setup the IP options. */
-#ifdef Not_Yet_Avail
- build_options(iph, opt);
-#endif
+ DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
+ opt = &optmem;
+ }
+ else
+ {
+ /* We still need the address of the first hop. */
+ rt = rt_route(daddr, &optmem);
+ raddr = (rt == NULL) ? 0 : rt->rt_gateway;
+ }
+ if (raddr == 0)
+ raddr = daddr;
+
+ /* Now build the MAC header. */
+ tmp = ip_send(skb, raddr, len, *dev, saddr);
+ buff += tmp;
+ len -= tmp;
+
+ skb->dev = *dev;
+ skb->saddr = saddr;
+ if (skb->sk)
+ skb->sk->saddr = saddr;
+
+ /* Now build the IP header. */
+
+ /* If we are using IPPROTO_RAW, then we don't need an IP header, since
+ one is being supplied to us by the user */
+
+ if(type == IPPROTO_RAW)
+ return (tmp);
+
+ iph = (struct iphdr *)buff;
+ iph->version = 4;
+ iph->tos = tos;
+ iph->frag_off = 0;
+ iph->ttl = ttl;
+ iph->daddr = daddr;
+ iph->saddr = saddr;
+ iph->protocol = type;
+ iph->ihl = 5;
+ iph->id = htons(count++);
+
+ /* Setup the IP options. Length is in longs.*/
- return(20 + tmp); /* IP header plus MAC header size */
+ optlen=build_options(iph, opt);
+ iph->ihl+=optlen;
+
+ return(20 + tmp + 4*optlen); /* IP header plus MAC header size */
}
-static int
-do_options(struct iphdr *iph, struct options *opt)
+/*
+ * Interpret the incoming options
+ */
+
+static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device *dev)
{
- unsigned char *buff;
- int done = 0;
- int i, len = sizeof(struct iphdr);
-
- /* Zero out the options. */
- opt->record_route.route_size = 0;
- opt->loose_route.route_size = 0;
- opt->strict_route.route_size = 0;
- opt->tstamp.ptr = 0;
- opt->security = 0;
- opt->compartment = 0;
- opt->handling = 0;
- opt->stream = 0;
- opt->tcc = 0;
- return(0);
-
- /* Advance the pointer to start at the options. */
- buff = (unsigned char *)(iph + 1);
-
- /* Now start the processing. */
- while (!done && len < iph->ihl*4) switch(*buff) {
- case IPOPT_END:
- done = 1;
- break;
- case IPOPT_NOOP:
- buff++;
- len++;
- break;
- case IPOPT_SEC:
- buff++;
- if (*buff != 11) return(1);
- buff++;
- opt->security = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->compartment = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->handling = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1));
- buff += 3;
- len += 11;
- break;
- case IPOPT_LSRR:
- buff++;
- if ((*buff - 3)% 4 != 0) return(1);
- len += *buff;
- opt->loose_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0) return(1);
- opt->loose_route.pointer = *buff/4 - 1;
- buff++;
- buff++;
- for (i = 0; i < opt->loose_route.route_size; i++) {
- if(i>=MAX_ROUTE)
+ unsigned char *buff;
+ int done = 0;
+ int i, len = sizeof(struct iphdr);
+ unsigned char *outbuf;
+ struct options *opt;
+ int ol;
+ int optsiz;
+
+ if(iph->ihl==5)
+ {
+ *opt_ptr=NULL;
+ return(0);
+ }
+
+ /* Allocate a buffer to stuff the options (decoded) and the raw option data into */
+
+ ol=(iph->ihl*4)-sizeof(struct iphdr);
+
+ opt=(struct options *)kmalloc(ol+sizeof(*opt),GFP_ATOMIC);
+ *opt_ptr=opt;
+
+ if(opt==NULL)
+ return(1);
+
+ opt->option_length=ol;
+ outbuf=(unsigned char *)(opt+1);
+ opt->option_data=outbuf;
+
+ /* Zero out the options. */
+ opt->record_route.route_size = 0;
+ opt->loose_route.route_size = 0;
+ opt->strict_route.route_size = 0;
+ opt->tstamp.ptr = 0;
+ opt->security = 0;
+ opt->compartment = 0;
+ opt->handling = 0;
+ opt->stream = 0;
+ opt->tcc = 0;
+
+
+ /* Advance the pointer to start at the options. */
+ buff = (unsigned char *)(iph + 1);
+ /* Copy the data */
+ memcpy(outbuf,buff,opt->option_length);
+ buff = outbuf;
+
+ /* Now start the processing. */
+ while (!done && len < iph->ihl*4) switch(*buff)
+ {
+ case IPOPT_END:
+ done = 1;
+ break;
+ case IPOPT_NOOP:
+ buff++;
+ len++;
+ break;
+ case IPOPT_SEC:
+ buff++;
+ if (*buff != 11)
return(1);
- opt->loose_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_SSRR:
- buff++;
- if ((*buff - 3)% 4 != 0) return(1);
- len += *buff;
- opt->strict_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0) return(1);
- opt->strict_route.pointer = *buff/4 - 1;
- buff++;
- buff++;
- for (i = 0; i < opt->strict_route.route_size; i++) {
- if(i>=MAX_ROUTE)
+ buff++;
+ opt->security = ntohs(*(unsigned short *)buff);
+ buff += 2;
+ opt->compartment = ntohs(*(unsigned short *)buff);
+ buff += 2;
+ opt->handling = ntohs(*(unsigned short *)buff);
+ buff += 2;
+ opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1));
+ buff += 3;
+ len += 11;
+ break;
+ case IPOPT_LSRR:
+ buff++;
+ if ((*buff - 3)% 4 != 0)
return(1);
- opt->strict_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_RR:
- buff++;
- if ((*buff - 3)% 4 != 0) return(1);
- len += *buff;
- opt->record_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0) return(1);
- opt->record_route.pointer = *buff/4 - 1;
- buff++;
- buff++;
- for (i = 0; i < opt->record_route.route_size; i++) {
- if(i>=MAX_ROUTE)
+ if(*buff<2)
+ return(1);
+ len += (optsiz= *buff);
+ opt->loose_route.route_size = (*buff -3)/4;
+ buff++;
+ if (*buff % 4 != 0)
+ return(1);
+ opt->loose_route.pointer = *buff/4 - 1;
+ if(*buff<=optsiz)
+ *buff+=4; /* Move on a route */
+ buff++;
+ buff++;
+ for (i = 0; i < opt->loose_route.route_size; i++)
+ {
+ if(i>=MAX_ROUTE)
+ return(1);
+ if(i==opt->strict_route.pointer)
+ *(unsigned long *)buff=dev->pa_addr;
+ opt->loose_route.route[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ case IPOPT_SSRR:
+ buff++;
+ if ((*buff - 3)% 4 != 0)
+ return(1);
+ if(*buff<2)
+ return(1);
+ len += (optsiz= *buff);
+ opt->strict_route.route_size = (*buff -3)/4;
+ buff++;
+ if (*buff % 4 != 0)
+ return(1);
+ opt->strict_route.pointer = *buff/4 - 1;
+ if(*buff<=optsiz)
+ *buff+=4;
+ buff++;
+ buff++;
+ for (i = 0; i < opt->strict_route.route_size; i++)
+ {
+ if(i>=MAX_ROUTE)
+ return(1);
+ if(i==opt->strict_route.pointer)
+ *(unsigned long *)buff=dev->pa_addr;
+ opt->strict_route.route[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ case IPOPT_RR:
+ buff++;
+ if ((*buff - 3)% 4 != 0)
+ return(1);
+ if(*buff<2)
+ return(1);
+ len += (optsiz= *buff);
+ opt->record_route.route_size = (*buff -3)/4;
+ buff++;
+ if (*buff % 4 != 0)
+ return(1);
+ opt->record_route.pointer = *buff/4 - 1;
+ if(*buff+4<=optsiz)
+ *buff+=4;
+ buff++;
+ buff++;
+ for (i = 0; i < opt->record_route.route_size; i++)
+ {
+ if(i>=MAX_ROUTE)
+ return 1;
+ if(i==opt->record_route.pointer)
+ *(unsigned long *)buff=dev->pa_addr;
+ opt->record_route.route[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ case IPOPT_SID:
+ len += 4;
+ buff +=2;
+ opt->stream = *(unsigned short *)buff;
+ buff += 2;
+ break;
+ case IPOPT_TIMESTAMP:
+ /* FIXME: This one isn't altered correctly yet */
+ buff++;
+ if(*buff<2)
return 1;
- opt->record_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_SID:
- len += 4;
- buff +=2;
- opt->stream = *(unsigned short *)buff;
- buff += 2;
- break;
- case IPOPT_TIMESTAMP:
- buff++;
- len += *buff;
- if (*buff % 4 != 0) return(1);
- opt->tstamp.len = *buff / 4 - 1;
- buff++;
- if ((*buff - 1) % 4 != 0) return(1);
- opt->tstamp.ptr = (*buff-1)/4;
- buff++;
- opt->tstamp.x.full_char = *buff;
- buff++;
- for (i = 0; i < opt->tstamp.len; i++) {
- opt->tstamp.data[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- default:
- return(1);
- }
+ len += *buff;
+ if (*buff % 4 != 0)
+ return(1);
+ opt->tstamp.len = *buff / 4 - 1;
+ buff++;
+ if ((*buff - 1) % 4 != 0)
+ return(1);
+ opt->tstamp.ptr = (*buff-1)/4;
+ buff++;
+ opt->tstamp.x.full_char = *buff;
+ buff++;
+ for (i = 0; i < opt->tstamp.len; i++)
+ {
+ opt->tstamp.data[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ default:
+ return(1);
+ }
- if (opt->record_route.route_size == 0) {
- if (opt->strict_route.route_size != 0) {
- memcpy(&(opt->record_route), &(opt->strict_route),
+ if (opt->record_route.route_size == 0)
+ {
+ if (opt->strict_route.route_size != 0)
+ {
+ memcpy(&(opt->record_route), &(opt->strict_route),
sizeof(opt->record_route));
- } else if (opt->loose_route.route_size != 0) {
- memcpy(&(opt->record_route), &(opt->loose_route),
+ }
+ else if (opt->loose_route.route_size != 0)
+ {
+ memcpy(&(opt->record_route), &(opt->loose_route),
sizeof(opt->record_route));
+ }
}
- }
- if (opt->strict_route.route_size != 0 &&
- opt->strict_route.route_size != opt->strict_route.pointer) {
- strict_route(iph, opt);
- return(0);
- }
+ if (opt->strict_route.route_size != 0 &&
+ opt->strict_route.route_size != opt->strict_route.pointer)
+ {
+ strict_route(iph, opt);
+ return(0);
+ }
- if (opt->loose_route.route_size != 0 &&
- opt->loose_route.route_size != opt->loose_route.pointer) {
- loose_route(iph, opt);
- return(0);
- }
+ if (opt->loose_route.route_size != 0 &&
+ opt->loose_route.route_size != opt->loose_route.pointer)
+ {
+ loose_route(iph, opt);
+ return(0);
+ }
- return(0);
+ return(0);
}
-/* This is a version of ip_compute_csum() optimized for IP headers, which
- always checksum on 4 octet boundaries. */
-static inline unsigned short
-ip_fast_csum(unsigned char * buff, int wlen)
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers, which
+ * always checksum on 4 octet boundaries.
+ */
+
+static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
{
- unsigned long sum = 0;
-
- if (wlen) {
- unsigned long bogus;
- __asm__("clc\n"
- "1:\t"
- "lodsl\n\t"
- "adcl %3, %0\n\t"
- "decl %2\n\t"
- "jne 1b\n\t"
- "adcl $0, %0\n\t"
- "movl %0, %3\n\t"
- "shrl $16, %3\n\t"
- "addw %w3, %w0\n\t"
- "adcw $0, %w0"
- : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
- : "0" (sum), "1" (buff), "2" (wlen));
- }
- return (~sum) & 0xffff;
+ unsigned long sum = 0;
+
+ if (wlen) {
+ unsigned long bogus;
+ __asm__("clc\n"
+ "1:\t"
+ "lodsl\n\t"
+ "adcl %3, %0\n\t"
+ "decl %2\n\t"
+ "jne 1b\n\t"
+ "adcl $0, %0\n\t"
+ "movl %0, %3\n\t"
+ "shrl $16, %3\n\t"
+ "addw %w3, %w0\n\t"
+ "adcw $0, %w0"
+ : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
+ : "0" (sum), "1" (buff), "2" (wlen));
+ }
+ return (~sum) & 0xffff;
}
/*
* This routine does all the checksum computations that don't
* require anything special (like copying or special headers).
*/
-unsigned short
-ip_compute_csum(unsigned char * buff, int len)
+
+unsigned short ip_compute_csum(unsigned char * buff, int len)
{
- unsigned long sum = 0;
-
- /* Do the first multiple of 4 bytes and convert to 16 bits. */
- if (len > 3) {
- __asm__("clc\n"
- "1:\t"
- "lodsl\n\t"
- "adcl %%eax, %%ebx\n\t"
- "loop 1b\n\t"
- "adcl $0, %%ebx\n\t"
- "movl %%ebx, %%eax\n\t"
- "shrl $16, %%eax\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum) , "=S" (buff)
- : "0" (sum), "c" (len >> 2) ,"1" (buff)
- : "ax", "cx", "si", "bx" );
- }
- if (len & 2) {
- __asm__("lodsw\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum), "=S" (buff)
- : "0" (sum), "1" (buff)
- : "bx", "ax", "si");
- }
- if (len & 1) {
- __asm__("lodsb\n\t"
- "movb $0, %%ah\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum), "=S" (buff)
- : "0" (sum), "1" (buff)
- : "bx", "ax", "si");
- }
- sum =~sum;
- return(sum & 0xffff);
+ unsigned long sum = 0;
+
+ /* Do the first multiple of 4 bytes and convert to 16 bits. */
+ if (len > 3) {
+ __asm__("clc\n"
+ "1:\t"
+ "lodsl\n\t"
+ "adcl %%eax, %%ebx\n\t"
+ "loop 1b\n\t"
+ "adcl $0, %%ebx\n\t"
+ "movl %%ebx, %%eax\n\t"
+ "shrl $16, %%eax\n\t"
+ "addw %%ax, %%bx\n\t"
+ "adcw $0, %%bx"
+ : "=b" (sum) , "=S" (buff)
+ : "0" (sum), "c" (len >> 2) ,"1" (buff)
+ : "ax", "cx", "si", "bx" );
+ }
+ if (len & 2) {
+ __asm__("lodsw\n\t"
+ "addw %%ax, %%bx\n\t"
+ "adcw $0, %%bx"
+ : "=b" (sum), "=S" (buff)
+ : "0" (sum), "1" (buff)
+ : "bx", "ax", "si");
+ }
+ if (len & 1) {
+ __asm__("lodsb\n\t"
+ "movb $0, %%ah\n\t"
+ "addw %%ax, %%bx\n\t"
+ "adcw $0, %%bx"
+ : "=b" (sum), "=S" (buff)
+ : "0" (sum), "1" (buff)
+ : "bx", "ax", "si");
+ }
+ sum =~sum;
+ return(sum & 0xffff);
}
-/* Check the header of an incoming IP datagram. This version is still used in slhc.c. */
-int
-ip_csum(struct iphdr *iph)
+/*
+ * Check the header of an incoming IP datagram. This version is still used in slhc.c.
+ */
+
+int ip_csum(struct iphdr *iph)
{
- return ip_fast_csum((unsigned char *)iph, iph->ihl);
+ return ip_fast_csum((unsigned char *)iph, iph->ihl);
}
-/* Generate a checksym for an outgoing IP datagram. */
-static void
-ip_send_check(struct iphdr *iph)
+/*
+ * Generate a checksym for an outgoing IP datagram. (RFC791, Page 14)
+ */
+
+static void ip_send_check(struct iphdr *iph)
{
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/
static struct ipq *ipqueue = NULL; /* IP fragment queue */
- /* Create a new fragment entry. */
+
+/*
+ * Create a new fragment entry.
+ */
+
static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
{
- struct ipfrag *fp;
+ struct ipfrag *fp;
- fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
- if (fp == NULL)
- {
+ fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
+ if (fp == NULL)
+ {
printk("IP: frag_create: no memory left !\n");
return(NULL);
- }
- memset(fp, 0, sizeof(struct ipfrag));
+ }
+ memset(fp, 0, sizeof(struct ipfrag));
/* Fill in the structure. */
fp->offset = offset;
@@ -539,6 +664,7 @@ 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;
@@ -548,14 +674,14 @@ static struct ipq *ip_find(struct iphdr *iph)
qplast = NULL;
for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next)
{
- if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr &&
+ if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr &&
iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol)
{
del_timer(&qp->timer); /* So it doesnt vanish on us. The timer will be reset anyway */
- sti();
- return(qp);
- }
- }
+ sti();
+ return(qp);
+ }
+ }
sti();
return(NULL);
}
@@ -583,60 +709,62 @@ static void ip_free(struct ipq *qp)
ipqueue = qp->next;
if (ipqueue != NULL)
ipqueue->prev = NULL;
- }
- else
- {
- qp->prev->next = qp->next;
- if (qp->next != NULL)
- qp->next->prev = qp->prev;
- }
-
- /* Release all fragment data. */
+ }
+ else
+ {
+ qp->prev->next = qp->next;
+ if (qp->next != NULL)
+ qp->next->prev = qp->prev;
+ }
+
+ /* Release all fragment data. */
/* printk("ip_free: kill frag data\n");*/
- fp = qp->fragments;
- while (fp != NULL)
- {
- xp = fp->next;
- IS_SKB(fp->skb);
- kfree_skb(fp->skb,FREE_READ);
- kfree_s(fp, sizeof(struct ipfrag));
- fp = xp;
- }
-
+ fp = qp->fragments;
+ while (fp != NULL)
+ {
+ xp = fp->next;
+ IS_SKB(fp->skb);
+ kfree_skb(fp->skb,FREE_READ);
+ kfree_s(fp, sizeof(struct ipfrag));
+ fp = xp;
+ }
+
/* printk("ip_free: cleanup\n");*/
- /* Release the MAC header. */
- kfree_s(qp->mac, qp->maclen);
+ /* Release the MAC header. */
+ kfree_s(qp->mac, qp->maclen);
- /* Release the IP header. */
- kfree_s(qp->iph, qp->ihlen + 8);
+ /* Release the IP header. */
+ kfree_s(qp->iph, qp->ihlen + 8);
- /* Finally, release the queue descriptor itself. */
- kfree_s(qp, sizeof(struct ipq));
+ /* Finally, release the queue descriptor itself. */
+ kfree_s(qp, sizeof(struct ipq));
/* printk("ip_free:done\n");*/
- sti();
+ sti();
}
- /* Oops- a fragment queue timed out. Kill it and send an ICMP reply. */
+/*
+ * Oops- a fragment queue timed out. Kill it and send an ICMP reply.
+ */
static void ip_expire(unsigned long arg)
{
- struct ipq *qp;
+ struct ipq *qp;
- qp = (struct ipq *)arg;
- DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp));
+ qp = (struct ipq *)arg;
+ DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp));
- /* Send an ICMP "Fragment Reassembly Timeout" message. */
+ /* Send an ICMP "Fragment Reassembly Timeout" message. */
#if 0
- icmp_send(qp->iph->ip_src.s_addr, ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, qp->iph);
+ icmp_send(qp->iph->ip_src.s_addr, ICMP_TIME_EXCEEDED,
+ ICMP_EXC_FRAGTIME, qp->iph);
#endif
- if(qp->fragments!=NULL)
- icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, qp->dev);
+ if(qp->fragments!=NULL)
+ icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
+ ICMP_EXC_FRAGTIME, qp->dev);
- /* Nuke the fragment queue. */
+ /* Nuke the fragment queue. */
ip_free(qp);
}
@@ -650,158 +778,168 @@ static void ip_expire(unsigned long arg)
static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev)
{
- struct ipq *qp;
- int maclen;
- int ihlen;
+ struct ipq *qp;
+ int maclen;
+ int ihlen;
- qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC);
- if (qp == NULL)
- {
+ qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC);
+ if (qp == NULL)
+ {
printk("IP: create: no memory left !\n");
return(NULL);
- }
- memset(qp, 0, sizeof(struct ipq));
-
- /* Allocate memory for the MAC header. */
- maclen = ((unsigned long) iph) - ((unsigned long) (skb + 1));
- qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC);
- if (qp->mac == NULL)
- {
+ }
+ memset(qp, 0, sizeof(struct ipq));
+
+ /* Allocate memory for the MAC header. */
+ maclen = ((unsigned long) iph) - ((unsigned long) (skb + 1));
+ qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC);
+ if (qp->mac == NULL)
+ {
printk("IP: create: no memory left !\n");
kfree_s(qp, sizeof(struct ipq));
return(NULL);
- }
+ }
- /* Allocate memory for the IP header (plus 8 octects for ICMP). */
- ihlen = (iph->ihl * sizeof(unsigned long));
- qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC);
- if (qp->iph == NULL)
- {
+ /* Allocate memory for the IP header (plus 8 octects for ICMP). */
+ ihlen = (iph->ihl * sizeof(unsigned long));
+ qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC);
+ if (qp->iph == NULL)
+ {
printk("IP: create: no memory left !\n");
kfree_s(qp->mac, maclen);
kfree_s(qp, sizeof(struct ipq));
return(NULL);
- }
-
- /* Fill in the structure. */
- memcpy(qp->mac, (skb + 1), maclen);
- memcpy(qp->iph, iph, ihlen + 8);
- qp->len = 0;
- qp->ihlen = ihlen;
- qp->maclen = maclen;
- qp->fragments = NULL;
- qp->dev = dev;
+ }
+
+ /* Fill in the structure. */
+ memcpy(qp->mac, (skb + 1), maclen);
+ memcpy(qp->iph, iph, ihlen + 8);
+ qp->len = 0;
+ qp->ihlen = ihlen;
+ qp->maclen = maclen;
+ qp->fragments = NULL;
+ qp->dev = dev;
/* printk("Protocol = %d\n",qp->iph->protocol);*/
- /* Start a timer for this entry. */
- qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
-
- /* Add this entry to the queue. */
- qp->prev = NULL;
- cli();
- qp->next = ipqueue;
- if (qp->next != NULL)
- qp->next->prev = qp;
- ipqueue = qp;
- sti();
- return(qp);
+ /* Start a timer for this entry. */
+ qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
+ qp->timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->timer.function = ip_expire; /* expire function */
+ add_timer(&qp->timer);
+
+ /* Add this entry to the queue. */
+ qp->prev = NULL;
+ cli();
+ qp->next = ipqueue;
+ if (qp->next != NULL)
+ qp->next->prev = qp;
+ ipqueue = qp;
+ sti();
+ return(qp);
}
- /* See if a fragment queue is complete. */
+/*
+ * See if a fragment queue is complete.
+ */
+
static int ip_done(struct ipq *qp)
{
struct ipfrag *fp;
int offset;
- /* Only possible if we received the final fragment. */
- if (qp->len == 0)
- return(0);
-
- /* Check all fragment offsets to see if they connect. */
- fp = qp->fragments;
- offset = 0;
- while (fp != NULL)
- {
- if (fp->offset > offset)
- return(0); /* fragment(s) missing */
- offset = fp->end;
- fp = fp->next;
- }
-
- /* All fragments are present. */
- return(1);
+ /* Only possible if we received the final fragment. */
+ if (qp->len == 0)
+ return(0);
+
+ /* Check all fragment offsets to see if they connect. */
+ fp = qp->fragments;
+ offset = 0;
+ while (fp != NULL)
+ {
+ if (fp->offset > offset)
+ return(0); /* fragment(s) missing */
+ offset = fp->end;
+ fp = fp->next;
+ }
+
+ /* All fragments are present. */
+ return(1);
}
-/* Build a new IP datagram from all its fragments. */
+/*
+ * Build a new IP datagram from all its fragments.
+ */
+
static struct sk_buff *ip_glue(struct ipq *qp)
{
struct sk_buff *skb;
- struct iphdr *iph;
- struct ipfrag *fp;
- unsigned char *ptr;
- int count, len;
-
- /* Allocate a new buffer for the datagram. */
- len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len;
- if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL)
- {
- printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp);
- ip_free(qp);
- return(NULL);
- }
-
- /* Fill in the basic details. */
- skb->len = (len - qp->maclen);
- skb->h.raw = (unsigned char *) (skb + 1);
- skb->free = 1;
- skb->lock = 1;
-
- /* Copy the original MAC and IP headers into the new buffer. */
- ptr = (unsigned char *) skb->h.raw;
- memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen);
+ struct iphdr *iph;
+ struct ipfrag *fp;
+ unsigned char *ptr;
+ int count, len;
+
+ /* Allocate a new buffer for the datagram. */
+ len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len;
+ if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL)
+ {
+ printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp);
+ ip_free(qp);
+ return(NULL);
+ }
+
+ /* Fill in the basic details. */
+ skb->len = (len - qp->maclen);
+ skb->h.raw = (unsigned char *) (skb + 1);
+ skb->free = 1;
+ skb->lock = 1;
+
+ /* Copy the original MAC and IP headers into the new buffer. */
+ ptr = (unsigned char *) skb->h.raw;
+ memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen);
/* printk("Copied %d bytes of mac header.\n",qp->maclen);*/
- ptr += qp->maclen;
- memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
+ ptr += qp->maclen;
+ memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
/* printk("Copied %d byte of ip header.\n",qp->ihlen);*/
- ptr += qp->ihlen;
- skb->h.raw += qp->maclen;
-
+ ptr += qp->ihlen;
+ skb->h.raw += qp->maclen;
+
/* printk("Protocol = %d\n",skb->h.iph->protocol);*/
- count = 0;
-
- /* Copy the data portions of all fragments into the new buffer. */
- fp = qp->fragments;
- while(fp != NULL)
- {
- if(count+fp->len>skb->len)
- {
- printk("Invalid fragment list: Fragment over size.\n");
- kfree_skb(skb,FREE_WRITE);
- return NULL;
- }
+ count = 0;
+
+ /* Copy the data portions of all fragments into the new buffer. */
+ fp = qp->fragments;
+ while(fp != NULL)
+ {
+ if(count+fp->len>skb->len)
+ {
+ /* In case some fool sends us a silly fragment. */
+ printk("Invalid fragment list: Fragment over size.\n");
+ kfree_skb(skb,FREE_WRITE);
+ return NULL;
+ }
/* printk("Fragment %d size %d\n",fp->offset,fp->len);*/
- memcpy((ptr + fp->offset), fp->ptr, fp->len);
- count += fp->len;
- fp = fp->next;
- }
-
- /* We glued together all fragments, so remove the queue entry. */
- ip_free(qp);
-
- /* Done with all fragments. Fixup the new IP header. */
- iph = skb->h.iph;
- iph->frag_off = 0;
- iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count);
- return(skb);
+ memcpy((ptr + fp->offset), fp->ptr, fp->len);
+ count += fp->len;
+ fp = fp->next;
+ }
+
+ /* We glued together all fragments, so remove the queue entry. */
+ ip_free(qp);
+
+ /* Done with all fragments. Fixup the new IP header. */
+ iph = skb->h.iph;
+ iph->frag_off = 0;
+ iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count);
+ return(skb);
}
-/* Process an incoming IP datagram fragment. */
+/*
+ * Process an incoming IP datagram fragment.
+ */
+
static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev)
{
struct ipfrag *prev, *next;
@@ -813,135 +951,135 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
int i, ihl, end;
/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
- qp = ip_find(iph);
-
- /* Is this a non-fragmented datagram? */
- offset = ntohs(iph->frag_off);
- flags = offset & ~IP_OFFSET;
- offset &= IP_OFFSET;
- if (((flags & IP_MF) == 0) && (offset == 0))
- {
- if (qp != NULL)
- ip_free(qp); /* Huh? How could this exist?? */
- return(skb);
- }
- offset <<= 3; /* offset is in 8-byte chunks */
-
- /*
- * If the queue already existed, keep restarting its timer as long
- * as we still are receiving fragments. Otherwise, create a fresh
- * queue entry.
- */
- if (qp != NULL)
- {
- del_timer(&qp->timer);
- qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
- }
- else
- {
- if ((qp = ip_create(skb, iph, dev)) == NULL)
- return(NULL);
- }
-
- /* Determine the position of this fragment. */
- ihl = (iph->ihl * sizeof(unsigned long));
- end = offset + ntohs(iph->tot_len) - ihl;
-
- /* Point into the IP datagram 'data' part. */
- ptr = ((unsigned char *) (skb + 1)) + dev->hard_header_len + ihl;
-
- /* Is this the final fragment? */
- if ((flags & IP_MF) == 0)
- qp->len = end;
-
- /*
- * Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
- */
- prev = NULL;
- for(next = qp->fragments; next != NULL; next = next->next)
- {
- if (next->offset > offset)
- break; /* bingo! */
- prev = next;
- }
-
- /*
- * We found where to put this one.
- * Check for overlap with preceeding fragment, and, if needed,
- * align things so that any overlaps are eliminated.
- */
- if (prev != NULL && offset < prev->end)
- {
- i = prev->end - offset;
- offset += i; /* ptr into datagram */
- ptr += i; /* ptr into fragment data */
- DPRINTF((DBG_IP, "IP: defrag: fixed low overlap %d bytes\n", i));
- }
-
- /*
- * Look for overlap with succeeding segments.
- * If we can merge fragments, do it.
+ qp = ip_find(iph);
+
+ /* Is this a non-fragmented datagram? */
+ offset = ntohs(iph->frag_off);
+ flags = offset & ~IP_OFFSET;
+ offset &= IP_OFFSET;
+ if (((flags & IP_MF) == 0) && (offset == 0))
+ {
+ if (qp != NULL)
+ ip_free(qp); /* Huh? How could this exist?? */
+ return(skb);
+ }
+ offset <<= 3; /* offset is in 8-byte chunks */
+
+ /*
+ * If the queue already existed, keep restarting its timer as long
+ * as we still are receiving fragments. Otherwise, create a fresh
+ * queue entry.
+ */
+ if (qp != NULL)
+ {
+ del_timer(&qp->timer);
+ qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
+ qp->timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->timer.function = ip_expire; /* expire function */
+ add_timer(&qp->timer);
+ }
+ else
+ {
+ if ((qp = ip_create(skb, iph, dev)) == NULL)
+ return(NULL);
+ }
+
+ /* Determine the position of this fragment. */
+ ihl = (iph->ihl * sizeof(unsigned long));
+ end = offset + ntohs(iph->tot_len) - ihl;
+
+ /* Point into the IP datagram 'data' part. */
+ ptr = ((unsigned char *) (skb + 1)) + dev->hard_header_len + ihl;
+
+ /* Is this the final fragment? */
+ if ((flags & IP_MF) == 0)
+ qp->len = end;
+
+ /*
+ * Find out which fragments are in front and at the back of us
+ * in the chain of fragments so far. We must know where to put
+ * this fragment, right?
+ */
+ prev = NULL;
+ for(next = qp->fragments; next != NULL; next = next->next)
+ {
+ if (next->offset > offset)
+ break; /* bingo! */
+ prev = next;
+ }
+
+ /*
+ * We found where to put this one.
+ * Check for overlap with preceeding fragment, and, if needed,
+ * align things so that any overlaps are eliminated.
+ */
+ if (prev != NULL && offset < prev->end)
+ {
+ i = prev->end - offset;
+ offset += i; /* ptr into datagram */
+ ptr += i; /* ptr into fragment data */
+ DPRINTF((DBG_IP, "IP: defrag: fixed low overlap %d bytes\n", i));
+ }
+
+ /*
+ * Look for overlap with succeeding segments.
+ * If we can merge fragments, do it.
*/
- for(; next != NULL; next = tfp)
- {
- tfp = next->next;
- if (next->offset >= end)
- break; /* no overlaps at all */
-
- i = end - next->offset; /* overlap is 'i' bytes */
- next->len -= i; /* so reduce size of */
- next->offset += i; /* next fragment */
- next->ptr += i;
-
- /* If we get a frag size of <= 0, remove it. */
- if (next->len <= 0)
- {
- DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n",
- next, next->len));
- if (next->prev != NULL)
- next->prev->next = next->next;
- else
- qp->fragments = next->next;
-
- if (tfp->next != NULL)
- next->next->prev = next->prev;
-
- kfree_s(next, sizeof(struct ipfrag));
- }
- DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i));
- }
-
- /* Insert this fragment in the chain of fragments. */
- tfp = NULL;
- tfp = ip_frag_create(offset, end, skb, ptr);
- tfp->prev = prev;
- tfp->next = next;
- if (prev != NULL)
- prev->next = tfp;
+ for(; next != NULL; next = tfp)
+ {
+ tfp = next->next;
+ if (next->offset >= end)
+ break; /* no overlaps at all */
+
+ i = end - next->offset; /* overlap is 'i' bytes */
+ next->len -= i; /* so reduce size of */
+ next->offset += i; /* next fragment */
+ next->ptr += i;
+
+ /* If we get a frag size of <= 0, remove it. */
+ if (next->len <= 0)
+ {
+ DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n",
+ next, next->len));
+ if (next->prev != NULL)
+ next->prev->next = next->next;
+ else
+ qp->fragments = next->next;
+
+ if (tfp->next != NULL)
+ next->next->prev = next->prev;
+
+ kfree_s(next, sizeof(struct ipfrag));
+ }
+ DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i));
+ }
+
+ /* Insert this fragment in the chain of fragments. */
+ tfp = NULL;
+ tfp = ip_frag_create(offset, end, skb, ptr);
+ tfp->prev = prev;
+ tfp->next = next;
+ if (prev != NULL)
+ prev->next = tfp;
else
qp->fragments = tfp;
- if (next != NULL)
- next->prev = tfp;
-
- /*
- * OK, so we inserted this new fragment into the chain.
- * Check if we now have a full IP datagram which we can
- * bump up to the IP layer...
- */
+ if (next != NULL)
+ next->prev = tfp;
+
+ /*
+ * OK, so we inserted this new fragment into the chain.
+ * Check if we now have a full IP datagram which we can
+ * bump up to the IP layer...
+ */
- if (ip_done(qp))
- {
- skb2 = ip_glue(qp); /* glue together the fragments */
- return(skb2);
- }
- return(NULL);
+ if (ip_done(qp))
+ {
+ skb2 = ip_glue(qp); /* glue together the fragments */
+ return(skb2);
+ }
+ return(NULL);
}
@@ -953,363 +1091,398 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
* ip_queue_xmit(). Note that this is recursion, and bad things will happen
* if this function causes a loop...
*/
+
void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag)
{
- struct iphdr *iph;
- unsigned char *raw;
- unsigned char *ptr;
- struct sk_buff *skb2;
- int left, mtu, hlen, len;
- int offset;
-
- /* Point into the IP datagram header. */
- raw = (unsigned char *) (skb + 1);
- iph = (struct iphdr *) (raw + dev->hard_header_len);
-
- /* Setup starting values. */
- hlen = (iph->ihl * sizeof(unsigned long));
- left = ntohs(iph->tot_len) - hlen;
- hlen += dev->hard_header_len;
- mtu = (dev->mtu - hlen);
- ptr = (raw + hlen);
-
- DPRINTF((DBG_IP, "IP: Fragmentation Desired\n"));
- DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
- dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
-
- /* Check for any "DF" flag. */
- if (ntohs(iph->frag_off) & IP_DF)
- {
- DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n"));
- DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
- dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
-
- /*
- * FIXME:
- * We should send an ICMP warning message here!
- */
-
- icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev);
- return;
- }
-
- /* Fragment the datagram. */
+ struct iphdr *iph;
+ unsigned char *raw;
+ unsigned char *ptr;
+ struct sk_buff *skb2;
+ int left, mtu, hlen, len;
+ int offset;
+
+ /* Point into the IP datagram header. */
+ raw = (unsigned char *) (skb + 1);
+ iph = (struct iphdr *) (raw + dev->hard_header_len);
+
+ /* Setup starting values. */
+ hlen = (iph->ihl * sizeof(unsigned long));
+ left = ntohs(iph->tot_len) - hlen;
+ hlen += dev->hard_header_len;
+ mtu = (dev->mtu - hlen);
+ ptr = (raw + hlen);
+
+ DPRINTF((DBG_IP, "IP: Fragmentation Desired\n"));
+ DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
+ dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
+
+ /* Check for any "DF" flag. */
+ if (ntohs(iph->frag_off) & IP_DF)
+ {
+ DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n"));
+ DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
+ dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
+
+ /*
+ * FIXME:
+ * We should send an ICMP warning message here!
+ */
+
+ icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev);
+ return;
+ }
+
+ /*
+ * 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;
else
- offset = 0;
- while(left > 0)
- {
- len = left;
- if (len+8 > mtu)
- len = (dev->mtu - hlen - 8);
- if ((left - len) >= 8)
- {
- len /= 8;
- len *= 8;
- }
- DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
- len, len + hlen));
-
- /* Allocate buffer. */
- if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL)
- {
- printk("IP: frag: no memory for new fragment!\n");
- return;
- }
- skb2->arp = skb->arp;
- skb2->free = skb->free;
- skb2->len = len + hlen;
- skb2->h.raw=(char *)(skb2+1);
-
- if (sk)
- sk->wmem_alloc += skb2->mem_len;
-
- /* Copy the packet header into the new buffer. */
- memcpy(skb2->h.raw, raw, hlen);
-
- /* Copy a block of the IP datagram. */
- memcpy(skb2->h.raw + hlen, ptr, len);
- left -= len;
+ offset = 0;
+ while(left > 0)
+ {
+ len = left;
+ if (len+8 > mtu)
+ len = (dev->mtu - hlen - 8);
+ if ((left - len) >= 8)
+ {
+ len /= 8;
+ len *= 8;
+ }
+ DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
+ len, len + hlen));
+
+ /* Allocate buffer. */
+ if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL)
+ {
+ printk("IP: frag: no memory for new fragment!\n");
+ return;
+ }
+ skb2->arp = skb->arp;
+ skb2->free = skb->free;
+ skb2->len = len + hlen;
+ skb2->h.raw=(char *)(skb2+1);
+
+ if (sk)
+ sk->wmem_alloc += skb2->mem_len;
+
+ /* Copy the packet header into the new buffer. */
+ memcpy(skb2->h.raw, raw, hlen);
+
+ /* Copy a block of the IP datagram. */
+ memcpy(skb2->h.raw + hlen, ptr, len);
+ left -= len;
skb2->h.raw+=dev->hard_header_len;
- /* Fill in the new header fields. */
- iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/);
- iph->frag_off = htons((offset >> 3));
- /* Added AC : If we are fragmenting a fragment thats not the
- last fragment then keep MF on each bit */
- if (left > 0 || (is_frag & 1))
- iph->frag_off |= htons(IP_MF);
- ptr += len;
- offset += len;
+ /* Fill in the new header fields. */
+ iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/);
+ iph->frag_off = htons((offset >> 3));
+ /* Added AC : If we are fragmenting a fragment thats not the
+ last fragment then keep MF on each bit */
+ if (left > 0 || (is_frag & 1))
+ iph->frag_off |= htons(IP_MF);
+ ptr += len;
+ offset += len;
/* printk("Queue frag\n");*/
- /* Put this fragment into the sending queue. */
- ip_queue_xmit(sk, dev, skb2, 1);
+ /* Put this fragment into the sending queue. */
+ ip_queue_xmit(sk, dev, skb2, 1);
/* printk("Queued\n");*/
- }
+ }
}
#ifdef CONFIG_IP_FORWARD
-/* Forward an IP datagram to its next destination. */
-static void
-ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
+/*
+ * Forward an IP datagram to its next destination.
+ */
+
+static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
{
- struct device *dev2;
- struct iphdr *iph;
- struct sk_buff *skb2;
- struct rtable *rt;
- unsigned char *ptr;
- unsigned long raddr;
+ struct device *dev2;
+ struct iphdr *iph;
+ struct sk_buff *skb2;
+ struct rtable *rt;
+ unsigned char *ptr;
+ unsigned long raddr;
- /*
- * Only forward packets that were fired at us when we are in promiscuous
- * mode. In standard mode we rely on the driver to filter for us.
- */
+ /*
+ * Only forward packets that were fired at us when we are in promiscuous
+ * mode. In standard mode we rely on the driver to filter for us.
+ */
- if(dev->flags&IFF_PROMISC)
- {
- if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len))
- return;
- }
+ if(dev->flags&IFF_PROMISC)
+ {
+ if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len))
+ return;
+ }
- /*
- * According to the RFC, we must first decrease the TTL field. If
- * that reaches zero, we must reply an ICMP control message telling
- * that the packet's lifetime expired.
- */
- iph = skb->h.iph;
- iph->ttl--;
- if (iph->ttl <= 0) {
- DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));
- DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
-
- /* Tell the sender its packet died... */
- icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev);
- return;
- }
-
- /* Re-compute the IP header checksum. */
- ip_send_check(iph);
-
- /*
- * OK, the packet is still valid. Fetch its destination address,
- * and give it to the IP sender for further processing.
- */
- rt = rt_route(iph->daddr, NULL);
- if (rt == NULL) {
- DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));
-
- /* Tell the sender its packet cannot be delivered... */
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev);
- return;
- }
+ /*
+ * According to the RFC, we must first decrease the TTL field. If
+ * that reaches zero, we must reply an ICMP control message telling
+ * that the packet's lifetime expired. RFC791 page 30.
+ */
+ iph = skb->h.iph;
+ iph->ttl--;
+ if (iph->ttl <= 0)
+ {
+ DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));
+ DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
+
+ /* Tell the sender its packet died... */
+ icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev);
+ return;
+ }
+ /* Re-compute the IP header checksum. */
+ ip_send_check(iph);
- /*
- * Gosh. Not only is the packet valid; we even know how to
- * forward it onto its final destination. Can we say this
- * is being plain lucky?
- * If the router told us that there is no GW, use the dest.
- * IP address itself- we seem to be connected directly...
- */
- raddr = rt->rt_gateway;
- if (raddr != 0) {
- rt = rt_route(raddr, NULL);
- if (rt == NULL) {
- DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));
+ /*
+ * OK, the packet is still valid. Fetch its destination address,
+ * and give it to the IP sender for further processing.
+ */
+ rt = rt_route(iph->daddr, NULL);
+ if (rt == NULL)
+ {
+ DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));
/* Tell the sender its packet cannot be delivered... */
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev);
return;
}
- if (rt->rt_gateway != 0) raddr = rt->rt_gateway;
- } else raddr = iph->daddr;
- dev2 = rt->rt_dev;
- if (dev == dev2)
- return;
- /*
- * We now allocate a new buffer, and copy the datagram into it.
- * If the indicated interface is up and running, kick it.
- */
- DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n",
+ /*
+ * Gosh. Not only is the packet valid; we even know how to
+ * forward it onto its final destination. Can we say this
+ * is being plain lucky?
+ * If the router told us that there is no GW, use the dest.
+ * IP address itself- we seem to be connected directly...
+ */
+ raddr = rt->rt_gateway;
+ if (raddr != 0)
+ {
+ rt = rt_route(raddr, NULL);
+ if (rt == NULL)
+ {
+ DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));
+
+ /* Tell the sender its packet cannot be delivered... */
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);
+ return;
+ }
+ if (rt->rt_gateway != 0)
+ raddr = rt->rt_gateway;
+ }
+ else
+ raddr = iph->daddr;
+ dev2 = rt->rt_dev;
+
+ /*
+ * Never forward out on the same interface, its not allowed, its often not pretty either (except for on
+ * source routing)
+ */
+ if (dev == dev2)
+ return;
+ /*
+ * We now allocate a new buffer, and copy the datagram into it.
+ * If the indicated interface is up and running, kick it.
+ */
+ DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n",
in_ntoa(raddr), dev2->name, skb->len));
- if (dev2->flags & IFF_UP) {
- skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +
+ if (dev2->flags & IFF_UP)
+ {
+ skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +
dev2->hard_header_len + skb->len, GFP_ATOMIC);
- if (skb2 == NULL) {
- printk("\nIP: No memory available for IP forward\n");
- return;
- }
- ptr = (unsigned char *)(skb2 + 1);
- skb2->sk = NULL;
- skb2->free = 1;
- skb2->len = skb->len + dev2->hard_header_len;
- skb2->mem_addr = skb2;
- skb2->mem_len = sizeof(struct sk_buff) + skb2->len;
- skb2->next = NULL;
- skb2->h.raw = ptr;
-
- /* Copy the packet data into the new buffer. */
- memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len);
+ if (skb2 == NULL)
+ {
+ printk("\nIP: No memory available for IP forward\n");
+ return;
+ }
+ ptr = (unsigned char *)(skb2 + 1);
+ skb2->sk = NULL;
+ skb2->free = 1;
+ skb2->len = skb->len + dev2->hard_header_len;
+ skb2->next = NULL;
+ skb2->h.raw = ptr;
+
+ /* Copy the packet data into the new buffer. */
+ memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len);
- /* Now build the MAC header. */
- (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);
+ /* Now build the MAC header. */
+ (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);
- if(skb2->len > dev2->mtu)
- {
- ip_fragment(NULL,skb2,dev2, is_frag);
- kfree_skb(skb2,FREE_WRITE);
+ if(skb2->len > dev2->mtu)
+ {
+ ip_fragment(NULL,skb2,dev2, is_frag);
+ kfree_skb(skb2,FREE_WRITE);
+ }
+ else
+ dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL);
}
- else
- dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL);
- }
}
#endif
-/* This function receives all incoming IP datagrams. */
-int
-ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+
+/*
+ * This function receives all incoming IP datagrams.
+ */
+
+int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- struct iphdr *iph = skb->h.iph;
- unsigned char hash;
- unsigned char flag = 0;
- unsigned char opts_p = 0; /* Set iff the packet has options. */
- struct inet_protocol *ipprot;
- static struct options opt; /* since we don't use these yet, and they
- take up stack space. */
- int brd;
- int is_frag=0;
-
- DPRINTF((DBG_IP, "<<\n"));
-
- /* Is the datagram acceptable? */
- if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) {
- DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
- DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */
- ip_print(iph); /* Bogus, only for debugging. */
- memset((char *) &opt, 0, sizeof(opt));
- if (do_options(iph, &opt) != 0)
- return 0;
- opts_p = 1;
- }
-
- if (iph->frag_off & 0x0020)
- is_frag|=1;
- if (ntohs(iph->frag_off) & 0x1fff)
- is_frag|=2;
-
- /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */
- if ((brd = chk_addr(iph->daddr)) == 0) {
+ struct iphdr *iph = skb->h.iph;
+ unsigned char hash;
+ unsigned char flag = 0;
+ unsigned char opts_p = 0; /* Set iff the packet has options. */
+ struct inet_protocol *ipprot;
+ struct options *opt=NULL;
+
+ int brd;
+ int is_frag=0;
+
+ DPRINTF((DBG_IP, "<<\n"));
+
+ /* Is the datagram acceptable? */
+ if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)
+ {
+ DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
+ DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+
+ if (iph->ihl != 5)
+ { /* Fast path for the typical optionless IP packet. */
+#ifdef IP_DEBUG
+ ip_print(iph); /* Bogus, only for debugging. */
+#endif
+ if (do_options(iph, &opt,dev) != 0)
+ {
+ if(opt)
+ kfree(opt);
+ return 0;
+ }
+/* skb->ip_options=opt_ptr;*/
+ kfree(opt);
+ opt = NULL;
+ opts_p = 0/*1*/;
+ }
+
+ if (iph->frag_off & 0x0020)
+ is_frag|=1;
+ if (ntohs(iph->frag_off) & 0x1fff)
+ is_frag|=2;
+
+ /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */
+ if ((brd = chk_addr(iph->daddr)) == 0)
+ {
#ifdef CONFIG_IP_FORWARD
- ip_forward(skb, dev, is_frag);
+ ip_forward(skb, dev, is_frag);
#else
- printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n",
+ printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n",
iph->saddr,iph->daddr);
#endif
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
/*
* Reassemble IP fragments.
*/
- if(is_frag)
- {
+ if(is_frag)
+ {
#ifdef CONFIG_IP_DEFRAG
- skb=ip_defrag(iph,skb,dev);
- if(skb==NULL)
- {
- return 0;
- }
- iph=skb->h.iph;
+ skb=ip_defrag(iph,skb,dev);
+ if(skb==NULL)
+ {
+ return 0;
+ }
+ iph=skb->h.iph;
#else
- printk("\nIP: *** datagram fragmentation not yet implemented ***\n");
- printk(" SRC = %s ", in_ntoa(iph->saddr));
- printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr));
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
+ printk("\nIP: *** datagram fragmentation not yet implemented ***\n");
+ printk(" SRC = %s ", in_ntoa(iph->saddr));
+ printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr));
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
#endif
- }
+ }
+ /* Point into the IP datagram, just past the header. */
+ skb->ip_hdr = iph;
+ skb->h.raw += iph->ihl*4;
+ hash = iph->protocol & (MAX_INET_PROTOS -1);
+
+ /* Find someone to deliver it too */
+
+ for (ipprot = (struct inet_protocol *)inet_protos[hash];
+ ipprot != NULL;
+ ipprot=(struct inet_protocol *)ipprot->next)
+ {
+ struct sk_buff *skb2;
- if(brd==IS_INVBCAST)
- {
-/* printk("Invalid broadcast address from %x [target %x] (Probably they have a wrong netmask)\n",
- iph->saddr,iph->daddr);*/
- skb->sk=NULL;
- kfree_skb(skb,FREE_WRITE);
- return(0);
- }
-
- /* Point into the IP datagram, just past the header. */
- skb->h.raw += iph->ihl*4;
- hash = iph->protocol & (MAX_INET_PROTOS -1);
- for (ipprot = (struct inet_protocol *)inet_protos[hash];
- ipprot != NULL;
- ipprot=(struct inet_protocol *)ipprot->next)
- {
- struct sk_buff *skb2;
-
- if (ipprot->protocol != iph->protocol) continue;
- DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot));
- print_ipprot(ipprot);
+ if (ipprot->protocol != iph->protocol)
+ continue;
+ DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot));
+ print_ipprot(ipprot);
/*
* See if we need to make a copy of it. This will
* only be set if more than one protocol wants it.
* and then not for the last one.
*/
- if (ipprot->copy) {
- skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
- if (skb2 == NULL)
- continue;
- memcpy(skb2, skb, skb->mem_len);
- skb2->mem_addr = skb2;
- skb2->h.raw = (unsigned char *)(
+ if (ipprot->copy)
+ {
+ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
+ if (skb2 == NULL)
+ continue;
+ memcpy(skb2, skb, skb->mem_len);
+ skb2->mem_addr = skb2;
+ skb2->h.raw = (unsigned char *)(
(unsigned long)skb2 +
(unsigned long) skb->h.raw -
(unsigned long)skb);
- skb2->free=1;
- } else {
- skb2 = skb;
- }
- flag = 1;
+ skb2->free=1;
+ }
+ else
+ {
+ skb2 = skb;
+ }
+ flag = 1;
- /*
- * Pass on the datagram to each protocol that wants it,
- * based on the datagram protocol. We should really
- * check the protocol handler's return values here...
- */
- ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,
+ /*
+ * Pass on the datagram to each protocol that wants it,
+ * based on the datagram protocol. We should really
+ * check the protocol handler's return values here...
+ */
+ ipprot->handler(skb2, dev, opts_p ? opt : 0, iph->daddr,
(ntohs(iph->tot_len) - (iph->ihl * 4)),
iph->saddr, 0, ipprot);
- }
+ }
/*
* All protocols checked.
@@ -1317,14 +1490,15 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* causes (proven, grin) ARP storms and a leakage of memory (i.e. all
* ICMP reply messages get queued up for transmission...)
*/
- if (!flag) {
- if (brd != IS_BROADCAST)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- }
+ if (!flag)
+ {
+ if (brd != IS_BROADCAST)
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ }
- return(0);
+ return(0);
}
@@ -1335,136 +1509,159 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* This routine also needs to put in the total length, and
* compute the checksum.
*/
-void
-ip_queue_xmit(struct sock *sk, struct device *dev,
+void ip_queue_xmit(struct sock *sk, struct device *dev,
struct sk_buff *skb, int free)
{
- struct iphdr *iph;
- unsigned char *ptr;
-
- if (sk == NULL) free = 1;
- if (dev == NULL) {
- printk("IP: ip_queue_xmit dev = NULL\n");
- return;
- }
- IS_SKB(skb);
- skb->free = free;
- skb->dev = dev;
- skb->when = jiffies;
+ struct iphdr *iph;
+ unsigned char *ptr;
+
+ if (sk == NULL)
+ free = 1;
+ if (dev == NULL)
+ {
+ printk("IP: ip_queue_xmit dev = NULL\n");
+ return;
+ }
+ IS_SKB(skb);
+ skb->free = free;
+ skb->dev = dev;
+ skb->when = jiffies;
- DPRINTF((DBG_IP, ">>\n"));
- ptr = (unsigned char *)(skb + 1);
- ptr += dev->hard_header_len;
- iph = (struct iphdr *)ptr;
- iph->tot_len = ntohs(skb->len-dev->hard_header_len);
-
- if(skb->len > dev->mtu)
- {
-/* printk("Fragment!\n");*/
- ip_fragment(sk,skb,dev,0);
- IS_SKB(skb);
- kfree_skb(skb,FREE_WRITE);
- return;
- }
+ DPRINTF((DBG_IP, ">>\n"));
+ ptr = (unsigned char *)(skb + 1);
+ ptr += dev->hard_header_len;
+ iph = (struct iphdr *)ptr;
+ iph->tot_len = ntohs(skb->len-dev->hard_header_len);
+
+ if(skb->len > dev->mtu)
+ {
+/* printk("Fragment!\n");*/
+ ip_fragment(sk,skb,dev,0);
+ IS_SKB(skb);
+ kfree_skb(skb,FREE_WRITE);
+ return;
+ }
- ip_send_check(iph);
- ip_print(iph);
- skb->next = NULL;
-
- /* See if this is the one trashing our queue. Ross? */
- skb->magic = 1;
- if (!free) {
- skb->link3 = NULL;
- sk->packets_out++;
- cli();
- if (sk->send_head == NULL) {
- sk->send_tail = skb;
- sk->send_head = skb;
- } else {
- /* See if we've got a problem. */
- if (sk->send_tail == NULL) {
- printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");
- sort_send(sk);
- } else {
- sk->send_tail->link3 = skb;
+ ip_send_check(iph);
+#ifdef IP_DEBUG
+ ip_print(iph);
+#endif
+ skb->next = NULL;
+
+ /* See if this is the one trashing our queue. Ross? */
+ skb->magic = 1;
+ if (!free)
+ {
+ skb->link3 = NULL;
+ sk->packets_out++;
+ cli();
+ if (sk->send_head == NULL)
+ {
sk->send_tail = skb;
+ sk->send_head = skb;
+ }
+ else
+ {
+ /* See if we've got a problem. */
+ if (sk->send_tail == NULL)
+ {
+ printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");
+ sort_send(sk);
+ }
+ else
+ {
+ sk->send_tail->link3 = skb;
+ sk->send_tail = skb;
+ }
}
- }
- sti();
- reset_timer(sk, TIME_WRITE,
+ sti();
+ reset_timer(sk, TIME_WRITE,
backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
- } else {
- skb->sk = sk;
- }
-
- /* If the indicated interface is up and running, kick it. */
- if (dev->flags & IFF_UP) {
- if (sk != NULL) {
- dev->queue_xmit(skb, dev, sk->priority);
}
- else {
- dev->queue_xmit(skb, dev, SOPRI_NORMAL);
+ else
+ {
+ skb->sk = sk;
+ }
+
+ /* If the indicated interface is up and running, kick it. */
+ if (dev->flags & IFF_UP)
+ {
+ if (sk != NULL)
+ {
+ dev->queue_xmit(skb, dev, sk->priority);
+ }
+ else
+ {
+ dev->queue_xmit(skb, dev, SOPRI_NORMAL);
+ }
+ }
+ else
+ {
+ if (free) kfree_skb(skb, FREE_WRITE);
}
- } else {
- if (free) kfree_skb(skb, FREE_WRITE);
- }
}
-void
-ip_retransmit(struct sock *sk, int all)
+void ip_retransmit(struct sock *sk, int all)
{
- struct sk_buff * skb;
- struct proto *prot;
- struct device *dev;
-
- prot = sk->prot;
- skb = sk->send_head;
- while (skb != NULL) {
- dev = skb->dev;
- /* I know this can't happen but as it does.. */
- if(dev==NULL)
- {
- printk("ip_retransmit: NULL device bug!\n");
- goto oops;
- }
+ struct sk_buff * skb;
+ struct proto *prot;
+ struct device *dev;
- IS_SKB(skb);
+ prot = sk->prot;
+ skb = sk->send_head;
+ while (skb != NULL)
+ {
+ dev = skb->dev;
+ /* I know this can't happen but as it does.. */
+ if(dev==NULL)
+ {
+ printk("ip_retransmit: NULL device bug!\n");
+ goto oops;
+ }
- /*
- * The rebuild_header function sees if the ARP is done.
- * If not it sends a new ARP request, and if so it builds
- * the header.
- */
- cli(); /* We might get interrupted by an arp reply here and fill
- the frame in twice. Because of the technique used this
- would be a little sad */
- if (!skb->arp) {
- if (dev->rebuild_header(skb+1, dev)) {
- sti(); /* Failed to rebuild - next */
- if (!all) break;
- skb = (struct sk_buff *)skb->link3;
- continue;
+ IS_SKB(skb);
+
+ /*
+ * The rebuild_header function sees if the ARP is done.
+ * If not it sends a new ARP request, and if so it builds
+ * the header.
+ */
+ cli(); /* We might get interrupted by an arp reply here and fill
+ the frame in twice. Because of the technique used this
+ would be a little sad */
+ if (!skb->arp)
+ {
+ if (dev->rebuild_header(skb+1, dev))
+ {
+ sti(); /* Failed to rebuild - next */
+ if (!all)
+ break;
+ skb = (struct sk_buff *)skb->link3;
+ continue;
+ }
+ }
+ skb->arp = 1;
+ sti();
+ skb->when = jiffies;
+
+ /* If the interface is (still) up and running, kick it. */
+ if (dev->flags & IFF_UP)
+ {
+ if (sk)
+ dev->queue_xmit(skb, dev, sk->priority);
}
- }
- skb->arp = 1;
- sti();
- 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);
- /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
- }
-oops: sk->retransmits++;
- sk->prot->retransmits ++;
- if (!all) break;
+oops: sk->retransmits++;
+ sk->prot->retransmits ++;
+ if (!all)
+ break;
- /* This should cut it off before we send too many packets. */
- if (sk->retransmits > sk->cong_window) break;
- skb = (struct sk_buff *)skb->link3;
- }
+ /* This should cut it off before we send too many packets. */
+ if (sk->retransmits > sk->cong_window)
+ break;
+ skb = (struct sk_buff *)skb->link3;
+ }
/*
* Increase the RTT time every time we retransmit.
@@ -1472,11 +1669,14 @@ oops: sk->retransmits++;
* get through again. Once we get through, the rtt will settle
* back down reasonably quickly.
*/
- sk->backoff++;
- reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
-}
+ sk->backoff++;
+ 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
@@ -1504,3 +1704,73 @@ int backoff(int n)
}
}
+
+/*
+ * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
+ * an IP socket.
+ */
+
+int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+ int val,err;
+
+ if (optval == NULL)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
+ val = get_fs_long((unsigned long *)optval);
+
+ if(level!=SOL_IP)
+ return -EOPNOTSUPP;
+
+ switch(optname)
+ {
+ case IP_TOS:
+ if(val<0||val>255)
+ return -EINVAL;
+ sk->ip_tos=val;
+ return 0;
+ case IP_TTL:
+ if(val<1||val<255)
+ return -EINVAL;
+ sk->ip_ttl=val;
+ return 0;
+ /* IP_OPTIONS and friends go here eventually */
+ default:
+ return(-ENOPROTOOPT);
+ }
+}
+
+int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+ int val,err;
+
+ if(level!=SOL_IP)
+ return -EOPNOTSUPP;
+
+ switch(optname)
+ {
+ case IP_TOS:
+ val=sk->ip_tos;
+ break;
+ case IP_TTL:
+ val=sk->ip_ttl;
+ break;
+ default:
+ return(-ENOPROTOOPT);
+ }
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(val,(unsigned long *)optval);
+
+ return(0);
+}
diff --git a/net/inet/ip.h b/net/inet/ip.h
index 3c01cc8..95daf2c 100644
--- a/net/inet/ip.h
+++ b/net/inet/ip.h
@@ -21,8 +21,8 @@
#include <linux/ip.h>
+#include "sockinet.h"
-#include "sock.h" /* struct sock */
/* IP flags. */
#define IP_CE 0x8000 /* Flag: "Congestion" */
@@ -69,7 +69,8 @@ extern int ip_build_header(struct sk_buff *skb,
unsigned long saddr,
unsigned long daddr,
struct device **dev, int type,
- struct options *opt, int len);
+ struct options *opt, int len,
+ int tos,int ttl);
extern unsigned short ip_compute_csum(unsigned char * buff, int len);
extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
@@ -77,5 +78,6 @@ extern void ip_queue_xmit(struct sock *sk,
struct device *dev, struct sk_buff *skb,
int free);
extern void ip_retransmit(struct sock *sk, int all);
-
+extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
+extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
#endif /* _IP_H */
diff --git a/net/inet/loopback.c b/net/inet/loopback.c
index 66203eb..949e41a 100644
--- a/net/inet/loopback.c
+++ b/net/inet/loopback.c
@@ -5,71 +5,77 @@
*
* Pseudo-driver for the loopback interface.
*
- * Version: @(#)loopback.c 1.0.4b 08/16/93
+ * Version: @(#)loopback.c 1.28 20/12/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 "dev.h"
+#include "devinet.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include "arp.h"
-static int
-loopback_xmit(struct sk_buff *skb, struct device *dev)
+static int loopback_xmit(struct sk_buff *skb, struct device *dev)
{
- struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
- int done;
+ struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+ int done;
- DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
- if (skb == NULL || dev == NULL) return(0);
+ DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
+ if (skb == NULL || dev == NULL)
+ return(0);
- cli();
- if (dev->tbusy != 0) {
- sti();
- stats->tx_errors++;
- return(1);
- }
- dev->tbusy = 1;
- sti();
+ cli();
+ if (dev->tbusy != 0)
+ {
+ sti();
+ stats->tx_errors++;
+ return(1);
+ }
+ dev->tbusy = 1;
+ sti();
- done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev);
- if (skb->free) kfree_skb(skb, FREE_WRITE);
+ done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev);
+ if (skb->free)
+ kfree_skb(skb, FREE_WRITE);
- while (done != 1) {
- done = dev_rint(NULL, 0, 0, dev);
- }
- stats->tx_packets++;
+ while (done != 1)
+ {
+ done = dev_rint(NULL, 0, 0, dev);
+ }
+ stats->tx_packets++;
- dev->tbusy = 0;
+ dev->tbusy = 0;
#if 1
__asm__("cmpl $0,_intr_count\n\t"
@@ -86,52 +92,50 @@ loopback_xmit(struct sk_buff *skb, struct device *dev)
: "ax", "dx", "cx");
#endif
- return(0);
+ return(0);
}
-static struct enet_statistics *
-get_stats(struct device *dev)
+static struct enet_statistics *get_stats(struct device *dev)
{
return (struct enet_statistics *)dev->priv;
}
/* Initialize the rest of the LOOPBACK device. */
-int
-loopback_init(struct device *dev)
+int loopback_init(struct device *dev)
{
- dev->mtu = 2000; /* MTU */
- dev->tbusy = 0;
- dev->hard_start_xmit = loopback_xmit;
- dev->open = NULL;
+ dev->mtu = 2000; /* MTU */
+ dev->tbusy = 0;
+ dev->hard_start_xmit = loopback_xmit;
+ dev->open = NULL;
#if 1
- dev->hard_header = eth_header;
- dev->add_arp = NULL;
- dev->hard_header_len = ETH_HLEN; /* 14 */
- dev->addr_len = ETH_ALEN; /* 6 */
- dev->type = ARPHRD_ETHER; /* 0x0001 */
- dev->type_trans = eth_type_trans;
- dev->rebuild_header = eth_rebuild_header;
+ dev->hard_header = eth_header;
+ dev->add_arp = NULL;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->type = ARPHRD_ETHER; /* 0x0001 */
+ dev->type_trans = eth_type_trans;
+ dev->rebuild_header = eth_rebuild_header;
#else
- dev->hard_header_length = 0;
- dev->add_arp = NULL;
- dev->addr_len = 0;
- dev->type = 0; /* loopback_type (0) */
- dev->hard_header = NULL;
- dev->type_trans = NULL;
- dev->rebuild_header = NULL;
+ dev->hard_header_length = 0;
+ dev->add_arp = NULL;
+ dev->addr_len = 0;
+ dev->type = 0; /* loopback_type (0) */
+ dev->hard_header = NULL;
+ dev->type_trans = NULL;
+ dev->rebuild_header = NULL;
#endif
- dev->queue_xmit = dev_queue_xmit;
+ dev->queue_xmit = dev_queue_xmit;
/* New-style flags. */
- dev->flags = IFF_LOOPBACK;
- dev->family = AF_INET;
- dev->pa_addr = in_aton("127.0.0.1");
- dev->pa_brdaddr = in_aton("127.255.255.255");
- dev->pa_mask = in_aton("255.0.0.0");
- dev->pa_alen = sizeof(unsigned long);
- dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct enet_statistics));
- dev->get_stats = get_stats;
+ dev->flags = IFF_LOOPBACK;
+ dev->family = AF_INET;
+ dev->pa_addr = in_aton("127.0.0.1");
+ dev->pa_brdaddr = in_aton("127.255.255.255");
+ dev->pa_mask = in_aton("255.0.0.0");
+ dev->pa_alen = sizeof(unsigned long);
+ dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct enet_statistics));
+ dev->get_stats = get_stats;
- return(0);
+ return(0);
};
diff --git a/net/inet/packet.c b/net/inet/packet.c
index c0585a6..48b2184 100644
--- a/net/inet/packet.c
+++ b/net/inet/packet.c
@@ -5,7 +5,7 @@
*
* PACKET - implements raw packet sockets.
*
- * Version: @(#)packet.c 1.0.6 05/25/93
+ * Version: @(#)packet.c 1.28 20/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -18,6 +18,7 @@
* added. Also fixed the peek/read crash
* from all old Linux datagram code.
* Alan Cox : Uses the improved datagram code.
+ * Alan Cox : Clean up for final release.
*
*
* This program is free software; you can redistribute it and/or
@@ -31,12 +32,12 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
@@ -44,138 +45,152 @@
#include "udp.h"
#include "raw.h"
+/*
+ * I'm sure there should be one of these, not one every file.
+ */
-static unsigned long
-min(unsigned long a, unsigned long b)
+static unsigned long min(unsigned long a, unsigned long b)
{
- if (a < b) return(a);
- return(b);
+ if (a < b)
+ return(a);
+ return(b);
}
-/* This should be the easiest of all, all we do is copy it into a buffer. */
-int
-packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+/*
+ * This should be the easiest of all, all we do is copy it into a buffer.
+ */
+
+int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- struct sock *sk;
-
- sk = (struct sock *) pt->data;
- skb->dev = dev;
- skb->len += dev->hard_header_len;
-
- skb->sk = sk;
-
- /* Charge it too the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk->rmem_alloc += skb->mem_len;
- skb_queue_tail(&sk->rqueue,skb);
- wake_up(sk->sleep);
- release_sock(sk);
- return(0);
+ struct sock *sk;
+
+ sk = (struct sock *) pt->data;
+ skb->dev = dev;
+ skb->len += dev->hard_header_len;
+
+ skb->sk = sk;
+
+ /* Charge it too the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
+ skb_queue_tail(&sk->rqueue,skb);
+ release_sock(sk);
+ sk->data_ready(sk,skb->len);
+ return(0);
}
-/* This will do terrible things if len + ipheader + devheader > dev->mtu */
-static int
-packet_sendto(struct sock *sk, unsigned char *from, int len,
+/*
+ * 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,
int noblock, unsigned flags, struct sockaddr_in *usin,
int addr_len)
{
- struct sk_buff *skb;
- struct device *dev;
- struct sockaddr saddr;
- int err;
-
- /* Check the flags. */
- if (flags) return(-EINVAL);
- if (len < 0) return(-EINVAL);
-
- /* Get and verify the address. */
- if (usin) {
- if (addr_len < sizeof(saddr)) return(-EINVAL);
- err=verify_area(VERIFY_READ, usin, sizeof(saddr));
- if(err)
- return err;
- memcpy_fromfs(&saddr, usin, sizeof(saddr));
- } else
- return(-EINVAL);
+ struct sk_buff *skb;
+ struct device *dev;
+ struct sockaddr saddr;
+ int err;
+
+ /* Check the flags. */
+ if (flags)
+ return(-EINVAL);
+ if (len < 0)
+ return(-EINVAL);
+
+ /* Get and verify the address. */
+ if (usin)
+ {
+ if (addr_len < sizeof(saddr))
+ return(-EINVAL);
+ err=verify_area(VERIFY_READ, usin, sizeof(saddr));
+ if(err)
+ return err;
+ memcpy_fromfs(&saddr, usin, sizeof(saddr));
+ }
+ else
+ return(-EINVAL);
- err=verify_area(VERIFY_READ,from,len);
- if(err)
- return(err);
-/* Find the device first to size check it */
-
- saddr.sa_data[13] = 0;
- dev = dev_get(saddr.sa_data);
- if (dev == NULL) {
- return(-ENXIO);
- }
- if(len>dev->mtu)
- return -EMSGSIZE;
-
-/* Now allocate the buffer, knowing 4K pagelimits wont break this line */
- skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
-
- /* This shouldn't happen, but it could. */
- if (skb == NULL) {
- DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
- return(-ENOMEM);
- }
- /* Fill it in */
- skb->mem_addr = skb;
- skb->mem_len = len + sizeof(*skb);
- skb->sk = sk;
- skb->free = 1;
- memcpy_fromfs (skb+1, from, len);
- skb->len = len;
- skb->next = NULL;
- if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority);
- else kfree_skb(skb, FREE_WRITE);
- return(len);
+ err=verify_area(VERIFY_READ,from,len);
+ if(err)
+ return(err);
+ /* Find the device first to size check it */
+
+ saddr.sa_data[13] = 0;
+ dev = dev_get(saddr.sa_data);
+ if (dev == NULL)
+ {
+ return(-ENXIO);
+ }
+ if(len>dev->mtu)
+ return -EMSGSIZE;
+
+ /* Now allocate the buffer, knowing 4K pagelimits wont break this line */
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
+
+ /* This shouldn't happen, but it could. */
+ if (skb == NULL)
+ {
+ DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
+ return(-ENOMEM);
+ }
+ /* Fill it in */
+ skb->sk = sk;
+ skb->free = 1;
+ memcpy_fromfs (skb+1, from, len);
+ skb->len = len;
+ skb->next = NULL;
+ if (dev->flags & IFF_UP)
+ dev->queue_xmit(skb, dev, sk->priority);
+ else
+ kfree_skb(skb, FREE_WRITE);
+ return(len);
}
-static int
-packet_write(struct sock *sk, unsigned char *buff,
+static int packet_write(struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
- return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
+ return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
-static void
-packet_close(struct sock *sk, int timeout)
+static void packet_close(struct sock *sk, int timeout)
{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
- dev_remove_pack((struct packet_type *)sk->pair);
- kfree_s((void *)sk->pair, sizeof(struct packet_type));
- sk->pair = NULL;
- release_sock(sk);
+ sk->inuse = 1;
+ sk->state = TCP_CLOSE;
+ dev_remove_pack((struct packet_type *)sk->pair);
+ kfree_s((void *)sk->pair, sizeof(struct packet_type));
+ sk->pair = NULL;
+ release_sock(sk);
}
-static int
-packet_init(struct sock *sk)
+static int packet_init(struct sock *sk)
{
- struct packet_type *p;
+ struct packet_type *p;
- p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL) return(-ENOMEM);
+ p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p == NULL)
+ return(-ENOMEM);
- p->func = packet_rcv;
- p->type = sk->num;
- p->data = (void *)sk;
- dev_add_pack(p);
-
- /* We need to remember this somewhere. */
- sk->pair = (struct sock *)p;
+ p->func = packet_rcv;
+ p->type = sk->num;
+ p->data = (void *)sk;
+ dev_add_pack(p);
+
+ /* We need to remember this somewhere. */
+ sk->pair = (struct sock *)p;
- return(0);
+ return(0);
}
@@ -183,89 +198,95 @@ packet_init(struct sock *sk)
* This should be easy, if there is something there
* we return it, otherwise we block.
*/
-int
-packet_recvfrom(struct sock *sk, unsigned char *to, int len,
+int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
- int copied=0;
- struct sk_buff *skb;
- struct sockaddr *saddr;
- int err;
-
- saddr = (struct sockaddr *)sin;
- if (len == 0) return(0);
- if (len < 0) return(-EINVAL);
-
- if (sk->shutdown & RCV_SHUTDOWN) return(0);
- if (addr_len) {
- err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
- if(err)
- return err;
- put_fs_long(sizeof(*saddr), addr_len);
- }
+ int copied=0;
+ struct sk_buff *skb;
+ struct sockaddr *saddr;
+ int err;
+
+ saddr = (struct sockaddr *)sin;
+ if (len == 0)
+ return(0);
+ if (len < 0)
+ return(-EINVAL);
+
+ if (sk->shutdown & RCV_SHUTDOWN)
+ return(0);
+ if (addr_len)
+ {
+ err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(err)
+ return err;
+ put_fs_long(sizeof(*saddr), addr_len);
+ }
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
- skb=skb_recv_datagram(sk,flags,noblock,&err);
- if(skb==NULL)
- return err;
- copied = min(len, skb->len);
-
- memcpy_tofs(to, skb+1, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */
-
- /* Copy the address. */
- if (saddr) {
- struct sockaddr addr;
-
- addr.sa_family = skb->dev->type;
- memcpy(addr.sa_data,skb->dev->name, 14);
- verify_area(VERIFY_WRITE, saddr, sizeof(*saddr));
- memcpy_tofs(saddr, &addr, sizeof(*saddr));
- }
-
- skb_free_datagram(skb); /* Its either been used up, or its a peek_copy anyway */
-
- release_sock(sk);
- return(copied);
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
+ copied = min(len, skb->len);
+
+ memcpy_tofs(to, skb+1, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */
+
+ /* Copy the address. */
+ if (saddr)
+ {
+ struct sockaddr addr;
+
+ addr.sa_family = skb->dev->type;
+ memcpy(addr.sa_data,skb->dev->name, 14);
+ verify_area(VERIFY_WRITE, saddr, sizeof(*saddr));
+ memcpy_tofs(saddr, &addr, sizeof(*saddr));
+ }
+
+ skb_free_datagram(skb); /* Its either been used up, or its a peek_copy anyway */
+
+ release_sock(sk);
+ return(copied);
}
-int
-packet_read(struct sock *sk, unsigned char *buff,
+int packet_read(struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
- return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
+ return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
-struct proto packet_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- packet_close,
- packet_read,
- packet_write,
- packet_sendto,
- packet_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- ip_retransmit,
- NULL,
- NULL,
- NULL,
- datagram_select,
- NULL,
- packet_init,
- NULL,
- 128,
- 0,
- {NULL,},
- "PACKET"
+struct proto packet_prot =
+{
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ packet_close,
+ packet_read,
+ packet_write,
+ packet_sendto,
+ packet_recvfrom,
+ ip_build_header,
+ udp_connect,
+ NULL,
+ ip_queue_xmit,
+ ip_retransmit,
+ NULL,
+ NULL,
+ NULL,
+ datagram_select,
+ NULL,
+ packet_init,
+ NULL,
+ NULL, /* No set/get socket options */
+ NULL,
+ 128,
+ 0,
+ {NULL,},
+ "PACKET"
};
diff --git a/net/inet/proc.c b/net/inet/proc.c
index d5bc16e..04ed9e8 100644
--- a/net/inet/proc.c
+++ b/net/inet/proc.c
@@ -7,7 +7,7 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: @(#)proc.c 1.0.5 05/27/93
+ * Version: @(#)proc.c 1.28 20/12/93
*
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -18,10 +18,7 @@
* using hint flag for the netinfo.
* Pauline Middelink : Pidentd support
* Alan Cox : Make /proc safer.
- *
- * To Do:
- * Put the creating userid in the proc/net/... files. This will
- * allow us to write an RFC931 daemon for Linux
+ * Alan Cox : Final clean up.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -37,13 +34,13 @@
#include <linux/in.h>
#include <linux/param.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "udp.h"
-#include "skbuff.h"
-#include "sock.h"
+#include "socket/skbuff.h"
+#include "sockinet.h"
#include "raw.h"
/*
@@ -53,81 +50,83 @@
* As in get_unix_netinfo, the buffer might be too small. If this
* happens, get__netinfo returns only part of the available infos.
*/
-static int
-get__netinfo(struct proto *pro, char *buffer, int format)
+static int get__netinfo(struct proto *pro, char *buffer, int format)
{
- struct sock **s_array;
- struct sock *sp;
- char *pos=buffer;
- int i;
- int timer_active;
- unsigned long dest, src;
- unsigned short destp, srcp;
-
- s_array = pro->sock_array;
- pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n");
+ struct sock **s_array;
+ struct sock *sp;
+ char *pos=buffer;
+ int i;
+ int timer_active;
+ unsigned long dest, src;
+ unsigned short destp, srcp;
+
+ s_array = pro->sock_array;
+ pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n");
/*
* This was very pretty but didn't work when a socket is destroyed at the wrong moment
* (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing
* with timers we just concede defeat and cli().
*/
- for(i = 0; i < SOCK_ARRAY_SIZE; i++) {
- cli();
- sp = s_array[i];
- while(sp != NULL) {
- dest = sp->daddr;
- src = sp->saddr;
- destp = sp->dummy_th.dest;
- srcp = sp->dummy_th.source;
+ for(i = 0; i < SOCK_ARRAY_SIZE; i++)
+ {
+ cli();
+ sp = s_array[i];
+ while(sp != NULL)
+ {
+ dest = sp->daddr;
+ src = sp->saddr;
+ destp = sp->dummy_th.dest;
+ srcp = sp->dummy_th.source;
- /* Since we are Little Endian we need to swap the bytes :-( */
- destp = ntohs(destp);
- srcp = ntohs(srcp);
- timer_active = del_timer(&sp->timer);
- if (!timer_active)
- sp->timer.expires = 0;
- pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n",
- i, src, srcp, dest, destp, sp->state,
- format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc,
- format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
- timer_active, sp->timer.expires, (unsigned) sp->retransmits,
- SOCK_INODE(sp->socket)->i_uid);
- if (timer_active)
- add_timer(&sp->timer);
- /* Is place in buffer too rare? then abort. */
- if (pos > buffer+PAGE_SIZE-80) {
- printk("oops, too many %s sockets for netinfo.\n",
+ /* Since we are Little Endian we need to swap the bytes :-( */
+ destp = ntohs(destp);
+ srcp = ntohs(srcp);
+ timer_active = del_timer(&sp->timer);
+ if (!timer_active)
+ sp->timer.expires = 0;
+ pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n",
+ i, src, srcp, dest, destp, sp->state,
+ format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc,
+ format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
+ timer_active, sp->timer.expires, (unsigned) sp->retransmits,
+ SOCK_INODE(sp->socket)->i_uid);
+ if (timer_active)
+ add_timer(&sp->timer);
+ /* Is place in buffer too rare? then abort. */
+ if (pos > buffer+PAGE_SIZE-80)
+ {
+ printk("oops, too many %s sockets for netinfo.\n",
pro->name);
- return(strlen(buffer));
- }
+ return(strlen(buffer));
+ }
- /*
- * All sockets with (port mod SOCK_ARRAY_SIZE) = i
- * are kept in sock_array[i], so we must follow the
- * 'next' link to get them all.
- */
- sp = sp->next;
- }
- sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up
+ /*
+ * All sockets with (port mod SOCK_ARRAY_SIZE) = i
+ * are kept in sock_array[i], so we must follow the
+ * 'next' link to get them all.
+ */
+ sp = sp->next;
+ }
+ sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up
before this will clear before we jump back and cli, so its not as bad as it looks */
- }
- return(strlen(buffer));
+ }
+ return(strlen(buffer));
}
int tcp_get_info(char *buffer)
{
- return get__netinfo(&tcp_prot, buffer,0);
+ return get__netinfo(&tcp_prot, buffer,0);
}
int udp_get_info(char *buffer)
{
- return get__netinfo(&udp_prot, buffer,1);
+ return get__netinfo(&udp_prot, buffer,1);
}
int raw_get_info(char *buffer)
{
- return get__netinfo(&raw_prot, buffer,1);
+ return get__netinfo(&raw_prot, buffer,1);
}
diff --git a/net/inet/protocol.c b/net/inet/protocol.c
index 5690267..b6390db 100644
--- a/net/inet/protocol.c
+++ b/net/inet/protocol.c
@@ -5,7 +5,7 @@
*
* INET protocol dispatch tables.
*
- * Version: @(#)protocol.c 1.0.5 05/25/93
+ * Version: @(#)protocol.c 1.28 20/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -14,7 +14,8 @@
* 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!)
+ * proper fragmentation (_NO_ 4K limits!).
+ * Alan Cox : Final clean up.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,132 +31,143 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
-#include "skbuff.h"
-#include "sock.h"
+#include "socket/skbuff.h"
+#include "sockinet.h"
#include "icmp.h"
#include "udp.h"
-static struct inet_protocol tcp_protocol = {
- tcp_rcv, /* TCP handler */
- NULL, /* No fragment handler (and won't be for a long time) */
- tcp_err, /* TCP error control */
- NULL, /* next */
- IPPROTO_TCP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "TCP" /* name */
+static struct inet_protocol tcp_protocol =
+{
+ tcp_rcv, /* TCP handler */
+ NULL, /* No fragment handler (and won't be for a long time) */
+ tcp_err, /* TCP error control */
+ NULL, /* next */
+ IPPROTO_TCP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "TCP" /* name */
};
-static struct inet_protocol udp_protocol = {
- udp_rcv, /* UDP handler */
- NULL, /* Will be UDP fraglist handler */
- udp_err, /* UDP error control */
- &tcp_protocol, /* next */
- IPPROTO_UDP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "UDP" /* name */
+static struct inet_protocol udp_protocol =
+{
+ udp_rcv, /* UDP handler */
+ NULL, /* Will be UDP fraglist handler */
+ udp_err, /* UDP error control */
+ &tcp_protocol, /* next */
+ IPPROTO_UDP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "UDP" /* name */
};
-static struct inet_protocol icmp_protocol = {
- icmp_rcv, /* ICMP handler */
- NULL, /* ICMP never fragments anyway */
- NULL, /* ICMP error control */
- &udp_protocol, /* next */
- IPPROTO_ICMP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "ICMP" /* name */
+static struct inet_protocol icmp_protocol =
+{
+ icmp_rcv, /* ICMP handler */
+ NULL, /* ICMP never fragments anyway */
+ NULL, /* ICMP error control */
+ &udp_protocol, /* next */
+ IPPROTO_ICMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "ICMP" /* name */
};
struct inet_protocol *inet_protocol_base = &icmp_protocol;
-struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
- NULL
+
+struct inet_protocol *inet_protos[MAX_INET_PROTOS] =
+{
+ NULL
};
-struct inet_protocol *
-inet_get_protocol(unsigned char prot)
+struct inet_protocol *inet_get_protocol(unsigned char prot)
{
- unsigned char hash;
- struct inet_protocol *p;
-
- DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
- hash = prot & (MAX_INET_PROTOS - 1);
- for (p = inet_protos[hash] ; p != NULL; p=p->next) {
- DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
- if (p->protocol == prot) return((struct inet_protocol *) p);
- }
- return(NULL);
+ unsigned char hash;
+ struct inet_protocol *p;
+
+ DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
+ hash = prot & (MAX_INET_PROTOS - 1);
+ for (p = inet_protos[hash] ; p != NULL; p=p->next)
+ {
+ DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
+ if (p->protocol == prot)
+ return((struct inet_protocol *) p);
+ }
+ return(NULL);
}
-void
-inet_add_protocol(struct inet_protocol *prot)
+void inet_add_protocol(struct inet_protocol *prot)
{
- unsigned char hash;
- struct inet_protocol *p2;
-
- hash = prot->protocol & (MAX_INET_PROTOS - 1);
- prot ->next = inet_protos[hash];
- inet_protos[hash] = prot;
- prot->copy = 0;
-
- /* Set the copy bit if we need to. */
- p2 = (struct inet_protocol *) prot->next;
- while(p2 != NULL) {
- if (p2->protocol == prot->protocol) {
- prot->copy = 1;
- break;
- }
- p2 = (struct inet_protocol *) prot->next;
- }
+ unsigned char hash;
+ struct inet_protocol *p2;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ prot ->next = inet_protos[hash];
+ inet_protos[hash] = prot;
+ prot->copy = 0;
+
+ /* Set the copy bit if we need to. */
+ p2 = (struct inet_protocol *) prot->next;
+ while(p2 != NULL)
+ {
+ if (p2->protocol == prot->protocol)
+ {
+ prot->copy = 1;
+ break;
+ }
+ p2 = (struct inet_protocol *) prot->next;
+ }
}
-int
-inet_del_protocol(struct inet_protocol *prot)
+int inet_del_protocol(struct inet_protocol *prot)
{
- struct inet_protocol *p;
- struct inet_protocol *lp = NULL;
- unsigned char hash;
-
- hash = prot->protocol & (MAX_INET_PROTOS - 1);
- if (prot == inet_protos[hash]) {
- inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
- return(0);
- }
-
- p = (struct inet_protocol *) inet_protos[hash];
- while(p != NULL) {
- /*
- * 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 we are the last one with this protocol and
- * there is a previous one, reset its copy bit.
- */
- if (p->copy == 0 && lp != NULL) lp->copy = 0;
- p->next = prot->next;
- return(0);
- }
-
- if (p->next != NULL && p->next->protocol == prot->protocol) {
- lp = p;
+ struct inet_protocol *p;
+ struct inet_protocol *lp = NULL;
+ unsigned char hash;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ if (prot == inet_protos[hash])
+ {
+ inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
+ return(0);
}
- p = (struct inet_protocol *) p->next;
- }
- return(-1);
+ p = (struct inet_protocol *) inet_protos[hash];
+ while(p != NULL)
+ {
+ /*
+ * We have to worry if the protocol being deleted is
+ * the last one on the list, then we may need to reset
+ * someones copied bit.
+ */
+ if (p->next != NULL && p->next == prot)
+ {
+ /*
+ * if we are the last one with this protocol and
+ * there is a previous one, reset its copy bit.
+ */
+ if (p->copy == 0 && lp != NULL)
+ lp->copy = 0;
+ p->next = prot->next;
+ return(0);
+ }
+
+ if (p->next != NULL && p->next->protocol == prot->protocol)
+ {
+ lp = p;
+ }
+
+ p = (struct inet_protocol *) p->next;
+ }
+ return(-1);
}
diff --git a/net/inet/raw.c b/net/inet/raw.c
index 7533532..aa56a3c 100644
--- a/net/inet/raw.c
+++ b/net/inet/raw.c
@@ -5,7 +5,7 @@
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: @(#)raw.c 1.0.4 05/25/93
+ * Version: @(#)raw.c 1.28 20/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -19,12 +19,16 @@
* 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>
@@ -37,269 +41,301 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include "icmp.h"
#include "udp.h"
-static unsigned long
-min(unsigned long a, unsigned long b)
+static unsigned long min(unsigned long a, unsigned long b)
{
- if (a < b) return(a);
- return(b);
+ if (a < b)
+ return(a);
+ return(b);
}
-/* raw_err gets called by the icmp module. */
-void
-raw_err (int err, unsigned char *header, unsigned long daddr,
+/*
+ * raw_err gets called by the icmp module.
+ */
+
+void raw_err (int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
- struct sock *sk;
+ struct sock *sk;
- DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n",
+ DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n",
err, header, daddr, saddr, protocol));
- if (protocol == NULL) return;
- sk = (struct sock *) protocol->data;
- if (sk == NULL) return;
+ if (protocol == NULL)
+ return;
+
+ sk = (struct sock *) protocol->data;
+ if (sk == NULL)
+ return;
- /* This is meaningless in raw sockets. */
- if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) {
- if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
- return;
- }
+ /* This is meaningless in raw sockets. */
- sk->err = icmp_err_convert[err & 0xff].errno;
- wake_up(sk->sleep);
-
- return;
+ if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8))
+ {
+ if (sk->cong_window > 1)
+ sk->cong_window = sk->cong_window/2;
+ return;
+ }
+
+ sk->err = icmp_err_convert[err & 0xff].errno;
+ sk->error_report(sk);
+ return;
}
/*
- * This should be the easiest of all, all we do is\
- * copy it into a buffer.
+ * This should be the easiest of all, all we do is\
+ * copy it into a buffer. We do have to diddle the pointer
+ * to get the ip header too.
*/
-int
-raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+
+int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long saddr,
int redo, struct inet_protocol *protocol)
{
- struct sock *sk;
-
- DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n"
- " len=%d, saddr=%X, redo=%d, protocol=%X)\n",
- skb, dev, opt, daddr, len, saddr, redo, protocol));
-
- if (skb == NULL) return(0);
- if (protocol == NULL) {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk = (struct sock *) protocol->data;
- if (sk == NULL) {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- /* Now we need to copy this into memory. */
- skb->sk = sk;
- skb->len = len;
- skb->dev = dev;
- skb->saddr = daddr;
- skb->daddr = saddr;
-
- /* Charge it too the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk->rmem_alloc += skb->mem_len;
- skb_queue_tail(&sk->rqueue,skb);
- wake_up(sk->sleep);
- release_sock(sk);
- return(0);
+ struct sock *sk;
+
+ DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n"
+ " len=%d, saddr=%X, redo=%d, protocol=%X)\n",
+ skb, dev, opt, daddr, len, saddr, redo, protocol));
+
+ if (skb == NULL)
+ return(0);
+
+ if (protocol == NULL)
+ {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+ sk = (struct sock *) protocol->data;
+ if (sk == NULL)
+ {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ /* Now we need to copy this into memory. */
+ skb->sk = sk;
+ /*
+ * Adjust to get the header back
+ */
+
+ skb->len += skb->ip_hdr->ihl*sizeof(long);
+ skb->h.iph = skb->ip_hdr;
+ skb->dev = dev;
+ skb->saddr = daddr;
+ skb->daddr = saddr;
+
+ /* Charge it too the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
+ skb_queue_tail(&sk->rqueue,skb);
+ release_sock(sk);
+ sk->data_ready(sk,skb->len);
+ return(0);
}
-/* This will do terrible things if len + ipheader + devheader > dev->mtu */
-static int
-raw_sendto(struct sock *sk, unsigned char *from, int len,
+/*
+ * 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,
int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
- struct sk_buff *skb;
- struct device *dev=NULL;
- struct sockaddr_in sin;
- int tmp;
- int err;
-
- DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
- " usin=%X, addr_len = %d)\n", sk, from, len, noblock,
- flags, usin, addr_len));
-
- /* Check the flags. */
- if (flags) return(-EINVAL);
- if (len < 0) return(-EINVAL);
-
- err=verify_area(VERIFY_READ,from,len);
- if(err)
- return err;
- /* Get and verify the address. */
- if (usin) {
- if (addr_len < sizeof(sin)) return(-EINVAL);
- err=verify_area (VERIFY_READ, usin, sizeof (sin));
- if(err)
- return err;
- memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
- } else {
- if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->protocol;
- sin.sin_addr.s_addr = sk->daddr;
- }
- if (sin.sin_port == 0) sin.sin_port = sk->protocol;
+ struct sk_buff *skb;
+ struct device *dev=NULL;
+ struct sockaddr_in sin;
+ int tmp;
+ int err;
+
+ DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
+ " usin=%X, addr_len = %d)\n", sk, from, len, noblock,
+ flags, usin, addr_len));
+
+ /* Check the flags. */
+ if (flags)
+ return(-EINVAL);
+ if (len < 0)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ,from,len);
+ if(err)
+ return err;
+ /* Get and verify the address. */
+ if (usin)
+ {
+ if (addr_len < sizeof(sin))
+ return(-EINVAL);
+ err=verify_area (VERIFY_READ, usin, sizeof (sin));
+ if(err)
+ return err;
+ memcpy_fromfs(&sin, usin, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EINVAL);
+ }
+ else
+ {
+ if (sk->state != TCP_ESTABLISHED)
+ return(-EINVAL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = sk->protocol;
+ sin.sin_addr.s_addr = sk->daddr;
+ }
+ if (sin.sin_port == 0)
+ sin.sin_port = sk->protocol;
- if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -ENETUNREACH;
+ if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -EACCES;
- sk->inuse = 1;
- skb = NULL;
- while (skb == NULL) {
- if(sk->err!=0)
+ sk->inuse = 1;
+ skb = NULL;
+ while (skb == NULL)
{
- err= -sk->err;
- sk->err=0;
- release_sock(sk);
- return(err);
- }
+ if(sk->err!=0)
+ {
+ err= -sk->err;
+ sk->err=0;
+ release_sock(sk);
+ return(err);
+ }
- skb = (struct sk_buff *) sk->prot->wmalloc(sk,
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk,
len+sizeof(*skb) + sk->prot->max_header,
0, GFP_KERNEL);
- if (skb == NULL) {
- int tmp;
-
- DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
- if (noblock)
- return(-EAGAIN);
- tmp = sk->wmem_alloc;
- release_sock(sk);
- cli();
- if (tmp <= sk->wmem_alloc) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- sti();
- return(-ERESTARTSYS);
+ if (skb == NULL)
+ {
+ int tmp;
+
+ DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
+ if (noblock)
+ return(-EAGAIN);
+ tmp = sk->wmem_alloc;
+ release_sock(sk);
+ cli();
+ if (tmp <= sk->wmem_alloc)
+ {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ return(-ERESTARTSYS);
+ }
}
+ sk->inuse = 1;
+ sti();
}
- sk->inuse = 1;
- sti();
- }
- }
- skb->mem_addr = skb;
- skb->mem_len = len + sizeof(*skb) +sk->prot->max_header;
- skb->sk = sk;
-
- skb->free = 1; /* these two should be unecessary. */
- skb->arp = 0;
-
- tmp = sk->prot->build_header(skb, sk->saddr,
+ }
+ skb->sk = sk;
+
+ skb->free = 1; /* these two should be unecessary. */
+ skb->arp = 0;
+
+ tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev,
- sk->protocol, sk->opt, skb->mem_len);
- if (tmp < 0) {
- DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
- kfree_skb(skb,FREE_WRITE);
- release_sock(sk);
- return(tmp);
- }
-
- /* verify_area(VERIFY_WRITE, from, len);*/
- memcpy_fromfs ((unsigned char *)(skb+1)+tmp, from, len);
-
- /* If we are using IPPROTO_RAW, we need to fill in the source address in
- the IP header */
-
- if(sk->protocol==IPPROTO_RAW) {
- unsigned char *buff;
- struct iphdr *iph;
-
- buff = (unsigned char *)(skb + 1);
- buff += tmp;
- iph = (struct iphdr *)buff;
- iph->saddr = sk->saddr;
- }
-
- skb->len = tmp + len;
+ sk->protocol, sk->opt, skb->mem_len,
+ sk->ip_ttl,sk->ip_tos);
+ if (tmp < 0)
+ {
+ DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
+ kfree_skb(skb,FREE_WRITE);
+ release_sock(sk);
+ return(tmp);
+ }
+
+ memcpy_fromfs ((unsigned char *)(skb+1)+tmp, from, len);
+
+ /* If we are using IPPROTO_RAW, we need to fill in the source address in
+ the IP header */
+
+ if(sk->protocol==IPPROTO_RAW)
+ {
+ unsigned char *buff;
+ struct iphdr *iph;
+
+ buff = (unsigned char *)(skb + 1);
+ buff += tmp;
+ iph = (struct iphdr *)buff;
+ iph->saddr = sk->saddr;
+ }
+
+ skb->len = tmp + len;
- if(dev!=NULL && skb->len > 4095)
- {
- kfree_skb(skb, FREE_WRITE);
- release_sock(sk);
- return(-EMSGSIZE);
- }
+ if(dev!=NULL && skb->len > 4095)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ release_sock(sk);
+ return(-EMSGSIZE);
+ }
- sk->prot->queue_xmit(sk, dev, skb, 1);
- release_sock(sk);
- return(len);
+ sk->prot->queue_xmit(sk, dev, skb, 1);
+ release_sock(sk);
+ return(len);
}
-static int
-raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
+static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
+ return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
-static void
-raw_close(struct sock *sk, int timeout)
+static void raw_close(struct sock *sk, int timeout)
{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
+ sk->inuse = 1;
+ sk->state = TCP_CLOSE;
- DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
- ((struct inet_protocol *)sk->pair)->protocol));
+ DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
+ ((struct inet_protocol *)sk->pair)->protocol));
- if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
+ if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n"));
- kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
- sk->pair = NULL;
- release_sock(sk);
+ kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
+ sk->pair = NULL;
+ release_sock(sk);
}
-static int
-raw_init(struct sock *sk)
+static int raw_init(struct sock *sk)
{
- struct inet_protocol *p;
-
- p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
- if (p == NULL) return(-ENOMEM);
-
- p->handler = raw_rcv;
- p->protocol = sk->protocol;
- p->data = (void *)sk;
- p->err_handler = raw_err;
- p->name="USER";
- p->frag_handler = NULL; /* For now */
- inet_add_protocol(p);
+ struct inet_protocol *p;
+
+ p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
+ if (p == NULL)
+ return(-ENOMEM);
+
+ p->handler = raw_rcv;
+ p->protocol = sk->protocol;
+ p->data = (void *)sk;
+ p->err_handler = raw_err;
+ p->name="USER";
+ p->frag_handler = NULL; /* For now */
+ inet_add_protocol(p);
- /* We need to remember this somewhere. */
- sk->pair = (struct sock *)p;
+ /* We need to remember this somewhere. */
+ sk->pair = (struct sock *)p;
- DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol));
+ DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol));
- return(0);
+ return(0);
}
@@ -307,91 +343,98 @@ raw_init(struct sock *sk)
* This should be easy, if there is something there
* we return it, otherwise we block.
*/
-int
-raw_recvfrom(struct sock *sk, unsigned char *to, int len,
+
+int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
- int copied=0;
- struct sk_buff *skb;
- int err;
+ int copied=0;
+ struct sk_buff *skb;
+ int err;
- DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n"
- " sin=%X, addr_len=%X)\n",
+ DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n"
+ " sin=%X, addr_len=%X)\n",
sk, to, len, noblock, flags, sin, addr_len));
- if (len == 0) return(0);
- if (len < 0) return(-EINVAL);
-
- if (sk->shutdown & RCV_SHUTDOWN) return(0);
- if (addr_len) {
- err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
- if(err)
- return err;
- put_fs_long(sizeof(*sin), addr_len);
- }
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
-
- skb=skb_recv_datagram(sk,flags,noblock,&err);
- if(skb==NULL)
- return err;
-
- copied = min(len, skb->len);
-
- skb_copy_datagram(skb, 0, to, copied);
+ if (len == 0)
+ return(0);
+ if (len < 0)
+ return(-EINVAL);
- /* Copy the address. */
- if (sin) {
- struct sockaddr_in addr;
+ if (sk->shutdown & RCV_SHUTDOWN)
+ return(0);
+ if (addr_len)
+ {
+ err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(err)
+ return err;
+ put_fs_long(sizeof(*sin), addr_len);
+ }
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = skb->daddr;
- verify_area(VERIFY_WRITE, sin, sizeof(*sin));
- memcpy_tofs(sin, &addr, sizeof(*sin));
- }
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
- skb_free_datagram(skb);
- release_sock(sk);
- return (copied);
+ copied = min(len, skb->len);
+
+ skb_copy_datagram(skb, 0, to, copied);
+
+ /* Copy the address. */
+ if (sin)
+ {
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = skb->daddr;
+ verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+ memcpy_tofs(sin, &addr, sizeof(*sin));
+ }
+
+ skb_free_datagram(skb);
+ release_sock(sk);
+ return (copied);
}
-int
-raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,
+int raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
+ return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
-struct proto raw_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- raw_close,
- raw_read,
- raw_write,
- raw_sendto,
- raw_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- ip_retransmit,
- NULL,
- NULL,
- raw_rcv,
- datagram_select,
- NULL,
- raw_init,
- NULL,
- 128,
- 0,
- {NULL,},
- "RAW"
+struct proto raw_prot =
+{
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ raw_close,
+ raw_read,
+ raw_write,
+ raw_sendto,
+ raw_recvfrom,
+ ip_build_header,
+ udp_connect,
+ NULL,
+ ip_queue_xmit,
+ ip_retransmit,
+ NULL,
+ NULL,
+ raw_rcv,
+ datagram_select,
+ NULL,
+ raw_init,
+ NULL,
+ ip_setsockopt,
+ ip_getsockopt,
+ 128,
+ 0,
+ {NULL,},
+ "RAW"
};
diff --git a/net/inet/route.c b/net/inet/route.c
index 269c80d..cd2e355 100644
--- a/net/inet/route.c
+++ b/net/inet/route.c
@@ -47,18 +47,18 @@ static struct rtable *rt_base = NULL;
static struct rtable *rt_loopback = NULL;
/* Dump the contents of a routing table entry. */
-static void
-rt_print(struct rtable *rt)
+static void rt_print(struct rtable *rt)
{
- if (rt == NULL || inet_debug != DBG_RT) return;
+ if (rt == NULL || inet_debug != DBG_RT)
+ return;
- printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
+ printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
(long) rt, (long) rt->rt_next, rt->rt_flags);
- printk(" TARGET=%s ", in_ntoa(rt->rt_dst));
- printk("GW=%s ", in_ntoa(rt->rt_gateway));
- printk(" DEV=%s USE=%ld REF=%d\n",
- (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
- rt->rt_use, rt->rt_refcnt);
+ printk(" TARGET=%s ", in_ntoa(rt->rt_dst));
+ printk("GW=%s ", in_ntoa(rt->rt_gateway));
+ printk(" DEV=%s USE=%ld REF=%d\n",
+ (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
+ rt->rt_use, rt->rt_refcnt);
}
@@ -162,8 +162,8 @@ static inline struct device * get_gw_dev(unsigned long gw)
/*
* rewrote rt_add(), as the old one was weird. Linus
*/
-void
-rt_add(short flags, unsigned long dst, unsigned long mask, unsigned long gw, struct device *dev)
+void rt_add(short flags, unsigned long dst, unsigned long mask,
+ unsigned long gw, struct device *dev)
{
struct rtable *r, *rt;
struct rtable **rp;
@@ -280,38 +280,35 @@ 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);
+ struct sockaddr_in *trg;
- return(0);
+ trg = (struct sockaddr_in *) &r->rt_dst;
+ rt_del(trg->sin_addr.s_addr);
+ return 0;
}
/* Called from the PROCfs module. */
-int
-rt_get_info(char *buffer)
+int rt_get_info(char *buffer)
{
- struct rtable *r;
- char *pos;
+ struct rtable *r;
+ char *pos;
- pos = buffer;
+ pos = buffer;
- pos += sprintf(pos,
- "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
+ pos += sprintf(pos,
+ "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
- /* This isn't quite right -- r->rt_dst is a struct! */
- for (r = rt_base; r != NULL; r = r->rt_next) {
- pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
- r->rt_dev->name, r->rt_dst, r->rt_gateway,
- r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
- r->rt_mask);
- }
- return(pos - buffer);
+ /* This isn't quite right -- r->rt_dst is a struct! */
+ for (r = rt_base; r != NULL; r = r->rt_next) {
+ pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
+ r->rt_dev->name, r->rt_dst, r->rt_gateway,
+ r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
+ r->rt_mask);
+ }
+ return pos - buffer;
}
/*
@@ -340,39 +337,41 @@ no_route:
}
-int
-rt_ioctl(unsigned int cmd, void *arg)
+int rt_ioctl(unsigned int cmd, void *arg)
{
- struct device *dev;
- struct rtentry rt;
- char namebuf[32];
- int ret;
- int err;
+ struct device *dev;
+ struct rtentry rt;
+ char namebuf[32];
+ int ret;
+ int err;
- switch(cmd) {
+ switch(cmd) {
case DDIOCSDBG:
ret = dbg_ioctl(arg, DBG_RT);
break;
+
case SIOCADDRT:
case SIOCDELRT:
- if (!suser()) return(-EPERM);
- err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
+ if (!suser())
+ return -EPERM;
+ err = verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
if(err)
return err;
memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
if (rt.rt_dev) {
- err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
- if(err)
- return err;
- memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
- dev = dev_get(namebuf);
- rt.rt_dev = dev;
+ err = verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
+ if(err)
+ return err;
+ memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
+ dev = dev_get(namebuf);
+ rt.rt_dev = dev;
}
ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
break;
+
default:
ret = -EINVAL;
- }
+ }
- return(ret);
+ return ret;
}
diff --git a/net/inet/route.h b/net/inet/route.h
index bba3acf..c5429c6 100644
--- a/net/inet/route.h
+++ b/net/inet/route.h
@@ -24,15 +24,15 @@
/* This is an entry in the IP routing table. */
struct rtable {
- struct rtable *rt_next;
- unsigned long rt_dst;
- unsigned long rt_mask;
- unsigned long rt_gateway;
- u_char rt_flags;
- u_char rt_metric;
- short rt_refcnt;
- u_long rt_use;
- struct device *rt_dev;
+ struct rtable *rt_next;
+ unsigned long rt_dst;
+ unsigned long rt_mask;
+ unsigned long rt_gateway;
+ u_char rt_flags;
+ u_char rt_metric;
+ short rt_refcnt;
+ u_long rt_use;
+ struct device *rt_dev;
};
diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c
index 1f3299d..e69de29 100644
--- a/net/inet/skbuff.c
+++ b/net/inet/skbuff.c
@@ -1,454 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * A saner implementation of the skbuff stuff scattered everywhere
- * in the old NET2D code.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
- *
- * Fixes:
- * Alan Cox : Tracks memory and number of buffers for kernel memory report
- * and memory leak hunting.
- * Alan Cox : More generic kfree handler
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include "inet.h"
-#include "dev.h"
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include "skbuff.h"
-#include "sock.h"
-
-
-/* Socket buffer operations. Ideally much of this list swap stuff ought to be using
- exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
- slow C version. No doubt when Linus sees this comment he'll do horrible things
- to this code 8-)
-*/
-
-/*
- * Resource tracking variables
- */
-
-volatile unsigned long net_memory=0;
-volatile unsigned long net_skbcount=0;
-
-/*
- * Debugging paranoia. Can go later when this crud stack works
- */
-
-
-
-void skb_check(struct sk_buff *skb, int line, char *file)
-{
- if(skb->magic_debug_cookie==SK_FREED_SKB)
- {
- printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
- file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
- skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
- }
- if(skb->magic_debug_cookie!=SK_GOOD_SKB)
- {
- printk("File: %s Line %d, passed a non skb!\n", file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
- skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
- }
- if(skb->mem_len!=skb->truesize)
- {
- printk("File: %s Line %d, Dubious size setting!\n",file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n",
- skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
- }
- /* Guess it might be acceptable then */
-}
-
-/*
- * Insert an sk_buff at the start of a list.
- */
-
-void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
-{
- unsigned long flags;
-
- IS_SKB(newsk);
- if(newsk->list)
- printk("Suspicious queue head: sk_buff on list!\n");
- save_flags(flags);
- cli();
- newsk->list=list;
-
- newsk->next=*list;
-
- if(*list)
- newsk->prev=(*list)->prev;
- else
- newsk->prev=newsk;
- newsk->prev->next=newsk;
- newsk->next->prev=newsk;
- IS_SKB(newsk->prev);
- IS_SKB(newsk->next);
- *list=newsk;
- restore_flags(flags);
-}
-
-/*
- * Insert an sk_buff at the end of a list.
- */
-
-void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- if(newsk->list)
- printk("Suspicious queue tail: sk_buff on list!\n");
-
- IS_SKB(newsk);
- save_flags(flags);
- cli();
-
- newsk->list=list;
- if(*list)
- {
- (*list)->prev->next=newsk;
- newsk->prev=(*list)->prev;
- newsk->next=*list;
- (*list)->prev=newsk;
- }
- else
- {
- newsk->next=newsk;
- newsk->prev=newsk;
- *list=newsk;
- }
- IS_SKB(newsk->prev);
- IS_SKB(newsk->next);
- restore_flags(flags);
-
-}
-
-/*
- * Remove an sk_buff from a list. This routine is also interrupt safe
- * so you can grab read and free buffers as another process adds them.
- */
-
-struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
-{
- long flags;
- struct sk_buff *result;
-
- save_flags(flags);
- cli();
-
- if(*list==NULL)
- {
- restore_flags(flags);
- return(NULL);
- }
-
- result=*list;
- if(result->next==result)
- *list=NULL;
- else
- {
- result->next->prev=result->prev;
- result->prev->next=result->next;
- *list=result->next;
- }
-
- IS_SKB(result);
- restore_flags(flags);
-
- if(result->list!=list)
- printk("Dequeued packet has invalid list pointer\n");
-
- result->list=0;
- result->next=0;
- result->prev=0;
- return(result);
-}
-
-/*
- * Insert a packet before another one in a list.
- */
-
-void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- IS_SKB(old);
- IS_SKB(newsk);
-
- if(!old->list)
- printk("insert before unlisted item!\n");
- if(newsk->list)
- printk("inserted item is already on a list.\n");
-
- save_flags(flags);
- cli();
- newsk->list=old->list;
- newsk->next=old;
- newsk->prev=old->prev;
- newsk->next->prev=newsk;
- newsk->prev->next=newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Place a packet after a given packet in a list.
- */
-
-void skb_append(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- IS_SKB(old);
- IS_SKB(newsk);
-
- if(!old->list)
- printk("append before unlisted item!\n");
- if(newsk->list)
- printk("append item is already on a list.\n");
-
- save_flags(flags);
- cli();
- newsk->list=old->list;
- newsk->prev=old;
- newsk->next=old->next;
- newsk->next->prev=newsk;
- newsk->prev->next=newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Remove an sk_buff from its list. Works even without knowing the list it
- * is sitting on, which can be handy at times. It also means that THE LIST
- * MUST EXIST when you unlink. Thus a list must have its contents unlinked
- * _FIRST_.
- */
-
-void skb_unlink(struct sk_buff *skb)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
-
- IS_SKB(skb);
-
- if(skb->list)
- {
- skb->next->prev=skb->prev;
- skb->prev->next=skb->next;
- if(*skb->list==skb)
- {
- if(skb->next==skb)
- *skb->list=NULL;
- else
- *skb->list=skb->next;
- }
- skb->next=0;
- skb->prev=0;
- skb->list=0;
- }
- restore_flags(flags);
-}
-
-/*
- * An skbuff list has had its head reassigned. Move all the list
- * pointers. Must be called with ints off during the whole head
- * shifting
- */
-
-void skb_new_list_head(struct sk_buff *volatile* list)
-{
- struct sk_buff *skb=skb_peek(list);
- if(skb!=NULL)
- {
- do
- {
- IS_SKB(skb);
- skb->list=list;
- skb=skb->next;
- }
- while(skb!=*list);
- }
-}
-
-/*
- * Peek an sk_buff. Unlike most other operations you _MUST_
- * be careful with this one. A peek leaves the buffer on the
- * list and someone else may run off with it. For an interrupt
- * type system cli() peek the buffer copy the data and sti();
- */
-
-struct sk_buff *skb_peek(struct sk_buff *volatile* list)
-{
- return *list;
-}
-
-/*
- * Get a clone of an sk_buff. This is the safe way to peek at
- * a socket queue without accidents. Its a bit long but most
- * of it acutally ends up as tiny bits of inline assembler
- * anyway. Only the memcpy of upto 4K with ints off is not
- * as nice as I'd like.
- */
-
-struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
-{
- struct sk_buff *orig,*newsk;
- unsigned long flags;
- unsigned int len;
- /* Now for some games to avoid races */
-
- do
- {
- save_flags(flags);
- cli();
- orig=skb_peek(list);
- if(orig==NULL)
- {
- restore_flags(flags);
- return NULL;
- }
- IS_SKB(orig);
- len=orig->truesize;
- restore_flags(flags);
-
- newsk=alloc_skb(len,GFP_KERNEL); /* May sleep */
-
- if(newsk==NULL) /* Oh dear... not to worry */
- return NULL;
-
- save_flags(flags);
- cli();
- if(skb_peek(list)!=orig) /* List changed go around another time */
- {
- restore_flags(flags);
- newsk->sk=NULL;
- newsk->free=1;
- newsk->mem_addr=newsk;
- newsk->mem_len=len;
- kfree_skb(newsk, FREE_WRITE);
- continue;
- }
-
- IS_SKB(orig);
- IS_SKB(newsk);
- memcpy(newsk,orig,len);
- newsk->list=NULL;
- newsk->magic=0;
- newsk->next=NULL;
- newsk->prev=NULL;
- newsk->mem_addr=newsk;
- newsk->h.raw+=((char *)newsk-(char *)orig);
- newsk->link3=NULL;
- newsk->sk=NULL;
- newsk->free=1;
- }
- while(0);
-
- restore_flags(flags);
- return(newsk);
-}
-
-/*
- * Free an sk_buff. This still knows about things it should
- * not need to like protocols and sockets.
- */
-
-void kfree_skb(struct sk_buff *skb, int rw)
-{
- if (skb == NULL) {
- printk("kfree_skb: skb = NULL\n");
- return;
- }
- IS_SKB(skb);
- if(skb->free == 2)
- printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
- if(skb->list)
- printk("Warning: kfree_skb passed an skb still on a list.\n");
- skb->magic = 0;
- if (skb->sk)
- {
- if(skb->sk->prot!=NULL)
- {
- if (rw)
- skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
- else
- skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
-
- }
- else
- {
- /* Non INET - default wmalloc/rmalloc handler */
- if (rw)
- skb->sk->rmem_alloc-=skb->mem_len;
- else
- skb->sk->wmem_alloc-=skb->mem_len;
- if(!skb->sk->dead)
- wake_up(skb->sk->sleep);
- kfree_skbmem(skb->mem_addr,skb->mem_len);
- }
- }
- else
- kfree_skbmem(skb->mem_addr, skb->mem_len);
-}
-
-/*
- * Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
- * fields and also do memory statistics to find all the [BEEP] leaks.
- */
-
- struct sk_buff *alloc_skb(unsigned int size,int priority)
- {
- struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
- if(skb==NULL)
- return NULL;
- skb->free= 2; /* Invalid so we pick up forgetful users */
- skb->list= 0; /* Not on a list */
- skb->truesize=size;
- skb->mem_len=size;
- skb->mem_addr=skb;
- skb->fraglist=NULL;
- net_memory+=size;
- net_skbcount++;
- skb->magic_debug_cookie=SK_GOOD_SKB;
- skb->users=0;
- return skb;
- }
-
-/*
- * Free an skbuff by memory
- */
-
-void kfree_skbmem(void *mem,unsigned size)
-{
- struct sk_buff *x=mem;
- IS_SKB(x);
- if(x->magic_debug_cookie==SK_GOOD_SKB)
- {
- x->magic_debug_cookie=SK_FREED_SKB;
- kfree_s(mem,size);
- net_skbcount--;
- net_memory-=size;
- }
-}
-
diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h
index 6d5f879..e69de29 100644
--- a/net/inet/skbuff.h
+++ b/net/inet/skbuff.h
@@ -1,107 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the 'struct sk_buff' memory handlers.
- *
- * Version: @(#)skbuff.h 1.0.4 05/20/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- *
- * Fixes:
- * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff)
- * Alan Cox : Declaration for new primitives
- * Alan Cox : Fraglist support (idea by Donald Becker)
- * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy
- * being used.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _SKBUFF_H
-#define _SKBUFF_H
-#include <linux/malloc.h>
-
-#ifdef CONFIG_IPX
-#include "ipx.h"
-#endif
-
-#define HAVE_ALLOC_SKB /* For the drivers to know */
-
-
-#define FREE_READ 1
-#define FREE_WRITE 0
-
-
-struct sk_buff {
- unsigned long magic_debug_cookie;
- struct sk_buff *volatile next;
- struct sk_buff *volatile prev;
- struct sk_buff *volatile link3;
- struct sk_buff *volatile* list;
- struct sock *sk;
- volatile unsigned long when; /* used to compute rtt's */
- struct device *dev;
- void *mem_addr;
- union {
- struct tcphdr *th;
- struct ethhdr *eth;
- struct iphdr *iph;
- struct udphdr *uh;
- struct arphdr *arp;
- unsigned char *raw;
- unsigned long seq;
-#ifdef CONFIG_IPX
- ipx_packet *ipx;
-#endif
- } h;
- unsigned long mem_len;
- unsigned long len;
- unsigned long fraglen;
- struct sk_buff *fraglist; /* Fragment list */
- unsigned long truesize;
- unsigned long saddr;
- unsigned long daddr;
- int magic;
- volatile char acked,
- used,
- free,
- arp,
- urg_used;
- unsigned char tries,lock; /* Lock is now unused */
- unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
-};
-
-#define SK_WMEM_MAX 8192
-#define SK_RMEM_MAX 32767
-
-#define SK_FREED_SKB 0x0DE2C0DE
-#define SK_GOOD_SKB 0xDEC0DED1
-
-extern void print_skb(struct sk_buff *);
-extern void kfree_skb(struct sk_buff *skb, int rw);
-extern void skb_queue_head(struct sk_buff * volatile *list,struct sk_buff *buf);
-extern void skb_queue_tail(struct sk_buff * volatile *list,struct sk_buff *buf);
-extern struct sk_buff * skb_dequeue(struct sk_buff * volatile *list);
-extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk);
-extern void skb_append(struct sk_buff *old,struct sk_buff *newsk);
-extern void skb_unlink(struct sk_buff *buf);
-extern void skb_new_list_head(struct sk_buff *volatile* list);
-extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
-extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
-extern struct sk_buff * alloc_skb(unsigned int size, int priority);
-extern void kfree_skbmem(void *mem, unsigned size);
-
-extern void skb_check(struct sk_buff *skb,int, char *);
-#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
-
-extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
-extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
-extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
-extern void skb_free_datagram(struct sk_buff *skb);
-#endif /* _SKBUFF_H */
diff --git a/net/inet/sockinet.c b/net/inet/sockinet.c
new file mode 100644
index 0000000..004d63c
--- /dev/null
+++ b/net/inet/sockinet.c
@@ -0,0 +1,1636 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * SOCK - AF_INET protocol family socket handler.
+ *
+ * Version: @(#)sock.c 1.28 24/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ *
+ * Fixes:
+ * Alan Cox : Numerous verify_area() problems
+ * Alan Cox : Connecting on a connecting socket
+ * now returns an error for tcp.
+ * Alan Cox : sock->protocol is set correctly.
+ * and is not sometimes left as 0.
+ * Alan Cox : connect handles icmp errors on a
+ * connect properly. Unfortunately there
+ * is a restart syscall nasty there. I
+ * can't match BSD without hacking the C
+ * library. Ideas urgently sought!
+ * Alan Cox : Disallow bind() to addresses that are
+ * not ours - especially broadcast ones!!
+ * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost)
+ * Alan Cox : sock_wfree/sock_rfree don't destroy sockets,
+ * instead they leave that for the DESTROY timer.
+ * Alan Cox : Clean up error flag in accept
+ * Alan Cox : TCP ack handling is buggy, the DESTROY timer
+ * was buggy. Put a remove_sock() in the handler
+ * for memory when we hit 0. Also altered the timer
+ * code. The ACK stuff can wait and needs major
+ * TCP layer surgery.
+ * Alan Cox : Fixed TCP ack bug, removed remove sock
+ * and fixed timer/inet_bh race.
+ * Alan Cox : Added zapped flag for TCP
+ * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code
+ * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
+ * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources
+ * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing.
+ * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenely occured to me how easy it was so...
+ * Rick Sladkey : Relaxed UDP rules for matching packets.
+ * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
+ * Pauline Middelink : Pidentd support
+ * Alan Cox : Fixed connect() taking signals I think.
+ * Alan Cox : SO_LINGER supported
+ * Alan Cox : Error reporting fixes
+ * Anonymous : inet_create tidied up (sk->reuse setting)
+ * Alan Cox : Tidy up for release.
+ * Alan Cox : Moved this to sockinet.c and removed generic code.
+ * Alan Cox : inet sockets don't set sk->type!
+ *
+ *
+ * To Fix:
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include "inet.h"
+#include "devinet.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sockinet.h"
+#include "raw.h"
+#include "icmp.h"
+
+
+int inet_debug = DBG_OFF; /* INET module debug flag */
+
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+extern struct proto packet_prot;
+
+
+
+static int sk_inuse(struct proto *prot, int num)
+{
+ struct sock *sk;
+
+ for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];sk != NULL;sk=sk->next)
+ {
+ if (sk->num == num) return(1);
+ }
+ return(0);
+}
+
+
+unsigned short get_new_socknum(struct proto *prot, unsigned short base)
+{
+ static int start=0;
+
+ /*
+ * Used to cycle through the port numbers so the
+ * chances of a confused connection drop.
+ */
+ int i, j;
+ int best = 0;
+ int size = 32767; /* a big num. */
+ struct sock *sk;
+
+ if (base == 0)
+ base = PROT_SOCK+1+(start % 1024);
+ if (base <= PROT_SOCK)
+ {
+ base += PROT_SOCK+(start % 1024);
+ }
+
+ /* Now look through the entire array and try to find an empty ptr. */
+ for(i=0; i < SOCK_ARRAY_SIZE; i++)
+ {
+ j = 0;
+ sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];
+ while(sk != NULL)
+ {
+ sk = sk->next;
+ j++;
+ }
+ if (j == 0)
+ {
+ start =(i+1+start )%1024;
+ DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n",
+ i + base + 1, start));
+ return(i+base+1);
+ }
+ if (j < size)
+ {
+ best = i;
+ size = j;
+ }
+ }
+
+ /* Now make sure the one we want is not in use. */
+ while(sk_inuse(prot, base +best+1))
+ {
+ best += SOCK_ARRAY_SIZE;
+ }
+ DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n",
+ best + base + 1, start));
+ return(best+base+1);
+}
+
+
+void put_sock(unsigned short num, struct sock *sk)
+{
+ struct sock *sk1;
+ struct sock *sk2;
+ int mask;
+
+ DPRINTF((DBG_INET, "put_sock(num = %d, sk = %X\n", num, sk));
+ sk->num = num;
+ sk->next = NULL;
+ num = num &(SOCK_ARRAY_SIZE -1);
+
+ /* We can't have an interupt re-enter here. */
+ cli();
+ if (sk->prot->sock_array[num] == NULL)
+ {
+ sk->prot->sock_array[num] = sk;
+ sti();
+ return;
+ }
+ sti();
+ for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask)
+ {
+ if ((mask & sk->saddr) &&
+ (mask & sk->saddr) != (mask & 0xffffffff))
+ {
+ mask = mask << 8;
+ break;
+ }
+ }
+ DPRINTF((DBG_INET, "mask = %X\n", mask));
+
+ cli();
+ sk1 = sk->prot->sock_array[num];
+ for(sk2 = sk1; sk2 != NULL; sk2=sk2->next)
+ {
+ if (!(sk2->saddr & mask))
+ {
+ if (sk2 == sk1)
+ {
+ sk->next = sk->prot->sock_array[num];
+ sk->prot->sock_array[num] = sk;
+ sti();
+ return;
+ }
+ sk->next = sk2;
+ sk1->next= sk;
+ sti();
+ return;
+ }
+ sk1 = sk2;
+ }
+
+ /* Goes at the end. */
+ sk->next = NULL;
+ sk1->next = sk;
+ sti();
+}
+
+
+static void remove_sock(struct sock *sk1)
+{
+ struct sock *sk2;
+
+ DPRINTF((DBG_INET, "remove_sock(sk1=%X)\n", sk1));
+
+ if (!sk1)
+ {
+ printk("sock.c: remove_sock: sk1 == NULL\n");
+ return;
+ }
+
+ if (!sk1->prot)
+ {
+ printk("sock.c: remove_sock: sk1->prot == NULL\n");
+ return;
+ }
+
+ /* We can't have this changing out from under us. */
+ cli();
+ sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
+ if (sk2 == sk1)
+ {
+ sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
+ sti();
+ return;
+ }
+
+ while(sk2 && sk2->next != sk1)
+ {
+ sk2 = sk2->next;
+ }
+
+ if (sk2)
+ {
+ sk2->next = sk1->next;
+ sti();
+ return;
+ }
+
+ sti();
+
+ if (sk1->num != 0)
+ DPRINTF((DBG_INET, "remove_sock: sock not found.\n"));
+}
+
+
+void destroy_sock(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ DPRINTF((DBG_INET, "destroying socket %X\n", sk));
+ sk->inuse = 1; /* just to be safe. */
+
+ /* Incase it's sleeping somewhere. */
+ if (!sk->dead)
+ wake_up(sk->sleep);
+
+ remove_sock(sk);
+
+ /* Now we can no longer get new packets. */
+ delete_timer(sk);
+
+
+ if (sk->send_tmp != NULL)
+ {
+ IS_SKB(sk->send_tmp);
+ kfree_skb(sk->send_tmp, FREE_WRITE);
+ }
+
+ /* Cleanup up the write buffer. */
+ for(skb = sk->wfront; skb != NULL; )
+ {
+ struct sk_buff *skb2;
+
+ skb2=(struct sk_buff *)skb->next;
+ if (skb->magic != TCP_WRITE_QUEUE_MAGIC)
+ {
+ printk("sock.c:destroy_sock write queue with bad magic(%X)\n",
+ skb->magic);
+ break;
+ }
+ IS_SKB(skb);
+ kfree_skb(skb, FREE_WRITE);
+ skb = skb2;
+ }
+
+ sk->wfront = NULL;
+ sk->wback = NULL;
+
+ if (sk->rqueue != NULL)
+ {
+ while((skb=skb_dequeue(&sk->rqueue))!=NULL)
+ {
+ /*
+ * This will take care of closing sockets that were
+ * listening and didn't accept everything.
+ */
+ if (skb->sk != NULL && skb->sk != sk)
+ {
+ IS_SKB(skb);
+ skb->sk->dead = 1;
+ skb->sk->prot->close(skb->sk, 0);
+ }
+ IS_SKB(skb);
+ kfree_skb(skb, FREE_READ);
+ }
+ }
+ sk->rqueue = NULL;
+
+ /* Now we need to clean up the send head. */
+ for(skb = sk->send_head; skb != NULL; )
+ {
+ struct sk_buff *skb2;
+
+ /*
+ * We need to remove skb from the transmit queue,
+ * or maybe the arp queue.
+ */
+ cli();
+
+ if (skb->next != NULL)
+ {
+ IS_SKB(skb);
+ skb_unlink(skb);
+ }
+
+ skb->dev = NULL;
+ sti();
+ skb2 = (struct sk_buff *)skb->link3;
+ kfree_skb(skb, FREE_WRITE);
+ skb = skb2;
+ }
+ sk->send_head = NULL;
+
+ /* And now the backlog. */
+ if (sk->back_log != NULL)
+ {
+ /* this should never happen. */
+ printk("Socket Error: Socket destroyed with data backlog.\n");
+ cli();
+ skb = (struct sk_buff *)sk->back_log;
+ do
+ {
+ struct sk_buff *skb2;
+
+ skb2 = (struct sk_buff *)skb->next;
+ kfree_skb(skb, FREE_READ);
+ skb = skb2;
+ }
+ while(skb != sk->back_log);
+ sti();
+ }
+ sk->back_log = NULL;
+
+ /* Now if it has a half accepted/ closed socket. */
+ if (sk->pair)
+ {
+ sk->pair->dead = 1;
+ sk->pair->prot->close(sk->pair, 0);
+ sk->pair = NULL;
+ }
+
+ /*
+ * Now if everything is gone we can free the socket
+ * structure, otherwise we need to keep it around until
+ * everything is gone.
+ */
+ if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
+ {
+ kfree_s((void *)sk,sizeof(*sk));
+ }
+ else
+ {
+ /* this should never happen. */
+ /* actually it can if an ack has just been sent. */
+ DPRINTF((DBG_INET, "possible memory leak in socket = %X\n", sk));
+ sk->destroy = 1;
+ sk->ack_backlog = 0;
+ sk->inuse = 0;
+ reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
+ }
+ DPRINTF((DBG_INET, "leaving destroy_sock\n"));
+}
+
+
+static int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ switch(cmd)
+ {
+ case F_SETOWN:
+ /*
+ * This is a little restrictive, but it's the only
+ * way to make sure that you can't send a sigurg to
+ * another process.
+ */
+ if (!suser() && current->pgrp != -arg && current->pid != arg)
+ return(-EPERM);
+ sk->proc = arg;
+ return(0);
+ case F_GETOWN:
+ return(sk->proc);
+ default:
+ return(-EINVAL);
+ }
+}
+
+
+/*
+ * Set socket options on an inet socket.
+ */
+
+static int inet_setsockopt(struct socket *sock, int level, int optname,
+ char *optval, int optlen)
+{
+ struct sock *sk = (struct sock *) sock->data;
+ if (level == SOL_SOCKET)
+ return sock_setsockopt(sk,level,optname,optval,optlen);
+ if (sk->prot->setsockopt==NULL)
+ return(-EOPNOTSUPP);
+ else
+ return sk->prot->setsockopt(sk,level,optname,optval,optlen);
+}
+
+
+
+
+static int inet_getsockopt(struct socket *sock, int level, int optname,
+ char *optval, int *optlen)
+{
+ struct sock *sk = sock->data;
+ if (level == SOL_SOCKET)
+ return sock_getsockopt(sk,level,optname,optval,optlen);
+ if(sk->prot->getsockopt==NULL)
+ return(-EOPNOTSUPP);
+ else
+ return sk->prot->getsockopt(sk,level,optname,optval,optlen);
+}
+
+
+
+static int inet_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ /* No listen() on a busy socket. */
+
+ if(sk->state != TCP_CLOSE)
+ return -EINVAL;
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+
+ /* Some sanity checks here are a good idea */
+ if(backlog<0)
+ return -EINVAL;
+ /* Pick a number, any number 8-) */
+ if(backlog>5)
+ backlog=5;
+
+ /* We might as well re use these. */
+ sk->max_ack_backlog = backlog;
+ if (sk->state != TCP_LISTEN)
+ {
+ sk->ack_backlog = 0;
+ sk->state = TCP_LISTEN;
+ }
+ return(0);
+}
+
+/*
+ * Default callbacks for user INET sockets. These just wake up
+ * the user owning the socket.
+ */
+
+static void def_callback1(struct sock *sk)
+{
+ if(!sk->dead)
+ wake_up(sk->sleep);
+}
+
+static void def_callback2(struct sock *sk,int len)
+{
+ if(!sk->dead)
+ wake_up(sk->sleep);
+}
+
+
+/*
+ * Create an inet socket. Note that sock=NULL is now legal, and means a kernel
+ * created socket.
+ */
+
+static int inet_create(struct socket *sock, int protocol)
+{
+ struct sock *sk;
+ struct proto *prot;
+ int err;
+
+ sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
+
+ if (sk == NULL)
+ return(-ENOMEM);
+ sk->num = 0;
+ sk->reuse = 0;
+ switch(sock->type)
+ {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ if (protocol && protocol != IPPROTO_TCP)
+ {
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-EPROTONOSUPPORT);
+ }
+ protocol = IPPROTO_TCP;
+ sk->no_check = TCP_NO_CHECK;
+ prot = &tcp_prot;
+ break;
+
+ case SOCK_DGRAM:
+ if (protocol && protocol != IPPROTO_UDP)
+ {
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-EPROTONOSUPPORT);
+ }
+ protocol = IPPROTO_UDP;
+ sk->no_check = UDP_NO_CHECK;
+ prot=&udp_prot;
+ break;
+
+ case SOCK_RAW:
+ if (!suser())
+ {
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-EPERM);
+ }
+ if (!protocol)
+ {
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-EPROTONOSUPPORT);
+ }
+ prot = &raw_prot;
+ sk->reuse = 1;
+ sk->no_check = 0; /*
+ * Doesn't matter no checksum is
+ * preformed anyway.
+ */
+ sk->num = protocol;
+ break;
+
+ case SOCK_PACKET:
+ if (!suser())
+ {
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-EPERM);
+ }
+ if (!protocol)
+ {
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-EPROTONOSUPPORT);
+ }
+ prot = &packet_prot;
+ sk->reuse = 1;
+ sk->no_check = 0; /* Doesn't matter no checksum is
+ * preformed anyway.
+ */
+ sk->num = protocol;
+ break;
+
+ default:
+ kfree_s((void *)sk, sizeof(*sk));
+ return(-ESOCKTNOSUPPORT);
+ }
+ sk->socket = sock;
+ sk->type = sock->type;
+ sk->protocol = protocol;
+ sk->wmem_alloc = 0;
+ sk->rmem_alloc = 0;
+ sk->sndbuf = SK_WMEM_MAX;
+ sk->rcvbuf = SK_RMEM_MAX;
+ sk->pair = NULL;
+ sk->opt = NULL;
+ sk->send_seq = 0;
+ sk->acked_seq = 0;
+ sk->copied_seq = 0;
+ sk->fin_seq = 0;
+ sk->proc = 0;
+ sk->rtt = TCP_WRITE_TIME;
+ sk->mdev = 0;
+ sk->backoff = 0;
+ sk->packets_out = 0;
+ sk->cong_window = 1; /* start with only sending one packet at a time. */
+ sk->exp_growth = 1; /* if set cong_window grow exponentially every time
+ we get an ack. */
+ sk->urginline = 0;
+ sk->intr = 0;
+ sk->linger = 0;
+ sk->destroy = 0;
+
+ sk->priority = 1;
+ sk->shutdown = 0;
+ sk->urg = 0;
+ sk->keepopen = 0;
+ sk->zapped = 0;
+ sk->done = 0;
+ sk->ack_backlog = 0;
+ sk->window = 0;
+ sk->bytes_rcv = 0;
+ sk->state = TCP_CLOSE;
+ sk->dead = 0;
+ sk->ack_timed = 0;
+ sk->send_tmp = NULL;
+ sk->mss = 0; /* we will try not to send any packets smaller than this. */
+ sk->debug = 0;
+
+ /* this is how many unacked bytes we will accept for this socket. */
+ sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
+
+ /* how many packets we should send before forcing an ack.
+ * if this is set to zero it is the same as sk->delay_acks = 0
+ */
+ sk->max_ack_backlog = 0;
+ sk->inuse = 0;
+ sk->delay_acks = 0;
+ sk->wback = NULL;
+ sk->wfront = NULL;
+ sk->rqueue = NULL;
+ sk->mtu = 576; /* This is a reasonable typical choice. RFC791 guarantees this is acceptable */
+ sk->prot = prot;
+ sk->sleep = sock->wait;
+ sk->daddr = 0;
+ sk->saddr = my_addr();
+ sk->err = 0;
+ sk->next = NULL;
+ sk->pair = NULL;
+ sk->send_tail = NULL;
+ sk->send_head = NULL;
+ sk->timeout = 0;
+ sk->broadcast = 0;
+ sk->timer.data = (unsigned long)sk;
+ sk->timer.function = &net_timer;
+ sk->back_log = NULL;
+ sk->blog = 0;
+ sock->data =(void *) sk;
+ sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
+ sk->dummy_th.res1=0;
+ sk->dummy_th.res2=0;
+ sk->dummy_th.urg_ptr = 0;
+ sk->dummy_th.fin = 0;
+ sk->dummy_th.syn = 0;
+ sk->dummy_th.rst = 0;
+ sk->dummy_th.psh = 0;
+ sk->dummy_th.ack = 0;
+ sk->dummy_th.urg = 0;
+ sk->dummy_th.dest = 0;
+
+ sk->ip_tos=0;
+ sk->ip_ttl=64;
+
+ sk->state_change = def_callback1;
+ sk->data_ready = def_callback2;
+ sk->write_space = def_callback1;
+ sk->error_report = def_callback1;
+
+ if (sk->num)
+ {
+ /*
+ * It assumes that any protocol which allows
+ * the user to assign a number at socket
+ * creation time automatically
+ * shares.
+ */
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+
+ if (sk->prot->init)
+ {
+ err = sk->prot->init(sk);
+ if (err != 0)
+ {
+ destroy_sock(sk);
+ return(err);
+ }
+ }
+ return(0);
+}
+
+
+static int inet_dup(struct socket *newsock, struct socket *oldsock)
+{
+ return(inet_create(newsock,((struct sock *)(oldsock->data))->protocol));
+}
+
+
+/* The peer socket should always be NULL. */
+static int inet_release(struct socket *sock, struct socket *peer)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ return(0);
+
+ DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer));
+ wake_up(sk->sleep);
+
+ /* Start closing the connection. This may take a while. */
+ /*
+ * If linger is set, we don't return until the close
+ * is complete. Other wise we return immediately. The
+ * actually closing is done the same either way.
+ */
+ if (sk->linger == 0)
+ {
+ sk->prot->close(sk,0);
+ sk->dead = 1;
+ }
+ else
+ {
+ DPRINTF((DBG_INET, "sk->linger set.\n"));
+ sk->prot->close(sk, 0);
+ cli();
+ if (sk->lingertime)
+ current->timeout = jiffies + HZ*sk->lingertime;
+ while(sk->state != TCP_CLOSE && sk->state != TCP_FIN_WAIT2 && sk->state !=TCP_TIME_WAIT && current->timeout>0)
+ {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ current->timeout=0;
+ return(-ERESTARTSYS);
+ }
+ }
+ current->timeout=0;
+ sti();
+ sk->dead = 1;
+ }
+ sk->inuse = 1;
+
+ /* This will destroy it. */
+ release_sock(sk);
+ sock->data = NULL;
+ DPRINTF((DBG_INET, "inet_release returning\n"));
+ return(0);
+}
+
+
+/* this needs to be changed to dissallow
+ the rebinding of sockets. What error
+ should it return? */
+
+static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
+ int addr_len)
+{
+ struct sockaddr_in addr;
+ struct sock *sk, *sk2;
+ unsigned short snum;
+ int err;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ /* check this error. */
+ if (sk->state != TCP_CLOSE)
+ return(-EIO);
+ if (sk->num != 0)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, uaddr, addr_len);
+ if(err)
+ return err;
+ memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len));
+
+ snum = ntohs(addr.sin_port);
+ DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum));
+ sk = (struct sock *) sock->data;
+ if (snum == 0)
+ {
+ snum = get_new_socknum(sk->prot, 0);
+ }
+ if (snum < PROT_SOCK && !suser())
+ return(-EACCES);
+
+ if (addr.sin_addr.s_addr!=0 && chk_addr(addr.sin_addr.s_addr)!=IS_MYADDR)
+ return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
+
+ if (chk_addr(addr.sin_addr.s_addr) || addr.sin_addr.s_addr == 0)
+ sk->saddr = addr.sin_addr.s_addr;
+
+ DPRINTF((DBG_INET, "sock_array[%d] = %X:\n", snum &(SOCK_ARRAY_SIZE -1),
+ sk->prot->sock_array[snum &(SOCK_ARRAY_SIZE -1)]));
+
+ /* Make sure we are allowed to bind here. */
+ cli();
+outside_loop:
+ for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];sk2 != NULL; sk2 = sk2->next)
+ {
+ if (sk2->num != snum)
+ continue;
+ if (sk2->saddr != sk->saddr)
+ continue;
+ if (sk2->dead && !sk2->inuse) /* Added in use check AC 24/12/93 */
+ {
+ destroy_sock(sk2);
+ goto outside_loop;
+ }
+ if (!sk->reuse)
+ {
+ sti();
+ return(-EADDRINUSE);
+ }
+ if (sk2->num != snum)
+ continue; /* more than one */
+ if (sk2->saddr != sk->saddr)
+ continue; /* socket per slot ! -FB */
+ if (!sk2->reuse)
+ {
+ sti();
+ return(-EADDRINUSE);
+ }
+ }
+ sti();
+
+ remove_sock(sk);
+ put_sock(snum, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ sk->daddr = 0;
+ sk->dummy_th.dest = 0;
+ return(0);
+}
+
+
+static int inet_connect(struct socket *sock, struct sockaddr * uaddr,
+ int addr_len, int flags)
+{
+ struct sock *sk;
+ int err;
+
+ sock->conn = NULL;
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
+ {
+ sock->state = SS_CONNECTED;
+ /* Connection completing after a connect/EINPROGRESS/select/connect */
+ return 0; /* Rock and roll */
+ }
+
+ if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
+ return -EALREADY; /* Connecting is currently in progress */
+
+ if (sock->state != SS_CONNECTING)
+ {
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = htons(sk->num);
+ }
+
+ if (sk->prot->connect == NULL)
+ return(-EOPNOTSUPP);
+
+ err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len);
+ if (err < 0)
+ return(err);
+
+ sock->state = SS_CONNECTING;
+ }
+
+ if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))
+ return(-EINPROGRESS);
+
+ cli(); /* avoid the race condition */
+ while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
+ {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ return(-ERESTARTSYS);
+ }
+ /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
+ icmp error packets wanting to close a tcp or udp socket. */
+ if(sk->err && sk->protocol == IPPROTO_TCP)
+ {
+ sti();
+ sock->state = SS_UNCONNECTED;
+ err = -sk->err;
+ sk->err=0;
+ return err; /* set by tcp_err() */
+ }
+ }
+ sti();
+ sock->state = SS_CONNECTED;
+
+ if (sk->state != TCP_ESTABLISHED && sk->err)
+ {
+ sock->state = SS_UNCONNECTED;
+ err=sk->err;
+ sk->err=0;
+ return(err);
+ }
+ return(0);
+}
+
+
+static int inet_socketpair(struct socket *sock1, struct socket *sock2)
+{
+ return(-EOPNOTSUPP);
+}
+
+
+static int inet_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ struct sock *sk1, *sk2;
+ int err;
+
+ sk1 = (struct sock *) sock->data;
+ if (sk1 == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ /*
+ * We've been passed an extra socket.
+ * We need to free it up because the tcp module creates
+ * it's own when it accepts one.
+ */
+
+ if (newsock->data)
+ kfree_s(newsock->data, sizeof(struct sock));
+ newsock->data = NULL;
+
+ if (sk1->prot->accept == NULL)
+ return(-EOPNOTSUPP);
+
+ /* Restore the state if we have been interrupted, and then returned. */
+ if (sk1->pair != NULL )
+ {
+ sk2 = sk1->pair;
+ sk1->pair = NULL;
+ }
+ else
+ {
+ sk2 = sk1->prot->accept(sk1,flags);
+ if (sk2 == NULL)
+ {
+ if (sk1->err <= 0)
+ printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n");
+ err=sk1->err;
+ sk1->err=0;
+ return(-err);
+ }
+ }
+ newsock->data = (void *)sk2;
+ sk2->sleep = newsock->wait;
+ newsock->conn = NULL;
+ if (flags & O_NONBLOCK)
+ return(0);
+
+ cli(); /* avoid the race. */
+
+ while(sk2->state == TCP_SYN_RECV)
+ {
+ interruptible_sleep_on(sk2->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ sk1->pair = sk2;
+ sk2->sleep = NULL;
+ newsock->data = NULL;
+ return(-ERESTARTSYS);
+ }
+ }
+ sti();
+
+ if (sk2->state != TCP_ESTABLISHED && sk2->err > 0)
+ {
+
+ err = -sk2->err;
+ sk2->err=0;
+ destroy_sock(sk2);
+ newsock->data = NULL;
+ return(err);
+ }
+ newsock->state = SS_CONNECTED;
+ return(0);
+}
+
+
+static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *uaddr_len, int peer)
+{
+ struct sockaddr_in sin;
+ struct sock *sk;
+ int len;
+ int err;
+
+
+ err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long));
+ if(err)
+ return err;
+
+ len=get_fs_long(uaddr_len);
+
+ err = verify_area(VERIFY_WRITE, uaddr, len);
+ if(err)
+ return err;
+
+ /* Check this error. */
+ if (len < sizeof(sin))
+ return(-EINVAL);
+
+ sin.sin_family = AF_INET;
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+ if (peer)
+ {
+ if (!tcp_connected(sk->state))
+ return(-ENOTCONN);
+ sin.sin_port = sk->dummy_th.dest;
+ sin.sin_addr.s_addr = sk->daddr;
+ }
+ else
+ {
+ sin.sin_port = sk->dummy_th.source;
+ if (sk->saddr == 0)
+ sin.sin_addr.s_addr = my_addr();
+ else
+ sin.sin_addr.s_addr = sk->saddr;
+ }
+ len = sizeof(sin);
+ memcpy_tofs(uaddr, &sin, sizeof(sin));
+ put_fs_long(len, uaddr_len);
+ return(0);
+}
+
+
+static int inet_read(struct socket *sock, char *ubuf, int size, int noblock)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+ return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock,0));
+}
+
+
+static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+ return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags));
+}
+
+
+static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+
+ return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, 0));
+}
+
+
+static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,
+ unsigned flags)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+
+ return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));
+}
+
+
+static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
+ unsigned flags, struct sockaddr *sin, int addr_len)
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+
+ if (sk->prot->sendto == NULL)
+ return(-EOPNOTSUPP);
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+
+ return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags,
+ (struct sockaddr_in *)sin, addr_len));
+}
+
+
+static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
+ unsigned flags, struct sockaddr *sin, int *addr_len )
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ if (sk->prot->recvfrom == NULL)
+ return(-EOPNOTSUPP);
+
+ /* We may need to bind the socket. */
+ if (sk->num == 0)
+ {
+ sk->num = get_new_socknum(sk->prot, 0);
+ if (sk->num == 0)
+ return(-EAGAIN);
+ put_sock(sk->num, sk);
+ sk->dummy_th.source = ntohs(sk->num);
+ }
+
+ return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags,
+ (struct sockaddr_in*)sin, addr_len));
+}
+
+
+static int inet_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk;
+
+ /*
+ * This should really check to make sure
+ * the socket is a TCP socket.
+ */
+ how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
+ 1->2 bit 2 snds.
+ 2->3 */
+ if (how & ~SHUTDOWN_MASK)
+ return(-EINVAL);
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+ if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
+ sock->state = SS_CONNECTED;
+
+ if (!tcp_connected(sk->state))
+ return(-ENOTCONN);
+ sk->shutdown |= how;
+ if (sk->prot->shutdown)
+ sk->prot->shutdown(sk, how);
+ return(0);
+}
+
+
+static int inet_select(struct socket *sock, int sel_type, select_table *wait )
+{
+ struct sock *sk;
+
+ sk = (struct sock *) sock->data;
+ if (sk == NULL)
+ {
+ printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
+ return(0);
+ }
+
+ if (sk->prot->select == NULL)
+ {
+ DPRINTF((DBG_INET, "select on non-selectable socket.\n"));
+ return(0);
+ }
+ return(sk->prot->select(sk, sel_type, wait));
+}
+
+
+static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct sock *sk;
+ int err;
+
+ DPRINTF((DBG_INET, "INET: in inet_ioctl\n"));
+ sk = NULL;
+ if (sock && (sk = (struct sock *) sock->data) == NULL)
+ {
+ printk("AF_INET: Warning: sock->data = NULL: %d\n" , __LINE__);
+ return(0);
+ }
+
+ switch(cmd)
+ {
+ case FIOSETOWN:
+ case SIOCSPGRP:
+ err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
+ if(err)
+ return err;
+ if (sk)
+ sk->proc = get_fs_long((int *) arg);
+ return(0);
+ case FIOGETOWN:
+ case SIOCGPGRP:
+ if (sk)
+ {
+ err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
+ if(err)
+ return err;
+ put_fs_long(sk->proc,(int *)arg);
+ }
+ return(0);
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_INET));
+
+ case SIOCADDRT:
+ case SIOCDELRT:
+ return(rt_ioctl(cmd,(void *) arg));
+
+ case SIOCDARP:
+ case SIOCGARP:
+ case SIOCSARP:
+ return(arp_ioctl(cmd,(void *) arg));
+
+ case IP_SET_DEV:
+ case SIOCGIFCONF:
+ case SIOCGIFFLAGS:
+ case SIOCSIFFLAGS:
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ case SIOCGIFMEM:
+ case SIOCSIFMEM:
+ case SIOCGIFMTU:
+ case SIOCSIFMTU:
+ case SIOCSIFLINK:
+ case SIOCGIFHWADDR:
+ return(dev_ioctl(cmd,(void *) arg));
+
+ default:
+ if (!sk || !sk->prot->ioctl)
+ return(-EINVAL);
+ return(sk->prot->ioctl(sk, cmd, arg));
+ }
+ /*NOTREACHED*/
+ return(0);
+}
+
+
+
+/*
+ * This routine must find a socket given a TCP or UDP header.
+ * Everyhting is assumed to be in net order.
+ */
+struct sock *get_sock(struct proto *prot, unsigned short num,
+ unsigned long raddr,
+ unsigned short rnum, unsigned long laddr)
+{
+ struct sock *s;
+ unsigned short hnum;
+
+ hnum = ntohs(num);
+ DPRINTF((DBG_INET, "get_sock(prot=%X, num=%d, raddr=%X, rnum=%d, laddr=%X)\n",
+ prot, num, raddr, rnum, laddr));
+
+ /*
+ * SOCK_ARRAY_SIZE must be a power of two. This will work better
+ * than a prime unless 3 or more sockets end up using the same
+ * array entry. This should not be a problem because most
+ * well known sockets don't overlap that much, and for
+ * the other ones, we can just be careful about picking our
+ * socket number when we choose an arbitrary one.
+ */
+ for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];s != NULL; s = s->next)
+ {
+ if (s->num != hnum)
+ continue;
+ if(s->dead && (s->state == TCP_CLOSE))
+ continue;
+ if(prot == &udp_prot)
+ return s;
+ if(ip_addr_match(s->daddr,raddr)==0)
+ continue;
+ if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
+ continue;
+ if(ip_addr_match(s->saddr,laddr) == 0)
+ continue;
+ return(s);
+ }
+ return(NULL);
+}
+
+
+void release_sock(struct sock *sk)
+{
+ if (!sk)
+ {
+ printk("sock.c: release_sock sk == NULL\n");
+ return;
+ }
+ /* This one _IS_ legal */
+ if (!sk->prot)
+ {
+ return;
+ }
+
+ if (sk->blog)
+ return;
+
+ /* See if we have any packets built up. */
+ cli();
+ sk->inuse = 1;
+ while(sk->back_log != NULL)
+ {
+ struct sk_buff *skb;
+
+ sk->blog = 1;
+ skb =(struct sk_buff *)sk->back_log;
+ DPRINTF((DBG_INET, "release_sock: skb = %X:\n", skb));
+ if (skb->next != skb)
+ {
+ sk->back_log = skb->next;
+ skb->prev->next = skb->next;
+ skb->next->prev = skb->prev;
+ }
+ else
+ {
+ sk->back_log = NULL;
+ }
+ sti();
+ DPRINTF((DBG_INET, "sk->back_log = %X\n", sk->back_log));
+ if (sk->prot->rcv)
+ sk->prot->rcv(skb, skb->dev, sk->opt,
+ skb->saddr, skb->len, skb->daddr, 1,
+ /* Only used for/by raw sockets. */
+ (struct inet_protocol *)sk->pair);
+ cli();
+ }
+ sk->blog = 0;
+ sk->inuse = 0;
+ sti();
+ if (sk->dead && sk->state == TCP_CLOSE)
+ {
+ /* Should be about 2 rtt's */
+ reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
+ }
+}
+
+
+static int inet_fioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int minor, ret;
+
+ /* Extract the minor number on which we work. */
+ minor = MINOR(inode->i_rdev);
+ if (minor != 0)
+ return(-ENODEV);
+
+ /* Now dispatch on the minor device. */
+ switch(minor)
+ {
+ case 0: /* INET */
+ ret = inet_ioctl(NULL, cmd, arg);
+ break;
+ case 1: /* IP */
+ ret = ip_ioctl(NULL, cmd, arg);
+ break;
+ case 2: /* ICMP */
+ ret = icmp_ioctl(NULL, cmd, arg);
+ break;
+ case 3: /* TCP */
+ ret = tcp_ioctl(NULL, cmd, arg);
+ break;
+ case 4: /* UDP */
+ ret = udp_ioctl(NULL, cmd, arg);
+ break;
+ default:
+ ret = -ENODEV;
+ }
+
+ return(ret);
+}
+
+
+static struct file_operations inet_fops =
+{
+ NULL, /* LSEEK */
+ NULL, /* READ */
+ NULL, /* WRITE */
+ NULL, /* READDIR */
+ NULL, /* SELECT */
+ inet_fioctl, /* IOCTL */
+ NULL, /* MMAP */
+ NULL, /* OPEN */
+ NULL /* CLOSE */
+};
+
+
+static struct proto_ops inet_proto_ops =
+{
+ AF_INET,
+
+ inet_create,
+ inet_dup,
+ inet_release,
+ inet_bind,
+ inet_connect,
+ inet_socketpair,
+ inet_accept,
+ inet_getname,
+ inet_read,
+ inet_write,
+ inet_select,
+ inet_ioctl,
+ inet_listen,
+ inet_send,
+ inet_recv,
+ inet_sendto,
+ inet_recvfrom,
+ inet_shutdown,
+ inet_setsockopt,
+ inet_getsockopt,
+ inet_fcntl,
+};
+
+extern unsigned long seq_offset;
+
+/*
+ * Called by ddi.c on kernel startup.
+ */
+
+void inet_proto_init(struct ddi_proto *pro)
+{
+ struct inet_protocol *p;
+ int i;
+
+ printk("Swansea University Computer Society Net2Debugged [1.28]\n");
+ /* Set up our UNIX VFS major device. */
+ if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0)
+ {
+ printk("%s: cannot register major device %d!\n",
+ pro->name, AF_INET_MAJOR);
+ return;
+ }
+
+ /* Tell SOCKET that we are alive... */
+ (void) sock_register(inet_proto_ops.family, &inet_proto_ops);
+
+ seq_offset = CURRENT_TIME*250;
+
+ /* Add all the protocols. */
+ for(i = 0; i < SOCK_ARRAY_SIZE; i++)
+ {
+ tcp_prot.sock_array[i] = NULL;
+ udp_prot.sock_array[i] = NULL;
+ raw_prot.sock_array[i] = NULL;
+ }
+ printk("IP Protocols: ");
+ for(p = inet_protocol_base; p != NULL;)
+ {
+ struct inet_protocol *tmp;
+
+ tmp = (struct inet_protocol *) p->next;
+ inet_add_protocol(p);
+ printk("%s%s",p->name,tmp?", ":"\n");
+ p = tmp;
+ }
+
+}
diff --git a/net/inet/sockinet.h b/net/inet/sockinet.h
new file mode 100644
index 0000000..2e25e03
--- /dev/null
+++ b/net/inet/sockinet.h
@@ -0,0 +1,118 @@
+/*
+ * Definitions for the socket handler
+ *
+ * Version: @(#)sock.h 1.28 26/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche <flla@stud.uni-sb.de>
+ *
+ * Fixes:
+ * Alan Cox : Volatiles in skbuff pointers. See
+ * skbuff comments. May be overdone,
+ * better to prove they can be removed
+ * than the reverse.
+ * Alan Cox : Added a zapped field for tcp to note
+ * a socket is reset and must stay shut up
+ * Alan Cox : New fields for options
+ * Pauline Middelink : identd support
+ * Alan Cox : Split into sock.h and sockinet.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _SOCKINET_H
+#define _SOCKINET_H
+
+#ifndef _SOCK_H
+#include "socket/sock.h"
+#endif
+
+#ifndef _PROTOCOL_H_
+#include "protocol.h"
+#endif
+
+struct proto {
+ void *(*wmalloc)(struct sock *sk,
+ unsigned long size, int force,
+ int priority);
+ void *(*rmalloc)(struct sock *sk,
+ unsigned long size, int force,
+ int priority);
+ void (*wfree)(struct sock *sk, void *mem,
+ unsigned long size);
+ void (*rfree)(struct sock *sk, void *mem,
+ unsigned long size);
+ unsigned long (*rspace)(struct sock *sk);
+ unsigned long (*wspace)(struct sock *sk);
+ void (*close)(struct sock *sk, int timeout);
+ int (*read)(struct sock *sk, unsigned char *to,
+ int len, int nonblock, unsigned flags);
+ int (*write)(struct sock *sk, unsigned char *to,
+ int len, int nonblock, unsigned flags);
+ int (*sendto)(struct sock *sk,
+ unsigned char *from, int len, int noblock,
+ unsigned flags, struct sockaddr_in *usin,
+ int addr_len);
+ int (*recvfrom)(struct sock *sk,
+ unsigned char *from, int len, int noblock,
+ unsigned flags, struct sockaddr_in *usin,
+ int *addr_len);
+ int (*build_header)(struct sk_buff *skb,
+ unsigned long saddr,
+ unsigned long daddr,
+ struct device **dev, int type,
+ struct options *opt, int len,
+ int ttl, int tos);
+ int (*connect)(struct sock *sk,
+ struct sockaddr_in *usin, int addr_len);
+ struct sock *(*accept) (struct sock *sk, int flags);
+ void (*queue_xmit)(struct sock *sk,
+ struct device *dev, struct sk_buff *skb,
+ int free);
+ void (*retransmit)(struct sock *sk, int all);
+ void (*write_wakeup)(struct sock *sk);
+ void (*read_wakeup)(struct sock *sk);
+ int (*rcv)(struct sk_buff *buff, struct device *dev,
+ struct options *opt, unsigned long daddr,
+ unsigned short len, unsigned long saddr,
+ int redo, struct inet_protocol *protocol);
+ int (*select)(struct sock *sk, int which,
+ select_table *wait);
+ int (*ioctl)(struct sock *sk, int cmd,
+ unsigned long arg);
+ int (*init)(struct sock *sk);
+ void (*shutdown)(struct sock *sk, int how);
+ int (*setsockopt)(struct sock *sk, int level, int optname,
+ char *optval, int optlen);
+ int (*getsockopt)(struct sock *sk, int level, int optname,
+ char *optval, int *option);
+ unsigned short max_header;
+ unsigned long retransmits;
+ struct sock *sock_array[SOCK_ARRAY_SIZE];
+ char name[80];
+};
+
+extern void destroy_sock(struct sock *sk);
+extern unsigned short get_new_socknum(struct proto *, unsigned short);
+extern void put_sock(unsigned short, struct sock *);
+extern void release_sock(struct sock *sk);
+extern struct sock *get_sock(struct proto *, unsigned short,
+ unsigned long, unsigned short,
+ unsigned long);
+
+
+/* declarations from timer.c */
+extern struct sock *timer_base;
+
+void delete_timer (struct sock *);
+void reset_timer (struct sock *, int, unsigned long);
+void net_timer (unsigned long);
+
+
+
+#endif
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 83dfb41..7239e09 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -4,8 +4,9 @@
* interface as the means of communication with the user level.
*
* Implementation of the Transmission Control Protocol(TCP).
+ * This protocol is described in RFC793.
*
- * Version: @(#)tcp.c 1.0.16 05/25/93
+ * Version: @(#)tcp.c 1.28 25/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -14,9 +15,9 @@
* Florian La Roche, <flla@stud.uni-sb.de>
*
* Fixes:
- * Alan Cox : Numerous verify_area() calls
- * Alan Cox : Set the ACK bit on a reset
- * Alan Cox : Stopped it crashing if it closed while sk->inuse=1
+ * Alan Cox : Numerous verify_area() calls.
+ * Alan Cox : Set the ACK bit on a reset.
+ * Alan Cox : Stopped it crashing if it closed while sk->inuse=1.
* and was trying to connect (tcp_err()).
* Alan Cox : All icmp error handling was broken
* pointers passed where wrong and the
@@ -24,29 +25,39 @@
* tested any icmp error code obviously.
* Alan Cox : tcp_err() now handled properly. It wakes people
* on errors. select behaves and the icmp error race
- * has gone by moving it into sock.c
+ * has gone by moving it into sock.c.
* Alan Cox : tcp_reset() fixed to work for everything not just
* packets for unknown sockets.
* Alan Cox : tcp option processing.
- * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong]
- * Herp Rosmanith : More reset fixes
+ * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong].
+ * Herp Rosmanith : More reset fixes.
* Alan Cox : No longer acks invalid rst frames. Acking
* any kind of RST is right out.
* Alan Cox : Sets an ignore me flag on an rst receive
- * otherwise odd bits of prattle escape still
+ * otherwise odd bits of prattle escape still.
* Alan Cox : Fixed another acking RST frame bug. Should stop
* LAN workplace lockups.
- * Alan Cox : Some tidyups using the new skb list facilities
- * Alan Cox : sk->keepopen now seems to work
- * Alan Cox : Pulls options out correctly on accepts
- * Alan Cox : Fixed assorted sk->rqueue->next errors
+ * Alan Cox : Some tidyups using the new skb list facilities.
+ * Alan Cox : sk->keepopen now seems to work.
+ * Alan Cox : Pulls options out correctly on accepts.
+ * Alan Cox : Fixed assorted sk->rqueue->next errors.
* Alan Cox : PSH doesn't end a TCP read. Switched a bit to skb ops.
* Alan Cox : Tidied tcp_data to avoid a potential nasty.
- * Alan Cox : Added some beter commenting, as the tcp is hard to follow
- * Alan Cox : Removed incorrect check for 20 * psh
+ * Alan Cox : Added some beter commenting, as the tcp is hard to follow.
+ * Alan Cox : Removed incorrect check for 20 * psh.
* Michael O'Reilly : ack < copied bug fix.
* Johannes Stille : Misc tcp fixes (not all in yet).
- * Alan Cox : FIN with no memory -> CRASH
+ * Alan Cox : FIN with no memory -> CRASH.
+ * Alan Cox : Tidied up ready for final release and merge of other fixes.
+ * Alan Cox : Missing logic on FIN events.
+ * Alan Cox : Missing SYN bit check added (was #defined out in error).
+ * Alan Cox : recvfrom() semantics corrected - short recv ok, return on PSH flag.
+ * Alan Cox : window no longer memory driven so doesn't shrink illegally.
+ * Alan Cox : Added socket option proto entries. Also added awareness of them to accept.
+ * Alan Cox : State machine error causing Linus the ACK explosion problem found
+ * Unsynchronized states now send RST to bad ack frames as per RFC793 page 34.
+ * Alan Cox : Added TCP options (SOL_TCP)
+ * Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets.
*
*
* To Fix:
@@ -54,12 +65,9 @@
* it causes a select. Linux can - given the official select semantics I
* feel that _really_ its the BSD network programs that are bust (notably
* inetd, which hangs occasionally because of this).
- * Proper processing of piggybacked data on connect.
- * Add VJ Fastrecovery algorithm ?
* Protocol closedown badly messed up.
- * Incompatiblity with spider ports (tcp hangs on that
- * socket occasionally).
- * MSG_PEEK and read on same socket at once can cause crashes.
+ * MSG_PEEK and read on same socket at once can cause crashes (in theory)
+ * Should use the partial packet to piggy back acks.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -76,13 +84,13 @@
#include <linux/in.h>
#include <linux/fcntl.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include "arp.h"
#include <linux/errno.h>
#include <linux/timer.h>
@@ -96,67 +104,72 @@ unsigned long seq_offset;
static __inline__ int
min(unsigned int a, unsigned int b)
{
- if (a < b) return(a);
- return(b);
+ if (a < b)
+ return(a);
+ return(b);
}
-void
-print_th(struct tcphdr *th)
+void print_th(struct tcphdr *th)
{
- unsigned char *ptr;
-
- if (inet_debug != DBG_TCP) return;
-
- printk("TCP header:\n");
- ptr =(unsigned char *)(th + 1);
- printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
- ntohs(th->source), ntohs(th->dest),
- ntohl(th->seq), ntohl(th->ack_seq));
- printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
- th->fin, th->syn, th->rst, th->psh, th->ack,
- th->urg, th->res1, th->res2);
- printk(" window = %d, check = %d urg_ptr = %d\n",
- ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
- printk(" doff = %d\n", th->doff);
- printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
+ unsigned char *ptr;
+
+ if (inet_debug != DBG_TCP)
+ return;
+
+ printk("TCP header:\n");
+ ptr =(unsigned char *)(th + 1);
+ printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
+ ntohs(th->source), ntohs(th->dest),
+ ntohl(th->seq), ntohl(th->ack_seq));
+ printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
+ th->fin, th->syn, th->rst, th->psh, th->ack,
+ th->urg, th->res1, th->res2);
+ printk(" window = %d, check = %d urg_ptr = %d\n",
+ ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
+ printk(" doff = %d\n", th->doff);
+ printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
}
-/* This routine grabs the first thing off of a rcv queue. */
-static struct sk_buff *
-get_firstr(struct sock *sk)
+/*
+ * This routine grabs the first thing off of a rcv queue.
+ */
+
+static struct sk_buff *get_firstr(struct sock *sk)
{
- return skb_dequeue(&sk->rqueue);
+ return skb_dequeue(&sk->rqueue);
}
/*
* Difference between two values in tcp ack terms.
*/
-static long
-diff(unsigned long seq1, unsigned long seq2)
+static long diff(unsigned long seq1, unsigned long seq2)
{
- long d;
+ long d;
- d = seq1 - seq2;
- if (d > 0) return(d);
+ d = seq1 - seq2;
+ if (d > 0)
+ return(d);
- /* I hope this returns what I want. */
- return(~d+1);
+ /* I hope this returns what I want. */
+ return(~d+1);
}
-/* Enter the time wait state. */
+/*
+ * Enter the time wait state.
+ */
static void tcp_time_wait(struct sock *sk)
{
- sk->state = TCP_TIME_WAIT;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- wake_up(sk->sleep);
- reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ sk->state = TCP_TIME_WAIT;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ sk->state_change(sk);
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
}
/*
@@ -166,20 +179,20 @@ static void tcp_time_wait(struct sock *sk)
* nothing clever here.
*/
-static void
-tcp_retransmit(struct sock *sk, int all)
+static void tcp_retransmit(struct sock *sk, int all)
{
- if (all) {
- ip_retransmit(sk, all);
- return;
- }
+ if (all)
+ {
+ ip_retransmit(sk, all);
+ return;
+ }
- if (sk->cong_window > 4)
- sk->cong_window = sk->cong_window / 2;
- sk->exp_growth = 0;
+ if (sk->cong_window > 4)
+ sk->cong_window = sk->cong_window / 2;
+ sk->exp_growth = 0;
- /* Do the actuall retransmit. */
- ip_retransmit(sk, all);
+ /* Do the actuall retransmit. */
+ ip_retransmit(sk, all);
}
@@ -191,56 +204,61 @@ tcp_retransmit(struct sock *sk, int all)
* header points to the first 8 bytes of the tcp header. We need
* to find the appropriate port.
*/
-void
-tcp_err(int err, unsigned char *header, unsigned long daddr,
+void tcp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
- struct tcphdr *th;
- struct sock *sk;
- struct iphdr *iph=(struct iphdr *)header;
+ struct tcphdr *th;
+ struct sock *sk;
+ struct iphdr *iph=(struct iphdr *)header;
- header+=4*iph->ihl;
+ header+=4*iph->ihl;
- DPRINTF((DBG_TCP, "TCP: tcp_err(%d, hdr=%X, daddr=%X saddr=%X, protocol=%X)\n",
+ DPRINTF((DBG_TCP, "TCP: tcp_err(%d, hdr=%X, daddr=%X saddr=%X, protocol=%X)\n",
err, header, daddr, saddr, protocol));
- th =(struct tcphdr *)header;
- sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr);
- print_th(th);
+ th =(struct tcphdr *)header;
+ sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr);
+ print_th(th);
- if (sk == NULL) return;
+ if (sk == NULL)
+ return;
- if(err<0)
- {
- sk->err = -err;
- wake_up(sk->sleep);
- return;
- }
+ if(err<0)
+ {
+ sk->err = -err;
+ sk->error_report(sk);
+ return;
+ }
- if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) {
- /*
- * FIXME:
- * For now we will just trigger a linear backoff.
- * The slow start code should cause a real backoff here.
- */
- if (sk->cong_window > 4) sk->cong_window--;
- return;
- }
+ if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8))
+ {
+ /*
+ * FIXME:
+ * For now we will just trigger a linear backoff.
+ * The slow start code should cause a real backoff here.
+ */
+ if (sk->cong_window > 4) sk->cong_window--;
+ return;
+ }
- DPRINTF((DBG_TCP, "TCP: icmp_err got error\n"));
- sk->err = icmp_err_convert[err & 0xff].errno;
+ DPRINTF((DBG_TCP, "TCP: icmp_err got error\n"));
+ sk->err = icmp_err_convert[err & 0xff].errno;
- /*
- * If we've already connected we will keep trying
- * until we time out, or the user gives up.
- */
- if (icmp_err_convert[err & 0xff].fatal) {
- if (sk->state == TCP_SYN_SENT) {
- sk->state = TCP_CLOSE;
- wake_up(sk->sleep); /* Wake people up to see the error (see connect in sock.c) */
- }
- }
- return;
+ /*
+ * If we've already connected we will keep trying
+ * until we time out, or the user gives up.
+ */
+
+ if (icmp_err_convert[err & 0xff].fatal)
+ {
+ if (sk->state == TCP_SYN_SENT)
+ {
+ sk->state = TCP_CLOSE;
+ sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
+ sk->state_change(sk);
+ }
+ }
+ return;
}
@@ -249,66 +267,63 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
* in the received data queue (ie a frame missing that needs sending to us)
*/
-static int
-tcp_readable(struct sock *sk)
+static int tcp_readable(struct sock *sk)
{
- unsigned long counted;
- unsigned long amount;
- struct sk_buff *skb;
- int count=0;
- int sum;
- unsigned long flags;
-
- DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk));
- if(sk && sk->debug)
- printk("tcp_readable: %p - ",sk);
-
- if (sk == NULL || skb_peek(&sk->rqueue) == NULL) /* Empty sockets are easy! */
- {
- if(sk && sk->debug)
- printk("empty\n");
- return(0);
- }
+ unsigned long counted;
+ unsigned long amount;
+ struct sk_buff *skb;
+ int count=0;
+ int sum;
+ unsigned long flags;
+
+ DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk));
+ if(sk && sk->debug)
+ printk("tcp_readable: %p - ",sk);
+
+ if (sk == NULL || skb_peek(&sk->rqueue) == NULL) /* Empty sockets are easy! */
+ {
+ if(sk && sk->debug)
+ printk("empty\n");
+ return(0);
+ }
- counted = sk->copied_seq+1; /* Where we are at the moment */
- amount = 0;
+ counted = sk->copied_seq+1; /* Where we are at the moment */
+ amount = 0;
- save_flags(flags); /* So nobody adds things at the wrong moment */
- cli();
- skb =(struct sk_buff *)sk->rqueue;
-
- /* Do until a push or until we are out of data. */
- do {
- count++;
-#ifdef OLD
- /* This is wrong: It breaks Chameleon amongst other stacks */
- if (count > 20) {
- restore_flags(flags);
- DPRINTF((DBG_TCP, "tcp_readable, more than 20 packets without a psh\n"));
- printk("tcp_read: possible read_queue corruption.\n");
- return(amount);
- }
-#endif
- if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */
- break;
- sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */
- if (skb->h.th->syn) sum++;
- if (skb->h.th->urg) {
- sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */
- }
- if (sum >= 0) { /* Add it up, move on */
- amount += sum;
- if (skb->h.th->syn) amount--;
- counted += sum;
- }
-/* if (amount && skb->h.th->psh) break;*/
- skb =(struct sk_buff *)skb->next; /* Move along */
- } while(skb != sk->rqueue);
- restore_flags(flags);
- DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount));
- if(sk->debug)
- printk("got %lu bytes.\n",amount);
- return(amount);
+ save_flags(flags); /* So nobody adds things at the wrong moment */
+ cli();
+ skb =(struct sk_buff *)sk->rqueue;
+
+ /* Do until a push or until we are out of data. */
+ do
+ {
+ count++;
+ if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */
+ break;
+ sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */
+ if (skb->h.th->syn)
+ sum++;
+ if (skb->h.th->urg)
+ {
+ sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */
+ }
+ if (sum >= 0)
+ { /* Add it up, move on */
+ amount += sum;
+ if (skb->h.th->syn)
+ amount--;
+ counted += sum;
+ }
+/* if (amount && skb->h.th->psh)
+ break;*/
+ skb =(struct sk_buff *)skb->next; /* Move along */
+ }
+ while(skb != sk->rqueue);
+ restore_flags(flags);
+ DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount));
+ if(sk->debug)
+ printk("got %lu bytes.\n",amount);
+ return(amount);
}
@@ -317,112 +332,120 @@ tcp_readable(struct sock *sk)
* listening socket has a receive queue of sockets to accept.
*/
-static int
-tcp_select(struct sock *sk, int sel_type, select_table *wait)
+static int tcp_select(struct sock *sk, int sel_type, select_table *wait)
{
- DPRINTF((DBG_TCP, "tcp_select(sk=%X, sel_type = %d, wait = %X)\n",
+ DPRINTF((DBG_TCP, "tcp_select(sk=%X, sel_type = %d, wait = %X)\n",
sk, sel_type, wait));
- sk->inuse = 1;
- switch(sel_type) {
- case SEL_IN:
- if(sk->debug)
- printk("select in");
- select_wait(sk->sleep, wait);
- if(sk->debug)
+ sk->inuse = 1;
+ switch(sel_type)
+ {
+ case SEL_IN:
+ if(sk->debug)
+ printk("select in");
+ select_wait(sk->sleep, wait);
+ if(sk->debug)
printk("-select out");
- if (skb_peek(&sk->rqueue) != NULL) {
- if (sk->state == TCP_LISTEN || tcp_readable(sk)) {
+ if (skb_peek(&sk->rqueue) != NULL)
+ {
+ if (sk->state == TCP_LISTEN || tcp_readable(sk))
+ {
+ release_sock(sk);
+ if(sk->debug)
+ printk("-select ok data\n");
+ return(1);
+ }
+ }
+ if (sk->err != 0) /* Receiver error */
+ {
release_sock(sk);
if(sk->debug)
- printk("-select ok data\n");
+ printk("-select ok error");
return(1);
}
- }
- if (sk->err != 0) /* Receiver error */
- {
- release_sock(sk);
- if(sk->debug)
- printk("-select ok error");
- return(1);
- }
- if (sk->shutdown & RCV_SHUTDOWN) {
- release_sock(sk);
- if(sk->debug)
- printk("-select ok down\n");
- return(1);
- } else {
- release_sock(sk);
- if(sk->debug)
- printk("-select fail\n");
- return(0);
- }
- case SEL_OUT:
- select_wait(sk->sleep, wait);
- if (sk->shutdown & SEND_SHUTDOWN) {
- DPRINTF((DBG_TCP,
- "write select on shutdown socket.\n"));
-
- /* FIXME: should this return an error? */
- release_sock(sk);
- return(0);
- }
-
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ release_sock(sk);
+ if(sk->debug)
+ printk("-select ok down\n");
+ return(1);
+ }
+ else
+ {
+ release_sock(sk);
+ if(sk->debug)
+ printk("-select fail\n");
+ return(0);
+ }
+ case SEL_OUT:
+ select_wait(sk->sleep, wait);
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ DPRINTF((DBG_TCP,
+ "write select on shutdown socket.\n"));
+ /* FIXME: should this return an error? */
+ release_sock(sk);
+ return(0);
+ }
/*
* FIXME:
* Hack so it will probably be able to write
* something if it says it's ok to write.
*/
- if (sk->prot->wspace(sk) >= sk->mtu) {
+ if (sk->prot->wspace(sk) >= sk->mtu)
+ {
+ release_sock(sk);
+ /* This should cause connect to work ok. */
+ if (sk->state == TCP_SYN_RECV ||
+ sk->state == TCP_SYN_SENT)
+ return(0);
+ return(1);
+ }
+ DPRINTF((DBG_TCP,
+ "tcp_select: sleeping on write sk->wmem_alloc = %d, "
+ "sk->packets_out = %d\n"
+ "sk->wback = %X, sk->wfront = %X\n"
+ "sk->send_seq = %u, sk->window_seq=%u\n",
+ sk->wmem_alloc, sk->packets_out,
+ sk->wback, sk->wfront,
+ sk->send_seq, sk->window_seq));
+
release_sock(sk);
- /* This should cause connect to work ok. */
- if (sk->state == TCP_SYN_RECV ||
- sk->state == TCP_SYN_SENT) return(0);
- return(1);
- }
- DPRINTF((DBG_TCP,
- "tcp_select: sleeping on write sk->wmem_alloc = %d, "
- "sk->packets_out = %d\n"
- "sk->wback = %X, sk->wfront = %X\n"
- "sk->send_seq = %u, sk->window_seq=%u\n",
- sk->wmem_alloc, sk->packets_out,
- sk->wback, sk->wfront,
- sk->send_seq, sk->window_seq));
-
- release_sock(sk);
- return(0);
- case SEL_EX:
- select_wait(sk->sleep,wait);
- if (sk->err) {
+ return(0);
+ case SEL_EX:
+ select_wait(sk->sleep,wait);
+ if (sk->err)
+ {
+ release_sock(sk);
+ return(1);
+ }
release_sock(sk);
- return(1);
- }
- release_sock(sk);
- return(0);
- }
+ return(0);
+ }
- release_sock(sk);
- return(0);
+ release_sock(sk);
+ return(0);
}
-int
-tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- int err;
- DPRINTF((DBG_TCP, "tcp_ioctl(sk=%X, cmd = %d, arg=%X)\n", sk, cmd, arg));
- switch(cmd) {
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_TCP));
+ int err;
+ DPRINTF((DBG_TCP, "tcp_ioctl(sk=%X, cmd = %d, arg=%X)\n", sk, cmd, arg));
+ switch(cmd)
+ {
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_TCP));
- case TIOCINQ:
+ case TIOCINQ:
#ifdef FIXME /* FIXME: */
- case FIONREAD:
+ case FIONREAD:
#endif
{
unsigned long amount;
- if (sk->state == TCP_LISTEN) return(-EINVAL);
+ if (sk->state == TCP_LISTEN)
+ return(-EINVAL);
sk->inuse = 1;
amount = tcp_readable(sk);
@@ -435,7 +458,7 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
- case SIOCATMARK:
+ case SIOCATMARK:
{
struct sk_buff *skb;
int answ = 0;
@@ -448,7 +471,7 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
if ((skb=skb_peek(&sk->rqueue)) != NULL)
{
if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
- answ = 1;
+ answ = 1;
}
release_sock(sk);
err=verify_area(VERIFY_WRITE,(void *) arg,
@@ -458,11 +481,12 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
put_fs_long(answ,(int *) arg);
return(0);
}
- case TIOCOUTQ:
+ case TIOCOUTQ:
{
unsigned long amount;
- if (sk->state == TCP_LISTEN) return(-EINVAL);
+ if (sk->state == TCP_LISTEN)
+ return(-EINVAL);
amount = sk->prot->wspace(sk);
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
@@ -471,986 +495,1288 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
- default:
- return(-EINVAL);
- }
+ default:
+ return(-EINVAL);
+ }
}
-/* This routine computes a TCP checksum. */
-unsigned short
-tcp_check(struct tcphdr *th, int len,
+/*
+ * This routine computes a TCP checksum.
+ */
+
+unsigned short tcp_check(struct tcphdr *th, int len,
unsigned long saddr, unsigned long daddr)
{
- unsigned long sum;
+ unsigned long sum;
- if (saddr == 0) saddr = my_addr();
- print_th(th);
- __asm__("\t addl %%ecx,%%ebx\n"
- "\t adcl %%edx,%%ebx\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum)
- : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
- : "cx","bx","dx" );
+ if (saddr == 0)
+ saddr = my_addr();
+ print_th(th);
+ __asm__("\t addl %%ecx,%%ebx\n"
+ "\t adcl %%edx,%%ebx\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum)
+ : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
+ : "cx","bx","dx" );
- if (len > 3) {
- __asm__("\tclc\n"
- "1:\n"
- "\t lodsl\n"
- "\t adcl %%eax, %%ebx\n"
- "\t loop 1b\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum) , "=S"(th)
- : "0"(sum), "c"(len/4) ,"1"(th)
- : "ax", "cx", "bx", "si" );
- }
-
- /* Convert from 32 bits to 16 bits. */
- __asm__("\t movl %%ebx, %%ecx\n"
- "\t shrl $16,%%ecx\n"
- "\t addw %%cx, %%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum)
- : "bx", "cx");
+ if (len > 3)
+ {
+ __asm__("\tclc\n"
+ "1:\n"
+ "\t lodsl\n"
+ "\t adcl %%eax, %%ebx\n"
+ "\t loop 1b\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum) , "=S"(th)
+ : "0"(sum), "c"(len/4) ,"1"(th)
+ : "ax", "cx", "bx", "si" );
+ }
- /* Check for an extra word. */
- if ((len & 2) != 0) {
- __asm__("\t lodsw\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum), "=S"(th)
- : "0"(sum) ,"1"(th)
- : "si", "ax", "bx");
- }
+ /* Convert from 32 bits to 16 bits. */
+ __asm__("\t movl %%ebx, %%ecx\n"
+ "\t shrl $16,%%ecx\n"
+ "\t addw %%cx, %%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum)
+ : "bx", "cx");
+
+ /* Check for an extra word. */
+ if ((len & 2) != 0)
+ {
+ __asm__("\t lodsw\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum), "=S"(th)
+ : "0"(sum) ,"1"(th)
+ : "si", "ax", "bx");
+ }
- /* Now check for the extra byte. */
- if ((len & 1) != 0) {
- __asm__("\t lodsb\n"
- "\t movb $0,%%ah\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum) ,"S"(th)
- : "si", "ax", "bx");
- }
+ /* Now check for the extra byte. */
+ if ((len & 1) != 0)
+ {
+ __asm__("\t lodsb\n"
+ "\t movb $0,%%ah\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum) ,"S"(th)
+ : "si", "ax", "bx");
+ }
- /* We only want the bottom 16 bits, but we never cleared the top 16. */
- return((~sum) & 0xffff);
+ /* We only want the bottom 16 bits, but we never cleared the top 16. */
+ return((~sum) & 0xffff);
}
-void
-tcp_send_check(struct tcphdr *th, unsigned long saddr,
+void tcp_send_check(struct tcphdr *th, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
- th->check = 0;
- th->check = tcp_check(th, len, saddr, daddr);
- return;
+ th->check = 0;
+ th->check = tcp_check(th, len, saddr, daddr);
+ return;
}
+/*
+ * Send current partially built frame
+ */
-static void
-tcp_send_partial(struct sock *sk)
+static void tcp_send_partial(struct sock *sk)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
- if (sk == NULL || sk->send_tmp == NULL) return;
+ if (sk == NULL || sk->send_tmp == NULL)
+ return;
- skb = sk->send_tmp;
+ skb = sk->send_tmp;
- /* We need to complete and send the packet. */
- tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
+ /* We need to complete and send the packet. */
+
+ /*
+ * Fill in the checksum
+ */
+
+ tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
skb->len-(unsigned long)skb->h.th +
(unsigned long)(skb+1), sk);
- skb->h.seq = sk->send_seq;
- if (after(sk->send_seq , sk->window_seq) ||
- sk->packets_out >= sk->cong_window) {
- DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
- sk->cong_window, sk->packets_out));
- DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
- sk->send_seq, sk->window_seq));
- skb->next = NULL;
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (sk->wback == NULL) {
- sk->wfront=skb;
- } else {
- sk->wback->next = skb;
- }
- sk->wback = skb;
- } else {
- sk->prot->queue_xmit(sk, skb->dev, skb,0);
- }
- sk->send_tmp = NULL;
+ /*
+ * Fill in the sequence number
+ */
+ skb->h.seq = sk->send_seq;
+
+ /*
+ * Check the window and packet counts to
+ * see where it goes
+ */
+ if (after(sk->send_seq , sk->window_seq) ||
+ sk->packets_out >= sk->cong_window)
+ {
+ DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
+ sk->cong_window, sk->packets_out));
+ DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
+ sk->send_seq, sk->window_seq));
+ skb->next = NULL;
+ skb->magic = TCP_WRITE_QUEUE_MAGIC;
+ if (sk->wback == NULL)
+ {
+ sk->wfront=skb;
+ }
+ else
+ {
+ sk->wback->next = skb;
+ }
+ sk->wback = skb;
+ }
+ else
+ {
+ sk->prot->queue_xmit(sk, skb->dev, skb,0);
+ }
+ sk->send_tmp = NULL;
}
-/* This routine sends an ack and also updates the window. */
-static void
-tcp_send_ack(unsigned long sequence, unsigned long ack,
+/*
+ * This routine sends an ack and also updates the window.
+ */
+
+static void tcp_send_ack(unsigned long sequence, unsigned long ack,
struct sock *sk,
struct tcphdr *th, unsigned long daddr)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- struct device *dev = NULL;
- int tmp;
-
- if(sk->zapped)
- return; /* We have been reset, we may not send again */
- /*
- * We need to grab some memory, and put together an ack,
- * and then put it into the queue to be sent.
- */
- buff = (struct sk_buff *) sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL) {
- /* Force it to send an ack. */
- sk->ack_backlog++;
- if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) {
- reset_timer(sk, TIME_WRITE, 10);
- }
-if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
- return;
- }
-
- buff->mem_addr = buff;
- buff->mem_len = MAX_ACK_SIZE;
- buff->len = sizeof(struct tcphdr);
- buff->sk = sk;
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
- if (tmp < 0) {
- buff->free=1;
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
-if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
- return;
- }
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)t1 +tmp);
-
- /* FIXME: */
- memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
-
- /* swap the send and the receive. */
- t1->dest = th->source;
- t1->source = th->dest;
- t1->seq = ntohl(sequence);
- t1->ack = 1;
- sk->window = sk->prot->rspace(sk);
- t1->window = ntohs(sk->window);
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
- t1->fin = 0;
- if (ack == sk->acked_seq) {
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->ack_timed = 0;
- if (sk->send_head == NULL && sk->wfront == NULL) {
-/* delete_timer(sk);*/
- }
- }
- t1->ack_seq = ntohl(ack);
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
- if (sk->debug)
- printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
- sk->prot->queue_xmit(sk, dev, buff, 1);
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ struct device *dev = NULL;
+ int tmp;
+
+ if(sk->zapped)
+ return; /* We have been reset, we may not send again */
+ /*
+ * We need to grab some memory, and put together an ack,
+ * and then put it into the queue to be sent.
+ */
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL)
+ {
+ /* Force it to send an ack. */
+ sk->ack_backlog++;
+ if (sk->timeout != TIME_WRITE && tcp_connected(sk->state))
+ {
+ reset_timer(sk, TIME_WRITE, 10);
+ }
+ if (inet_debug == DBG_SLIP)
+ printk("\rtcp_ack: malloc failed\n");
+ return;
+ }
+
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_ACK_SIZE;
+ buff->len = sizeof(struct tcphdr);
+ buff->sk = sk;
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,
+ sk->ip_ttl,sk->ip_tos);
+ if (tmp < 0)
+ {
+ buff->free=1;
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
+ return;
+ }
+ buff->len += tmp;
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+
+ /* FIXME: */
+ memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
+
+ /* swap the send and the receive. */
+ t1->dest = th->source;
+ t1->source = th->dest;
+ t1->seq = ntohl(sequence);
+ t1->ack = 1;
+ sk->window = 4096/*sk->prot->rspace(sk)*/;
+ t1->window = ntohs(sk->window);
+ t1->res1 = 0;
+ t1->res2 = 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->syn = 0;
+ t1->psh = 0;
+ t1->fin = 0;
+ if (ack == sk->acked_seq)
+ {
+ sk->ack_backlog = 0;
+ sk->bytes_rcv = 0;
+ sk->ack_timed = 0;
+ if (sk->send_head == NULL && sk->wfront == NULL)
+ {
+/* delete_timer(sk);*/
+ }
+ }
+ t1->ack_seq = ntohl(ack);
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
+ if (sk->debug)
+ printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
+ sk->prot->queue_xmit(sk, dev, buff, 1);
}
-/* This routine builds a generic TCP header. */
-static int
-tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
+/*
+ * This routine builds a generic TCP header.
+ */
+
+static int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
{
- /* FIXME: want to get rid of this. */
- memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
- th->seq = htonl(sk->send_seq);
- th->psh =(push == 0) ? 1 : 0;
- th->doff = sizeof(*th)/4;
- th->ack = 1;
- th->fin = 0;
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->ack_timed = 0;
- th->ack_seq = htonl(sk->acked_seq);
- sk->window = sk->prot->rspace(sk);
- th->window = htons(sk->window);
-
- return(sizeof(*th));
+ /* FIXME: want to get rid of this. */
+ memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
+ th->seq = htonl(sk->send_seq);
+ th->psh =(push == 0) ? 1 : 0;
+ th->doff = sizeof(*th)/4;
+ th->ack = 1;
+ th->fin = 0;
+ sk->ack_backlog = 0;
+ sk->bytes_rcv = 0;
+ sk->ack_timed = 0;
+ th->ack_seq = htonl(sk->acked_seq);
+ sk->window = 4096-diff(sk->acked_seq,sk->copied_seq); /* sk->prot->rspace(sk); */
+ th->window = htons(sk->window);
+
+ return(sizeof(*th));
}
/*
- * This routine copies from a user buffer into a socket,
- * and starts the transmit system.
+ * This routine copies from a user buffer into a socket,
+ * and starts the transmit system.
*/
-static int
-tcp_write(struct sock *sk, unsigned char *from,
- int len, int nonblock, unsigned flags)
+
+static int tcp_write(struct sock *sk, unsigned char *from,
+ int len, int nonblock, unsigned flags)
{
- int copied = 0;
- int copy;
- int tmp;
- struct sk_buff *skb;
- unsigned char *buff;
- struct proto *prot;
- struct device *dev = NULL;
-
- DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
+ int copied = 0;
+ int copy;
+ int tmp;
+ struct sk_buff *skb;
+ unsigned char *buff;
+ struct proto *prot;
+ struct device *dev = NULL;
+
+ DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, from, len, nonblock, flags));
- sk->inuse=1;
- prot = sk->prot;
- while(len > 0) {
- if (sk->err) { /* Stop on an error */
- release_sock(sk);
- if (copied) return(copied);
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
-
- /* First thing we do is make sure that we are established. */
- if (sk->shutdown & SEND_SHUTDOWN) {
- release_sock(sk);
- sk->err = EPIPE;
- if (copied) return(copied);
- sk->err = 0;
- return(-EPIPE);
- }
-
-
- /* Wait for a connection to finish. */
-
- while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) {
- if (sk->err) {
+ sk->inuse=1;
+ prot = sk->prot;
+
+ while(len > 0)
+ {
+ if (sk->err)
+ { /* Stop on an error */
release_sock(sk);
- if (copied) return(copied);
+ if (copied)
+ return(copied);
+ /* FIXME: An error occuring between these two instructions _is_ remotely
+ possible. This occurs throughout the old and new net code and needs
+ fixing one day */
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
- if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) {
+ /* First thing we do is make sure that we are established. */
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
- if (copied) return(copied);
+ sk->err = EPIPE;
+ if (copied)
+ return(copied);
+ sk->err = 0;
+ return(-EPIPE);
+ }
+
- if (sk->err) {
+ /* Wait for a connection to finish. */
+
+ while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
+ {
+ if (sk->err)
+ {
+ release_sock(sk);
+ if (copied)
+ return(copied);
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
- if (sk->keepopen) {
- send_sig(SIGPIPE, current, 0);
+ if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
+ {
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
+ if (copied)
+ return(copied);
+
+ if (sk->err)
+ {
+ tmp = -sk->err;
+ sk->err = 0;
+ return(tmp);
+ }
+
+ if (sk->keepopen)
+ {
+ send_sig(SIGPIPE, current, 0);
+ }
+ return(-EPIPE);
}
- return(-EPIPE);
- }
- if (nonblock || copied) {
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
- if (copied) return(copied);
- return(-EAGAIN);
- }
+ if (nonblock /*|| copied*/)
+ {
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
+ if (copied)
+ return(copied);
+ return(-EAGAIN);
+ }
- release_sock(sk);
- cli();
- if (sk->state != TCP_ESTABLISHED &&
- sk->state != TCP_CLOSE_WAIT && sk->err == 0) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- sti();
- DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
- if (copied) return(copied);
- return(-ERESTARTSYS);
+ release_sock(sk);
+ cli();
+ if (sk->state != TCP_ESTABLISHED &&
+ sk->state != TCP_CLOSE_WAIT && sk->err == 0)
+ {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
+ if (copied)
+ return(copied);
+ return(-ERESTARTSYS);
+ }
}
+ sk->inuse = 1;
+ sti();
}
- sk->inuse = 1;
- sti();
- }
-
- /* Now we need to check if we have a half built packet. */
- if (sk->send_tmp != NULL) {
- /* If sk->mss has been changed this could cause problems. */
+ /*
+ * When we finally arrive at this point we can consider transmission
+ */
- /* Add more stuff to the end of skb->len */
- skb = sk->send_tmp;
- if (!(flags & MSG_OOB)) {
- copy = min(sk->mss - skb->len + 128 +
+ /*
+ * Now we need to check if we have a half built packet. If so append to
+ * it.
+ */
+
+ if (sk->send_tmp != NULL)
+ {
+ copy=0;
+ /* Add more stuff to the end of skb->len */
+ skb = sk->send_tmp;
+ if (!(flags & MSG_OOB))
+ {
+ copy = min(sk->mss - skb->len + 128 +
prot->max_header, len);
- /* FIXME: this is really a bug. */
- if (copy <= 0) {
- printk("TCP: **bug**: \"copy\" <= 0!!\n");
- copy = 0;
- }
-
- memcpy_fromfs((unsigned char *)(skb+1) + skb->len, from, copy);
- skb->len += copy;
- from += copy;
- copied += copy;
- len -= copy;
- sk->send_seq += copy;
- }
-
- if (skb->len -(unsigned long)skb->h.th +
- (unsigned long)(skb+1) >= sk->mss ||(flags & MSG_OOB)) {
- tcp_send_partial(sk);
- }
- continue;
- }
+ /* FIXME: this is really a bug. */
+ if (copy <= 0)
+ {
+ printk("TCP: **bug**: \"copy\" <= 0!!\n");
+ copy = 0;
+ }
+
+ /*
+ * Add data to the packet
+ */
+
+ memcpy_fromfs((unsigned char *)(skb+1) + skb->len, from, copy);
+ skb->len += copy;
+ from += copy;
+ copied += copy;
+ len -= copy;
+ sk->send_seq += copy;
+ }
- /*
- * We also need to worry about the window.
- * The smallest we will send is about 200 bytes.
- * This is a bit sad for TCP/AMPR people running
- * 196 byte windows! - FIXME
- */
- copy = min(sk->mtu, diff(sk->window_seq, sk->send_seq));
-
- /* FIXME: redundent check here. */
- if (copy < 200 || copy > sk->mtu) copy = sk->mtu;
- copy = min(copy, len);
-
- /* We should really check the window here also. */
- if (sk->packets_out && copy < sk->mss && !(flags & MSG_OOB)) {
- /* We will release the socket incase we sleep here. */
- release_sock(sk);
- skb = (struct sk_buff *) prot->wmalloc(sk,
- sk->mss + 128 + prot->max_header +
- sizeof(*skb), 0, GFP_KERNEL);
- sk->inuse = 1;
- sk->send_tmp = skb;
- if (skb != NULL)
- skb->mem_len = sk->mss + 128 + prot->max_header + sizeof(*skb);
- } else {
- /* We will release the socket incase we sleep here. */
- release_sock(sk);
- skb = (struct sk_buff *) prot->wmalloc(sk,
- copy + prot->max_header +
+ /*
+ * Do we need to send it yet or can it wait for more data ?
+ */
+
+ if (skb->len -(unsigned long)skb->h.th + (unsigned long)(skb+1) >= sk->mss ||(flags & MSG_OOB) || copy==0)
+ {
+ tcp_send_partial(sk);
+ }
+ continue;
+ }
+
+ /*
+ * We also need to worry about the window.
+ * The smallest we will send is about 200 bytes.
+ * This is a bit sad for TCP/AMPR people running
+ * 196 byte windows! - FIXME
+ */
+
+ copy = min(sk->mtu, diff(sk->window_seq, sk->send_seq));
+
+ /* FIXME: redundant check here. */
+ if (copy < 200 || copy > sk->mtu) copy = sk->mtu;
+ copy = min(copy, len);
+
+ /*
+ * We should really check the window here also.
+ * [Why ?, Alan]
+ */
+
+ if (sk->packets_out && copy < sk->mss && !(flags & MSG_OOB))
+ {
+ /* We will release the socket in case we sleep here. */
+ release_sock(sk);
+
+ /*
+ * Grab a packet to suit the mss.
+ */
+
+ skb = (struct sk_buff *) prot->wmalloc(sk,
+ sk->mss + 128 + prot->max_header +
sizeof(*skb), 0, GFP_KERNEL);
- sk->inuse = 1;
- if (skb != NULL)
- skb->mem_len = copy+prot->max_header + sizeof(*skb);
- }
-
- /* If we didn't get any memory, we need to sleep. */
- if (skb == NULL) {
- if (nonblock /* || copied */) {
+ sk->inuse = 1;
+ sk->send_tmp = skb;
+ if (skb != NULL)
+ skb->mem_len = sk->mss + 128 + prot->max_header + sizeof(*skb);
+ }
+ else
+ {
+ /* We will release the socket in case we sleep here. */
release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
- if (copied) return(copied);
- return(-EAGAIN);
+ skb = (struct sk_buff *) prot->wmalloc(sk,
+ copy + prot->max_header +
+ sizeof(*skb), 0, GFP_KERNEL);
+ sk->inuse = 1;
+ if (skb != NULL)
+ skb->mem_len = copy+prot->max_header + sizeof(*skb);
}
- /* FIXME: here is another race condition. */
- tmp = sk->wmem_alloc;
- release_sock(sk);
- cli();
- /* Again we will try to avoid it. */
- if (tmp <= sk->wmem_alloc &&
- (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
- && sk->err == 0) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- sti();
- DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
- if (copied) return(copied);
- return(-ERESTARTSYS);
+ /* If we didn't get any memory, we need to sleep. */
+ if (skb == NULL)
+ {
+ if (nonblock /* || copied */)
+ {
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
+ if (copied)
+ return(copied);
+ return(-EAGAIN);
}
- }
- sk->inuse = 1;
- sti();
- continue;
- }
- skb->mem_addr = skb;
- skb->len = 0;
- skb->sk = sk;
- skb->free = 0;
+ /* FIXME: here is another race condition. */
+ tmp = sk->wmem_alloc;
+ release_sock(sk);
+ cli();
+ /* Again we will try to avoid it. */
+ if (tmp <= sk->wmem_alloc && (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT) && sk->err == 0)
+ {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
+ if (copied)
+ return(copied);
+ return(-ERESTARTSYS);
+ }
+ }
+ sk->inuse = 1;
+ sti();
+ continue;
+ }
+
+ skb->mem_addr = skb;
+ skb->len = 0;
+ skb->sk = sk;
+ skb->free = 0;
- buff =(unsigned char *)(skb+1);
+ buff =(unsigned char *)(skb+1);
- /*
- * FIXME: we need to optimize this.
- * Perhaps some hints here would be good.
- */
- tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, skb->mem_len);
- if (tmp < 0 ) {
- prot->wfree(sk, skb->mem_addr, skb->mem_len);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
- if (copied) return(copied);
- return(tmp);
- }
- skb->len += tmp;
- skb->dev = dev;
- buff += tmp;
- skb->h.th =(struct tcphdr *) buff;
- tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
- if (tmp < 0) {
- prot->wfree(sk, skb->mem_addr, skb->mem_len);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
- if (copied) return(copied);
- return(tmp);
- }
+ /*
+ * FIXME: we need to optimize this.
+ * Perhaps some hints here would be good.
+ */
+
+ /*
+ * Begin putting the headers on the packet
+ */
+
+ tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt, skb->mem_len, sk->ip_ttl,sk->ip_tos);
+ if (tmp < 0 )
+ {
+ prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
+ if (copied)
+ return(copied);
+ return(tmp);
+ }
+
+ skb->len += tmp;
+ skb->dev = dev;
+ buff += tmp;
+ skb->h.th =(struct tcphdr *) buff;
+
+ /*
+ * Put the TCP header in
+ */
+
+ tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
+ if (tmp < 0)
+ {
+ prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
+ if (copied)
+ return(copied);
+ return(tmp);
+ }
- if (flags & MSG_OOB) {
- ((struct tcphdr *)buff)->urg = 1;
- ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
- }
- skb->len += tmp;
- memcpy_fromfs(buff+tmp, from, copy);
+ /*
+ * If this was OOB data it goes at the start of a packet
+ * with the urg flag and urg ptr set.
+ */
+
+ if (flags & MSG_OOB)
+ {
+ ((struct tcphdr *)buff)->urg = 1;
+ ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
+ }
+
+ /*
+ * Set the length
+ */
+
+ skb->len += tmp;
+
+ /*
+ * Insert user data
+ */
+
+ memcpy_fromfs(buff+tmp, from, copy);
- from += copy;
- copied += copy;
- len -= copy;
- skb->len += copy;
- skb->free = 0;
- sk->send_seq += copy;
+ from += copy;
+ copied += copy;
+ len -= copy;
+ skb->len += copy;
+ skb->free = 0;
+ sk->send_seq += copy;
- if (sk->send_tmp != NULL) continue;
+ if (sk->send_tmp != NULL)
+ continue;
+
+ /*
+ * Checksum
+ */
- tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr,
+ tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr,
copy + sizeof(struct tcphdr), sk);
- skb->h.seq = sk->send_seq;
- if (after(sk->send_seq , sk->window_seq) ||
- sk->packets_out >= sk->cong_window) {
- DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
- sk->cong_window, sk->packets_out));
- DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
- sk->send_seq, sk->window_seq));
- skb->next = NULL;
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (sk->wback == NULL) {
- sk->wfront = skb;
- } else {
- sk->wback->next = skb;
+ /*
+ * Set the sequence number
+ */
+
+ skb->h.seq = sk->send_seq;
+
+ /*
+ * Can we send (will it fit in the window and is our packet out count low
+ * enough.
+ */
+
+ if (after(sk->send_seq , sk->window_seq) || sk->packets_out >= sk->cong_window)
+ {
+
+ /*
+ * Nope - add it to the write queue
+ */
+
+ DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
+ sk->cong_window, sk->packets_out));
+ DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
+ sk->send_seq, sk->window_seq));
+ skb->next = NULL;
+ skb->magic = TCP_WRITE_QUEUE_MAGIC;
+ if (sk->wback == NULL)
+ {
+ sk->wfront = skb;
+ }
+ else
+ {
+ sk->wback->next = skb;
+ }
+ sk->wback = skb;
+ }
+ else
+ {
+ /*
+ * Kick it our to IP for transmission (and maybe retransmission)
+ */
+
+ prot->queue_xmit(sk, dev, skb,0);
}
- sk->wback = skb;
- } else {
- prot->queue_xmit(sk, dev, skb,0);
- }
- }
- sk->err = 0;
- /* Avoid possible race on send_tmp - c/o Johannes Stille */
- if(sk->send_tmp && !sk->packets_out)
- tcp_send_partial(sk);
- /* -- */
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
- return(copied);
+ }
+ sk->err = 0;
+
+ /* Avoid possible race on send_tmp - c/o Johannes Stille */
+ if(sk->send_tmp && sk->packets_out <sk->cong_window)
+ tcp_send_partial(sk);
+ /* -- */
+
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
+ return(copied);
}
-static int
-tcp_sendto(struct sock *sk, unsigned char *from,
+static int tcp_sendto(struct sock *sk, unsigned char *from,
int len, int nonblock, unsigned flags,
struct sockaddr_in *addr, int addr_len)
{
- struct sockaddr_in sin;
-
- if (addr_len < sizeof(sin)) return(-EINVAL);
- memcpy_fromfs(&sin, addr, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
- if (sin.sin_port != sk->dummy_th.dest) return(-EINVAL);
- if (sin.sin_addr.s_addr != sk->daddr) return(-EINVAL);
- return(tcp_write(sk, from, len, nonblock, flags));
+ struct sockaddr_in sin;
+
+ if (addr_len < sizeof(sin))
+ return(-EINVAL);
+
+ memcpy_fromfs(&sin, addr, sizeof(sin));
+
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EINVAL);
+ if (sin.sin_port != sk->dummy_th.dest)
+ return(-EINVAL);
+ if (sin.sin_addr.s_addr != sk->daddr)
+ return(-EINVAL);
+ return(tcp_write(sk, from, len, nonblock, flags));
}
static void
tcp_read_wakeup(struct sock *sk)
{
- int tmp;
- struct device *dev = NULL;
- struct tcphdr *t1;
- struct sk_buff *buff;
-
- DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
- if (!sk->ack_backlog) return;
+ int tmp;
+ struct device *dev = NULL;
+ struct tcphdr *t1;
+ struct sk_buff *buff;
+
+ DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
+ if (!sk->ack_backlog)
+ return;
+
+ /*
+ * FIXME: we need to put code here to prevent this routine from
+ * being called. Being called once in a while is ok, so only check
+ * if this is the second time in a row.
+ */
+
+ /*
+ * We need to grab some memory, and put together an ack,
+ * and then put it into the queue to be sent.
+ *
+ * The current code is rather keen to do this. It ought to first look
+ * for more optimal options like kicking out the pending partial packet.
+ */
+
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+ if (buff == NULL)
+ {
+ /* Try again real soon. */
+ reset_timer(sk, TIME_WRITE, 10);
+ return;
+ }
- /*
- * FIXME: we need to put code here to prevent this routine from
- * being called. Being called once in a while is ok, so only check
- * if this is the second time in a row.
- */
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_ACK_SIZE;
+ buff->len = sizeof(struct tcphdr);
+ buff->sk = sk;
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE, sk->ip_ttl,sk->ip_tos);
+ if (tmp < 0)
+ {
+ buff->free=1;
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ return;
+ }
+
+ buff->len += tmp;
+ t1 =(struct tcphdr *)((char *)(buff+1) +tmp);
- /*
- * We need to grab some memory, and put together an ack,
- * and then put it into the queue to be sent.
- */
- buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
- if (buff == NULL) {
- /* Try again real soon. */
- reset_timer(sk, TIME_WRITE, 10);
- return;
- }
-
- buff->mem_addr = buff;
- buff->mem_len = MAX_ACK_SIZE;
- buff->len = sizeof(struct tcphdr);
- buff->sk = sk;
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
- if (tmp < 0) {
- buff->free=1;
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
-
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)(buff+1) +tmp);
-
- memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
- t1->seq = ntohl(sk->send_seq);
- t1->ack = 1;
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->window = sk->prot->rspace(sk);
- t1->window = ntohs(sk->window);
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
- sk->prot->queue_xmit(sk, dev, buff, 1);
+ /*
+ * Fill in the header.
+ */
+
+ memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq);
+ t1->ack = 1;
+ t1->res1 = 0;
+ t1->res2 = 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->syn = 0;
+ t1->psh = 0;
+ sk->ack_backlog = 0;
+ sk->bytes_rcv = 0;
+ sk->window = 4096/*sk->prot->rspace(sk)*/;
+ t1->window = ntohs(sk->window);
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+ /*
+ * These go straight out and don't retransmit
+ */
+
+ sk->prot->queue_xmit(sk, dev, buff, 1);
}
/*
- * FIXME:
- * This routine frees used buffers.
- * It should consider sending an ACK to let the
- * other end know we now have a bigger window.
+ * FIXME:
+ * This routine frees used buffers.
+ * It should consider sending an ACK to let the
+ * other end know we now have a bigger window.
*/
-static void
-cleanup_rbuf(struct sock *sk)
+
+static void cleanup_rbuf(struct sock *sk)
{
- unsigned long flags;
- int left;
- struct sk_buff *skb;
+ unsigned long flags;
+ int left;
+ struct sk_buff *skb;
- if(sk->debug)
- printk("cleaning rbuf for sk=%p\n", sk);
+ if(sk->debug)
+ printk("cleaning rbuf for sk=%p\n", sk);
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
- left = sk->prot->rspace(sk);
+ left = sk->prot->rspace(sk);
- /*
- * We have to loop through all the buffer headers,
- * and try to free up all the space we can.
- */
- while((skb=skb_peek(&sk->rqueue)) != NULL )
- {
- if (!skb->used)
- break;
- skb_unlink(skb);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- }
+ /*
+ * We have to loop through all the buffer headers,
+ * and try to free up all the space we can.
+ */
- restore_flags(flags);
+ while((skb=skb_peek(&sk->rqueue)) != NULL )
+ {
+ if (!skb->used)
+ break;
+ skb_unlink(skb);
+ skb->sk = sk;
+ kfree_skb(skb, FREE_READ);
+ }
- /*
- * FIXME:
- * At this point we should send an ack if the difference
- * in the window, and the amount of space is bigger than
- * TCP_WINDOW_DIFF.
- */
- DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
+ restore_flags(flags);
+
+ /*
+ * FIXME:
+ * At this point we should send an ack if the difference
+ * in the window, and the amount of space is bigger than
+ * TCP_WINDOW_DIFF.
+ */
+ DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk)));
- if(sk->debug)
- printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),
- left);
- if (sk->prot->rspace(sk) != left)
- {
- /*
- * This area has caused the most trouble. The current strategy
- * is to simply do nothing if the other end has room to send at
- * least 3 full packets, because the ack from those will auto-
- * matically update the window. If the other end doesn't think
- * we have much space left, but we have room for atleast 1 more
- * complete packet than it thinks we do, we will send an ack
- * immediatedly. Otherwise we will wait up to .5 seconds in case
- * the user reads some more.
- */
- sk->ack_backlog++;
- if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) {
- /* Send an ack right now. */
- tcp_read_wakeup(sk);
- } else {
- /* Force it to send an ack soon. */
- int was_active = del_timer(&sk->timer);
- if (!was_active || TCP_ACK_TIME < sk->timer.expires) {
- reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- } else
- add_timer(&sk->timer);
- }
- }
+ if(sk->debug)
+ printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),left);
+ if (sk->prot->rspace(sk) != left)
+ {
+ /*
+ * This area has caused the most trouble. The current strategy
+ * is to simply do nothing if the other end has room to send at
+ * least 3 full packets, because the ack from those will auto-
+ * matically update the window. If the other end doesn't think
+ * we have much space left, but we have room for atleast 1 more
+ * complete packet than it thinks we do, we will send an ack
+ * immediatedly. Otherwise we will wait up to .5 seconds in case
+ * the user reads some more.
+ *
+ * Changes this to reflect real windows - Alan
+ */
+ sk->ack_backlog++;
+ if (4096-diff(sk->acked_seq,sk->copied_seq) - sk->bytes_rcv < 3*sk->mtu)
+ {
+ /* Send an ack right now. */
+ tcp_read_wakeup(sk);
+ }
+ else
+ {
+ /* Force it to send an ack soon. */
+ int was_active = del_timer(&sk->timer);
+ if (!was_active || TCP_ACK_TIME < sk->timer.expires)
+ {
+ reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
+ }
+ else
+ add_timer(&sk->timer);
+ }
+ }
}
-/* Handle reading urgent data. */
-static int
-tcp_read_urg(struct sock * sk, int nonblock,
+/*
+ * Handle reading urgent data.
+ */
+
+static int tcp_read_urg(struct sock * sk, int nonblock,
unsigned char *to, int len, unsigned flags)
{
- int copied = 0;
- struct sk_buff *skb;
+ int copied = 0;
+ struct sk_buff *skb;
+ int err;
- DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n",
+ DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n",
sk, to, len, flags));
- while(len > 0)
- {
- sk->inuse = 1;
- while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL) {
- if (sk->err) {
- int tmp;
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+
+ while(len > 0)
+ {
+ sk->inuse = 1;
+ while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL)
+ {
+ if (sk->err)
+ {
+ int tmp;
- release_sock(sk);
- if (copied) return(copied);
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
+ release_sock(sk);
+ if (copied)
+ return(copied);
+ tmp = -sk->err;
+ sk->err = 0;
+ return(tmp);
+ }
- if (sk->state == TCP_CLOSE || sk->done) {
- release_sock(sk);
- if (copied) return(copied);
- if (!sk->done) {
- sk->done = 1;
- return(0);
+ if (sk->state == TCP_CLOSE || sk->done)
+ {
+ release_sock(sk);
+ if (copied)
+ return(copied);
+ if (!sk->done)
+ {
+ sk->done = 1;
+ return(0);
+ }
+ return(-ENOTCONN);
}
- return(-ENOTCONN);
- }
- if (sk->shutdown & RCV_SHUTDOWN) {
- release_sock(sk);
- if (copied == 0)
- sk->done = 1;
- return(copied);
- }
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ release_sock(sk);
+ if (copied == 0)
+ sk->done = 1;
+ return(copied);
+ }
- if (nonblock || copied) {
- release_sock(sk);
- if (copied) return(copied);
- return(-EAGAIN);
- }
+ if (nonblock || copied)
+ {
+ release_sock(sk);
+ if (copied)
+ return(copied);
+ return(-EAGAIN);
+ }
- /* Now at this point, we may have gotten some data. */
- release_sock(sk);
- cli();
- if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) &&
- sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- sti();
- if (copied) return(copied);
- return(-ERESTARTSYS);
+ /* Now at this point, we may have gotten some data. */
+ release_sock(sk);
+ cli();
+ if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) &&
+ sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN))
+ {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ if (copied)
+ return(copied);
+ return(-ERESTARTSYS);
+ }
}
+ sk->inuse = 1;
+ sti();
}
- sk->inuse = 1;
- sti();
- }
- skb = skb_peek(&sk->rqueue);
- do {
- int amt;
+ skb = skb_peek(&sk->rqueue);
+ do
+ {
+ int amt;
- if (skb->h.th->urg && !skb->urg_used) {
- if (skb->h.th->urg_ptr == 0) {
- skb->h.th->urg_ptr = ntohs(skb->len);
- }
- amt = min(ntohs(skb->h.th->urg_ptr),len);
- if(amt)
+ if (skb->h.th->urg && !skb->urg_used)
{
- verify_area(VERIFY_WRITE, to, amt);
- memcpy_tofs(to,(unsigned char *)(skb->h.th) +
- skb->h.th->doff*4, amt);
- }
+ if (skb->h.th->urg_ptr == 0)
+ {
+ skb->h.th->urg_ptr = ntohs(skb->len);
+ }
+ amt = min(ntohs(skb->h.th->urg_ptr),len);
+ if(amt)
+ {
+ verify_area(VERIFY_WRITE, to, amt);
+ memcpy_tofs(to,(unsigned char *)(skb->h.th) +
+ skb->h.th->doff*4, amt);
+ }
- if (!(flags & MSG_PEEK)) {
- skb->urg_used = 1;
- sk->urg--;
+ if (!(flags & MSG_PEEK))
+ {
+ skb->urg_used = 1;
+ sk->urg--;
+ }
+ release_sock(sk);
+ copied += amt;
+ return(copied);
}
- release_sock(sk);
- copied += amt;
- return(copied);
- }
- skb =(struct sk_buff *)skb->next;
- } while(skb != sk->rqueue);
- }
- sk->urg = 0;
- release_sock(sk);
- return(0);
+ skb =(struct sk_buff *)skb->next;
+ }
+ while(skb != sk->rqueue);
+ }
+ sk->urg = 0;
+ release_sock(sk);
+ return(0);
}
-/* This routine copies from a sock struct into the user buffer. */
-static int
-tcp_read(struct sock *sk, unsigned char *to,
+/*
+ * This routine copies from a sock struct into the user buffer.
+ */
+
+static int tcp_read_data(int type,struct sock *sk, unsigned char *to,
int len, int nonblock, unsigned flags)
{
- int copied=0; /* will be used to say how much has been copied. */
- struct sk_buff *skb;
- unsigned long offset;
- unsigned long used;
- int err;
-
- if (len == 0) return(0);
- if (len < 0) {
- return(-EINVAL);
- }
+ /* Type is 0 for read, 1 for recv()/recvfrom() */
+
+ int copied=0; /* will be used to say how much has been copied. */
+ struct sk_buff *skb;
+ unsigned long offset;
+ unsigned long used;
+ int err;
+
+ if (len == 0)
+ return(0);
+ if (len < 0)
+ {
+ return(-EINVAL);
+ }
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
- /* This error should be checked. */
- if (sk->state == TCP_LISTEN) return(-ENOTCONN);
+ /* This error should be checked. */
+ if (sk->state == TCP_LISTEN)
+ return(-ENOTCONN);
- /* Urgent data needs to be handled specially. */
- if ((flags & MSG_OOB))
- return(tcp_read_urg(sk, nonblock, to, len, flags));
+ /* Urgent data needs to be handled specially. */
+ if ((flags & MSG_OOB))
+ return(tcp_read_urg(sk, nonblock, to, len, flags));
- /* So no-one else will use this socket. */
- sk->inuse = 1;
+ /* So no-one else will use this socket. */
+ sk->inuse = 1;
- skb=skb_peek(&sk->rqueue);
-
- DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
+ skb=skb_peek(&sk->rqueue);
+
+ DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, to, len, nonblock, flags));
- while(len > 0) {
- /* skb->used just checks to see if we've gone all the way around. */
+ while(len > 0)
+ {
+ /* skb->used just checks to see if we've gone all the way around. */
- /* While no data, or first data indicates some is missing, or data is used */
- while(skb == NULL ||
- before(sk->copied_seq+1, skb->h.th->seq) || skb->used) {
- DPRINTF((DBG_TCP, "skb = %X:\n", skb));
- cleanup_rbuf(sk);
- if (sk->err)
+ /* While no data, or first data indicates some is missing, or data is used */
+ while(skb == NULL || before(sk->copied_seq+1, skb->h.th->seq) || skb->used)
{
- int tmp;
+ DPRINTF((DBG_TCP, "skb = %X:\n", skb));
+
+ /*
+ * Clean up anything we can
+ */
+ cleanup_rbuf(sk);
+
+ /*
+ * If an error has come in off the net report it
+ */
+ if (sk->err)
+ {
+ int tmp;
+
+ release_sock(sk);
+ if (copied)
+ {
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ copied));
+ return(copied);
+ }
+ tmp = -sk->err;
+ sk->err = 0;
+ return(tmp);
+ }
- release_sock(sk);
- if (copied)
+ /*
+ * If we have become closed
+ */
+ if (sk->state == TCP_CLOSE)
{
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ release_sock(sk);
+ if (copied)
+ {
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
copied));
- return(copied);
+ return(copied);
+ }
+ if (!sk->done)
+ {
+ sk->done = 1;
+ return(0);
+ }
+ return(-ENOTCONN);
}
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
- if (sk->state == TCP_CLOSE)
- {
- release_sock(sk);
- if (copied) {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
+ /*
+ * If we have been shutdown
+ */
+
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ release_sock(sk);
+ if (copied == 0)
+ sk->done = 1;
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
return(copied);
}
- if (!sk->done) {
- sk->done = 1;
- return(0);
+
+ /*
+ * If we don't want to wait.
+ */
+
+ if (nonblock || copied) /* Altered AC 24/12/93 */
+ {
+ release_sock(sk);
+ if(sk->debug)
+ printk("read: EAGAIN\n");
+ if (copied)
+ {
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ copied));
+ return(copied);
+ }
+ return(-EAGAIN);
}
- return(-ENOTCONN);
- }
-
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- if (copied == 0) sk->done = 1;
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- return(copied);
- }
- if (nonblock || copied)
- {
- release_sock(sk);
- if(sk->debug)
- printk("read: EAGAIN\n");
- if (copied)
+ /*
+ * Peeking doesn't wait around
+ */
+
+ if ((flags & MSG_PEEK) && copied != 0)
{
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
return(copied);
}
- return(-EAGAIN);
- }
-
- if ((flags & MSG_PEEK) && copied != 0)
- {
+
+ DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
+ sk->state));
release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- return(copied);
- }
-
- DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
- sk->state));
- release_sock(sk);
+
+ /*
+ * Now we may have some data waiting or we could
+ * have changed state.
+ */
+ cli();
+
+ /*
+ * We just missed an event. Go round and
+ * reprocess it. This happens normally because
+ * release_sock will catch up on the backlog
+ * queue.
+ */
+
+ if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0)
+ {
+ sk->inuse = 1;
+ sti();
+ continue;
+ }
+
+ /*
+ * Anything present, if so make sure it fits at our current position
+ */
- /*
- * Now we may have some data waiting or we could
- * have changed state.
- */
- cli();
- if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) {
+ if (skb_peek(&sk->rqueue) == NULL || before(sk->copied_seq+1, sk->rqueue->h.th->seq))
+ {
+ if(sk->debug)
+ printk("Read wait sleep\n");
+ interruptible_sleep_on(sk->sleep);
+ if(sk->debug)
+ printk("Read wait wakes\n");
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ if (copied)
+ {
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ copied));
+ return(copied);
+ }
+ return(-ERESTARTSYS);
+ }
+ }
sk->inuse = 1;
sti();
- continue;
- }
+ DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
- if (skb_peek(&sk->rqueue) == NULL ||
- before(sk->copied_seq+1, sk->rqueue->h.th->seq)) {
- if(sk->debug)
- printk("Read wait sleep\n");
- interruptible_sleep_on(sk->sleep);
- if(sk->debug)
- printk("Read wait wakes\n");
- if (current->signal & ~current->blocked) {
- sti();
- if (copied) {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
+ /*
+ * Grab the first packet pointer
+ */
- skb=skb_peek(&sk->rqueue);
- /* That may have been null if we were beaten, if so we loop again */
- }
+ skb=skb_peek(&sk->rqueue);
+
+ /*
+ * That may have been null if we were beaten, if so we loop again
+ */
+ }
- /*
- * Copy anything from the current block that needs
- * to go into the user buffer.
- */
- offset = sk->copied_seq+1 - skb->h.th->seq;
-
- if (skb->h.th->syn) offset--;
- if (offset < skb->len) /* Some of the packet is useful */
- {
/*
- * If there is urgent data we must either
- * return or skip over it.
+ * Copy anything from the current block that needs
+ * to go into the user buffer.
*/
- if (skb->h.th->urg)
- {
- if (skb->urg_used)
+
+ offset = sk->copied_seq+1 - skb->h.th->seq;
+
+ if (skb->h.th->syn)
+ offset--;
+
+ if (offset < skb->len) /* Some of the packet is useful */
+ {
+ /*
+ * If there is urgent data we must either
+ * return or skip over it.
+ */
+ if (skb->h.th->urg)
{
- sk->copied_seq += ntohs(skb->h.th->urg_ptr);
- offset += ntohs(skb->h.th->urg_ptr);
- if (offset >= skb->len)
+ if (skb->urg_used)
{
- skb->used = 1;
- skb =(struct sk_buff *)skb->next;
- continue;
+ sk->copied_seq += ntohs(skb->h.th->urg_ptr);
+ offset += ntohs(skb->h.th->urg_ptr);
+ if (offset >= skb->len)
+ {
+ skb->used = 1;
+ skb =(struct sk_buff *)skb->next;
+ continue;
+ }
+ }
+ else
+ {
+ release_sock(sk);
+ if (copied)
+ return(copied);
+
+ /*
+ * This is technically wrong. What do we do if SIGURG is
+ * being ignored. EINTR as a return is certainly wrong.
+ */
+
+ send_sig(SIGURG, current, 0);
+ return(-EINTR);
}
- }
- else
- {
- release_sock(sk);
- if (copied)
- return(copied);
- send_sig(SIGURG, current, 0);
- return(-EINTR);
}
- }
- /* Ok so how much can we use ? */
- used = min(skb->len - offset, len);
- /* Copy it */
- memcpy_tofs(to,((unsigned char *)skb->h.th) +
- skb->h.th->doff*4 + offset, used);
- copied += used;
- len -= used;
- to += used;
+
+ /*
+ * Ok so how much can we use ?
+ */
+ used = min(skb->len - offset, len);
+ /*
+ * Copy it
+ */
+ memcpy_tofs(to,((unsigned char *)skb->h.th) +
+ skb->h.th->doff*4 + offset, used);
+ copied += used;
+ len -= used;
+ to += used;
- /* If we were reading the data is 'eaten' */
- if (!(flags & MSG_PEEK))
- sk->copied_seq += used;
+ /*
+ * If we were reading the data is 'eaten'
+ */
+
+ if (!(flags & MSG_PEEK))
+ sk->copied_seq += used;
- /*
- * Mark this data used if we are really reading it,
- * and if it doesn't contain any urgent data. And we
- * have used all the data.
- */
- if (!(flags & MSG_PEEK) &&
- (!skb->h.th->urg || skb->urg_used) &&
- (used + offset >= skb->len))
- skb->used = 1;
+ /*
+ * Mark this data used if we are really reading it,
+ * and if it doesn't contain any urgent data. And we
+ * have used all the data.
+ */
+
+ if (!(flags & MSG_PEEK) && (!skb->h.th->urg || skb->urg_used) && (used + offset >= skb->len))
+ skb->used = 1;
- /*
- * See if this is the end of a message or if the
- * remaining data is urgent.
- */
- if (/*skb->h.th->psh || */skb->h.th->urg)
- {
- break;
+ /*
+ * See if this is the end of a message or if the
+ * remaining data is urgent.
+ */
+
+ if ((skb->h.th->psh && type) || skb->h.th->urg)
+ {
+ break;
+ }
+ }
+ else
+ { /*
+ * already used this data, must be a retransmit
+ */
+ skb->used = 1;
}
- }
- else
- { /* already used this data, must be a retransmit */
- skb->used = 1;
- }
- /* Move along a packet */
- skb =(struct sk_buff *)skb->next;
- }
- /* Clean up data we have read: This will do ACK frames */
- cleanup_rbuf(sk);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- if (copied == 0 && nonblock)
- return(-EAGAIN);
- return(copied);
+
+ /*
+ * Move along a packet. We might reach the end if so we will wait
+ * for more.
+ */
+
+ skb =(struct sk_buff *)skb->next;
+ }
+
+
+ /*
+ * Clean up data we have read: This will do ACK frames
+ */
+
+ cleanup_rbuf(sk);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+ if (copied == 0 && nonblock)
+ return(-EAGAIN);
+ return(copied);
}
+/*
+ * The read() user function. Read data, block and don't care
+ * about PSH and no partial reads
+ */
+
+static int tcp_read(struct sock *sk, unsigned char *to,
+ int len, int nonblock, unsigned flags)
+{
+ return(tcp_read_data(1,sk,to,len,nonblock,flags));
+}
+
/*
- * Send a FIN without closing the connection.
- * Not called at interrupt time.
+ * Send a FIN without closing the connection.
+ * Not called at interrupt time.
*/
-void
-tcp_shutdown(struct sock *sk, int how)
+
+void tcp_shutdown(struct sock *sk, int how)
{
- struct sk_buff *buff;
- struct tcphdr *t1, *th;
- struct proto *prot;
- int tmp;
- struct device *dev = NULL;
+ struct sk_buff *buff;
+ struct tcphdr *t1, *th;
+ struct proto *prot;
+ int tmp;
+ struct device *dev = NULL;
/*
* We need to grab some memory, and put together a FIN,
@@ -1460,179 +1786,204 @@ tcp_shutdown(struct sock *sk, int how)
* Most of this is guesswork, so maybe it will work...
*/
/* If we've already sent a FIN, return. */
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) return;
- if (!(how & SEND_SHUTDOWN)) return;
- sk->inuse = 1;
-
- /* Clear out any half completed packets. */
- if (sk->send_tmp) tcp_send_partial(sk);
-
- prot =(struct proto *)sk->prot;
- th =(struct tcphdr *)&sk->dummy_th;
- release_sock(sk); /* incase the malloc sleeps. */
- buff = (struct sk_buff *) prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
- if (buff == NULL) return;
- sk->inuse = 1;
-
- DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
- buff->mem_addr = buff;
- buff->mem_len = MAX_RESET_SIZE;
- buff->sk = sk;
- buff->len = sizeof(*t1);
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr));
- if (tmp < 0) {
- buff->free=1;
- prot->wfree(sk,buff->mem_addr, buff->mem_len);
- release_sock(sk);
- DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
- return;
- }
-
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff ->len += tmp;
- buff->dev = dev;
- memcpy(t1, th, sizeof(*t1));
- t1->seq = ntohl(sk->send_seq);
- sk->send_seq++;
- buff->h.seq = sk->send_seq;
- t1->ack = 1;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->prot->rspace(sk));
- t1->fin = 1;
- t1->rst = 0;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2)
+ return;
+ if (!(how & SEND_SHUTDOWN))
+ return;
+ sk->inuse = 1;
- /*
- * Can't just queue this up.
- * It should go at the end of the write queue.
- */
- if (sk->wback != NULL) {
- buff->free=0;
- buff->next = NULL;
- sk->wback->next = buff;
- sk->wback = buff;
- buff->magic = TCP_WRITE_QUEUE_MAGIC;
- } else {
- sk->prot->queue_xmit(sk, dev, buff, 0);
- }
-
- if (sk->state == TCP_ESTABLISHED) sk->state = TCP_FIN_WAIT1;
- else sk->state = TCP_FIN_WAIT2;
-
- release_sock(sk);
+ /* Clear out any half completed packets. */
+ if (sk->send_tmp)
+ tcp_send_partial(sk);
+
+ prot =(struct proto *)sk->prot;
+ th =(struct tcphdr *)&sk->dummy_th;
+ release_sock(sk); /* incase the malloc sleeps. */
+ buff = (struct sk_buff *) prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
+
+ if (buff == NULL)
+ return;
+
+ sk->inuse = 1;
+
+ DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_RESET_SIZE;
+ buff->sk = sk;
+ buff->len = sizeof(*t1);
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt,
+ sizeof(struct tcphdr),
+ sk->ip_ttl,sk->ip_tos
+ );
+ if (tmp < 0)
+ {
+ buff->free=1;
+ prot->wfree(sk,buff->mem_addr, buff->mem_len);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
+ return;
+ }
+
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+ buff ->len += tmp;
+ buff->dev = dev;
+ memcpy(t1, th, sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq);
+ sk->send_seq++;
+ buff->h.seq = sk->send_seq;
+ t1->ack = 1;
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->window = ntohs(sk->prot->rspace(sk));
+ t1->fin = 1;
+ t1->rst = 0;
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+ /*
+ * Can't just queue this up.
+ * It should go at the end of the write queue.
+ */
+
+ if (sk->wback != NULL)
+ {
+ buff->free=0;
+ buff->next = NULL;
+ sk->wback->next = buff;
+ sk->wback = buff;
+ buff->magic = TCP_WRITE_QUEUE_MAGIC;
+ }
+ else
+ {
+ sk->prot->queue_xmit(sk, dev, buff, 0);
+ }
+
+ if (sk->state == TCP_ESTABLISHED)
+ sk->state = TCP_FIN_WAIT1;
+ else
+ sk->state = TCP_FIN_WAIT2;
+
+ release_sock(sk);
}
-static int
-tcp_recvfrom(struct sock *sk, unsigned char *to,
+static int tcp_recvfrom(struct sock *sk, unsigned char *to,
int to_len, int nonblock, unsigned flags,
struct sockaddr_in *addr, int *addr_len)
{
- struct sockaddr_in sin;
- int len;
- int err;
- int result;
+ struct sockaddr_in sin;
+ int len;
+ int err;
+ int result;
- /* Have to check these first unlike the old code. If
- we check them after we lose data on an error
- which is wrong */
- err = verify_area(VERIFY_WRITE,addr_len,sizeof(long));
- if(err)
- return err;
- len = get_fs_long(addr_len);
- if(len > sizeof(sin))
- len = sizeof(sin);
- err=verify_area(VERIFY_WRITE, addr, len);
- if(err)
- return err;
-
- result=tcp_read(sk, to, to_len, nonblock, flags);
-
- if (result < 0) return(result);
+ /*
+ * Have to check these first unlike the old code. If
+ * we check them after we lose data on an error
+ * which is wrong
+ */
+
+ err = verify_area(VERIFY_WRITE,addr_len,sizeof(long));
+ if(err)
+ return err;
+ len = get_fs_long(addr_len);
+ if(len > sizeof(sin))
+ len = sizeof(sin);
+ err=verify_area(VERIFY_WRITE, addr, len);
+ if(err)
+ return err;
+
+ result=tcp_read_data(1,sk, to, to_len, nonblock, flags);
+
+ if (result < 0)
+ return(result);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->dummy_th.dest;
- sin.sin_addr.s_addr = sk->daddr;
+ sin.sin_family = AF_INET;
+ sin.sin_port = sk->dummy_th.dest;
+ sin.sin_addr.s_addr = sk->daddr;
- memcpy_tofs(addr, &sin, len);
- put_fs_long(len, addr_len);
- return(result);
+ memcpy_tofs(addr, &sin, len);
+ put_fs_long(len, addr_len);
+ return(result);
}
-/* This routine will send an RST to the other tcp. */
-static void
-tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
+/*
+ * This routine will send an RST to the other tcp.
+ */
+
+static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
struct proto *prot, struct options *opt, struct device *dev)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- int tmp;
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ int tmp;
/*
* We need to grab some memory, and put together an RST,
* and then put it into the queue to be sent.
*/
- buff = (struct sk_buff *) prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- return;
-
- DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
- buff->mem_addr = buff;
- buff->mem_len = MAX_RESET_SIZE;
- buff->len = sizeof(*t1);
- buff->sk = NULL;
- buff->dev = dev;
-
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
- sizeof(struct tcphdr));
- if (tmp < 0) {
- buff->free = 1;
- prot->wfree(NULL, buff->mem_addr, buff->mem_len);
- return;
- }
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff->len += tmp;
- memcpy(t1, th, sizeof(*t1));
-
- /* Swap the send and the receive. */
- t1->dest = th->source;
- t1->source = th->dest;
- t1->rst = 1;
- t1->window = 0;
+ buff = (struct sk_buff *) prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL)
+ return;
+
+ DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_RESET_SIZE;
+ buff->len = sizeof(*t1);
+ buff->sk = NULL;
+ buff->dev = dev;
+
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
+ sizeof(struct tcphdr),255, IPTOS_RELIABILITY);
+ if (tmp < 0)
+ {
+ buff->free = 1;
+ prot->wfree(NULL, buff->mem_addr, buff->mem_len);
+ return;
+ }
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+ buff->len += tmp;
+ memcpy(t1, th, sizeof(*t1));
+
+ /* Swap the send and the receive. */
+ t1->dest = th->source;
+ t1->source = th->dest;
+ t1->rst = 1;
+ t1->window = 0;
- if(th->ack)
- {
- t1->ack=0;
- t1->seq=th->ack_seq;
- t1->ack_seq=0;
- }
- else
- {
- t1->ack=1;
- if(!th->syn)
- t1->ack_seq=htonl(th->seq);
+ /*
+ * Fill in the ack field etc
+ */
+
+ if(th->ack)
+ {
+ t1->ack=0;
+ t1->seq=th->ack_seq;
+ t1->ack_seq=0;
+ }
else
- t1->ack_seq=htonl(th->seq+1);
- t1->seq=0;
- }
-
- t1->syn = 0;
- t1->urg = 0;
- t1->fin = 0;
- t1->psh = 0;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
- prot->queue_xmit(NULL, dev, buff, 1);
+ {
+ t1->ack=1;
+ if(!th->syn)
+ t1->ack_seq=htonl(th->seq);
+ else
+ t1->ack_seq=htonl(th->seq+1);
+ t1->seq=0;
+ }
+
+ t1->syn = 0;
+ t1->urg = 0;
+ t1->fin = 0;
+ t1->psh = 0;
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
+ prot->queue_xmit(NULL, dev, buff, 1);
}
@@ -1640,96 +1991,102 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
* Look for tcp options. Parses everything but only knows about MSS
*/
-static void
-tcp_options(struct sock *sk, struct tcphdr *th)
+static void tcp_options(struct sock *sk, struct tcphdr *th)
{
- unsigned char *ptr;
- int length=(th->doff*4)-sizeof(struct tcphdr);
- int mtuset=0;
+ unsigned char *ptr;
+ int length=(th->doff*4)-sizeof(struct tcphdr);
+ int mtuset=0;
- ptr = (unsigned char *)(th + 1);
+ ptr = (unsigned char *)(th + 1);
- while(length>0)
- {
- int opcode=*ptr++;
- int opsize=*ptr++;
- switch(opcode)
- {
- case TCPOPT_EOL:
- return;
- case TCPOPT_NOP:
- length-=2;
- continue;
-
- default:
- if(opsize<=2) /* Avoid silly options looping forever */
+ while(length>0)
+ {
+ int opcode=*ptr++;
+ int opsize=*ptr++;
+ switch(opcode)
+ {
+ case TCPOPT_EOL:
return;
- switch(opcode)
- {
- case TCPOPT_MSS:
- if(opsize==4)
- {
- sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
- mtuset=1;
- }
- break;
- /* Add other options here as people feel the urge to implement stuff like large windows */
- }
- ptr+=opsize-2;
- length-=opsize;
+ case TCPOPT_NOP:
+ length-=2;
+ continue;
+
+ default:
+ if(opsize<=2) /* Avoid silly options looping forever */
+ return;
+ switch(opcode)
+ {
+ case TCPOPT_MSS:
+ if(opsize==4)
+ {
+ sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
+ mtuset=1;
+ }
+ break;
+ /*
+ * Add other options here as people feel the urge to implement stuff like large windows
+ */
+ }
+ ptr+=opsize-2;
+ length-=opsize;
+ }
}
- }
- if (!mtuset)
- {
- sk->mtu = min(sk->mtu, 576 - HEADER_SIZE);
- return;
- }
+ if (!mtuset)
+ {
+ sk->mtu = min(sk->mtu, 576 - HEADER_SIZE);
+ return;
+ }
}
/*
- * This routine handles a connection request.
- * It should make sure we haven't already responded.
- * Because of the way BSD works, we have to send a syn/ack now.
- * This also means it will be harder to close a socket which is
- * listening.
+ * This routine handles a connection request.
+ * It should make sure we haven't already responded.
+ * Because of the way BSD works, we have to send a syn/ack now.
+ * This also means it will be harder to close a socket which is
+ * listening.
*/
-static void
-tcp_conn_request(struct sock *sk, struct sk_buff *skb,
+
+static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
unsigned long daddr, unsigned long saddr,
struct options *opt, struct device *dev)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- unsigned char *ptr;
- struct sock *newsk;
- struct tcphdr *th;
- int tmp;
-
- DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n"
- " opt = %X, dev = %X)\n",
- sk, skb, daddr, saddr, opt, dev));
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ unsigned char *ptr;
+ struct sock *newsk;
+ struct tcphdr *th;
+ int tmp;
+
+ DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n"
+ " opt = %X, dev = %X)\n",
+ sk, skb, daddr, saddr, opt, dev));
- th = skb->h.th;
-
- /* If the socket is dead, don't accept the connection. */
- if (!sk->dead) {
- wake_up(sk->sleep);
- } else {
- DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
- kfree_skb(skb, FREE_READ);
- return;
- }
+ th = skb->h.th;
+
+ /* If the socket is dead, don't accept the connection. */
+ if (!sk->dead)
+ {
+ sk->data_ready(sk,0);
+ }
+ else
+ {
+ DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));
+ tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
/*
* Make sure we can accept more. This will prevent a
* flurry of syns from eating up all our memory.
*/
- if (sk->ack_backlog >= sk->max_ack_backlog) {
- kfree_skb(skb, FREE_READ);
- return;
- }
+
+ if (sk->ack_backlog >= sk->max_ack_backlog)
+ {
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
/*
* We need to build a new sock struct.
@@ -1738,343 +2095,360 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
* and if the listening socket is destroyed before this is taken
* off of the queue, this will take care of it.
*/
- newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
- if (newsk == NULL) {
- /* just ignore the syn. It will get retransmitted. */
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- DPRINTF((DBG_TCP, "newsk = %X\n", newsk));
- memcpy((void *)newsk,(void *)sk, sizeof(*newsk));
- newsk->wback = NULL;
- newsk->wfront = NULL;
- newsk->rqueue = NULL;
- newsk->send_head = NULL;
- newsk->send_tail = NULL;
- newsk->back_log = NULL;
- newsk->rtt = TCP_CONNECT_TIME;
- newsk->mdev = 0;
- newsk->backoff = 0;
- newsk->blog = 0;
- newsk->intr = 0;
- newsk->proc = 0;
- newsk->done = 0;
- newsk->send_tmp = NULL;
- newsk->pair = NULL;
- newsk->wmem_alloc = 0;
- newsk->rmem_alloc = 0;
-
- newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
-
- newsk->err = 0;
- newsk->shutdown = 0;
- newsk->ack_backlog = 0;
- newsk->acked_seq = skb->h.th->seq+1;
- newsk->fin_seq = skb->h.th->seq;
- newsk->copied_seq = skb->h.th->seq;
- newsk->state = TCP_SYN_RECV;
- newsk->timeout = 0;
- newsk->send_seq = jiffies * SEQ_TICK - seq_offset;
- newsk->rcv_ack_seq = newsk->send_seq;
- newsk->urg =0;
- newsk->retransmits = 0;
- newsk->destroy = 0;
- newsk->timer.data = (unsigned long)newsk;
- newsk->timer.function = &net_timer;
- newsk->dummy_th.source = skb->h.th->dest;
- newsk->dummy_th.dest = skb->h.th->source;
-
- /* Swap these two, they are from our point of view. */
- newsk->daddr = saddr;
- newsk->saddr = daddr;
-
- put_sock(newsk->num,newsk);
- newsk->dummy_th.res1 = 0;
- newsk->dummy_th.doff = 6;
- newsk->dummy_th.fin = 0;
- newsk->dummy_th.syn = 0;
- newsk->dummy_th.rst = 0;
- newsk->dummy_th.psh = 0;
- newsk->dummy_th.ack = 0;
- newsk->dummy_th.urg = 0;
- newsk->dummy_th.res2 = 0;
- newsk->acked_seq = skb->h.th->seq + 1;
- newsk->copied_seq = skb->h.th->seq;
-
-#ifdef OLDWAY
- if (skb->h.th->doff == 5) {
- newsk->mtu = dev->mtu - HEADER_SIZE;
- } else {
- ptr =(unsigned char *)(skb->h.th + 1);
- if (ptr[0] != 2 || ptr[1] != 4) {
- newsk->mtu = dev->mtu - HEADER_SIZE;
- } else {
- newsk->mtu = min(ptr[2] * 256 + ptr[3] - HEADER_SIZE,
- dev->mtu - HEADER_SIZE);
- }
- }
-#else
- tcp_options(newsk,skb->h.th);
-#endif
- buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL) {
- sk->err = -ENOMEM;
- newsk->dead = 1;
- release_sock(newsk);
- kfree_skb(skb, FREE_READ);
- return;
- }
+ newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
+ if (newsk == NULL)
+ {
+ /* just ignore the syn. It will get retransmitted. */
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ DPRINTF((DBG_TCP, "newsk = %X\n", newsk));
+ memcpy((void *)newsk,(void *)sk, sizeof(*newsk));
+ newsk->wback = NULL;
+ newsk->wfront = NULL;
+ newsk->rqueue = NULL;
+ newsk->send_head = NULL;
+ newsk->send_tail = NULL;
+ newsk->back_log = NULL;
+ newsk->rtt = TCP_CONNECT_TIME;
+ newsk->mdev = 0;
+ newsk->backoff = 0;
+ newsk->blog = 0;
+ newsk->intr = 0;
+ newsk->proc = 0;
+ newsk->done = 0;
+ newsk->send_tmp = NULL;
+ newsk->pair = NULL;
+ newsk->wmem_alloc = 0;
+ newsk->rmem_alloc = 0;
+
+ newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
+
+ newsk->err = 0;
+ newsk->shutdown = 0;
+ newsk->ack_backlog = 0;
+ newsk->acked_seq = skb->h.th->seq+1;
+ newsk->fin_seq = skb->h.th->seq;
+ newsk->copied_seq = skb->h.th->seq;
+ newsk->state = TCP_SYN_RECV;
+ newsk->timeout = 0;
+ newsk->send_seq = jiffies * SEQ_TICK - seq_offset;
+ newsk->rcv_ack_seq = newsk->send_seq;
+ newsk->urg =0;
+ newsk->retransmits = 0;
+ newsk->destroy = 0;
+ newsk->timer.data = (unsigned long)newsk;
+ newsk->timer.function = &net_timer;
+ newsk->dummy_th.source = skb->h.th->dest;
+ newsk->dummy_th.dest = skb->h.th->source;
+
+ /* Swap these two, they are from our point of view. */
+ newsk->daddr = saddr;
+ newsk->saddr = daddr;
+
+ put_sock(newsk->num,newsk);
+ newsk->dummy_th.res1 = 0;
+ newsk->dummy_th.doff = 6;
+ newsk->dummy_th.fin = 0;
+ newsk->dummy_th.syn = 0;
+ newsk->dummy_th.rst = 0;
+ newsk->dummy_th.psh = 0;
+ newsk->dummy_th.ack = 0;
+ newsk->dummy_th.urg = 0;
+ newsk->dummy_th.res2 = 0;
+ newsk->acked_seq = skb->h.th->seq + 1;
+ newsk->copied_seq = skb->h.th->seq;
+
+ /* Grab the callers ttl and tos values and use them */
+ newsk->ip_ttl=skb->ip_hdr->ttl;
+ newsk->ip_tos=skb->ip_hdr->tos;
+
+ tcp_options(newsk,skb->h.th);
+
+ buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL)
+ {
+ sk->err = -ENOMEM;
+ newsk->dead = 1;
+ release_sock(newsk);
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
- buff->mem_addr = buff;
- buff->mem_len = MAX_SYN_SIZE;
- buff->len = sizeof(struct tcphdr)+4;
- buff->sk = newsk;
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_SYN_SIZE;
+ buff->len = sizeof(struct tcphdr)+4;
+ buff->sk = newsk;
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE);
-
- /* Something went wrong. */
- if (tmp < 0) {
- sk->err = tmp;
- buff->free=1;
- kfree_skb(buff,FREE_WRITE);
- newsk->dead = 1;
- release_sock(newsk);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)t1 +tmp);
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,
+ IPPROTO_TCP, NULL, MAX_SYN_SIZE,newsk->ip_ttl,newsk->ip_tos);
+
+ /* Something went wrong. */
+ if (tmp < 0)
+ {
+ sk->err = tmp;
+ buff->free=1;
+ kfree_skb(buff,FREE_WRITE);
+ newsk->dead = 1;
+ release_sock(newsk);
+ skb->sk = sk;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /*
+ * Assemble a syn|ack frame in reply
+ */
+
+ buff->len += tmp;
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
- memcpy(t1, skb->h.th, sizeof(*t1));
- buff->h.seq = newsk->send_seq;
-
- /* Swap the send and the receive. */
- t1->dest = skb->h.th->source;
- t1->source = newsk->dummy_th.source;
- t1->seq = ntohl(newsk->send_seq++);
- t1->ack = 1;
- newsk->window = newsk->prot->rspace(newsk);
- t1->window = ntohs(newsk->window);
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->syn = 1;
- t1->ack_seq = ntohl(skb->h.th->seq+1);
- t1->doff = sizeof(*t1)/4+1;
-
- ptr =(unsigned char *)(t1+1);
- ptr[0] = 2;
- ptr[1] = 4;
- ptr[2] =((dev->mtu - HEADER_SIZE) >> 8) & 0xff;
- ptr[3] =(dev->mtu - HEADER_SIZE) & 0xff;
-
- tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
- newsk->prot->queue_xmit(newsk, dev, buff, 0);
-
- reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME);
- skb->sk = newsk;
-
- /* Charge the sock_buff to newsk. */
- sk->rmem_alloc -= skb->mem_len;
- newsk->rmem_alloc += skb->mem_len;
-
- skb_queue_tail(&sk->rqueue,skb);
- sk->ack_backlog++;
- release_sock(newsk);
+ memcpy(t1, skb->h.th, sizeof(*t1));
+ buff->h.seq = newsk->send_seq;
+
+ /* Swap the send and the receive. */
+ t1->dest = skb->h.th->source;
+ t1->source = newsk->dummy_th.source;
+ t1->seq = ntohl(newsk->send_seq++);
+ t1->ack = 1;
+ newsk->window = 4096/*newsk->prot->rspace(newsk)*/;
+ t1->window = ntohs(newsk->window);
+ t1->res1 = 0;
+ t1->res2 = 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->psh = 0;
+ t1->syn = 1;
+ t1->ack_seq = ntohl(skb->h.th->seq+1);
+ t1->doff = sizeof(*t1)/4+1;
+
+ ptr =(unsigned char *)(t1+1);
+ ptr[0] = 2;
+ ptr[1] = 4;
+ ptr[2] =((dev->mtu - HEADER_SIZE) >> 8) & 0xff;
+ ptr[3] =(dev->mtu - HEADER_SIZE) & 0xff;
+
+ tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
+ newsk->prot->queue_xmit(newsk, dev, buff, 0);
+
+ reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME);
+ skb->sk = newsk;
+
+ /* Charge the sock_buff to newsk. */
+ sk->rmem_alloc -= skb->mem_len;
+ newsk->rmem_alloc += skb->mem_len;
+
+ skb_queue_tail(&sk->rqueue,skb);
+ sk->ack_backlog++;
+ release_sock(newsk);
}
+/*
+ * Close a tcp connection
+ */
-static void
-tcp_close(struct sock *sk, int timeout)
+static void tcp_close(struct sock *sk, int timeout)
{
- struct sk_buff *buff;
- int need_reset = 0;
- struct tcphdr *t1, *th;
- struct proto *prot;
- struct device *dev=NULL;
- int tmp;
+ struct sk_buff *buff;
+ int need_reset = 0;
+ struct tcphdr *t1, *th;
+ struct proto *prot;
+ struct device *dev=NULL;
+ int tmp;
/*
* We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent.
*/
- DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
- sk->inuse = 1;
- sk->keepopen = 1;
- sk->shutdown = SHUTDOWN_MASK;
-
- if (!sk->dead) wake_up(sk->sleep);
-
- /* We need to flush the recv. buffs. */
- if (skb_peek(&sk->rqueue) != NULL)
- {
- struct sk_buff *skb;
-#ifdef OLD
- struct sk_buff *skb2;
- skb = skb_peek(&sk->rqueue);
- do {
- skb2 =(struct sk_buff *)skb->next;
- /* if there is some real unread data, send a reset. */
- if (skb->len > 0 &&
- after(skb->h.th->seq + skb->len + 1, sk->copied_seq))
- need_reset = 1;
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- } while(skb != sk->rqueue);
-#else
- if(sk->debug)
- printk("Clean rcv queue\n");
- while((skb=skb_dequeue(&sk->rqueue))!=NULL)
- {
- if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
- need_reset = 1;
- kfree_skb(skb, FREE_READ);
- }
- if(sk->debug)
- printk("Cleaned.\n");
-#endif
- }
- sk->rqueue = NULL;
-
- /* Get rid off any half-completed packets. */
- if (sk->send_tmp) {
- tcp_send_partial(sk);
- }
-
- switch(sk->state) {
- case TCP_FIN_WAIT1:
- case TCP_FIN_WAIT2:
- case TCP_LAST_ACK:
- /* start a timer. */
- reset_timer(sk, TIME_CLOSE, 4 * sk->rtt);
- if (timeout) tcp_time_wait(sk);
- release_sock(sk);
- return; /* break causes a double release - messy */
- case TCP_TIME_WAIT:
- if (timeout) {
- sk->state = TCP_CLOSE;
+ DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
+ sk->inuse = 1;
+ sk->keepopen = 1;
+ sk->shutdown = SHUTDOWN_MASK;
+
+
+ /* We need to flush the recv. buffs. */
+ if (skb_peek(&sk->rqueue) != NULL)
+ {
+ struct sk_buff *skb;
+ if(sk->debug)
+ printk("Clean rcv queue\n");
+ while((skb=skb_dequeue(&sk->rqueue))!=NULL)
+ {
+ if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
+ need_reset = 1;
+ kfree_skb(skb, FREE_READ);
}
- release_sock(sk);
- return;
- case TCP_LISTEN:
- sk->state = TCP_CLOSE;
- release_sock(sk);
- return;
- case TCP_CLOSE:
- release_sock(sk);
- return;
- case TCP_CLOSE_WAIT:
- case TCP_ESTABLISHED:
- case TCP_SYN_SENT:
- case TCP_SYN_RECV:
- prot =(struct proto *)sk->prot;
- th =(struct tcphdr *)&sk->dummy_th;
- buff = (struct sk_buff *) prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL) {
- /* This will force it to try again later. */
- /* Or it would have if someone released the socket
- first. Anyway it might work now */
+ if(sk->debug)
+ printk("Cleaned.\n");
+ }
+ sk->rqueue = NULL;
+
+ /* Get rid off any half-completed packets. */
+ if (sk->send_tmp)
+ {
+ tcp_send_partial(sk);
+ }
+
+ switch(sk->state)
+ {
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_LAST_ACK:
+ /* start a timer. */
+ reset_timer(sk, TIME_CLOSE, 4 * sk->rtt);
+ if (timeout)
+ tcp_time_wait(sk);
release_sock(sk);
- if (sk->state != TCP_CLOSE_WAIT)
- sk->state = TCP_ESTABLISHED;
- reset_timer(sk, TIME_CLOSE, 100);
+ if (!sk->dead)
+ sk->state_change(sk);
+ return; /* break causes a double release - messy */
+ case TCP_TIME_WAIT:
+ if (timeout)
+ {
+ sk->state = TCP_CLOSE;
+ }
+ release_sock(sk);
+ if (!sk->dead)
+ sk->state_change(sk);
return;
- }
- buff->mem_addr = buff;
- buff->mem_len = MAX_FIN_SIZE;
- buff->sk = sk;
- buff->free = 1;
- buff->len = sizeof(*t1);
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr));
- if (tmp < 0) {
- kfree_skb(buff,FREE_WRITE);
- DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
+ case TCP_LISTEN:
+ sk->state = TCP_CLOSE;
release_sock(sk);
+ if (!sk->dead)
+ sk->state_change(sk);
return;
- }
-
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff ->len += tmp;
- buff->dev = dev;
- memcpy(t1, th, sizeof(*t1));
- t1->seq = ntohl(sk->send_seq);
- sk->send_seq++;
- buff->h.seq = sk->send_seq;
- t1->ack = 1;
-
- /* Ack everything immediately from now on. */
- sk->delay_acks = 0;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->prot->rspace(sk));
- t1->fin = 1;
- t1->rst = need_reset;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- if (sk->wfront == NULL) {
- prot->queue_xmit(sk, dev, buff, 0);
- } else {
- reset_timer(sk, TIME_WRITE,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
- buff->next = NULL;
- if (sk->wback == NULL) {
- sk->wfront=buff;
- } else {
- sk->wback->next = buff;
- }
- sk->wback = buff;
- buff->magic = TCP_WRITE_QUEUE_MAGIC;
- }
+ case TCP_CLOSE:
+ release_sock(sk);
+ if (!sk->dead)
+ sk->state_change(sk);
+ return;
+ case TCP_CLOSE_WAIT:
+ case TCP_ESTABLISHED:
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV:
+ prot =(struct proto *)sk->prot;
+ th =(struct tcphdr *)&sk->dummy_th;
+ buff = (struct sk_buff *) prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL)
+ {
+ /* This will force it to try again later. */
+ /* Or it would have if someone released the socket
+ first. Anyway it might work now */
+ release_sock(sk);
+ if (sk->state != TCP_CLOSE_WAIT)
+ sk->state = TCP_ESTABLISHED;
+ reset_timer(sk, TIME_CLOSE, 100);
+ return;
+ }
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_FIN_SIZE;
+ buff->sk = sk;
+ buff->free = 1;
+ buff->len = sizeof(*t1);
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt,
+ sizeof(struct tcphdr),sk->ip_ttl,sk->ip_tos);
+
+ if (tmp < 0)
+ {
+ kfree_skb(buff,FREE_WRITE);
+ DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
+ release_sock(sk);
+ if (!sk->dead)
+ sk->state_change(sk);
+ return;
+ }
+
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+ buff ->len += tmp;
+ buff->dev = dev;
+ memcpy(t1, th, sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq);
+ sk->send_seq++;
+ buff->h.seq = sk->send_seq;
+ t1->ack = 1;
+
+ /* Ack everything immediately from now on. */
+ sk->delay_acks = 0;
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->window = ntohs(sk->prot->rspace(sk));
+ t1->fin = 1;
+ t1->rst = need_reset;
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+ if (sk->wfront == NULL)
+ {
+ prot->queue_xmit(sk, dev, buff, 0);
+ }
+ else
+ {
+ buff->free=0;
+ reset_timer(sk, TIME_WRITE,backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ buff->next = NULL;
+ if (sk->wback == NULL)
+ {
+ sk->wfront=buff;
+ }
+ else
+ {
+ sk->wback->next = buff;
+ }
+ sk->wback = buff;
+ buff->magic = TCP_WRITE_QUEUE_MAGIC;
+ }
- if (sk->state == TCP_CLOSE_WAIT) {
- sk->state = TCP_FIN_WAIT2;
- } else {
- sk->state = TCP_FIN_WAIT1;
- }
- }
- release_sock(sk);
+ if (sk->state == TCP_CLOSE_WAIT)
+ {
+ sk->state = TCP_FIN_WAIT2;
+ }
+ else
+ {
+ sk->state = TCP_FIN_WAIT1;
+ }
+ break;
+ }
+ if (!sk->dead)
+ sk->state_change(sk);
+ release_sock(sk);
}
/*
- * This routine takes stuff off of the write queue,
- * and puts it in the xmit queue.
+ * This routine takes stuff off of the write queue,
+ * and puts it in the xmit queue.
*/
-static void
-tcp_write_xmit(struct sock *sk)
+
+static void tcp_write_xmit(struct sock *sk)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
- DPRINTF((DBG_TCP, "tcp_write_xmit(sk=%X)\n", sk));
+ DPRINTF((DBG_TCP, "tcp_write_xmit(sk=%X)\n", sk));
- /* The bytes will have to remain here. In time closedown will
- empty the write queue and all will be happy */
- if(sk->zapped)
- return;
+ /* The bytes will have to remain here. In time closedown will
+ empty the write queue and all will be happy */
+ if(sk->zapped)
+ return;
- while(sk->wfront != NULL &&
- before(sk->wfront->h.seq, sk->window_seq) &&
- sk->packets_out < sk->cong_window) {
+ while(sk->wfront != NULL &&
+ before(sk->wfront->h.seq, sk->window_seq) &&
+ sk->packets_out < sk->cong_window)
+ {
skb = sk->wfront;
IS_SKB(skb);
sk->wfront =(struct sk_buff *)skb->next;
- if (sk->wfront == NULL) sk->wback = NULL;
+ if (sk->wfront == NULL)
+ sk->wback = NULL;
skb->next = NULL;
- if (skb->magic != TCP_WRITE_QUEUE_MAGIC) {
+ if (skb->magic != TCP_WRITE_QUEUE_MAGIC)
+ {
printk("tcp.c skb with bad magic(%X) on write queue. Squashing "
"queue\n", skb->magic);
sk->wfront = NULL;
@@ -2085,11 +2459,15 @@ tcp_write_xmit(struct sock *sk)
DPRINTF((DBG_TCP, "Sending a packet.\n"));
/* See if we really need to send the packet. */
- if (before(skb->h.seq, sk->rcv_ack_seq +1)) {
+ if (before(skb->h.seq, sk->rcv_ack_seq +1))
+ {
sk->retransmits = 0;
kfree_skb(skb, FREE_WRITE);
- if (!sk->dead) wake_up(sk->sleep);
- } else {
+ if (!sk->dead)
+ sk->write_space(sk);
+ }
+ else
+ {
sk->prot->queue_xmit(sk, skb->dev, skb, skb->free);
}
}
@@ -2097,67 +2475,79 @@ tcp_write_xmit(struct sock *sk)
/*
- * This routine sorts the send list, and resets the
- * sk->send_head and sk->send_tail pointers.
+ * This routine sorts the send list, and resets the
+ * sk->send_head and sk->send_tail pointers.
*/
-void
-sort_send(struct sock *sk)
+
+void sort_send(struct sock *sk)
{
- struct sk_buff *list = NULL;
- struct sk_buff *skb,*skb2,*skb3;
-
- for (skb = sk->send_head; skb != NULL; skb = skb2) {
- skb2 = (struct sk_buff *)skb->link3;
- if (list == NULL || before (skb2->h.seq, list->h.seq)) {
- skb->link3 = list;
- sk->send_tail = skb;
- list = skb;
- } else {
- for (skb3 = list; ; skb3 = (struct sk_buff *)skb3->link3) {
- if (skb3->link3 == NULL ||
- before(skb->h.seq, skb3->link3->h.seq)) {
- skb->link3 = skb3->link3;
- skb3->link3 = skb;
- if (skb->link3 == NULL) sk->send_tail = skb;
- break;
+ struct sk_buff *list = NULL;
+ struct sk_buff *skb,*skb2,*skb3;
+
+ for (skb = sk->send_head; skb != NULL; skb = skb2)
+ {
+ skb2 = (struct sk_buff *)skb->link3;
+ if (list == NULL || before (skb2->h.seq, list->h.seq))
+ {
+ skb->link3 = list;
+ sk->send_tail = skb;
+ list = skb;
+ }
+ else
+ {
+ for (skb3 = list; ; skb3 = (struct sk_buff *)skb3->link3)
+ {
+ if (skb3->link3 == NULL || before(skb->h.seq, skb3->link3->h.seq))
+ {
+ skb->link3 = skb3->link3;
+ skb3->link3 = skb;
+ if (skb->link3 == NULL)
+ sk->send_tail = skb;
+ break;
+ }
}
}
- }
- }
- sk->send_head = list;
+ }
+ sk->send_head = list;
}
-/* This routine deals with incoming acks, but not outgoing ones. */
-static int
-tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
+/*
+ * This routine deals with incoming acks, but not outgoing ones.
+ */
+
+static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
{
- unsigned long ack;
- int flag = 0;
+ unsigned long ack;
+ int flag = 0;
- if(sk->zapped)
- return(1); /* Dead, cant ack any more so why bother */
+ if(sk->zapped)
+ return(1); /* Dead, cant ack any more so why bother */
- ack = ntohl(th->ack_seq);
- DPRINTF((DBG_TCP, "tcp_ack ack=%d, window=%d, "
- "sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
- ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq));
+ ack = ntohl(th->ack_seq);
+ DPRINTF((DBG_TCP, "tcp_ack ack=%d, window=%d, "
+ "sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
+ ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq));
- if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1)) {
- if (after(ack, sk->send_seq) ||
- (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) {
- return(0);
- }
- if (sk->keepopen) {
- reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- }
- return(1);
- }
+ if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1))
+ {
+ if (after(ack, sk->send_seq) || (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT))
+ {
+ return(0);
+ }
+ if (sk->keepopen)
+ {
+ reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+ }
+ return(1);
+ }
- if (len != th->doff*4) flag |= 1;
+ if (len != th->doff*4)
+ flag |= 1;
- /* See if our window has been shrunk. */
- if (after(sk->window_seq, ack+ntohs(th->window))) {
+ /* See if our window has been shrunk. */
+ if (after(sk->window_seq, ack+ntohs(th->window)))
+ {
/*
* We may need to move packets from the send queue
* to the write queue, if the window has been shrunk on us.
@@ -2165,271 +2555,312 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
* like this, but if the other end does, you must be able
* to deal with it.
*/
- struct sk_buff *skb;
- struct sk_buff *skb2;
- struct sk_buff *wskb = NULL;
+ struct sk_buff *skb;
+ struct sk_buff *skb2;
+ struct sk_buff *wskb = NULL;
- skb2 = sk->send_head;
- sk->send_head = NULL;
- sk->send_tail = NULL;
+ skb2 = sk->send_head;
+ sk->send_head = NULL;
+ sk->send_tail = NULL;
- flag |= 4;
+ flag |= 4;
- sk->window_seq = ack + ntohs(th->window);
- cli();
- while (skb2 != NULL) {
- skb = skb2;
- skb2 = (struct sk_buff *)skb->link3;
- skb->link3 = NULL;
- if (after(skb->h.seq, sk->window_seq)) {
- if (sk->packets_out > 0) sk->packets_out--;
- /* We may need to remove this from the dev send list. */
- if (skb->next != NULL) {
-#ifdef OLD_WAY
- int i;
-
- if (skb->next != skb) {
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
+ sk->window_seq = ack + ntohs(th->window);
+ cli();
+ while (skb2 != NULL)
+ {
+ skb = skb2;
+ skb2 = (struct sk_buff *)skb->link3;
+ skb->link3 = NULL;
+ if (after(skb->h.seq, sk->window_seq))
+ {
+ if (sk->packets_out > 0)
+ sk->packets_out--;
+ /*
+ * We may need to remove this from the dev send list.
+ */
+
+ if (skb->next != NULL)
+ {
+ skb_unlink(skb);
}
-
- for(i = 0; i < DEV_NUMBUFFS; i++) {
- if (skb->dev->buffs[i] == skb) {
- if (skb->next == skb)
- skb->dev->buffs[i] = NULL;
- else
- skb->dev->buffs[i] = skb->next;
- break;
- }
+ /* Now add it to the write_queue. */
+ skb->magic = TCP_WRITE_QUEUE_MAGIC;
+ if (wskb == NULL)
+ {
+ skb->next = sk->wfront;
+ sk->wfront = skb;
+ }
+ else
+ {
+ skb->next = wskb->next;
+ wskb->next = skb;
}
- if (arp_q == skb) {
- if (skb->next == skb) arp_q = NULL;
- else arp_q = skb->next;
+ if (sk->wback == wskb)
+ sk->wback = skb;
+ wskb = skb;
+ }
+ else
+ {
+ if (sk->send_head == NULL)
+ {
+ sk->send_head = skb;
+ sk->send_tail = skb;
+ }
+ else
+ {
+ sk->send_tail->link3 = skb;
+ sk->send_tail = skb;
}
-#else
- skb_unlink(skb);
-#endif
- }
- /* Now add it to the write_queue. */
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (wskb == NULL) {
- skb->next = sk->wfront;
- sk->wfront = skb;
- } else {
- skb->next = wskb->next;
- wskb->next = skb;
- }
- if (sk->wback == wskb) sk->wback = skb;
- wskb = skb;
- } else {
- if (sk->send_head == NULL) {
- sk->send_head = skb;
- sk->send_tail = skb;
- } else {
- sk->send_tail->link3 = skb;
- sk->send_tail = skb;
+ skb->link3 = NULL;
}
- skb->link3 = NULL;
}
- }
- sti();
- }
-
- if (sk->send_tail == NULL || sk->send_head == NULL) {
- sk->send_head = NULL;
- sk->send_tail = NULL;
- sk->packets_out= 0;
- }
-
- sk->window_seq = ack + ntohs(th->window);
-
- /* We don't want too many packets out there. */
- if (sk->cong_window < 2048 && ack != sk->rcv_ack_seq) {
- if (sk->exp_growth) sk->cong_window *= 2;
- else sk->cong_window++;
- }
-
- DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n"));
- sk->rcv_ack_seq = ack;
-
- /* See if we can take anything off of the retransmit queue. */
- while(sk->send_head != NULL) {
- /* Check for a bug. */
- if (sk->send_head->link3 &&
- after(sk->send_head->h.seq, sk->send_head->link3->h.seq)) {
- printk("INET: tcp.c: *** bug send_list out of order.\n");
- sort_send(sk);
- }
+ sti();
+ }
- if (before(sk->send_head->h.seq, ack+1)) {
- struct sk_buff *oskb;
+ if (sk->send_tail == NULL || sk->send_head == NULL)
+ {
+ sk->send_head = NULL;
+ sk->send_tail = NULL;
+ sk->packets_out= 0;
+ }
- sk->retransmits = 0;
+ sk->window_seq = ack + ntohs(th->window);
- /* We have one less packet out there. */
- if (sk->packets_out > 0) sk->packets_out --;
- DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n",
- sk->send_head, sk->send_head->h.seq, ack));
+ /* We don't want too many packets out there. */
+ if (sk->cong_window < 2048 && ack != sk->rcv_ack_seq)
+ {
+ if (sk->exp_growth)
+ sk->cong_window *= 2;
+ else
+ sk->cong_window++;
+ }
- /* Wake up the process, it can probably write more. */
- if (!sk->dead) wake_up(sk->sleep);
+ DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n"));
+ sk->rcv_ack_seq = ack;
- oskb = sk->send_head;
+ /* See if we can take anything off of the retransmit queue. */
+ while(sk->send_head != NULL)
+ {
+ /* Check for a bug. */
+ if (sk->send_head->link3 && after(sk->send_head->h.seq, sk->send_head->link3->h.seq))
+ {
+ printk("INET: tcp.c: *** bug send_list out of order.\n");
+ sort_send(sk);
+ }
- /* Estimate the RTT. Ignore the ones right after a retransmit. */
- if (sk->retransmits == 0 && !(flag&2)) {
- long abserr, rtt = jiffies - oskb->when;
+ if (before(sk->send_head->h.seq, ack+1))
+ {
+ struct sk_buff *oskb;
- if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- /* first ack, so nothing else to average with */
- sk->rtt = rtt;
- else {
- abserr = (rtt > sk->rtt) ? rtt - sk->rtt : sk->rtt - rtt;
- sk->rtt = (7 * sk->rtt + rtt) >> 3;
- sk->mdev = (3 * sk->mdev + abserr) >> 2;
- }
- sk->backoff = 0;
- }
- flag |= (2|4);
- /* no point retransmitting faster than .1 sec */
- /* 2 minutes is max legal rtt for Internet */
- if (sk->rtt < 10) sk->rtt = 10;
- if (sk->rtt > 12000) sk->rtt = 12000;
+ sk->retransmits = 0;
- cli();
+ /* We have one less packet out there. */
+ if (sk->packets_out > 0)
+ sk->packets_out --;
+ DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n",
+ sk->send_head, sk->send_head->h.seq, ack));
- oskb = sk->send_head;
- IS_SKB(oskb);
- sk->send_head =(struct sk_buff *)oskb->link3;
- if (sk->send_head == NULL) {
- sk->send_tail = NULL;
- }
+ /* Wake up the process, it can probably write more. */
+ if (!sk->dead)
+ sk->write_space(sk);
- /* We may need to remove this from the dev send list. */
- skb_unlink(oskb); /* Much easier! */
- sti();
- oskb->magic = 0;
- kfree_skb(oskb, FREE_WRITE); /* write. */
- if (!sk->dead) wake_up(sk->sleep);
- } else {
- break;
- }
- }
+ oskb = sk->send_head;
- /*
- * Maybe we can take some stuff off of the write queue,
- * and put it onto the xmit queue.
- */
- if (sk->wfront != NULL) {
- if (after (sk->window_seq, sk->wfront->h.seq) &&
- sk->packets_out < sk->cong_window) {
- flag |= 1;
- tcp_write_xmit(sk);
- }
- } else {
- if (sk->send_head == NULL && sk->ack_backlog == 0 &&
- sk->state != TCP_TIME_WAIT && !sk->keepopen) {
- DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n"));
- if (!sk->dead) wake_up(sk->sleep);
+ /* Estimate the RTT. Ignore the ones right after a retransmit. */
+
+ if (sk->retransmits == 0 && !(flag&2))
+ {
+ long abserr, rtt = jiffies - oskb->when;
+
+ if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
+ /* first ack, so nothing else to average with */
+ sk->rtt = rtt;
+ else
+ {
+ abserr = (rtt > sk->rtt) ? rtt - sk->rtt : sk->rtt - rtt;
+ sk->rtt = (7 * sk->rtt + rtt) >> 3;
+ sk->mdev = (3 * sk->mdev + abserr) >> 2;
+ }
+ sk->backoff = 0;
+ }
+ flag |= (2|4);
+ /* no point retransmitting faster than .1 sec */
+ /* 2 minutes is max legal rtt for Internet */
+
+ if (sk->rtt < 10)
+ sk->rtt = 10;
+
+ if (sk->rtt > 12000)
+ sk->rtt = 12000;
+
+ cli();
+
+ oskb = sk->send_head;
+ IS_SKB(oskb);
+ sk->send_head =(struct sk_buff *)oskb->link3;
+ if (sk->send_head == NULL)
+ {
+ sk->send_tail = NULL;
+ }
- if (sk->keepopen)
- reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- else
- delete_timer(sk);
- } else {
- if (sk->state != (unsigned char) sk->keepopen) {
- reset_timer(sk, TIME_WRITE,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ /* We may need to remove this from the dev send list. */
+ skb_unlink(oskb); /* Much easier! */
+ sti();
+ oskb->magic = 0;
+ kfree_skb(oskb, FREE_WRITE); /* write. */
+ if (!sk->dead)
+ sk->write_space(sk);
+ }
+ else
+ {
+ break;
}
- if (sk->state == TCP_TIME_WAIT) {
- reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ }
+
+ /*
+ * Maybe we can take some stuff off of the write queue,
+ * and put it onto the xmit queue.
+ */
+ if (sk->wfront != NULL)
+ {
+ if (after (sk->window_seq, sk->wfront->h.seq) && sk->packets_out < sk->cong_window)
+ {
+ flag |= 1;
+ tcp_write_xmit(sk);
}
- }
- }
-
- if (sk->packets_out == 0 && sk->send_tmp != NULL &&
- sk->wfront == NULL && sk->send_head == NULL) {
- flag |= 1;
- tcp_send_partial(sk);
- }
-
- /* See if we are done. */
- if (sk->state == TCP_TIME_WAIT) {
- if (!sk->dead) wake_up(sk->sleep);
- if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) {
- flag |= 1;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- }
- }
+ }
+ else
+ {
+ if (sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT && !sk->keepopen)
+ {
+ DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n"));
+ if (!sk->dead)
+ sk->write_space(sk);
+
+ if (sk->keepopen)
+ reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+ else
+ delete_timer(sk);
+ }
+ else
+ {
+ if (sk->state != (unsigned char) sk->keepopen)
+ {
+ reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ }
+ if (sk->state == TCP_TIME_WAIT)
+ {
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ }
+ }
+ }
- if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) {
- if (!sk->dead) wake_up(sk->sleep);
- if (sk->rcv_ack_seq == sk->send_seq) {
+ /*
+ * If we have nothing left to send then send the packet we are currently assembling
+ */
+
+ if (sk->packets_out == 0 && sk->send_tmp != NULL && sk->wfront == NULL && sk->send_head == NULL)
+ {
flag |= 1;
- if (sk->acked_seq != sk->fin_seq) {
- tcp_time_wait(sk);
- } else {
- DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk));
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk,
- th, sk->daddr);
- sk->shutdown = SHUTDOWN_MASK;
+ tcp_send_partial(sk);
+ }
+
+ /* See if we are done. */
+ if (sk->state == TCP_TIME_WAIT)
+ {
+
+ /*
+ * Our FIN has been acknowledged
+ */
+
+ if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq)
+ {
+ flag |= 1;
sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ sk->state_change(sk);
}
- }
- }
+ }
- if (((!flag) || (flag&4)) && sk->send_head != NULL &&
- (sk->send_head->when + backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)
- < jiffies)) {
- sk->exp_growth = 0;
- ip_retransmit(sk, 0);
- }
+ if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2)
+ {
+ if (sk->rcv_ack_seq == sk->send_seq)
+ {
+ flag |= 1;
+ if (sk->acked_seq != sk->fin_seq)
+ {
+ tcp_time_wait(sk);
+ }
+ else
+ {
+ DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk));
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk,
+ th, sk->daddr);
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->state = TCP_CLOSE;
+ }
+ }
+ if (!sk->dead)
+ sk->state_change(sk);
+
+ }
- DPRINTF((DBG_TCP, "leaving tcp_ack\n"));
- return(1);
+ if (((!flag) || (flag&4)) && sk->send_head != NULL && (sk->send_head->when + backoff(sk->backoff) * (2 * sk->mdev + sk->rtt) < jiffies))
+ {
+ sk->exp_growth = 0;
+ ip_retransmit(sk, 0);
+ }
+
+ DPRINTF((DBG_TCP, "leaving tcp_ack\n"));
+ return(1);
}
/*
- * This routine handles the data. If there is room in the buffer,
- * it will be have already been moved into it. If there is no
- * room, then we will just have to discard the packet.
+ * This routine handles the data. If there is room in the buffer,
+ * it will be have already been moved into it. If there is no
+ * room, then we will just have to discard the packet.
*/
-static int
-tcp_data(struct sk_buff *skb, struct sock *sk,
+
+static int tcp_data(struct sk_buff *skb, struct sock *sk,
unsigned long saddr, unsigned short len)
{
- struct sk_buff *skb1, *skb2;
- struct tcphdr *th;
- int dup_dumped=0;
-
- th = skb->h.th;
- print_th(th);
- skb->len = len -(th->doff*4);
-
- DPRINTF((DBG_TCP, "tcp_data len = %d sk = %X:\n", skb->len, sk));
-
- sk->bytes_rcv += skb->len;
- if (skb->len == 0 && !th->fin && !th->urg && !th->psh) {
- /* Don't want to keep passing ack's back and forth. */
- if (!th->ack) tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr);
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- if (sk->shutdown & RCV_SHUTDOWN) {
- sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
- tcp_reset(sk->saddr, sk->daddr, skb->h.th,
- sk->prot, NULL, skb->dev);
- sk->state = TCP_CLOSE;
- sk->err = EPIPE;
- sk->shutdown = SHUTDOWN_MASK;
- DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk));
- kfree_skb(skb, FREE_READ);
- if (!sk->dead) wake_up(sk->sleep);
- return(0);
- }
+ struct sk_buff *skb1, *skb2;
+ struct tcphdr *th;
+ int dup_dumped=0;
+
+ th = skb->h.th;
+ print_th(th);
+
+ skb->len = len -(th->doff*4);
+
+ DPRINTF((DBG_TCP, "tcp_data len = %d sk = %X:\n", skb->len, sk));
+
+ sk->bytes_rcv += skb->len;
+ if (skb->len == 0 && !th->fin && !th->urg && !th->psh)
+ {
+ /* Don't want to keep passing ack's back and forth. */
+ if (!th->ack)
+ tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr);
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
+ tcp_reset(sk->saddr, sk->daddr, skb->h.th, sk->prot, NULL, skb->dev);
+ sk->state = TCP_CLOSE;
+ sk->err = EPIPE;
+ sk->shutdown = SHUTDOWN_MASK;
+ DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk));
+ kfree_skb(skb, FREE_READ);
+ if (!sk->dead)
+ sk->state_change(sk);
+ return(0);
+ }
/*
* Now we have to walk the chain, and figure out where this one
@@ -2439,430 +2870,482 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
* out of order we will be able to fit things in nicely.
*/
- /* This should start at the last one, and then go around forwards. */
- if (sk->rqueue == NULL) {
- DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb));
-#ifdef OLDWAY
- sk->rqueue = skb;
- skb->next = skb;
- skb->prev = skb;
- skb->list = &sk->rqueue;
-#else
- skb_queue_head(&sk->rqueue,skb);
-#endif
- skb1= NULL;
- } else {
- DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk));
- for(skb1=sk->rqueue->prev; ; skb1 =(struct sk_buff *)skb1->prev) {
- if(sk->debug)
- {
- printk("skb1=%p :", skb1);
- printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
- printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
- printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
- sk->acked_seq);
- }
-#ifdef OLD
- if (after(th->seq+1, skb1->h.th->seq)) {
- skb->prev = skb1;
- skb->next = skb1->next;
- skb->next->prev = skb;
- skb1->next = skb;
- if (skb1 == sk->rqueue) sk->rqueue = skb;
- break;
- }
- if (skb1->prev == sk->rqueue) {
- skb->next= skb1;
- skb->prev = skb1->prev;
- skb->prev->next = skb;
- skb1->prev = skb;
- skb1 = NULL; /* so we know we might be able
- to ack stuff. */
- break;
- }
-#else
- if (th->seq==skb1->h.th->seq && skb->len>= skb1->len)
- {
- skb_append(skb1,skb);
- skb_unlink(skb1);
- kfree_skb(skb1,FREE_READ);
- dup_dumped=1;
- skb1=NULL;
- break;
- }
- if (after(th->seq+1, skb1->h.th->seq))
- {
- skb_append(skb1,skb);
- break;
- }
- if (skb1 == sk->rqueue)
+ /*
+ * This should start at the last one, and then go around forwards.
+ */
+
+ if (sk->rqueue == NULL)
+ {
+ DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb));
+ skb_queue_head(&sk->rqueue,skb);
+ skb1= NULL;
+ }
+ else
+ {
+ DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk));
+ for(skb1=sk->rqueue->prev; ; skb1 =(struct sk_buff *)skb1->prev)
{
- skb_queue_head(&sk->rqueue, skb);
- break;
- }
-#endif
- }
- DPRINTF((DBG_TCP, "skb = %X:\n", skb));
- }
-
- th->ack_seq = th->seq + skb->len;
- if (th->syn) th->ack_seq++;
- if (th->fin) th->ack_seq++;
-
- if (before(sk->acked_seq, sk->copied_seq)) {
- printk("*** tcp.c:tcp_data bug acked < copied\n");
- sk->acked_seq = sk->copied_seq;
- }
-
- /* Now figure out if we can ack anything. */
- if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) {
- if (before(th->seq, sk->acked_seq+1)) {
- if (after(th->ack_seq, sk->acked_seq))
- sk->acked_seq = th->ack_seq;
- skb->acked = 1;
-
- /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
- if (skb->h.th->fin) {
- if (!sk->dead) wake_up(sk->sleep);
- sk->shutdown |= RCV_SHUTDOWN;
+ if(sk->debug)
+ {
+ printk("skb1=%p :", skb1);
+ printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
+ printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
+ printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
+ sk->acked_seq);
+ }
+ if (th->seq==skb1->h.th->seq && skb->len>= skb1->len)
+ {
+ skb_append(skb1,skb);
+ skb_unlink(skb1);
+ kfree_skb(skb1,FREE_READ);
+ dup_dumped=1;
+ skb1=NULL;
+ break;
+ }
+ if (after(th->seq+1, skb1->h.th->seq))
+ {
+ skb_append(skb1,skb);
+ break;
+ }
+ if (skb1 == sk->rqueue)
+ {
+ skb_queue_head(&sk->rqueue, skb);
+ break;
+ }
}
+ DPRINTF((DBG_TCP, "skb = %X:\n", skb));
+ }
+
+ th->ack_seq = th->seq + skb->len;
+
+ if (th->syn)
+ th->ack_seq++;
+
+ if (th->fin)
+ th->ack_seq++;
+
+ if (before(sk->acked_seq, sk->copied_seq))
+ {
+ printk("*** tcp.c:tcp_data bug acked < copied\n");
+ sk->acked_seq = sk->copied_seq;
+ }
+
+ /* Now figure out if we can ack anything. */
+
+ if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1))
+ {
+ if (before(th->seq, sk->acked_seq+1))
+ {
+ if (after(th->ack_seq, sk->acked_seq))
+ sk->acked_seq = th->ack_seq;
+ skb->acked = 1;
+
+ /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
+ if (skb->h.th->fin)
+ {
+ if (!sk->dead)
+ sk->state_change(sk);
+ sk->shutdown |= RCV_SHUTDOWN;
+ }
- for(skb2 = (struct sk_buff *)skb->next;
- skb2 !=(struct sk_buff *) sk->rqueue;
- skb2 = (struct sk_buff *)skb2->next) {
- if (before(skb2->h.th->seq, sk->acked_seq+1)) {
- if (after(skb2->h.th->ack_seq, sk->acked_seq))
- sk->acked_seq = skb2->h.th->ack_seq;
- skb2->acked = 1;
+ for(skb2 = (struct sk_buff *)skb->next;
+ skb2 !=(struct sk_buff *) sk->rqueue;
+ skb2 = (struct sk_buff *)skb2->next)
+ {
+ if (before(skb2->h.th->seq, sk->acked_seq+1))
+ {
+ if (after(skb2->h.th->ack_seq, sk->acked_seq))
+ sk->acked_seq = skb2->h.th->ack_seq;
+ skb2->acked = 1;
+
+ /*
+ * When we ack the fin, we turn on
+ * the RCV_SHUTDOWN flag.
+ */
+ if (skb2->h.th->fin)
+ {
+ sk->shutdown |= RCV_SHUTDOWN;
+ if (!sk->dead)
+ sk->state_change(sk);
+ }
- /*
- * When we ack the fin, we turn on
- * the RCV_SHUTDOWN flag.
- */
- if (skb2->h.th->fin) {
- sk->shutdown |= RCV_SHUTDOWN;
- if (!sk->dead) wake_up(sk->sleep);
+ /* Force an immediate ack. */
+ sk->ack_backlog = sk->max_ack_backlog;
+ }
+ else
+ {
+ break;
}
+ }
- /* Force an immediate ack. */
- sk->ack_backlog = sk->max_ack_backlog;
- } else {
- break;
+ /*
+ * This also takes care of updating the window.
+ * This if statement needs to be simplified.
+ */
+ if (!sk->delay_acks || sk->ack_backlog >= sk->max_ack_backlog ||
+ sk->bytes_rcv > sk->max_unacked || th->fin)
+ {
+/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */
+ }
+ else
+ {
+ sk->ack_backlog++;
+ if(sk->debug)
+ printk("Ack queued.\n");
+ reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
}
}
+ }
+ /*
+ * If we've missed a packet, send an ack.
+ * Also start a timer to send another.
+ */
+ if (!skb->acked)
+ {
/*
- * This also takes care of updating the window.
- * This if statement needs to be simplified.
+ * This is important. If we don't have much room left,
+ * we need to throw out a few packets so we have a good
+ * window.
*/
- if (!sk->delay_acks ||
- sk->ack_backlog >= sk->max_ack_backlog ||
- sk->bytes_rcv > sk->max_unacked || th->fin) {
-/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */
- } else {
- sk->ack_backlog++;
- if(sk->debug)
- printk("Ack queued.\n");
- reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- }
- }
- }
-
- /*
- * If we've missed a packet, send an ack.
- * Also start a timer to send another.
- */
- if (!skb->acked) {
- /*
- * This is important. If we don't have much room left,
- * we need to throw out a few packets so we have a good
- * window.
- */
- while (sk->prot->rspace(sk) < sk->mtu) {
- skb1 = skb_peek(&sk->rqueue);
- if (skb1 == NULL) {
- printk("INET: tcp.c:tcp_data memory leak detected.\n");
- break;
- }
+ while (sk->prot->rspace(sk) < sk->mtu)
+ {
+ skb1 = skb_peek(&sk->rqueue);
+ if (skb1 == NULL)
+ {
+ printk("INET: tcp.c:tcp_data memory leak detected.\n");
+ break;
+ }
- /* Don't throw out something that has been acked. */
- if (skb1->acked) {
- break;
- }
+ /* Don't throw out something that has been acked. */
+ if (skb1->acked)
+ {
+ break;
+ }
- skb_unlink(skb1);
-#ifdef OLDWAY
- if (skb1->prev == skb1) {
- sk->rqueue = NULL;
- } else {
- sk->rqueue = (struct sk_buff *)skb1->prev;
- skb1->next->prev = skb1->prev;
- skb1->prev->next = skb1->next;
+ skb_unlink(skb1);
+ kfree_skb(skb1, FREE_READ);
}
-#endif
- kfree_skb(skb1, FREE_READ);
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ sk->ack_backlog++;
+ reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
+ }
+ else
+ {
+ /* We missed a packet. Send an ack to try to resync things. */
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ }
+
+ /* Now tell the user we may have some data. */
+ if (!sk->dead)
+ {
+ if(sk->debug)
+ printk("Data wakeup.\n");
+ sk->data_ready(sk,0);
+ }
+ else
+ {
+ DPRINTF((DBG_TCP, "data received on dead socket.\n"));
+ }
+
+ if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq)
+ {
+ DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk));
+
+/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->state = TCP_LAST_ACK;
+ if (!sk->dead)
+ sk->state_change(sk);
}
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- sk->ack_backlog++;
- reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- } else {
- /* We missed a packet. Send an ack to try to resync things. */
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- }
-
- /* Now tell the user we may have some data. */
- if (!sk->dead) {
- if(sk->debug)
- printk("Data wakeup.\n");
- wake_up(sk->sleep);
- } else {
- DPRINTF((DBG_TCP, "data received on dead socket.\n"));
- }
-
- if (sk->state == TCP_FIN_WAIT2 &&
- sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq) {
- DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk));
-
-/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
- sk->shutdown = SHUTDOWN_MASK;
- sk->state = TCP_LAST_ACK;
- if (!sk->dead) wake_up(sk->sleep);
- }
- return(0);
+ return(0);
}
-static int
-tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
+static int tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
{
- extern int kill_pg(int pg, int sig, int priv);
- extern int kill_proc(int pid, int sig, int priv);
+ extern int kill_pg(int pg, int sig, int priv);
+ extern int kill_proc(int pid, int sig, int priv);
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead)
+ sk->data_ready(sk,0);
- if (sk->urginline) {
- th->urg = 0;
- th->psh = 1;
- return(0);
- }
-
- if (!sk->urg) {
- /* So if we get more urgent data, we don't signal the user again. */
- if (sk->proc != 0) {
- if (sk->proc > 0) {
- kill_proc(sk->proc, SIGURG, 1);
- } else {
- kill_pg(-sk->proc, SIGURG, 1);
+ if (sk->urginline)
+ {
+ th->urg = 0;
+ th->psh = 1;
+ return(0);
+ }
+
+ if (!sk->urg)
+ {
+ /* So if we get more urgent data, we don't signal the user again. */
+ if (sk->proc != 0)
+ {
+ if (sk->proc > 0)
+ {
+ kill_proc(sk->proc, SIGURG, 1);
+ }
+ else
+ {
+ kill_pg(-sk->proc, SIGURG, 1);
+ }
}
- }
- }
- sk->urg++;
- return(0);
+ }
+ sk->urg++;
+ return(0);
}
-/* This deals with incoming fins. */
-static int
-tcp_fin(struct sock *sk, struct tcphdr *th,
+/*
+ * This deals with incoming fins. [Page 75]
+ */
+
+static int tcp_fin(struct sock *sk, struct tcphdr *th,
unsigned long saddr, struct device *dev)
{
- DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
+ DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
sk, th, saddr, dev));
- if (!sk->dead) {
- wake_up(sk->sleep);
- }
-
- switch(sk->state) {
- case TCP_SYN_RECV:
- case TCP_SYN_SENT:
- case TCP_ESTABLISHED:
- /* Contains the one that needs to be acked */
- sk->fin_seq = th->seq+1;
- sk->state = TCP_CLOSE_WAIT;
- if (th->rst) sk->shutdown = SHUTDOWN_MASK;
- break;
-
- case TCP_CLOSE_WAIT:
- case TCP_FIN_WAIT2:
- break; /* we got a retransmit of the fin. */
-
- case TCP_FIN_WAIT1:
- /* Contains the one that needs to be acked */
- sk->fin_seq = th->seq+1;
- sk->state = TCP_FIN_WAIT2;
- break;
-
- default:
- case TCP_TIME_WAIT:
- sk->state = TCP_LAST_ACK;
- /* Start the timers. */
- reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return(0);
- }
- sk->ack_backlog++;
+ switch(sk->state)
+ {
+ case TCP_SYN_RECV:
+ case TCP_SYN_SENT:
+ case TCP_ESTABLISHED:
+ /* Contains the one that needs to be acked */
+ sk->fin_seq = th->seq+1;
+ sk->state = TCP_CLOSE_WAIT;
+ if (th->rst)
+ sk->shutdown = SHUTDOWN_MASK;
+ break;
+
+ case TCP_CLOSE_WAIT:
+ break;
+
+ case TCP_FIN_WAIT2:
+ tcp_time_wait(sk);
+ break; /* we got a retransmit of the fin. */
+
+ case TCP_FIN_WAIT1:
+ /* Contains the one that needs to be acked */
+ if(before(sk->send_seq,sk->rcv_ack_seq+1) && after(sk->send_seq,sk->rcv_ack_seq-1))
+ tcp_time_wait(sk);
+ else
+ {
+ sk->fin_seq = th->seq+1;
+ sk->state = TCP_FIN_WAIT2;/* should be closing */
+ }
+ break;
+
+ default:
+ case TCP_TIME_WAIT:
+ sk->state = TCP_LAST_ACK;
+
+ /* Start the timers. */
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
+ return(0);
+ }
+ sk->ack_backlog++;
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
- return(0);
+ return(0);
}
-/* This will accept the next outstanding connection. */
-static struct sock *
-tcp_accept(struct sock *sk, int flags)
+/*
+ * This will accept the next outstanding connection.
+ */
+
+static struct sock *tcp_accept(struct sock *sk, int flags)
{
- struct sock *newsk;
- struct sk_buff *skb;
+ struct sock *newsk;
+ struct sk_buff *skb;
- DPRINTF((DBG_TCP, "tcp_accept(sk=%X, flags=%X, addr=%s)\n",
+ DPRINTF((DBG_TCP, "tcp_accept(sk=%X, flags=%X, addr=%s)\n",
sk, flags, in_ntoa(sk->saddr)));
- /*
- * We need to make sure that this socket is listening,
- * and that it has something pending.
- */
- if (sk->state != TCP_LISTEN) {
- sk->err = EINVAL;
- return(NULL);
- }
-
- /* avoid the race. */
- cli();
- sk->inuse = 1;
- while((skb = get_firstr(sk)) == NULL) {
- if (flags & O_NONBLOCK) {
- sti();
- release_sock(sk);
- sk->err = EAGAIN;
- return(NULL);
- }
+ /*
+ * We need to make sure that this socket is listening,
+ * and that it has something pending.
+ */
+
+ if (sk->state != TCP_LISTEN)
+ {
+ sk->err = EINVAL;
+ return(NULL);
+ }
- release_sock(sk);
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- sti();
- sk->err = ERESTARTSYS;
- return(NULL);
- }
- sk->inuse = 1;
- }
- sti();
+ /* avoid the race. */
+
+ cli();
+ sk->inuse = 1;
+ while((skb = get_firstr(sk)) == NULL)
+ {
+ /*
+ * Nobody connecting
+ */
+ if (flags & O_NONBLOCK)
+ {
+ sti();
+ release_sock(sk);
+ sk->err = EAGAIN;
+ return(NULL);
+ }
+
+ release_sock(sk);
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ sk->err = ERESTARTSYS;
+ return(NULL);
+ }
+ sk->inuse = 1;
+ }
+ sti();
- /* Now all we need to do is return skb->sk. */
- newsk = skb->sk;
+ /* Now all we need to do is return skb->sk. */
+ newsk = skb->sk;
- kfree_skb(skb, FREE_READ);
- sk->ack_backlog--;
- release_sock(sk);
- return(newsk);
+ kfree_skb(skb, FREE_READ);
+ sk->ack_backlog--;
+ release_sock(sk);
+ return(newsk);
}
-/* This will initiate an outgoing connection. */
-static int
-tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
+/*
+ * This will initiate an outgoing connection.
+ */
+
+static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{
- struct sk_buff *buff;
- struct sockaddr_in sin;
- struct device *dev=NULL;
- unsigned char *ptr;
- int tmp;
- struct tcphdr *t1;
- int err;
-
- if (sk->state != TCP_CLOSE) return(-EISCONN);
- if (addr_len < 8) return(-EINVAL);
-
- err=verify_area(VERIFY_READ, usin, addr_len);
- if(err)
- return err;
+ struct sk_buff *buff;
+ struct sockaddr_in sin;
+ struct device *dev=NULL;
+ unsigned char *ptr;
+ int tmp;
+ struct tcphdr *t1;
+ int err;
+
+ if (sk->state != TCP_CLOSE)
+ return(-EISCONN);
+
+ if (addr_len < 8)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, usin, addr_len);
+ if(err)
+ return err;
- memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
+ memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
- if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EAFNOSUPPORT);
- DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr)));
+ DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr)));
- /* Don't want a TCP connection going to a broadcast address */
- if (chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) {
- DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
- return(-ENETUNREACH);
- }
+ /*
+ * Don't want a TCP connection going to a broadcast address
+ */
+
+ if (chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST)
+ {
+ DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
+ return(-ENETUNREACH);
+ }
+
+ sk->inuse = 1;
+ sk->daddr = sin.sin_addr.s_addr;
+ sk->send_seq = jiffies * SEQ_TICK - seq_offset;
+ sk->rcv_ack_seq = sk->send_seq -1;
+ sk->err = 0;
+ sk->dummy_th.dest = sin.sin_port;
+ release_sock(sk);
+
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
+ if (buff == NULL)
+ {
+ return(-ENOMEM);
+ }
- sk->inuse = 1;
- sk->daddr = sin.sin_addr.s_addr;
- sk->send_seq = jiffies * SEQ_TICK - seq_offset;
- sk->rcv_ack_seq = sk->send_seq -1;
- sk->err = 0;
- sk->dummy_th.dest = sin.sin_port;
- release_sock(sk);
-
- buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
- if (buff == NULL) {
- return(-ENOMEM);
- }
- sk->inuse = 1;
- buff->mem_addr = buff;
- buff->mem_len = MAX_SYN_SIZE;
- buff->len = 24;
- buff->sk = sk;
- buff->free = 1;
- t1 = (struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- /* We need to build the routing stuff fromt the things saved in skb. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE);
- if (tmp < 0) {
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- release_sock(sk);
- return(-ENETUNREACH);
- }
- buff->len += tmp;
- t1 = (struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
- t1->seq = ntohl(sk->send_seq++);
- buff->h.seq = sk->send_seq;
- t1->ack = 0;
- t1->window = 2;
- t1->res1=0;
- t1->res2=0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->syn = 1;
- t1->urg_ptr = 0;
- t1->doff = 6;
-
- /* Put in the TCP options to say MTU. */
- ptr = (unsigned char *)(t1+1);
- ptr[0] = 2;
- ptr[1] = 4;
- ptr[2] = (dev->mtu- HEADER_SIZE) >> 8;
- ptr[3] = (dev->mtu- HEADER_SIZE) & 0xff;
- sk->mtu = dev->mtu - HEADER_SIZE;
- tcp_send_check(t1, sk->saddr, sk->daddr,
- sizeof(struct tcphdr) + 4, sk);
-
- /* This must go first otherwise a really quick response will get reset. */
- sk->state = TCP_SYN_SENT;
- sk->rtt = TCP_CONNECT_TIME;
- reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
- sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
-
- sk->prot->queue_xmit(sk, dev, buff, 0);
+ sk->inuse = 1;
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_SYN_SIZE;
+ buff->len = 24;
+ buff->sk = sk;
+ buff->free = 1;
+ t1 = (struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ /* We need to build the routing stuff fromt the things saved in skb. */
+ tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,IPPROTO_TCP, NULL, MAX_SYN_SIZE,
+ sk->ip_ttl,sk->ip_tos);
- release_sock(sk);
- return(0);
+ if (tmp < 0)
+ {
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ release_sock(sk);
+ return(-ENETUNREACH);
+ }
+ buff->len += tmp;
+ t1 = (struct tcphdr *)((char *)t1 +tmp);
+
+ memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq++);
+ buff->h.seq = sk->send_seq;
+ t1->ack = 0;
+ t1->window = 2;
+ t1->res1=0;
+ t1->res2=0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->psh = 0;
+ t1->syn = 1;
+ t1->urg_ptr = 0;
+ t1->doff = 6;
+
+ /* Put in the TCP options to say MTU. */
+ ptr = (unsigned char *)(t1+1);
+ ptr[0] = 2;
+ ptr[1] = 4;
+ ptr[2] = (dev->mtu- HEADER_SIZE) >> 8;
+ ptr[3] = (dev->mtu- HEADER_SIZE) & 0xff;
+ sk->mtu = dev->mtu - HEADER_SIZE;
+ tcp_send_check(t1, sk->saddr, sk->daddr,
+ sizeof(struct tcphdr) + 4, sk);
+
+ /*
+ * This must go first otherwise a really quick response will get reset.
+ */
+
+ sk->state = TCP_SYN_SENT;
+ sk->rtt = TCP_CONNECT_TIME;
+ reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
+ sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
+
+ sk->prot->queue_xmit(sk, dev, buff, 0);
+
+ release_sock(sk);
+ return(0);
}
-/* This functions checks to see if the tcp header is actually acceptible. */
-static int
-tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
- struct options *opt, unsigned long saddr)
+/*
+ * This functions checks to see if the tcp header is actually acceptible.
+ */
+
+static int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
+ struct options *opt, unsigned long saddr, struct device *dev)
{
/*
* This isn't quite right. sk->acked_seq could be more recent
@@ -2870,552 +3353,711 @@ tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
* slightly more packets than we should, but it should not cause
* problems unless someone is trying to forge packets.
*/
- DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n",
- sk, th, len, opt, saddr));
-
- if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)||
- between(th->seq + len-(th->doff*4), sk->acked_seq + 1,
- sk->acked_seq + sk->window) ||
- (before(th->seq, sk->acked_seq) &&
- after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window))) {
- return(1);
- }
- DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
+ DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n",
+ sk, th, len, opt, saddr));
+
+ /* Is it within the windows */
+ if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)||
+ between(th->seq + len-(th->doff*4), sk->acked_seq + 1, sk->acked_seq + sk->window) ||
+ (before(th->seq, sk->acked_seq) &&
+ after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window)))
+ {
+ return(1);
+ }
+ DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
+
+ /*
+ * Send a reset if we get something not ours and we are
+ * unsynchronized. Note: We don't do anything to our end. We
+ * are just killing the bogus remote connection then we will
+ * connect again and it will work (with luck).
+ */
+
+ if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV)
+ {
+ tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev);
+ return(1);
+ }
- /*
- * If it's too far ahead, send an ack to let the
- * other end know what we expect.
- */
- if (after(th->seq, sk->acked_seq + sk->window)) {
- if(!th->rst)
+ /*
+ * If it's too far ahead, send an ack to let the
+ * other end know what we expect.
+ */
+
+ if (after(th->seq, sk->acked_seq + sk->window))
+ {
+ if(!th->rst)
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ return(0);
+ }
+
+ /*
+ * In case it's just a late ack, let it through.
+ */
+
+ if (th->ack && len == (th->doff * 4) && after(th->seq, sk->acked_seq - 32767) && !th->fin && !th->syn)
+ return(1);
+
+ if (!th->rst)
+ {
+ /* Try to resync things. */
tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- return(0);
- }
-
- /* In case it's just a late ack, let it through. */
- if (th->ack && len == (th->doff * 4) &&
- after(th->seq, sk->acked_seq - 32767) &&
- !th->fin && !th->syn) return(1);
-
- if (!th->rst) {
- /* Try to resync things. */
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- }
- return(0);
+ }
+ return(0);
}
+/*
+ * A TCP frame has been received by the IP layer and will now
+ * be thrown to us for processing. I've dropped page numbers
+ * into this. These are from the ASCII version of the RFC
+ * and should help anyone following it.
+ */
-
-int
-tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol * protocol)
{
- struct tcphdr *th;
- struct sock *sk;
-
- if (!skb) {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n"));
- return(0);
- }
-#if 0 /* FIXME: it's ok for protocol to be NULL */
- if (!protocol) {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv protocol = NULL\n"));
- return(0);
- }
-
- if (!opt) { /* FIXME: it's ok for opt to be NULL */
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv opt = NULL\n"));
- }
-#endif
- if (!dev) {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n"));
- return(0);
- }
- th = skb->h.th;
-
- /* Find the socket. */
- sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
- DPRINTF((DBG_TCP, "<<\n"));
- DPRINTF((DBG_TCP, "len = %d, redo = %d, skb=%X\n", len, redo, skb));
-
- /* If this socket has got a reset its to all intents and purposes
- really dead */
- if (sk!=NULL && sk->zapped)
- sk=NULL;
-
- if (sk) {
- DPRINTF((DBG_TCP, "sk = %X:\n", sk));
- }
+ struct tcphdr *th;
+ struct sock *sk;
- if (!redo) {
- if (tcp_check(th, len, saddr, daddr )) {
- skb->sk = NULL;
- DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n"));
-if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
- kfree_skb(skb,FREE_READ);
- /*
- * We don't release the socket because it was
- * never marked in use.
- */
+ if (!skb)
+ {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n"));
return(0);
- }
+ }
- /* See if we know about the socket. */
- if (sk == NULL) {
- if (!th->rst)
- {
- th->seq = ntohl(th->seq);
- /* So reset is always called with th->seq in host order */
- tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ if (!dev)
+ {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n"));
return(0);
- }
+ }
+
+ th = skb->h.th;
+
+ /* Find the socket. */
+ sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
+ DPRINTF((DBG_TCP, "<<\n"));
+ DPRINTF((DBG_TCP, "len = %d, redo = %d, skb=%X\n", len, redo, skb));
+
+ /* If this socket has got a reset its to all intents and purposes
+ really dead */
+
+ if (sk!=NULL && sk->zapped)
+ sk=NULL;
+
+ if (sk)
+ {
+ DPRINTF((DBG_TCP, "sk = %X:\n", sk));
+ }
- skb->len = len;
- skb->sk = sk;
- skb->acked = 0;
- skb->used = 0;
- skb->free = 0;
- skb->urg_used = 0;
- skb->saddr = daddr;
- skb->daddr = saddr;
-
- th->seq = ntohl(th->seq);
-
- /* We may need to add it to the backlog here. */
- cli();
- if (sk->inuse) {
- if (sk->back_log == NULL) {
- sk->back_log = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- skb->next = sk->back_log;
- skb->prev = sk->back_log->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
+ if (!redo)
+ {
+ if (tcp_check(th, len, saddr, daddr ))
+ {
+ skb->sk = NULL;
+ DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n"));
+ if (inet_debug == DBG_SLIP)
+ printk("\rtcp_rcv: bad checksum\n");
+ kfree_skb(skb,FREE_READ);
+ /*
+ * We don't release the socket because it was
+ * never marked in use.
+ */
+ return(0);
}
- sti();
- return(0);
- }
- sk->inuse = 1;
- sti();
- } else {
- if (!sk) {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv bug sk=NULL redo = 1\n"));
- return(0);
- }
- }
-
- if (!sk->prot) {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv sk->prot = NULL \n"));
- return(0);
- }
-
- /* Charge the memory to the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
- skb->sk = NULL;
- DPRINTF((DBG_TCP, "dropping packet due to lack of buffer space.\n"));
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- sk->rmem_alloc += skb->mem_len;
-
- DPRINTF((DBG_TCP, "About to do switch.\n"));
-
- /* Now deal with it. */
- switch(sk->state) {
- /*
- * This should close the system down if it's waiting
- * for an ack that is never going to be sent.
- */
- case TCP_LAST_ACK:
- if (th->rst) {
- sk->zapped=1;
- sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead) {
- wake_up(sk->sleep);
+
+ /* See if we know about the socket. */
+ if (sk == NULL)
+ {
+ /*
+ * Segment to 'closed' socket [Page 65]
+ */
+ if (!th->rst)
+ {
+ th->seq = ntohl(th->seq);
+ /* So reset is always called with th->seq in host order */
+ tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
}
+ skb->sk = NULL;
kfree_skb(skb, FREE_READ);
- release_sock(sk);
return(0);
}
- case TCP_ESTABLISHED:
- case TCP_CLOSE_WAIT:
- case TCP_FIN_WAIT1:
- case TCP_FIN_WAIT2:
- case TCP_TIME_WAIT:
- if (!tcp_sequence(sk, th, len, opt, saddr)) {
-if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
- if(!th->rst)
- tcp_send_ack(sk->send_seq, sk->acked_seq,
- sk, th, saddr);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
+ skb->len = len;
+ skb->sk = sk;
+ skb->acked = 0;
+ skb->used = 0;
+ skb->free = 0;
+ skb->urg_used = 0;
+ skb->saddr = daddr;
+ skb->daddr = saddr;
+
+ th->seq = ntohl(th->seq);
+
+ /* We may need to add it to the backlog here. */
+ cli();
+ if (sk->inuse)
+ {
+ if (sk->back_log == NULL)
+ {
+ sk->back_log = skb;
+ skb->next = skb;
+ skb->prev = skb;
+ }
+ else
+ {
+ skb->next = sk->back_log;
+ skb->prev = sk->back_log->prev;
+ skb->prev->next = skb;
+ skb->next->prev = skb;
+ }
+ sti();
+ return(0);
+ }
+ sk->inuse = 1;
+ sti();
+ }
+ else
+ {
+ if (!sk)
+ {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv bug sk=NULL redo = 1\n"));
return(0);
}
+ }
- if (th->rst) {
- sk->zapped=1;
- /* This means the thing should really be closed. */
- sk->err = ECONNRESET;
+
+ if (!sk->prot)
+ {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv sk->prot = NULL \n"));
+ return(0);
+ }
- if (sk->state == TCP_CLOSE_WAIT) {
- sk->err = EPIPE;
+ /* Charge the memory to the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
+ {
+ skb->sk = NULL;
+ DPRINTF((DBG_TCP, "dropping packet due to lack of buffer space.\n"));
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ sk->rmem_alloc += skb->mem_len;
+
+ DPRINTF((DBG_TCP, "About to do switch.\n"));
+
+ /* Now deal with it. */
+
+ switch(sk->state)
+ {
+ /*
+ * This should close the system down if it's waiting
+ * for an ack that is never going to be sent.
+ *
+ * [Page 68]
+ */
+ case TCP_LAST_ACK:
+ if (th->rst)
+ {
+ sk->zapped=1;
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
}
- /*
- * A reset with a fin just means that
- * the data was not all read.
- */
-/* The comment above appears completely bogus --clh */
-/* if (!th->fin) { */
+ case TCP_ESTABLISHED:
+ case TCP_CLOSE_WAIT:
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_TIME_WAIT:
+ if (!tcp_sequence(sk, th, len, opt, saddr,dev))
+ {
+ if (inet_debug == DBG_SLIP)
+ printk("\rtcp_rcv: not in seq\n");
+ if(!th->rst)
+ tcp_send_ack(sk->send_seq, sk->acked_seq,
+ sk, th, saddr);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (th->rst)
+ {
+ sk->zapped=1;
+ /* This means the thing should really be closed. [Page 70] */
+ sk->err = ECONNRESET;
+
+ if (sk->state == TCP_CLOSE_WAIT)
+ {
+ sk->err = EPIPE;
+ }
+
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead) {
- wake_up(sk->sleep);
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
-/* } */
- }
-#if 0
- if (opt && (opt->security != 0 ||
- opt->compartment != 0 || th->syn)) {
- sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- if (!sk->dead) {
- wake_up(sk->sleep);
}
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-#endif
- if (th->ack) {
- if (!tcp_ack(sk, th, saddr, len)) {
+ /* [Page 71] - security options: We just say no thanks */
+ if (opt && (opt->security != 0 || opt->compartment != 0))
+ {
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
- }
- if (th->urg) {
- if (tcp_urg(sk, th, saddr)) {
+ if (th->syn)
+ {
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
- }
-
- if (th->fin && tcp_fin(sk, th, saddr, dev)) {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- if (tcp_data(skb, sk, saddr, len)) {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- release_sock(sk);
- return(0);
-
- case TCP_CLOSE:
- if (sk->dead || sk->daddr) {
- DPRINTF((DBG_TCP, "packet received for closed,dead socket\n"));
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- if (!th->rst) {
- if (!th->ack)
- th->ack_seq = 0;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
-
- case TCP_LISTEN:
- if (th->rst) {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- if (th->ack) {
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- if (th->syn) {
-#if 0
- if (opt->security != 0 || opt->compartment != 0) {
- tcp_reset(daddr, saddr, th, prot, opt,dev);
+
+ if (th->ack)
+ {
+ if (!tcp_ack(sk, th, saddr, len))
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ }
+ /* [Page 73] */
+ if (th->urg &&(sk->state==TCP_ESTABLISHED||sk->state==TCP_FIN_WAIT1||sk->state==TCP_FIN_WAIT2))
+ {
+ if (tcp_urg(sk, th, saddr))
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ }
+
+
+ /* [Page 74] */
+ if (tcp_data(skb, sk, saddr, len))
+ {
+ kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
-#endif
-
- /*
- * Now we just put the whole thing including
- * the header and saddr, and protocol pointer
- * into the buffer. We can't respond until the
- * user tells us to accept the connection.
- */
- tcp_conn_request(sk, skb, daddr, saddr, opt, dev);
- release_sock(sk);
- return(0);
- }
+ /* Move this below the data processing [Page 74/75] */
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
-
- default:
- if (!tcp_sequence(sk, th, len, opt, saddr)) {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- case TCP_SYN_SENT:
- if (th->rst) {
- sk->err = ECONNREFUSED;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- sk->zapped = 1;
- if (!sk->dead) {
- wake_up(sk->sleep);
+ if (th->fin && tcp_fin(sk, th, saddr, dev))
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
}
- kfree_skb(skb, FREE_READ);
+
release_sock(sk);
return(0);
- }
-#if 0
- if (opt->security != 0 || opt->compartment != 0) {
- sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
- if (!sk->dead) {
- wake_up(sk->sleep);
+
+ case TCP_CLOSE:
+ if (sk->dead || sk->daddr)
+ {
+ DPRINTF((DBG_TCP, "packet received for closed,dead socket\n"));
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
}
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-#endif
- if (!th->ack) {
- if (th->syn) {
- sk->state = TCP_SYN_RECV;
+
+ if (!th->rst)
+ {
+ if (!th->ack)
+ th->ack_seq = 0;
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
}
-
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
- }
- switch(sk->state) {
- case TCP_SYN_SENT:
- if (!tcp_ack(sk, th, saddr, len)) {
- tcp_reset(daddr, saddr, th,
- sk->prot, opt,dev);
- kfree_skb(skb, FREE_READ);
+ case TCP_LISTEN:
+ if (th->rst)
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ if (th->ack)
+ {
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (th->syn)
+ {
+ if (opt && (opt->security != 0 || opt->compartment != 0))
+ {
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
release_sock(sk);
return(0);
}
/*
- * If the syn bit is also set, switch to
- * tcp_syn_recv, and then to established.
+ * Now we just put the whole thing including
+ * the header and saddr, and protocol pointer
+ * into the buffer. We can't respond until the
+ * user tells us to accept the connection.
*/
- if (!th->syn) {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
+ tcp_conn_request(sk, skb, daddr, saddr, opt, dev);
+ release_sock(sk);
+ return(0);
+ }
+
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
- /* Ack the syn and fall through. */
- sk->acked_seq = th->seq+1;
- sk->fin_seq = th->seq;
- tcp_send_ack(sk->send_seq, th->seq+1,
- sk, th, sk->daddr);
+ default:
+ if (!tcp_sequence(sk, th, len, opt, saddr,dev))
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
- case TCP_SYN_RECV:
- if (!tcp_ack(sk, th, saddr, len)) {
- tcp_reset(daddr, saddr, th,
- sk->prot, opt, dev);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
+ case TCP_SYN_SENT:
+ if (th->rst)
+ {
+ sk->err = ECONNREFUSED;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->zapped = 1;
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
}
- sk->state = TCP_ESTABLISHED;
-
- /*
- * Now we need to finish filling out
- * some of the tcp header.
- */
- /* We need to check for mtu info. */
- tcp_options(sk, th);
- sk->dummy_th.dest = th->source;
- sk->copied_seq = sk->acked_seq-1;
- if (!sk->dead) {
- wake_up(sk->sleep);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ if (opt && (opt->security != 0 || opt->compartment != 0))
+ {
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ if (!th->ack)
+ {
+ if (th->syn)
+ {
+ sk->state = TCP_SYN_RECV;
}
+
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
- /*
- * Now process the rest like we were
- * already in the established state.
- */
- if (th->urg) {
- if (tcp_urg(sk, th, saddr)) {
+ switch(sk->state)
+ {
+ case TCP_SYN_SENT:
+ /* [Page 73] */
+ if (!tcp_ack(sk, th, saddr, len))
+ {
+ tcp_reset(daddr, saddr, th,
+ sk->prot, opt,dev);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
- }
- if (tcp_data(skb, sk, saddr, len))
+
+ /*
+ * If the syn bit is also set, switch to
+ * tcp_syn_recv, and then to established.
+ */
+ if (!th->syn)
+ {
kfree_skb(skb, FREE_READ);
-
- if (th->fin) tcp_fin(sk, th, saddr, dev);
- release_sock(sk);
- return(0);
- }
-
- if (th->urg) {
- if (tcp_urg(sk, th, saddr)) {
+ release_sock(sk);
+ return(0);
+ }
+
+ /* Ack the syn and fall through. */
+ sk->acked_seq = th->seq+1;
+ sk->fin_seq = th->seq;
+ tcp_send_ack(sk->send_seq, th->seq+1, sk, th, sk->daddr);
+
+ case TCP_SYN_RECV:
+ if (!tcp_ack(sk, th, saddr, len))
+ {
+ tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ sk->state = TCP_ESTABLISHED;
+
+ /*
+ * Now we need to finish filling out
+ * some of the tcp header.
+ */
+ /* We need to check for mtu info. */
+ tcp_options(sk, th);
+ sk->dummy_th.dest = th->source;
+ sk->copied_seq = sk->acked_seq-1;
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
+ }
+
+ /*
+ * Now process the rest like we were
+ * already in the established state.
+ */
+
+ if (th->urg)
+ {
+ if (tcp_urg(sk, th, saddr))
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ }
+ if (tcp_data(skb, sk, saddr, len))
+ kfree_skb(skb, FREE_READ);
+
+ if (th->fin)
+ tcp_fin(sk, th, saddr, dev);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (th->urg)
+ {
+ if (tcp_urg(sk, th, saddr))
+ {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ }
+
+ if (tcp_data(skb, sk, saddr, len))
+ {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
- }
-
- if (tcp_data(skb, sk, saddr, len)) {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- if (!th->fin) {
+ if (!th->fin)
+ {
+ release_sock(sk);
+ return(0);
+ }
+ tcp_fin(sk, th, saddr, dev);
release_sock(sk);
return(0);
- }
- tcp_fin(sk, th, saddr, dev);
- release_sock(sk);
- return(0);
}
}
-/*
- * This routine sends a packet with an out of date sequence
- * number. It assumes the other end will try to ack it.
+ /*
+ * This routine sends a packet with an out of date sequence
+ * number. It assumes the other end will try to ack it.
*/
-static void
-tcp_write_wakeup(struct sock *sk)
+
+static void tcp_write_wakeup(struct sock *sk)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- struct device *dev=NULL;
- int tmp;
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ struct device *dev=NULL;
+ int tmp;
+
+ if (sk->zapped)
+ return; /* Afer a valid reset we can send no more */
- if (sk->zapped)
- return; /* Afer a valid reset we can send no more */
+ if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
+ return;
- if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) return;
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+
+ if (buff == NULL)
+ return;
+
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_ACK_SIZE;
+ buff->len = sizeof(struct tcphdr);
+ buff->free = 1;
+ buff->sk = sk;
+ DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
+ t1 = (struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE, sk->ip_ttl,sk->ip_tos);
+ if (tmp < 0)
+ {
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ return;
+ }
- buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
- if (buff == NULL) return;
+ buff->len += tmp;
+ t1 = (struct tcphdr *)((char *)t1 +tmp);
+
+ memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
+
+ /*
+ * Use a previous sequence.
+ * This should cause the other end to send an ack.
+ */
+ t1->seq = ntohl(sk->send_seq-1);
+ t1->ack = 1;
+ t1->res1= 0;
+ t1->res2= 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->psh = 0;
+ t1->fin = 0;
+ t1->syn = 0;
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->window = ntohs(sk->prot->rspace(sk));
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+ /* Send it and free it.
+ * This will prevent the timer from automatically being restarted.
+ */
+ sk->prot->queue_xmit(sk, dev, buff, 1);
+}
- buff->mem_addr = buff;
- buff->mem_len = MAX_ACK_SIZE;
- buff->len = sizeof(struct tcphdr);
- buff->free = 1;
- buff->sk = sk;
- DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
- t1 = (struct tcphdr *)(buff + 1);
+/*
+ * Socket option code for TCP.
+ */
+
+int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+ int val,err;
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
- if (tmp < 0) {
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
+ if(level!=SOL_TCP)
+ return ip_setsockopt(sk,level,optname,optval,optlen);
- buff->len += tmp;
- t1 = (struct tcphdr *)((char *)t1 +tmp);
+ if (optval == NULL)
+ return(-EINVAL);
- memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
+ val = get_fs_long((unsigned long *)optval);
- /*
- * Use a previous sequence.
- * This should cause the other end to send an ack.
- */
- t1->seq = ntohl(sk->send_seq-1);
- t1->ack = 1;
- t1->res1= 0;
- t1->res2= 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->fin = 0;
- t1->syn = 0;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->prot->rspace(sk));
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- /* Send it and free it.
- * This will prevent the timer from automatically being restarted.
- */
- sk->prot->queue_xmit(sk, dev, buff, 1);
+ switch(optname)
+ {
+ case TCP_MSS:
+ if(val<200||val>2048)
+ return -EINVAL;
+ sk->mss=val;
+ return 0;
+ case TCP_NODELAY:
+ /* Ready for Johannes delayed ACK code */
+ return 0;
+ default:
+ return(-ENOPROTOOPT);
+ }
}
+int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+ int val,err;
+
+ if(level!=SOL_TCP)
+ return ip_getsockopt(sk,level,optname,optval,optlen);
+
+ switch(optname)
+ {
+ case TCP_MSS:
+ val=sk->mss;
+ break;
+ case TCP_NODELAY:
+ val=1; /* Until Johannes stuff is in */
+ break;
+ default:
+ return(-ENOPROTOOPT);
+ }
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(val,(unsigned long *)optval);
-struct proto tcp_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- tcp_close,
- tcp_read,
- tcp_write,
- tcp_sendto,
- tcp_recvfrom,
- ip_build_header,
- tcp_connect,
- tcp_accept,
- ip_queue_xmit,
- tcp_retransmit,
- tcp_write_wakeup,
- tcp_read_wakeup,
- tcp_rcv,
- tcp_select,
- tcp_ioctl,
- NULL,
- tcp_shutdown,
- 128,
- 0,
- {NULL,},
- "TCP"
+ return(0);
+}
+
+struct proto tcp_prot =
+{
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ tcp_close,
+ tcp_read,
+ tcp_write,
+ tcp_sendto,
+ tcp_recvfrom,
+ ip_build_header,
+ tcp_connect,
+ tcp_accept,
+ ip_queue_xmit,
+ tcp_retransmit,
+ tcp_write_wakeup,
+ tcp_read_wakeup,
+ tcp_rcv,
+ tcp_select,
+ tcp_ioctl,
+ NULL,
+ tcp_shutdown,
+ tcp_setsockopt,
+ tcp_getsockopt,
+ 128,
+ 0,
+ {NULL,},
+ "TCP"
};
diff --git a/net/inet/tcp.h b/net/inet/tcp.h
index cb051e4..9077dbf 100644
--- a/net/inet/tcp.h
+++ b/net/inet/tcp.h
@@ -75,43 +75,46 @@
* normal compare so long as neither of the numbers is within
* 4K of wrapping. Otherwise we must check for the wrap.
*/
-static inline int
-before (unsigned long seq1, unsigned long seq2)
+static inline int before (unsigned long seq1, unsigned long seq2)
{
- /* this inequality is strict. */
- if (seq1 == seq2) return(0);
-
- if (seq1 < seq2) {
- if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL) {
+ /* this inequality is strict. */
+ if (seq1 == seq2)
+ return(0);
+
+ if (seq1 < seq2)
+ {
+ if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL)
+ {
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+ }
+
+ /*
+ * Now we know seq1 > seq2. So all we need to do is check
+ * to see if seq1 has wrapped.
+ */
+ if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL))
+ {
return(1);
- } else {
- return(0);
- }
- }
-
- /*
- * Now we know seq1 > seq2. So all we need to do is check
- * to see if seq1 has wrapped.
- */
- if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL)) {
- return(1);
- }
- return(0);
+ }
+ return(0);
}
-static inline int
-after(unsigned long seq1, unsigned long seq2)
+static inline int after(unsigned long seq1, unsigned long seq2)
{
- return(before(seq2, seq1));
+ return(before(seq2, seq1));
}
/* is s2<=s1<=s3 ? */
-static inline int
-between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
+static inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
{
- return(after(seq1+1, seq2) && before(seq1, seq3+1));
+ return(after(seq1+1, seq2) && before(seq1, seq3+1));
}
@@ -121,12 +124,11 @@ between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
* convinced that this is the solution for the 'getpeername(2)'
* problem. Thanks to Stephen A. Wood <saw@cebaf.gov> -FvK
*/
-static inline const int
-tcp_connected(const int state)
+static inline const int tcp_connected(const int state)
{
- return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
- state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
- state == TCP_SYN_RECV);
+ return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
+ state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
+ state == TCP_SYN_RECV);
}
diff --git a/net/inet/timer.c b/net/inet/timer.c
index f6540a1..7cd66b5 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -5,7 +5,7 @@
*
* TIMER - implementation of software timers.
*
- * Version: @(#)timer.c 1.0.7 05/25/93
+ * Version: @(#)timer.c 1.28 22/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -24,6 +24,8 @@
* 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
@@ -41,188 +43,202 @@
#include <asm/system.h>
#include <linux/interrupt.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include "arp.h"
-void
-delete_timer (struct sock *t)
+void delete_timer (struct sock *t)
{
- unsigned long flags;
+ unsigned long flags;
- save_flags (flags);
- cli();
+ save_flags (flags);
+ cli();
- t->timeout = 0;
- del_timer (&t->timer);
+ t->timeout = 0;
+ del_timer (&t->timer);
- restore_flags (flags);
+ restore_flags (flags);
}
-void
-reset_timer (struct sock *t, int timeout, unsigned long len)
+void reset_timer (struct sock *t, int timeout, unsigned long len)
{
- delete_timer (t);
-
- if (timeout != -1)
- t->timeout = timeout;
+ delete_timer (t);
+ if (timeout != -1)
+ t->timeout = timeout;
#if 1
- /* FIXME: ??? */
- if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
- len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
+ /* FIXME: ??? */
+ if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
+ len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
#endif
- t->timer.expires = len;
- add_timer (&t->timer);
+ t->timer.expires = len;
+ add_timer (&t->timer);
}
/*
- * Now we will only be called whenever we need to do
- * something, but we must be sure to process all of the
- * sockets that need it.
+ * Now we will only be called whenever we need to do
+ * something, but we must be sure to process all of the
+ * sockets that need it.
*/
-void
-net_timer (unsigned long data)
+
+void net_timer (unsigned long data)
{
- struct sock *sk = (struct sock*)data;
- int why = sk->timeout;
- /* timeout is overwritten by 'delete_timer' and 'reset_timer' */
-
- if (sk->inuse || in_inet_bh()) {
- sk->timer.expires = 10;
- add_timer(&sk->timer);
- return;
- }
- sk->inuse = 1;
-
- DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why));
- if (sk->keepopen)
- reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
-
- /* Always see if we need to send an ack. */
- if (sk->ack_backlog) {
- sk->prot->read_wakeup (sk);
- if (! sk->dead)
- wake_up (sk->sleep);
- }
-
- /* Now we need to figure out why the socket was on the timer. */
- switch (why) {
- case TIME_DONE:
- if (! sk->dead || sk->state != TCP_CLOSE) {
- printk ("non dead socket in time_done\n");
- release_sock (sk);
- break;
- }
- destroy_sock (sk);
- break;
- case TIME_DESTROY:
- /* We've waited for a while for all the memory associated with
- * the socket to be freed. We need to print an error message.
- */
- if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
- {
- DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk));
- sk->wmem_alloc++; /* So it DOESNT go away */
- destroy_sock (sk);
- sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */
- sk->inuse = 0; /* This will be ok, the destroy won't totally work */
- }
- if(sk->wmem_alloc==0 && sk->rmem_alloc==0)
- destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */
- break;
- case TIME_CLOSE:
- /* We've waited long enough, close the socket. */
- sk->state = TCP_CLOSE;
- delete_timer (sk);
- /* Kill the ARP entry in case the hardware has changed. */
- arp_destroy (sk->daddr);
- if (!sk->dead)
- wake_up (sk->sleep);
- sk->shutdown = SHUTDOWN_MASK;
- reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME);
- release_sock (sk);
- break;
- case TIME_WRITE: /* try to retransmit. */
- /* It could be we got here because we needed to send an ack.
- * So we need to check for that.
- */
- if (sk->send_head) {
- if (jiffies < (sk->send_head->when + backoff (sk->backoff)
- * (2 * sk->mdev + sk->rtt))) {
- reset_timer (sk, TIME_WRITE, (sk->send_head->when
- + backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
- release_sock (sk);
- break;
- }
- /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq,
- sk->retransmits, sk->packets_out, sk->cong_window); */
- DPRINTF ((DBG_TMR, "retransmitting.\n"));
- sk->prot->retransmit (sk, 0);
- if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
- || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
- DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
- arp_destroy (sk->daddr);
- ip_route_check (sk->daddr);
- }
- if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
- DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n"));
- sk->err = ETIMEDOUT;
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2
- || sk->state == TCP_LAST_ACK) {
- sk->state = TCP_TIME_WAIT;
- reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- } else {
- sk->prot->close (sk, 1);
- break;
- }
- }
- }
- release_sock (sk);
- break;
- case TIME_KEEPOPEN:
- /* Send something to keep the connection open. */
- if (sk->prot->write_wakeup)
- sk->prot->write_wakeup (sk);
- sk->retransmits++;
- if (sk->shutdown == SHUTDOWN_MASK) {
- sk->prot->close (sk, 1);
- sk->state = TCP_CLOSE;
- }
-
- if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
- || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
- DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
- arp_destroy (sk->daddr);
- ip_route_check (sk->daddr);
- release_sock (sk);
- break;
- }
- if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
- DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
- arp_destroy (sk->daddr);
- sk->err = ETIMEDOUT;
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
- sk->state = TCP_TIME_WAIT;
- if (!sk->dead)
- wake_up (sk->sleep);
- release_sock (sk);
- } else {
- sk->prot->close (sk, 1);
- }
- break;
- }
- release_sock (sk);
- break;
- default:
- printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk);
- release_sock (sk);
- break;
- }
+ struct sock *sk = (struct sock*)data;
+ int why = sk->timeout;
+ /* timeout is overwritten by 'delete_timer' and 'reset_timer' */
+
+ if (sk->inuse || in_inet_bh())
+ {
+ sk->timer.expires = 10;
+ add_timer(&sk->timer);
+ return;
+ }
+ sk->inuse = 1;
+
+ DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why));
+ if (sk->keepopen)
+ reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+
+ /* Always see if we need to send an ack. */
+ if (sk->ack_backlog)
+ {
+ sk->prot->read_wakeup (sk);
+ if (! sk->dead)
+ wake_up (sk->sleep);
+ }
+
+ /* Now we need to figure out why the socket was on the timer. */
+ switch (why)
+ {
+ case TIME_DONE:
+ if (! sk->dead || sk->state != TCP_CLOSE)
+ {
+ printk ("non dead socket in time_done\n");
+ release_sock (sk);
+ break;
+ }
+ destroy_sock (sk);
+ break;
+ case TIME_DESTROY:
+ /* We've waited for a while for all the memory associated with
+ * the socket to be freed. We need to print an error message.
+ */
+ if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
+ {
+ DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk));
+ sk->wmem_alloc++; /* So it DOESNT go away */
+ destroy_sock (sk);
+ sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */
+ sk->inuse = 0; /* This will be ok, the destroy won't totally work */
+ }
+ if(sk->wmem_alloc==0 && sk->rmem_alloc==0)
+ destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */
+ break;
+ case TIME_CLOSE:
+ /* We've waited long enough, close the socket. */
+ sk->state = TCP_CLOSE;
+ delete_timer (sk);
+ /* Kill the ARP entry in case the hardware has changed. */
+ arp_destroy_maybe (sk->daddr);
+ if (!sk->dead)
+ wake_up (sk->sleep);
+ sk->shutdown = SHUTDOWN_MASK;
+ reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME);
+ release_sock (sk);
+ break;
+ case TIME_WRITE: /* try to retransmit. */
+ /* It could be we got here because we needed to send an ack.
+ * So we need to check for that.
+ */
+ if (sk->send_head)
+ {
+ if (jiffies < (sk->send_head->when + backoff (sk->backoff)
+ * (2 * sk->mdev + sk->rtt)))
+ {
+ reset_timer (sk, TIME_WRITE, (sk->send_head->when
+ + backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
+ release_sock (sk);
+ break;
+ }
+ /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq,
+ sk->retransmits, sk->packets_out, sk->cong_window); */
+ DPRINTF ((DBG_TMR, "retransmitting.\n"));
+ sk->prot->retransmit (sk, 0);
+ if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
+ || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
+ {
+ DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
+ arp_destroy_maybe (sk->daddr);
+ ip_route_check (sk->daddr);
+ }
+ if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2)
+ {
+ DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n"));
+ sk->err = ETIMEDOUT;
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2
+ || sk->state == TCP_LAST_ACK)
+ {
+ sk->state = TCP_TIME_WAIT;
+ reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ }
+ else
+ {
+ sk->prot->close (sk, 1);
+ break;
+ }
+ }
+ }
+ release_sock (sk);
+ break;
+ case TIME_KEEPOPEN:
+ /* Send something to keep the connection open. */
+ if (sk->prot->write_wakeup)
+ sk->prot->write_wakeup (sk);
+ sk->retransmits++;
+ if (sk->shutdown == SHUTDOWN_MASK)
+ {
+ sk->prot->close (sk, 1);
+ sk->state = TCP_CLOSE;
+ }
+
+ if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
+ || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
+ {
+ DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
+ arp_destroy_maybe (sk->daddr);
+ ip_route_check (sk->daddr);
+ release_sock (sk);
+ break;
+ }
+ if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2)
+ {
+ DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
+ arp_destroy_maybe (sk->daddr);
+ sk->err = ETIMEDOUT;
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2)
+ {
+ sk->state = TCP_TIME_WAIT;
+ if (!sk->dead)
+ wake_up (sk->sleep);
+ release_sock (sk);
+ }
+ else
+ {
+ sk->prot->close (sk, 1);
+ }
+ break;
+ }
+ release_sock (sk);
+ break;
+ default:
+ printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk);
+ release_sock (sk);
+ break;
+ }
}
diff --git a/net/inet/udp.c b/net/inet/udp.c
index 78066c3..33d2b38 100644
--- a/net/inet/udp.c
+++ b/net/inet/udp.c
@@ -5,7 +5,7 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: @(#)udp.c 1.0.13 06/02/93
+ * Version: @(#)udp.c 1.28 22/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -30,10 +30,11 @@
* bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram
+ * Alan Cox : 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
@@ -54,12 +55,12 @@
#include <linux/termios.h>
#include <linux/mm.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sock.h"
+#include "sockinet.h"
#include "udp.h"
#include "icmp.h"
@@ -67,17 +68,18 @@
#define min(a,b) ((a)<(b)?(a):(b))
-static void
-print_udp(struct udphdr *uh)
+static void print_udp(struct udphdr *uh)
{
- if (inet_debug != DBG_UDP) return;
-
- if (uh == NULL) {
- printk("(NULL)\n");
- return;
- }
- printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest));
- printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check));
+ if (inet_debug != DBG_UDP)
+ return;
+
+ if (uh == NULL)
+ {
+ printk("(NULL)\n");
+ return;
+ }
+ printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest));
+ printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check));
}
@@ -91,285 +93,289 @@ print_udp(struct udphdr *uh)
* header points to the first 8 bytes of the udp header. We need
* to find the appropriate port.
*/
-void
-udp_err(int err, unsigned char *header, unsigned long daddr,
+
+void udp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
- struct udphdr *th;
- struct sock *sk;
- struct iphdr *ip=(struct iphdr *)header;
-
- header += 4*ip->ihl;
-
- th = (struct udphdr *)header;
-
- DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
-sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
+ struct udphdr *th;
+ struct sock *sk;
+ struct iphdr *ip=(struct iphdr *)header;
- sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
+ header += 4*ip->ihl;
- if (sk == NULL)
- return; /* No socket for error */
+ th = (struct udphdr *)header;
+
+ DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
+ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
+
+ sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
+
+ if (sk == NULL)
+ return; /* No socket for error */
- if (err < 0) /* As per the calling spec */
- {
- sk->err = -err;
- wake_up(sk->sleep); /* User process wakes to see error */
- return;
- }
+ if (err < 0) /* As per the calling spec */
+ {
+ sk->err = -err;
+ sk->error_report(sk); /* User process wakes to see error */
+ return;
+ }
- if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */
- if (sk->cong_window > 1)
- sk->cong_window = sk->cong_window/2;
- return;
- }
-
- sk->err = icmp_err_convert[err & 0xff].errno;
-
- /* It's only fatal if we have connected to them. */
- if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
- sk->err=ECONNREFUSED;
- }
- wake_up(sk->sleep);
+ if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8))
+ { /* Slow down! */
+ if (sk->cong_window > 1)
+ sk->cong_window = sk->cong_window/2;
+ return;
+ }
+
+ sk->err = icmp_err_convert[err & 0xff].errno;
+
+ /* It's only fatal if we have connected to them. */
+ if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED)
+ {
+ sk->err=ECONNREFUSED;
+ }
+ sk->error_report(sk);
}
-static unsigned short
-udp_check(struct udphdr *uh, int len,
+static unsigned short udp_check(struct udphdr *uh, int len,
unsigned long saddr, unsigned long daddr)
{
- unsigned long sum;
+ unsigned long sum;
- DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n",
+ DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n",
uh, len, saddr, daddr));
- print_udp(uh);
-
- __asm__("\t addl %%ecx,%%ebx\n"
- "\t adcl %%edx,%%ebx\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum)
- : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
- : "cx","bx","dx" );
-
- if (len > 3) {
- __asm__("\tclc\n"
- "1:\n"
- "\t lodsl\n"
- "\t adcl %%eax, %%ebx\n"
- "\t loop 1b\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum) , "=S"(uh)
- : "0"(sum), "c"(len/4) ,"1"(uh)
- : "ax", "cx", "bx", "si" );
- }
-
- /* Convert from 32 bits to 16 bits. */
- __asm__("\t movl %%ebx, %%ecx\n"
- "\t shrl $16,%%ecx\n"
- "\t addw %%cx, %%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum)
- : "bx", "cx");
-
- /* Check for an extra word. */
- if ((len & 2) != 0) {
- __asm__("\t lodsw\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum), "=S"(uh)
- : "0"(sum) ,"1"(uh)
- : "si", "ax", "bx");
- }
-
- /* Now check for the extra byte. */
- if ((len & 1) != 0) {
- __asm__("\t lodsb\n"
- "\t movb $0,%%ah\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum) ,"S"(uh)
- : "si", "ax", "bx");
- }
-
- /* We only want the bottom 16 bits, but we never cleared the top 16. */
- return((~sum) & 0xffff);
+ print_udp(uh);
+
+ __asm__("\t addl %%ecx,%%ebx\n"
+ "\t adcl %%edx,%%ebx\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum)
+ : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
+ : "cx","bx","dx" );
+
+ if (len > 3)
+ {
+ __asm__("\tclc\n"
+ "1:\n"
+ "\t lodsl\n"
+ "\t adcl %%eax, %%ebx\n"
+ "\t loop 1b\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum) , "=S"(uh)
+ : "0"(sum), "c"(len/4) ,"1"(uh)
+ : "ax", "cx", "bx", "si" );
+ }
+
+ /* Convert from 32 bits to 16 bits. */
+ __asm__("\t movl %%ebx, %%ecx\n"
+ "\t shrl $16,%%ecx\n"
+ "\t addw %%cx, %%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum)
+ : "bx", "cx");
+
+ /* Check for an extra word. */
+ if ((len & 2) != 0)
+ {
+ __asm__("\t lodsw\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum), "=S"(uh)
+ : "0"(sum) ,"1"(uh)
+ : "si", "ax", "bx");
+ }
+
+ /* Now check for the extra byte. */
+ if ((len & 1) != 0)
+ {
+ __asm__("\t lodsb\n"
+ "\t movb $0,%%ah\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum) ,"S"(uh)
+ : "si", "ax", "bx");
+ }
+
+ /* We only want the bottom 16 bits, but we never cleared the top 16. */
+ return((~sum) & 0xffff);
}
+/*
+ * Calculate the UDP checksum. Note 0 becomes FFFF because 0 means
+ * 'no checksum'.
+ */
-static void
-udp_send_check(struct udphdr *uh, unsigned long saddr,
+static void udp_send_check(struct udphdr *uh, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
- uh->check = 0;
- if (sk && sk->no_check)
- return;
- uh->check = udp_check(uh, len, saddr, daddr);
- if (uh->check == 0) uh->check = 0xffff;
+ uh->check = 0;
+ if (sk && sk->no_check)
+ return;
+ uh->check = udp_check(uh, len, saddr, daddr);
+ if (uh->check == 0)
+ uh->check = 0xffff;
}
-static int
-udp_send(struct sock *sk, struct sockaddr_in *sin,
+static int udp_send(struct sock *sk, struct sockaddr_in *sin,
unsigned char *from, int len)
{
- struct sk_buff *skb;
- struct device *dev;
- struct udphdr *uh;
- unsigned char *buff;
- unsigned long saddr;
- int size, tmp;
- int err;
+ struct sk_buff *skb;
+ struct device *dev;
+ struct udphdr *uh;
+ unsigned char *buff;
+ unsigned long saddr;
+ int size, tmp;
+ int err;
- DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
+ DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),
from, len));
- err=verify_area(VERIFY_READ, from, len);
- if(err)
- return(err);
-
- /* Allocate a copy of the packet. */
- size = sizeof(struct sk_buff) + sk->prot->max_header + len;
- skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
- if (skb == NULL) return(-ENOMEM);
-
- skb->mem_addr = skb;
- skb->mem_len = size;
- skb->sk = NULL; /* to avoid changing sk->saddr */
- skb->free = 1;
- skb->arp = 0;
-
- /* Now build the IP and MAC header. */
- buff = (unsigned char *) (skb+1);
- saddr = 0;
- dev = NULL;
- DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
+ err=verify_area(VERIFY_READ, from, len);
+ if(err)
+ return(err);
+
+ /* Allocate a copy of the packet. */
+ size = sizeof(struct sk_buff) + sk->prot->max_header + len;
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
+ if (skb == NULL)
+ return(-ENOMEM);
+
+ skb->sk = NULL; /* to avoid changing sk->saddr */
+ skb->free = 1;
+ skb->arp = 0;
+
+ /* Now build the IP and MAC header. */
+ buff = (unsigned char *) (skb+1);
+ saddr = 0;
+ dev = NULL;
+ DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
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);
- skb->sk=sk; /* So memory is freed correctly */
+ tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
+ &dev, IPPROTO_UDP, sk->opt, skb->mem_len,
+ sk->ip_ttl,sk->ip_tos);
+ skb->sk=sk; /* So memory is freed correctly */
- if (tmp < 0 ) {
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(tmp);
- }
- buff += tmp;
- saddr = dev->pa_addr;
- DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp));
-
- skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
- skb->dev = dev;
-#ifdef OLD
- /*
- * This code used to hack in some form of fragmentation.
- * I removed that, since it didn't work anyway, and it made the
- * code a bad thing to read and understand. -FvK
- */
- if (len > dev->mtu) {
-#else
- if (skb->len > 4095)
- {
-#endif
- printk("UDP: send: length %d > mtu %d (ignored)\n", len, dev->mtu);
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(-EMSGSIZE);
- }
-
- /* Fill in the UDP header. */
- uh = (struct udphdr *) buff;
- uh->len = htons(len + sizeof(struct udphdr));
- uh->source = sk->dummy_th.source;
- uh->dest = sin->sin_port;
- buff = (unsigned char *) (uh + 1);
-
- /* Copy the user data. */
- memcpy_fromfs(buff, from, len);
-
- /* Set up the UDP checksum. */
- udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
-
- /* Send the datagram to the interface. */
- sk->prot->queue_xmit(sk, dev, skb, 1);
-
- return(len);
+ if (tmp < 0 )
+ {
+ sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ return(tmp);
+ }
+ buff += tmp;
+ saddr = dev->pa_addr;
+ DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp));
+
+ skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
+ skb->dev = dev;
+ if (skb->len > 4095)
+ {
+ printk("UDP: send: length %d > mtu %d (ignored)\n", len, 4095);
+ sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ return(-EMSGSIZE);
+ }
+
+ /* Fill in the UDP header. */
+ uh = (struct udphdr *) buff;
+ uh->len = htons(len + sizeof(struct udphdr));
+ uh->source = sk->dummy_th.source;
+ uh->dest = sin->sin_port;
+ buff = (unsigned char *) (uh + 1);
+
+ /* Copy the user data. */
+ memcpy_fromfs(buff, from, len);
+
+ /* Set up the UDP checksum. */
+ udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
+
+ /* Send the datagram to the interface. */
+ sk->prot->queue_xmit(sk, dev, skb, 1);
+
+ return(len);
}
-static int
-udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
+static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
- struct sockaddr_in sin;
- int tmp;
- int err;
-
- DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
-
- /* Check the flags. */
- if (flags)
- return(-EINVAL);
- if (len < 0)
- return(-EINVAL);
- if (len == 0)
- return(0);
-
- /* Get and verify the address. */
- if (usin) {
- if (addr_len < sizeof(sin)) return(-EINVAL);
- err=verify_area(VERIFY_READ, usin, sizeof(sin));
- if(err)
- return err;
- memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EINVAL);
- if (sin.sin_port == 0)
- return(-EINVAL);
- } else {
- if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->dummy_th.dest;
- sin.sin_addr.s_addr = sk->daddr;
- }
+ struct sockaddr_in sin;
+ int tmp;
+ int err;
+
+ DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
+
+ /* Check the flags. */
+ if (flags)
+ return(-EINVAL);
+ if (len < 0)
+ return(-EINVAL);
+ if (len == 0)
+ return(0);
+
+ /* Get and verify the address. */
+ if (usin)
+ {
+ if (addr_len < sizeof(sin))
+ return(-EINVAL);
+ err=verify_area(VERIFY_READ, usin, sizeof(sin));
+ if(err)
+ return err;
+ memcpy_fromfs(&sin, usin, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EINVAL);
+ if (sin.sin_port == 0)
+ return(-EINVAL);
+ }
+ else
+ {
+ if (sk->state != TCP_ESTABLISHED)
+ return(-EINVAL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = sk->dummy_th.dest;
+ sin.sin_addr.s_addr = sk->daddr;
+ }
- if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -ENETUNREACH; /* Must turn broadcast on first */
- sk->inuse = 1;
+ if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -EACCES; /* Must turn broadcast on first */
+ sk->inuse = 1;
- /* Send the packet. */
- tmp = udp_send(sk, &sin, from, len);
+ /* Send the packet. */
+ tmp = udp_send(sk, &sin, from, len);
- /* The datagram has been sent off. Release the socket. */
- release_sock(sk);
- return(tmp);
+ /* The datagram has been sent off. Release the socket. */
+ release_sock(sk);
+ return(tmp);
}
-static int
-udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
+static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
+ return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
-int
-udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- int err;
- switch(cmd) {
- case DDIOCSDBG:
+ int err;
+ switch(cmd)
+ {
+ case DDIOCSDBG:
{
int val;
- if (!suser()) return(-EPERM);
+ if (!suser())
+ return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err)
return err;
val = get_fs_long((int *)arg);
- switch(val) {
+ switch(val)
+ {
case 0:
inet_debug = 0;
break;
@@ -381,12 +387,14 @@ udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
}
break;
- case TIOCOUTQ:
+
+ case TIOCOUTQ:
{
unsigned long amount;
- if (sk->state == TCP_LISTEN) return(-EINVAL);
- amount = sk->prot->wspace(sk)/*/2*/;
+ if (sk->state == TCP_LISTEN)
+ return(-EINVAL);
+ amount = sk->prot->wspace(sk);
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
if(err)
@@ -395,15 +403,17 @@ udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
return(0);
}
- case TIOCINQ:
+ case TIOCINQ:
{
struct sk_buff *skb;
unsigned long amount;
- if (sk->state == TCP_LISTEN) return(-EINVAL);
+ if (sk->state == TCP_LISTEN)
+ return(-EINVAL);
amount = 0;
skb = sk->rqueue;
- if (skb != NULL) {
+ if (skb != NULL)
+ {
/*
* We will only return the amount
* of this packet since that is all
@@ -419,224 +429,233 @@ udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
return(0);
}
- default:
- return(-EINVAL);
- }
- return(0);
+ default:
+ return(-EINVAL);
+ }
+ return(0);
}
/*
- * This should be easy, if there is something there we\
+ * This should be easy, if there is something there we
* return it, otherwise we block.
*/
-int
-udp_recvfrom(struct sock *sk, unsigned char *to, int len,
+int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
- int copied = 0;
- struct sk_buff *skb;
- int er;
-
-
- /*
- * This will pick up errors that occured while the program
- * was doing something else.
- */
- if (sk->err) {
- int err;
-
- err = -sk->err;
- sk->err = 0;
- return(err);
- }
+ int copied = 0;
+ struct sk_buff *skb;
+ int er;
+
+
+ /*
+ * This will pick up errors that occured while the program
+ * was doing something else.
+ */
+ if (sk->err)
+ {
+ int err;
+
+ err = -sk->err;
+ sk->err = 0;
+ return(err);
+ }
- if (len == 0)
- return(0);
- if (len < 0)
- return(-EINVAL);
-
- if (addr_len) {
- er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
- if(er)
- return(er);
- put_fs_long(sizeof(*sin), addr_len);
- }
- if(sin)
- {
- er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+ if (len == 0)
+ return(0);
+ if (len < 0)
+ return(-EINVAL);
+
+ if (addr_len)
+ {
+ er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(er)
+ return(er);
+ put_fs_long(sizeof(*sin), addr_len);
+ }
+ if(sin)
+ {
+ er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+ if(er)
+ return(er);
+ }
+ er=verify_area(VERIFY_WRITE,to,len);
if(er)
- return(er);
- }
- er=verify_area(VERIFY_WRITE,to,len);
- if(er)
- return er;
- skb=skb_recv_datagram(sk,flags,noblock,&er);
- if(skb==NULL)
- return er;
- copied = min(len, skb->len);
-
+ return er;
+ skb=skb_recv_datagram(sk,flags,noblock,&er);
+ if(skb==NULL)
+ return er;
+ copied = min(len, skb->len);
+
/* FIXME : should use udp header size info value */
- skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
+ skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
/* Copy the address. */
- if (sin) {
- struct sockaddr_in addr;
-
- addr.sin_family = AF_INET;
- addr.sin_port = skb->h.uh->source;
- addr.sin_addr.s_addr = skb->daddr;
- memcpy_tofs(sin, &addr, sizeof(*sin));
- }
+ if (sin)
+ {
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = skb->h.uh->source;
+ addr.sin_addr.s_addr = skb->daddr;
+ memcpy_tofs(sin, &addr, sizeof(*sin));
+ }
- skb_free_datagram(skb);
- release_sock(sk);
- return(copied);
+ skb_free_datagram(skb);
+ release_sock(sk);
+ return(copied);
}
-int
-udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
+int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
+ return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
-int
-udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
+int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{
- struct sockaddr_in sin;
- int er;
+ struct sockaddr_in sin;
+ int er;
- if (addr_len < sizeof(sin))
- return(-EINVAL);
+ if (addr_len < sizeof(sin))
+ return(-EINVAL);
- er=verify_area(VERIFY_READ, usin, sizeof(sin));
- if(er)
- return er;
+ er=verify_area(VERIFY_READ, usin, sizeof(sin));
+ if(er)
+ return er;
- memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EAFNOSUPPORT);
+ memcpy_fromfs(&sin, usin, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EAFNOSUPPORT);
- if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -ENETUNREACH; /* Must turn broadcast on first */
+ if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -EACCES; /* Must turn broadcast on first */
- sk->daddr = sin.sin_addr.s_addr;
- sk->dummy_th.dest = sin.sin_port;
- sk->state = TCP_ESTABLISHED;
- return(0);
+ sk->daddr = sin.sin_addr.s_addr;
+ sk->dummy_th.dest = sin.sin_port;
+ sk->state = TCP_ESTABLISHED;
+ return(0);
}
-static void
-udp_close(struct sock *sk, int timeout)
+static void udp_close(struct sock *sk, int timeout)
{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
- if (sk->dead) destroy_sock(sk);
- else release_sock(sk);
+ sk->inuse = 1;
+ sk->state = TCP_CLOSE;
+ if (sk->dead)
+ destroy_sock(sk);
+ else
+ release_sock(sk);
}
-/* All we need to do is get the socket, and then do a checksum. */
-int
-udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+/*
+ * All we need to do is get the socket, and then do a checksum.
+ */
+
+int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
- struct sock *sk;
- struct udphdr *uh;
-
- uh = (struct udphdr *) skb->h.uh;
- sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
- if (sk == NULL)
- {
- if (chk_addr(daddr) == IS_MYADDR)
- {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
+ struct sock *sk;
+ struct udphdr *uh;
+
+ uh = (struct udphdr *) skb->h.uh;
+ sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
+ if (sk == NULL)
+ {
+ if (chk_addr(daddr) == IS_MYADDR)
+ {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
+ }
+ /*
+ * Hmm. We got an UDP broadcast to a port to which we
+ * don't wanna listen. The only thing we can do now is
+ * to ignore the packet... -FvK
+ */
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
}
- /*
- * Hmm. We got an UDP broadcast to a port to which we
- * don't wanna listen. The only thing we can do now is
- * to ignore the packet... -FvK
- */
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- if (uh->check && udp_check(uh, len, saddr, daddr)) {
- DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- skb->sk = sk;
- skb->dev = dev;
- skb->len = len;
-
-/* These are supposed to be switched. */
- skb->daddr = saddr;
- skb->saddr = daddr;
-
-
- /* Charge it to the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- release_sock(sk);
- return(0);
- }
- sk->rmem_alloc += skb->mem_len;
- /* At this point we should print the thing out. */
- DPRINTF((DBG_UDP, "<< \n"));
- print_udp(uh);
+ if (uh->check && udp_check(uh, len, saddr, daddr))
+ {
+ DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+
+ skb->sk = sk;
+ skb->dev = dev;
+ skb->len = len;
+
+ /* These are supposed to be switched. */
+ skb->daddr = saddr;
+ skb->saddr = daddr;
+
+
+ /* Charge it to the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ release_sock(sk);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
+
+ /* At this point we should print the thing out. */
+ DPRINTF((DBG_UDP, "<< \n"));
+ print_udp(uh);
- /* Now add it to the data chain and wake things up. */
+ /* Now add it to the data chain and wake things up. */
- skb_queue_tail(&sk->rqueue,skb);
+ skb_queue_tail(&sk->rqueue,skb);
- skb->len = len - sizeof(*uh);
+ skb->len = len - sizeof(*uh);
- if (!sk->dead) wake_up(sk->sleep);
+ release_sock(sk);
- release_sock(sk);
- return(0);
+ if (!sk->dead)
+ sk->data_ready(sk,skb->len);
+
+ return(0);
}
-struct proto udp_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- udp_close,
- udp_read,
- udp_write,
- udp_sendto,
- udp_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- ip_retransmit,
- NULL,
- NULL,
- udp_rcv,
- datagram_select,
- udp_ioctl,
- NULL,
- NULL,
- 128,
- 0,
- {NULL,},
- "UDP"
+struct proto udp_prot =
+{
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ udp_close,
+ udp_read,
+ udp_write,
+ udp_sendto,
+ udp_recvfrom,
+ ip_build_header,
+ udp_connect,
+ NULL,
+ ip_queue_xmit,
+ ip_retransmit,
+ NULL,
+ NULL,
+ udp_rcv,
+ datagram_select,
+ udp_ioctl,
+ NULL,
+ NULL,
+ ip_setsockopt,
+ ip_getsockopt,
+ 128,
+ 0,
+ {NULL,},
+ "UDP"
};
diff --git a/net/inet/utils.c b/net/inet/utils.c
index f9e81e3..821fbe8 100644
--- a/net/inet/utils.c
+++ b/net/inet/utils.c
@@ -6,12 +6,13 @@
* Various kernel-resident INET utility functions; mainly
* for format conversion and debugging output.
*
- * Version: @(#)utils.c 1.0.7 05/18/93
+ * Version: @(#)utils.c 1.28 20/12/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
@@ -32,7 +33,7 @@
#include <linux/stat.h>
#include <stdarg.h>
#include "inet.h"
-#include "dev.h"
+#include "devinet.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
@@ -41,107 +42,118 @@
#include "arp.h"
-/* Display an IP address in readable format. */
+/*
+ * Display an IP address in readable format.
+ */
+
char *in_ntoa(unsigned long in)
{
- static char buff[18];
- register char *p;
+ static char buff[18];
+ register char *p;
- p = (char *) &in;
- sprintf(buff, "%d.%d.%d.%d",
- (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
- return(buff);
+ p = (char *) &in;
+ sprintf(buff, "%d.%d.%d.%d",
+ (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
+ return(buff);
}
-/* Convert an ASCII string to binary IP. */
-unsigned long
-in_aton(char *str)
+/*
+ * Convert an ASCII string to binary IP.
+ */
+
+unsigned long in_aton(char *str)
{
- unsigned long l;
- unsigned int val;
- int i;
-
- l = 0;
- for (i = 0; i < 4; i++) {
- l <<= 8;
- if (*str != '\0') {
- val = 0;
- while (*str != '\0' && *str != '.') {
- val *= 10;
- val += *str - '0';
- str++;
+ unsigned long l;
+ unsigned int val;
+ int i;
+
+ l = 0;
+ for (i = 0; i < 4; i++)
+ {
+ l <<= 8;
+ if (*str != '\0')
+ {
+ val = 0;
+ while (*str != '\0' && *str != '.')
+ {
+ val *= 10;
+ val += *str - '0';
+ str++;
+ }
+ l |= val;
+ if (*str != '\0')
+ str++;
}
- l |= val;
- if (*str != '\0') str++;
- }
- }
- return(htonl(l));
+ }
+ return(htonl(l));
}
-void
-dprintf(int level, char *fmt, ...)
+void dprintf(int level, char *fmt, ...)
{
- va_list args;
- char *buff;
- extern int vsprintf(char * buf, const char * fmt, va_list args);
-
- if (level != inet_debug) return;
-
- buff = (char *) kmalloc(256, GFP_ATOMIC);
- if (buff != NULL) {
- va_start(args, fmt);
- vsprintf(buff, fmt, args);
- va_end(args);
- printk(buff);
- kfree(buff);
- }
+ va_list args;
+ char *buff;
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+ if (level != inet_debug)
+ return;
+
+ buff = (char *) kmalloc(256, GFP_ATOMIC);
+ if (buff != NULL)
+ {
+ va_start(args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end(args);
+ printk(buff);
+ kfree(buff);
+ }
}
-int
-dbg_ioctl(void *arg, int level)
+int dbg_ioctl(void *arg, int level)
{
- int val;
- int err;
+ int val;
+ int err;
- if (!suser()) return(-EPERM);
- err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
- if(err)
- return err;
- val = get_fs_long((int *)arg);
- switch(val) {
- case 0: /* OFF */
- inet_debug = DBG_OFF;
- break;
- case 1: /* ON, INET */
- inet_debug = level;
- break;
-
- case DBG_RT: /* modules */
- case DBG_DEV:
- case DBG_ETH:
- case DBG_PROTO:
- case DBG_TMR:
- case DBG_PKT:
- case DBG_RAW:
-
- case DBG_LOOPB: /* drivers */
- case DBG_SLIP:
-
- case DBG_ARP: /* protocols */
- case DBG_IP:
- case DBG_ICMP:
- case DBG_TCP:
- case DBG_UDP:
-
- inet_debug = val;
- break;
-
- default:
- return(-EINVAL);
- }
-
- return(0);
+ if (!suser())
+ return(-EPERM);
+ err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
+ if(err)
+ return err;
+ val = get_fs_long((int *)arg);
+ switch(val)
+ {
+ case 0: /* OFF */
+ inet_debug = DBG_OFF;
+ break;
+ case 1: /* ON, INET */
+ inet_debug = level;
+ break;
+
+ case DBG_RT: /* modules */
+ case DBG_DEV:
+ case DBG_ETH:
+ case DBG_PROTO:
+ case DBG_TMR:
+ case DBG_PKT:
+ case DBG_RAW:
+
+ case DBG_LOOPB: /* drivers */
+ case DBG_SLIP:
+
+ case DBG_ARP: /* protocols */
+ case DBG_IP:
+ case DBG_ICMP:
+ case DBG_TCP:
+ case DBG_UDP:
+
+ inet_debug = val;
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+
+ return(0);
}
diff --git a/net/socket/Makefile b/net/socket/Makefile
new file mode 100644
index 0000000..b3d5b42
--- /dev/null
+++ b/net/socket/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for the Linux socket support layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+CFLAGS := $(CFLAGS) -I../inet -I..
+CPP := $(CPP) -I../inet -I..
+
+.c.o:
+ $(CC) $(CFLAGS) -c -o $*.o $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.s:
+ $(CC) $(CFLAGS) -S -o $*.s $<
+
+
+OBJS = datagram.o dev.o skbuff.o sock.o
+
+socket.o: $(OBJS)
+ $(LD) -r -o socket.o $(OBJS)
+
+dep:
+ $(CPP) -M *.c > .depend
+
+tar:
+ tar -cvf /dev/f1 .
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/net/socket/datagram.c b/net/socket/datagram.c
new file mode 100644
index 0000000..b7ebe91
--- /dev/null
+++ b/net/socket/datagram.c
@@ -0,0 +1,213 @@
+/*
+ * SUCS NET2 Debugged.
+ *
+ * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
+ * of these would make sense. Not tonight however 8-).
+ * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
+ * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
+ *
+ * Fixes:
+ * Alan Cox : NULL return from skb_peek_copy() understood
+ * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
+ * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
+ * AX.25 now works right, and SPX is feasible.
+ * Alan Cox : Tidied up ready for the big day.
+ * Alan Cox : Fixed write select of no IP protocol crash.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+
+
+/*
+ * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
+ * races. This replaces identical code in packet,raw and udp, as well as the yet to
+ * be released IPX support. It also finally fixes the long standing peek and read
+ * race for datagram sockets. If you alter this routine remember it must be
+ * re-entrant.
+ */
+
+struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
+{
+ struct sk_buff *skb;
+
+ /* Socket is inuse - so the timer doesn't attack it */
+restart:
+ sk->inuse = 1;
+ while(sk->rqueue == NULL) /* No data */
+ {
+ /* If we are shutdown then no more data is going to appear. We are done */
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ release_sock(sk);
+ *err=0;
+ return NULL;
+ }
+
+ if(sk->err)
+ {
+ release_sock(sk);
+ *err=-sk->err;
+ sk->err=0;
+ return NULL;
+ }
+
+ /* Sequenced packets can come disconnected. If so we report the problem */
+ if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
+ {
+ release_sock(sk);
+ *err=-ENOTCONN;
+ return NULL;
+ }
+
+ /* User doesn't want to wait */
+ if (noblock)
+ {
+ release_sock(sk);
+ *err=-EAGAIN;
+ return NULL;
+ }
+ release_sock(sk);
+
+ /* Interrupts off so that no packet arrives before we begin sleeping.
+ Otherwise we might miss our wake up */
+ cli();
+ if (sk->rqueue == NULL)
+ {
+ interruptible_sleep_on(sk->sleep);
+ /* Signals may need a restart of the syscall */
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ *err=-ERESTARTSYS;
+ return(NULL);
+ }
+ if(sk->err != 0) /* Error while waiting for packet
+ eg an icmp sent earlier by the
+ peer has finaly turned up now */
+ {
+ *err = -sk->err;
+ sti();
+ sk->err=0;
+ return NULL;
+ }
+ }
+ sk->inuse = 1;
+ sti();
+ }
+ /* Again only user level code calls this function, so nothing interrupt level
+ will suddenely eat the rqueue */
+ if (!(flags & MSG_PEEK))
+ {
+ skb=skb_dequeue(&sk->rqueue);
+ if(skb!=NULL)
+ skb->users++;
+ else
+ goto restart; /* Avoid race if someone beats us to the data */
+ }
+ else
+ {
+ cli();
+ skb=skb_peek(&sk->rqueue);
+ if(skb!=NULL)
+ skb->users++;
+ sti();
+ if(skb==NULL) /* shouldn't happen but .. */
+ *err=-EAGAIN;
+ }
+ return skb;
+}
+
+/*
+ * Free a datagram buffer. This has some conditions to watch. We keep
+ * a user count so the last user may free the buffer. If however the
+ * buffer has a valid next pointer it was never removed and all the
+ * users PEEKed at it - so don't free it yet.
+ */
+
+void skb_free_datagram(struct sk_buff *skb)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ skb->users--;
+ if(skb->users>0)
+ {
+ restore_flags(flags);
+ return;
+ }
+ /* See if it needs destroying */
+ if(skb->list == NULL) /* Been dequeued by someone - ie its read */
+ kfree_skb(skb,FREE_READ);
+ restore_flags(flags);
+}
+
+void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
+{
+ /* We will know all about the fraglist options to allow >4K receives
+ but not this release */
+ memcpy_tofs(to,skb->h.raw+offset,size);
+}
+
+/*
+ * Datagram select: Again totally generic. Moved from udp.c
+ * Now does seqpacket.
+ */
+
+int datagram_select(struct sock *sk, int sel_type, select_table *wait)
+{
+ select_wait(sk->sleep, wait);
+ switch(sel_type)
+ {
+ case SEL_IN:
+ if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
+ {
+ /* Connection closed: Wake up */
+ return(1);
+ }
+ if (sk->rqueue != NULL || sk->err != 0)
+ { /* This appears to be consistent
+ with other stacks */
+ return(1);
+ }
+ return(0);
+
+ case SEL_OUT:
+ if(sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+ {
+ return(1);
+ }
+ if(sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
+ {
+ return(1);
+ }
+ return(0);
+
+ case SEL_EX:
+ if (sk->err)
+ return(1); /* Socket has gone into error state (eg icmp error) */
+ return(0);
+ }
+ return(0);
+}
diff --git a/net/socket/dev.c b/net/socket/dev.c
new file mode 100644
index 0000000..20ce0f6
--- /dev/null
+++ b/net/socket/dev.c
@@ -0,0 +1,980 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Interface (streams) handling functions.
+ *
+ * Version: @(#)dev.c 1.28 20/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox: check_addr returns a value for a wrong subnet
+ * ie not us but don't forward this!
+ * Alan Cox: block timer if the inet_bh handler is running
+ * Alan Cox: generic queue code added. A lot neater now
+ * C.E.Hawkins: SIOCGIFCONF only reports 'upped' interfaces
+ * C.E.Hawkins: IFF_PROMISC support
+ * Alan Cox: Supports Donald Beckers new hardware
+ * multicast layer, but not yet multicast lists.
+ * Alan Cox: ip_addr_match problems with class A/B nets.
+ * C.E.Hawkins IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT]
+ * Alan Cox: Removed bogus subnet check now the subnet code
+ * a) actually works for all A/B nets
+ * b) doesn't forward off the same interface.
+ * Alan Cox: Multiple extra protocols
+ * Alan Cox: A Couple more escaped verify_area calls die
+ * Alan Cox: IP_SET_DEV is gone (forever) as per Fred's comment.
+ * Alan Cox: Grand tidy up ready for the big day.
+ * Alan Cox: Handles dev_open errors correctly.
+ * Alan Cox: IP part split from main section
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include "inet.h"
+#include "dev.h"
+#include "eth.h"
+#include "ip.h"
+#include "route.h"
+#include "protocol.h"
+#include "tcp.h"
+#include "skbuff.h"
+#include "sock.h"
+#include "arp.h"
+#ifdef CONFIG_AX25
+#include "ax25/ax25.h"
+#endif
+#ifdef CONFIG_IPX
+#include "ipx/ipx.h"
+#endif
+
+
+#ifdef CONFIG_IPX
+
+/*
+ * These describe how each lowest level protocol is processed.
+ */
+
+static struct packet_type ipx_8023_type =
+{
+ NET16(ETH_P_802_3),
+ 0,
+ ipx_rcv,
+ NULL,
+ NULL
+};
+
+static struct packet_type ipx_packet_type =
+{
+ NET16(ETH_P_IPX), /* IPX over DIX - eg PDIPX */
+ 0,
+ ipx_rcv,
+ NULL,
+ &ipx_8023_type
+};
+
+#endif
+
+#ifdef CONFIG_AX25
+
+static struct packet_type ax25_packet_type =
+{
+ NET16(ETH_P_AX25),
+ 0,
+ ax25_rcv,
+ NULL,
+#ifdef CONFIG_IPX
+ &ipx_packet_type
+#else
+ NULL
+#endif
+};
+#endif
+
+
+static struct packet_type arp_packet_type =
+{
+ NET16(ETH_P_ARP),
+ 0, /* copy */
+ arp_rcv,
+ NULL,
+#ifdef CONFIG_IPX
+#ifndef CONFIG_AX25
+ &ipx_packet_type
+#else
+ &ax25_packet_type
+#endif
+#else
+ NULL /* next */
+#endif
+};
+
+
+static struct packet_type ip_packet_type =
+{
+ NET16(ETH_P_IP),
+ 0, /* copy */
+ ip_rcv,
+ NULL,
+ &arp_packet_type
+};
+
+/*
+ * The list of known protocols. Note that
+ * SOCK_PACKET sockets dynamically alter this.
+ */
+
+#ifdef CONFIG_INET
+struct packet_type *ptype_base = &ip_packet_type;
+#else
+#ifdef CONFIG_AX25
+struct packet_type *ptype_base = &ax25_packet_type;
+#else
+struct packet_type *ptype_base = &ipx_packet_type;
+#endif
+#endif
+
+/* A queue of all the packets we have to deal with */
+static struct sk_buff *volatile backlog = NULL;
+
+
+
+/*
+ * Return the lesser of the two values.
+ */
+
+static unsigned long
+min(unsigned long a, unsigned long b)
+{
+ if (a < b)
+ return(a);
+ return(b);
+}
+
+
+
+
+/*
+ * Add a protocol ID to the list of known protocols
+ * (see SOCK_PACKET code)
+ */
+
+void dev_add_pack(struct packet_type *pt)
+{
+ struct packet_type *p1;
+
+ pt->next = ptype_base;
+
+ /* See if we need to copy it. */
+ for (p1 = ptype_base; p1 != NULL; p1 = p1->next)
+ {
+ if (p1->type == pt->type)
+ {
+ pt->copy = 1;
+ break;
+ }
+ }
+ ptype_base = pt;
+}
+
+
+/*
+ * Remove a protocol ID from the list. Also used
+ * for SOCK_PACKET. Maybe one day we will do loadable
+ * protocol layers too.
+ */
+
+void dev_remove_pack(struct packet_type *pt)
+{
+ struct packet_type *lpt, *pt1;
+
+ if (pt == ptype_base)
+ {
+ ptype_base = pt->next;
+ return;
+ }
+
+ lpt = NULL;
+ for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next)
+ {
+ if (pt1->next == pt )
+ {
+ cli();
+ if (!pt->copy && lpt)
+ lpt->copy = 0;
+ pt1->next = pt->next;
+ sti();
+ return;
+ }
+
+ if (pt1->next -> type == pt ->type)
+ {
+ lpt = pt1->next;
+ }
+ }
+}
+
+
+/*
+ * Find an interface in the list.
+ */
+
+struct device *dev_get(char *name)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (strcmp(dev->name, name) == 0)
+ return(dev);
+ }
+ return(NULL);
+}
+
+
+/*
+ * Prepare an interface for use.
+ */
+
+int dev_open(struct device *dev)
+{
+ int ret = 0;
+
+ if (dev->open)
+ ret = dev->open(dev);
+ if (ret == 0)
+ dev->flags |= (IFF_UP | IFF_RUNNING);
+
+ return(ret);
+}
+
+
+/*
+ * Completely shutdown an interface.
+ */
+
+int dev_close(struct device *dev)
+{
+ if (dev->flags != 0)
+ {
+ int ct=0;
+ dev->flags = 0;
+ if (dev->stop)
+ dev->stop(dev);
+ rt_flush(dev);
+ dev->pa_addr = 0;
+ dev->pa_dstaddr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ /* Purge any queued packets when we down the link */
+ while(ct<DEV_NUMBUFFS)
+ {
+ struct sk_buff *skb;
+ while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL)
+ if(skb->free)
+ kfree_skb(skb,FREE_WRITE);
+ ct++;
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Send (or queue for sending) a packet.
+ */
+
+void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
+{
+ int where = 0; /* used to say if the packet should go */
+ /* at the front or the back of the */
+ /* queue. */
+
+ DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n",
+ skb, dev, pri));
+
+ if (dev == NULL)
+ {
+ printk("dev.c: dev_queue_xmit: dev = NULL\n");
+ return;
+ }
+
+ IS_SKB(skb);
+
+ skb->dev = dev;
+ if (skb->next != NULL)
+ {
+ /* Make sure we haven't missed an interrupt. */
+ dev->hard_start_xmit(NULL, dev);
+ return;
+ }
+
+ if (pri < 0)
+ {
+ pri = -pri-1;
+ where = 1;
+ }
+
+ if (pri >= DEV_NUMBUFFS)
+ {
+ printk("bad priority in dev_queue_xmit.\n");
+ pri = 1;
+ }
+
+ if (dev->hard_start_xmit(skb, dev) == 0)
+ {
+ /* It went out without fuss */
+ return;
+ }
+
+ /* The driver was busy.. */
+ /* Put skb into a bidirectional circular linked list. */
+ DPRINTF((DBG_DEV, "dev_queue_xmit dev->buffs[%d]=%X\n",
+ pri, dev->buffs[pri]));
+
+ /* Interrupts should already be cleared by hard_start_xmit. */
+ cli();
+ skb->magic = DEV_QUEUE_MAGIC;
+ if(where)
+ skb_queue_head(&dev->buffs[pri],skb);
+ else
+ skb_queue_tail(&dev->buffs[pri],skb);
+ skb->magic = DEV_QUEUE_MAGIC;
+ sti();
+}
+
+/*
+ * Receive a packet from a device driver and queue it for the upper
+ * (protocol) levels. It always succeeds.
+ */
+
+void netif_rx(struct sk_buff *skb)
+{
+ /* Set any necessary flags. */
+ skb->sk = NULL;
+ skb->free = 1;
+
+ /* and add it to the "backlog" queue. */
+ IS_SKB(skb);
+ skb_queue_tail(&backlog,skb);
+
+ /* If any packet arrived, mark it for processing. */
+ if (backlog != NULL)
+ mark_bh(INET_BH);
+
+ return;
+}
+
+
+/*
+ * The old interface to fetch a packet from a device driver.
+ * This function is the base level entry point for all drivers that
+ * want to send a packet to the upper (protocol) levels. It takes
+ * care of de-multiplexing the packet to the various modules based
+ * on their protocol ID.
+ *
+ * Return values: 1 <- exit I can't do any more
+ * 0 <- feed me more (i.e. "done", "OK").
+ *
+ * THIS FUNCTION IS OBSOLETE: DO NOT USE IT ANY MORE!!!!
+ */
+int dev_rint(unsigned char *buff, long len, int flags, struct device *dev)
+{
+ static int dropping = 0;
+ struct sk_buff *skb = NULL;
+ unsigned char *to;
+ int amount, left;
+ int len2;
+
+ if (dev == NULL || buff == NULL || len <= 0)
+ return(1);
+ if (flags & IN_SKBUFF)
+ {
+ skb = (struct sk_buff *) buff;
+ }
+ else
+ {
+ if (dropping)
+ {
+ if (backlog != NULL)
+ return(1);
+ printk("INET: dev_rint: no longer dropping packets.\n");
+ dropping = 0;
+ }
+
+ skb = alloc_skb(sizeof(*skb) + len, GFP_ATOMIC);
+ if (skb == NULL)
+ {
+ printk("dev_rint: packet dropped on %s (no memory) !\n",
+ dev->name);
+ dropping = 1;
+ return(1);
+ }
+
+ /* First we copy the packet into a buffer, and save it for later. */
+ to = (unsigned char *) (skb + 1);
+ left = len;
+ len2 = len;
+ while (len2 > 0)
+ {
+ amount = min(len2, (unsigned long) dev->rmem_end -
+ (unsigned long) buff);
+ memcpy(to, buff, amount);
+ len2 -= amount;
+ left -= amount;
+ buff += amount;
+ to += amount;
+ if ((unsigned long) buff == dev->rmem_end)
+ buff = (unsigned char *) dev->rmem_start;
+ }
+ }
+ skb->len = len;
+ skb->dev = dev;
+ skb->free = 1;
+
+ netif_rx(skb);
+ /* OK, all done. */
+ return(0);
+}
+
+
+/*
+ * This routine causes all interfaces to try to send some data.
+ */
+
+void dev_transmit(void)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (!dev->tbusy)
+ {
+ dev_tint(dev);
+ }
+ }
+}
+
+
+/* We need to know if we are re-entering the bottom level handler
+ for the network */
+
+static volatile char in_bh = 0;
+
+int in_inet_bh() /* Used by timer.c */
+{
+ return(in_bh==0?0:1);
+}
+
+/*
+ * This function gets called periodically, to see if we can
+ * process any data that came in from some interface.
+ *
+ */
+void inet_bh(void *tmp)
+{
+ struct sk_buff *skb;
+ struct packet_type *ptype;
+ unsigned short type;
+ unsigned char flag = 0;
+
+
+ /* Atomically check and mark our BUSY state. */
+ if (set_bit(1, (void*)&in_bh))
+ return;
+
+ /* Can we send anything now? */
+ dev_transmit();
+
+ /* Any data left to process? */
+ while((skb=skb_dequeue(&backlog))!=NULL)
+ {
+ flag=0;
+ sti();
+ /*
+ * Bump the pointer to the next structure.
+ * This assumes that the basic 'skb' pointer points to
+ * the MAC header, if any (as indicated by its "length"
+ * field). Take care now!
+ */
+ skb->h.raw = (unsigned char *) (skb + 1) + skb->dev->hard_header_len;
+ skb->len -= skb->dev->hard_header_len;
+
+ /*
+ * Fetch the packet protocol ID. This is also quite ugly, as
+ * it depends on the protocol driver (the interface itself) to
+ * know what the type is, or where to get it from. The Ethernet
+ * interfaces fetch the ID from the two bytes in the Ethernet MAC
+ * header (the h_proto field in struct ethhdr), but drivers like
+ * SLIP and PLIP have no alternative but to force the type to be
+ * IP or something like that. Sigh- FvK
+ */
+ type = skb->dev->type_trans(skb, skb->dev);
+
+ /*
+ * We got a packet ID. Now loop over the "known protocols"
+ * table (which is actually a linked list, but this will
+ * change soon if I get my way- FvK), and forward the packet
+ * to anyone who wants it.
+ */
+ for (ptype = ptype_base; ptype != NULL; ptype = ptype->next)
+ {
+ if (ptype->type == type)
+ {
+ struct sk_buff *skb2;
+
+ if (ptype->copy)
+ { /* copy if we need to */
+ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
+ if (skb2 == NULL)
+ continue;
+ memcpy(skb2, (const void *) skb, skb->mem_len);
+ skb2->mem_addr=skb2;
+ skb2->h.raw = (unsigned char *)
+ (
+ (unsigned long) skb2 +
+ (unsigned long) skb->h.raw -
+ (unsigned long) skb
+ );
+ skb2->free = 1;
+ }
+ else
+ {
+ skb2 = skb;
+ }
+
+ /* This used to be in the 'else' part, but then
+ * we don't have this flag set when we get a
+ * protocol that *does* require copying... -FvK
+ */
+ flag = 1;
+
+ /* Kick the protocol handler. */
+ ptype->func(skb2, skb->dev, ptype);
+ }
+ }
+
+ /*
+ * That's odd. We got an unknown packet. Who's using
+ * stuff like Novell or Amoeba on this network??
+ */
+ if (!flag)
+ {
+ DPRINTF((DBG_DEV,
+ "INET: unknown packet type 0x%04X (ignored)\n", type));
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ }
+
+ /* Again, see if we can transmit anything now. */
+ dev_transmit();
+ cli();
+ }
+ in_bh = 0;
+ sti();
+ dev_transmit(); /* Try and kick anything this processing produced */
+}
+
+
+/*
+ * This routine is called when an device driver (i.e. an
+ * interface) is * ready to transmit a packet.
+ */
+
+void dev_tint(struct device *dev)
+{
+ int i;
+ struct sk_buff *skb;
+
+ for(i = 0;i < DEV_NUMBUFFS; i++)
+ {
+ while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
+ {
+ skb->magic = 0;
+ dev->queue_xmit(skb,dev,-i - 1);
+ if (dev->tbusy)
+ return;
+ }
+ }
+}
+
+
+/*
+ * Perform a SIOCGIFCONF call.
+ */
+
+static int dev_ifconf(char *arg)
+{
+ struct ifconf ifc;
+ struct ifreq ifr;
+ struct device *dev;
+ char *pos;
+ int len;
+ int err;
+
+ /* Fetch the caller's info block. */
+ err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
+ if(err)
+ return -err;
+ memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
+ len = ifc.ifc_len;
+ pos = ifc.ifc_buf;
+
+ /* Loop over the interfaces, and write an info block for each. */
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if(!(dev->flags & IFF_UP))
+ continue;
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strcpy(ifr.ifr_name, dev->name);
+ (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family;
+ (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
+
+ /* Write this block to the caller's space. */
+ memcpy_tofs(pos, &ifr, sizeof(struct ifreq));
+ pos += sizeof(struct ifreq);
+ len -= sizeof(struct ifreq);
+ if (len < sizeof(struct ifreq)) break;
+ }
+
+ /* All done. Write the updated control block back to the caller. */
+ ifc.ifc_len = (pos - ifc.ifc_buf);
+ ifc.ifc_req = (struct ifreq *) ifc.ifc_buf;
+ memcpy_tofs(arg, &ifc, sizeof(struct ifconf));
+ return(pos - arg);
+}
+
+/*
+ * Print device statistics.
+ */
+
+char *sprintf_stats(char *buffer, struct device *dev)
+{
+ char *pos = buffer;
+ struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
+
+ if (stats)
+ pos += sprintf(pos, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",
+ dev->name,
+ stats->rx_packets, stats->rx_errors,
+ stats->rx_dropped + stats->rx_missed_errors,
+ stats->rx_fifo_errors,
+ stats->rx_length_errors + stats->rx_over_errors
+ + stats->rx_crc_errors + stats->rx_frame_errors,
+ stats->tx_packets, stats->tx_errors, stats->tx_dropped,
+ stats->tx_fifo_errors, stats->collisions,
+ stats->tx_carrier_errors + stats->tx_aborted_errors
+ + stats->tx_window_errors + stats->tx_heartbeat_errors);
+ else
+ pos += sprintf(pos, "%6s: No statistics available.\n", dev->name);
+
+ return pos;
+}
+
+/*
+ * Called from the PROCfs module (/proc/net/dev).
+ */
+
+int dev_get_info(char *buffer)
+{
+ char *pos = buffer;
+ struct device *dev;
+
+ pos +=
+ sprintf(pos,
+ "Inter-| Receive | Transmit\n"
+ " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ pos = sprintf_stats(pos, dev);
+ }
+ return pos - buffer;
+}
+
+/*
+ * Perform the SIOCxIFxxx calls.
+ */
+
+static int dev_ifsioc(void *arg, unsigned int getset)
+{
+ struct ifreq ifr;
+ struct device *dev;
+ int ret;
+ int err;
+
+ /* Fetch the caller's info block. */
+ err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
+ if(err)
+ return -err;
+ memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));
+
+ /* See which interface the caller is talking about. */
+ if ((dev = dev_get(ifr.ifr_name)) == NULL)
+ return(-EINVAL);
+
+ switch(getset)
+ {
+ case SIOCGIFFLAGS:
+ ifr.ifr_flags = dev->flags;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFFLAGS:
+ {
+ int old_flags = dev->flags;
+ dev->flags = ifr.ifr_flags & (
+ IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
+ IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
+ IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI);
+
+ if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
+ dev->set_multicast_list(dev,0,NULL);
+ if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
+ dev->set_multicast_list(dev,-1,NULL);
+ if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0))
+ {
+ ret = dev_close(dev);
+ }
+ else
+ {
+ ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
+ ? dev_open(dev) : 0;
+ if(ret!=0)
+ dev->flags&=~IFF_UP; /* Failed to come up so go down again */
+ }
+ }
+ break;
+ case SIOCGIFADDR:
+ (*(struct sockaddr_in *)
+ &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_addr).sin_family = dev->family;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_addr).sin_port = 0;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFADDR:
+ dev->pa_addr = (*(struct sockaddr_in *)
+ &ifr.ifr_addr).sin_addr.s_addr;
+ dev->family = ifr.ifr_addr.sa_family;
+ dev->pa_mask = ip_get_mask(dev->pa_addr);
+ dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+ ret = 0;
+ break;
+ case SIOCGIFBRDADDR:
+ (*(struct sockaddr_in *)
+ &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_broadaddr).sin_family = dev->family;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_broadaddr).sin_port = 0;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFBRDADDR:
+ dev->pa_brdaddr = (*(struct sockaddr_in *)
+ &ifr.ifr_broadaddr).sin_addr.s_addr;
+ ret = 0;
+ break;
+ case SIOCGIFDSTADDR:
+ (*(struct sockaddr_in *)
+ &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_broadaddr).sin_family = dev->family;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_broadaddr).sin_port = 0;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFDSTADDR:
+ dev->pa_dstaddr = (*(struct sockaddr_in *)
+ &ifr.ifr_dstaddr).sin_addr.s_addr;
+ ret = 0;
+ break;
+ case SIOCGIFNETMASK:
+ (*(struct sockaddr_in *)
+ &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_netmask).sin_family = dev->family;
+ (*(struct sockaddr_in *)
+ &ifr.ifr_netmask).sin_port = 0;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFNETMASK:
+ dev->pa_mask = (*(struct sockaddr_in *)
+ &ifr.ifr_netmask).sin_addr.s_addr;
+ ret = 0;
+ break;
+ case SIOCGIFMETRIC:
+ ifr.ifr_metric = dev->metric;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFMETRIC:
+ dev->metric = ifr.ifr_metric;
+ ret = 0;
+ break;
+ case SIOCGIFMTU:
+ ifr.ifr_mtu = dev->mtu;
+ memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
+ ret = 0;
+ break;
+ case SIOCSIFMTU:
+ dev->mtu = ifr.ifr_mtu;
+ ret = 0;
+ break;
+ case SIOCGIFMEM:
+ printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg);
+ ret = -EINVAL;
+ break;
+ case SIOCSIFMEM:
+ printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg);
+ ret = -EINVAL;
+ break;
+ case SIOCGIFHWADDR:
+ memcpy(ifr.ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN);
+ memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
+ ret=0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return(ret);
+}
+
+
+/*
+ * This function handles all "interface"-type I/O control requests.
+ */
+
+int dev_ioctl(unsigned int cmd, void *arg)
+{
+ int ret;
+
+ switch(cmd)
+ {
+ case IP_SET_DEV:
+ printk("IP_SET_DEV is obsolete. You need newer network tools.\n");
+ ret= -EINVAL;
+ case SIOCGIFCONF:
+ (void) dev_ifconf((char *) arg);
+ ret = 0;
+ break;
+ case SIOCGIFFLAGS:
+ case SIOCSIFFLAGS:
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ case SIOCGIFMTU:
+ case SIOCSIFMTU:
+ case SIOCGIFMEM:
+ case SIOCSIFMEM:
+ case SIOCGIFHWADDR:
+ if (!suser())
+ return(-EPERM);
+ ret = dev_ifsioc(arg, cmd);
+ break;
+ case SIOCSIFLINK:
+ if (!suser())
+ return(-EPERM);
+ default:
+ ret = -EINVAL;
+ }
+
+ return(ret);
+}
+
+/*
+ * Setup an ethernet type interface
+ */
+
+void eth_setup(char *str, int *ints)
+{
+ struct device *d = dev_base;
+
+ if (!str || !*str)
+ return;
+
+ /* Walk the device list */
+ while (d)
+ {
+ if (!strcmp(str,d->name))
+ {
+ if (ints[0] > 0)
+ d->irq=ints[1];
+ if (ints[0] > 1)
+ d->base_addr=ints[2];
+ if (ints[0] > 2)
+ d->mem_start=ints[3];
+ if (ints[0] > 3)
+ d->mem_end=ints[4];
+ break;
+ }
+ d=d->next;
+ }
+}
+
+
+/*
+ * Initialize the DEV module.
+ */
+
+void dev_init(void)
+{
+ struct device *dev, *dev2;
+
+ /* Add the devices.
+ * If the call to dev->init fails, the dev is removed
+ * from the chain disconnecting the device until the
+ * next reboot.
+ */
+ dev2 = NULL;
+ for (dev = dev_base; dev != NULL; dev=dev->next)
+ {
+ if (dev->init && dev->init(dev))
+ {
+ if (dev2 == NULL)
+ dev_base = dev->next;
+ else
+ dev2->next = dev->next;
+ }
+ else
+ {
+ dev2 = dev;
+ }
+ }
+
+}
+
diff --git a/net/socket/dev.h b/net/socket/dev.h
new file mode 100644
index 0000000..4cb829b
--- /dev/null
+++ b/net/socket/dev.h
@@ -0,0 +1,187 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the Interfaces handler.
+ *
+ * Version: @(#)dev.h 1.0.10 08/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Donald J. Becker, <becker@super.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _DEV_H
+#define _DEV_H
+
+#include <linux/if.h>
+#include <linux/if_ether.h>
+
+
+/* for future expansion when we will have different priorities. */
+#define DEV_NUMBUFFS 3
+#define MAX_ADDR_LEN 7
+#define MAX_HEADER 18
+
+#define IS_MYADDR 1 /* address is (one of) our own */
+#define IS_LOOPBACK 2 /* address is for LOOPBACK */
+#define IS_BROADCAST 3 /* address is a valid broadcast */
+#define IS_INVBCAST 4 /* Wrong netmask bcast not for us */
+
+/*
+ * The DEVICE structure.
+ * Actually, this whole structure is a big mistake. It mixes I/O
+ * data with strictly "high-level" data, and it has to know about
+ * almost every data structure used in the INET module. We will
+ * gradually phase out this structure, and replace it with the
+ * more general (but stolen :-) BSD "ifnet" structure. -FvK
+ */
+struct device {
+
+ /*
+ * This is the first field of the "visible" part of this structure
+ * (i.e. as seen by users in the "Space.c" file). It is the name
+ * the interface.
+ */
+ char *name;
+
+ /* I/O specific fields. These will be moved to DDI soon. */
+ unsigned long rmem_end; /* shmem "recv" end */
+ unsigned long rmem_start; /* shmem "recv" start */
+ unsigned long mem_end; /* sahared mem end */
+ unsigned long mem_start; /* shared mem start */
+ unsigned short base_addr; /* device I/O address */
+ unsigned char irq; /* device IRQ number */
+
+ /* Low-level status flags. */
+ volatile unsigned char start, /* start an operation */
+ tbusy, /* transmitter busy */
+ interrupt; /* interrupt arrived */
+
+ /*
+ * Another mistake.
+ * This points to the next device in the "dev" chain. It will
+ * be moved to the "invisible" part of the structure as soon as
+ * it has been cleaned up. -FvK
+ */
+ struct device *next;
+
+ /* The device initialization function. Called only once. */
+ int (*init)(struct device *dev);
+
+ /* Some hardware also needs these fields, but they are not part of the
+ usual set specified in Space.c. */
+ unsigned char if_port; /* Selectable AUI, TP,..*/
+ unsigned char dma; /* DMA channel */
+
+ struct enet_statistics* (*get_stats)(struct device *dev);
+
+ /*
+ * This marks the end of the "visible" part of the structure. All
+ * fields hereafter are internal to the system, and may change at
+ * will (read: may be cleaned up at will).
+ */
+
+ /* These may be needed for future network-power-down code. */
+ unsigned long trans_start; /* Time (in jiffies) of last Tx */
+ unsigned long last_rx; /* Time of last Rx */
+
+ unsigned short flags; /* interface flags (a la BSD) */
+ unsigned short family; /* address family ID (AF_INET) */
+ unsigned short metric; /* routing metric (not used) */
+ unsigned short mtu; /* interface MTU value */
+ unsigned short type; /* interface hardware type */
+ unsigned short hard_header_len; /* hardware hdr length */
+ void *priv; /* pointer to private data */
+
+ /* Interface address info. */
+ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */
+ unsigned char addr_len; /* harfware address length */
+ unsigned long pa_addr; /* protocol address */
+ unsigned long pa_brdaddr; /* protocol broadcast addr */
+ unsigned long pa_dstaddr; /* protocol P-P other side addr */
+ unsigned long pa_mask; /* protocol netmask */
+ unsigned short pa_alen; /* protocol address length */
+
+ /* Pointer to the interface buffers. */
+ struct sk_buff *volatile buffs[DEV_NUMBUFFS];
+
+ /* Pointers to interface service routines. */
+ int (*open)(struct device *dev);
+ int (*stop)(struct device *dev);
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct device *dev);
+ int (*hard_header) (unsigned char *buff,
+ struct device *dev,
+ unsigned short type,
+ unsigned long daddr,
+ unsigned long saddr,
+ unsigned len);
+ void (*add_arp) (unsigned long addr,
+ struct sk_buff *skb,
+ struct device *dev);
+ void (*queue_xmit)(struct sk_buff *skb,
+ struct device *dev, int pri);
+ int (*rebuild_header)(void *eth, struct device *dev);
+ unsigned short (*type_trans) (struct sk_buff *skb,
+ struct device *dev);
+#define HAVE_MULTICAST
+ void (*set_multicast_list)(struct device *dev,
+ int num_addrs, void *addrs);
+#define HAVE_SET_MAC_ADDR
+ int (*set_mac_address)(struct device *dev, void *addr);
+};
+
+
+struct packet_type {
+ unsigned short type; /* This is really NET16(ether_type) other
+ * devices will have to translate
+ * appropriately.
+ */
+ unsigned short copy:1;
+ int (*func) (struct sk_buff *, struct device *,
+ struct packet_type *);
+ void *data;
+ struct packet_type *next;
+};
+
+
+/* Used by dev_rint */
+#define IN_SKBUFF 1
+#define DEV_QUEUE_MAGIC 0x17432895
+
+
+extern struct device *dev_base;
+extern struct packet_type *ptype_base;
+
+
+extern unsigned long ip_get_mask(unsigned long);
+extern void dev_add_pack(struct packet_type *pt);
+extern void dev_remove_pack(struct packet_type *pt);
+extern struct device *dev_get(char *name);
+extern int dev_open(struct device *dev);
+extern int dev_close(struct device *dev);
+extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev,
+ int pri);
+#define HAVE_NETIF_RX 1
+extern void netif_rx(struct sk_buff *skb);
+/* The old interface to netif_rx(). */
+extern int dev_rint(unsigned char *buff, long len, int flags,
+ struct device * dev);
+extern void dev_transmit(void);
+extern int in_inet_bh(void);
+extern void inet_bh(void *tmp);
+extern void dev_tint(struct device *dev);
+extern int dev_get_info(char *buffer);
+extern int dev_ioctl(unsigned int cmd, void *);
+
+extern void dev_init(void);
+
+#endif /* _DEV_H */
diff --git a/net/socket/skbuff.c b/net/socket/skbuff.c
new file mode 100644
index 0000000..1b9ab93
--- /dev/null
+++ b/net/socket/skbuff.c
@@ -0,0 +1,461 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * A saner implementation of the skbuff stuff scattered everywhere
+ * in the old NET2D code.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox : Tracks memory and number of buffers for kernel memory report
+ * and memory leak hunting.
+ * Alan Cox : More generic kfree handler
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+
+
+/* Socket buffer operations. Ideally much of this list swap stuff ought to be using
+ exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
+ slow C version. No doubt when Linus sees this comment he'll do horrible things
+ to this code 8-)
+*/
+
+/*
+ * Resource tracking variables
+ */
+
+volatile unsigned long net_memory=0;
+volatile unsigned long net_skbcount=0;
+
+/*
+ * Debugging paranoia. Can go later when this crud stack works
+ */
+
+
+
+void skb_check(struct sk_buff *skb, int line, char *file)
+{
+ if(skb->magic_debug_cookie==SK_FREED_SKB)
+ {
+ printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
+ file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
+ }
+ if(skb->magic_debug_cookie!=SK_GOOD_SKB)
+ {
+ printk("File: %s Line %d, passed a non skb!\n", file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
+ }
+ if(skb->mem_len!=skb->truesize)
+ {
+ printk("File: %s Line %d, Dubious size setting!\n",file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
+ }
+ /* Guess it might be acceptable then */
+}
+
+/*
+ * Insert an sk_buff at the start of a list.
+ */
+
+void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ IS_SKB(newsk);
+ if(newsk->list)
+ printk("Suspicious queue head: sk_buff on list!\n");
+ save_flags(flags);
+ cli();
+ newsk->list=list;
+
+ newsk->next=*list;
+
+ if(*list)
+ newsk->prev=(*list)->prev;
+ else
+ newsk->prev=newsk;
+ newsk->prev->next=newsk;
+ newsk->next->prev=newsk;
+ IS_SKB(newsk->prev);
+ IS_SKB(newsk->next);
+ *list=newsk;
+ restore_flags(flags);
+}
+
+/*
+ * Insert an sk_buff at the end of a list.
+ */
+
+void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ if(newsk->list)
+ printk("Suspicious queue tail: sk_buff on list!\n");
+
+ IS_SKB(newsk);
+ save_flags(flags);
+ cli();
+
+ newsk->list=list;
+ if(*list)
+ {
+ (*list)->prev->next=newsk;
+ newsk->prev=(*list)->prev;
+ newsk->next=*list;
+ (*list)->prev=newsk;
+ }
+ else
+ {
+ newsk->next=newsk;
+ newsk->prev=newsk;
+ *list=newsk;
+ }
+ IS_SKB(newsk->prev);
+ IS_SKB(newsk->next);
+ restore_flags(flags);
+
+}
+
+/*
+ * Remove an sk_buff from a list. This routine is also interrupt safe
+ * so you can grab read and free buffers as another process adds them.
+ */
+
+struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
+{
+ long flags;
+ struct sk_buff *result;
+
+ save_flags(flags);
+ cli();
+
+ if(*list==NULL)
+ {
+ restore_flags(flags);
+ return(NULL);
+ }
+
+ result=*list;
+ if(result->next==result)
+ *list=NULL;
+ else
+ {
+ result->next->prev=result->prev;
+ result->prev->next=result->next;
+ *list=result->next;
+ }
+
+ IS_SKB(result);
+ restore_flags(flags);
+
+ if(result->list!=list)
+ printk("Dequeued packet has invalid list pointer\n");
+
+ result->list=0;
+ result->next=0;
+ result->prev=0;
+ return(result);
+}
+
+/*
+ * Insert a packet before another one in a list.
+ */
+
+void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ IS_SKB(old);
+ IS_SKB(newsk);
+
+ if(!old->list)
+ printk("insert before unlisted item!\n");
+ if(newsk->list)
+ printk("inserted item is already on a list.\n");
+
+ save_flags(flags);
+ cli();
+ newsk->list=old->list;
+ newsk->next=old;
+ newsk->prev=old->prev;
+ newsk->next->prev=newsk;
+ newsk->prev->next=newsk;
+
+ restore_flags(flags);
+}
+
+/*
+ * Place a packet after a given packet in a list.
+ */
+
+void skb_append(struct sk_buff *old, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ IS_SKB(old);
+ IS_SKB(newsk);
+
+ if(!old->list)
+ printk("append before unlisted item!\n");
+ if(newsk->list)
+ printk("append item is already on a list.\n");
+
+ save_flags(flags);
+ cli();
+ newsk->list=old->list;
+ newsk->prev=old;
+ newsk->next=old->next;
+ newsk->next->prev=newsk;
+ newsk->prev->next=newsk;
+
+ restore_flags(flags);
+}
+
+/*
+ * Remove an sk_buff from its list. Works even without knowing the list it
+ * is sitting on, which can be handy at times. It also means that THE LIST
+ * MUST EXIST when you unlink. Thus a list must have its contents unlinked
+ * _FIRST_.
+ */
+
+void skb_unlink(struct sk_buff *skb)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+
+ IS_SKB(skb);
+
+ if(skb->list)
+ {
+ skb->next->prev=skb->prev;
+ skb->prev->next=skb->next;
+ if(*skb->list==skb)
+ {
+ if(skb->next==skb)
+ *skb->list=NULL;
+ else
+ *skb->list=skb->next;
+ }
+ skb->next=0;
+ skb->prev=0;
+ skb->list=0;
+ }
+ restore_flags(flags);
+}
+
+/*
+ * An skbuff list has had its head reassigned. Move all the list
+ * pointers. Must be called with ints off during the whole head
+ * shifting
+ */
+
+void skb_new_list_head(struct sk_buff *volatile* list)
+{
+ struct sk_buff *skb=skb_peek(list);
+ if(skb!=NULL)
+ {
+ do
+ {
+ IS_SKB(skb);
+ skb->list=list;
+ skb=skb->next;
+ }
+ while(skb!=*list);
+ }
+}
+
+/*
+ * Peek an sk_buff. Unlike most other operations you _MUST_
+ * be careful with this one. A peek leaves the buffer on the
+ * list and someone else may run off with it. For an interrupt
+ * type system cli() peek the buffer copy the data and sti();
+ */
+
+struct sk_buff *skb_peek(struct sk_buff *volatile* list)
+{
+ return *list;
+}
+
+
+#ifdef UNUSED_NOW
+
+/*
+ * Get a clone of an sk_buff. This is the safe way to peek at
+ * a socket queue without accidents. Its a bit long but most
+ * of it acutally ends up as tiny bits of inline assembler
+ * anyway. Only the memcpy of upto 4K with ints off is not
+ * as nice as I'd like.
+ */
+
+struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
+{
+ struct sk_buff *orig,*newsk;
+ unsigned long flags;
+ unsigned int len;
+ /* Now for some games to avoid races */
+
+ do
+ {
+ save_flags(flags);
+ cli();
+ orig=skb_peek(list);
+ if(orig==NULL)
+ {
+ restore_flags(flags);
+ return NULL;
+ }
+ IS_SKB(orig);
+ len=orig->truesize;
+ restore_flags(flags);
+
+ newsk=alloc_skb(len,GFP_KERNEL); /* May sleep */
+
+ if(newsk==NULL) /* Oh dear... not to worry */
+ return NULL;
+
+ save_flags(flags);
+ cli();
+ if(skb_peek(list)!=orig) /* List changed go around another time */
+ {
+ restore_flags(flags);
+ newsk->sk=NULL;
+ newsk->free=1;
+ newsk->mem_addr=newsk;
+ newsk->mem_len=len;
+ kfree_skb(newsk, FREE_WRITE);
+ continue;
+ }
+
+ IS_SKB(orig);
+ IS_SKB(newsk);
+ memcpy(newsk,orig,len);
+ newsk->list=NULL;
+ newsk->magic=0;
+ newsk->next=NULL;
+ newsk->prev=NULL;
+ newsk->mem_addr=newsk;
+ newsk->h.raw+=((char *)newsk-(char *)orig);
+ newsk->link3=NULL;
+ newsk->sk=NULL;
+ newsk->free=1;
+ }
+ while(0);
+
+ restore_flags(flags);
+ return(newsk);
+}
+
+#endif
+
+/*
+ * Free an sk_buff. This still knows about things it should
+ * not need to like protocols and sockets.
+ */
+
+void kfree_skb(struct sk_buff *skb, int rw)
+{
+ if (skb == NULL) {
+ printk("kfree_skb: skb = NULL\n");
+ return;
+ }
+ IS_SKB(skb);
+ if(skb->free == 2)
+ printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
+ if(skb->list)
+ printk("Warning: kfree_skb passed an skb still on a list.\n");
+ skb->magic = 0;
+ if (skb->sk)
+ {
+ if(skb->sk->prot!=NULL)
+ {
+ if (rw)
+ skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
+ else
+ skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
+
+ }
+ else
+ {
+ /* Non INET - default wmalloc/rmalloc handler */
+ if (rw)
+ skb->sk->rmem_alloc-=skb->mem_len;
+ else
+ skb->sk->wmem_alloc-=skb->mem_len;
+ if(!skb->sk->dead)
+ skb->sk->write_space(skb->sk);
+ kfree_skbmem(skb->mem_addr,skb->mem_len);
+ }
+ }
+ else
+ {
+ kfree_skbmem(skb->mem_addr, skb->mem_len);
+ }
+}
+
+/*
+ * Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
+ * fields and also do memory statistics to find all the [BEEP] leaks.
+ */
+
+ struct sk_buff *alloc_skb(unsigned int size,int priority)
+ {
+ struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
+ if(skb==NULL)
+ return NULL;
+ skb->free= 2; /* Invalid so we pick up forgetful users */
+ skb->list= 0; /* Not on a list */
+ skb->truesize=size;
+ skb->mem_len=size;
+ skb->mem_addr=skb;
+ skb->fraglist=NULL;
+ net_memory+=size;
+ net_skbcount++;
+ skb->magic_debug_cookie=SK_GOOD_SKB;
+ skb->users=0;
+ return skb;
+ }
+
+/*
+ * Free an skbuff by memory
+ */
+
+void kfree_skbmem(void *mem,unsigned size)
+{
+ struct sk_buff *x=mem;
+ IS_SKB(x);
+ if(x->magic_debug_cookie==SK_GOOD_SKB)
+ {
+ x->magic_debug_cookie=SK_FREED_SKB;
+ kfree_s(mem,size);
+ net_skbcount--;
+ net_memory-=size;
+ }
+}
+
diff --git a/net/socket/skbuff.h b/net/socket/skbuff.h
new file mode 100644
index 0000000..ef04197
--- /dev/null
+++ b/net/socket/skbuff.h
@@ -0,0 +1,111 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the 'struct sk_buff' memory handlers.
+ *
+ * Version: @(#)skbuff.h 1.0.4 05/20/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ *
+ * Fixes:
+ * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff)
+ * Alan Cox : Declaration for new primitives
+ * Alan Cox : Fraglist support (idea by Donald Becker)
+ * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy
+ * being used.
+ * Alan Cox : Extra fields for RAW fixes
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _SKBUFF_H
+#define _SKBUFF_H
+#include <linux/malloc.h>
+
+#ifdef CONFIG_IPX
+#include "ipx/ipx.h"
+#endif
+
+#define HAVE_ALLOC_SKB /* For the drivers to know */
+
+
+#define FREE_READ 1
+#define FREE_WRITE 0
+
+
+struct sk_buff
+{
+ unsigned long magic_debug_cookie;
+ struct sk_buff *volatile next;
+ struct sk_buff *volatile prev;
+ struct sk_buff *volatile link3;
+ struct sk_buff *volatile* list;
+ struct sock *sk;
+ volatile unsigned long when; /* used to compute rtt's */
+ struct device *dev;
+ void *mem_addr;
+ union
+ {
+ struct tcphdr *th;
+ struct ethhdr *eth;
+ struct iphdr *iph;
+ struct udphdr *uh;
+ struct arphdr *arp;
+ unsigned char *raw;
+ unsigned long seq;
+#ifdef CONFIG_IPX
+ ipx_packet *ipx;
+#endif
+ } h;
+ struct iphdr * ip_hdr;
+ unsigned long mem_len;
+ unsigned long len;
+ unsigned long fraglen;
+ struct sk_buff *fraglist; /* Fragment list */
+ unsigned long truesize;
+ unsigned long saddr;
+ unsigned long daddr;
+ int magic;
+ volatile char acked,
+ used,
+ free,
+ arp,
+ urg_used;
+ unsigned char tries,lock; /* Lock is now unused */
+ unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
+};
+
+#define SK_WMEM_MAX 8192
+#define SK_RMEM_MAX 32767
+
+#define SK_FREED_SKB 0x0DE2C0DE
+#define SK_GOOD_SKB 0xDEC0DED1
+
+extern void print_skb(struct sk_buff *);
+extern void kfree_skb(struct sk_buff *skb, int rw);
+extern void skb_queue_head(struct sk_buff * volatile *list,struct sk_buff *buf);
+extern void skb_queue_tail(struct sk_buff * volatile *list,struct sk_buff *buf);
+extern struct sk_buff * skb_dequeue(struct sk_buff * volatile *list);
+extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk);
+extern void skb_append(struct sk_buff *old,struct sk_buff *newsk);
+extern void skb_unlink(struct sk_buff *buf);
+extern void skb_new_list_head(struct sk_buff *volatile* list);
+extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
+extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
+extern struct sk_buff * alloc_skb(unsigned int size, int priority);
+extern void kfree_skbmem(void *mem, unsigned size);
+
+extern void skb_check(struct sk_buff *skb,int, char *);
+#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
+
+extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
+extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
+extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
+extern void skb_free_datagram(struct sk_buff *skb);
+#endif /* _SKBUFF_H */
diff --git a/net/socket/sock.c b/net/socket/sock.c
new file mode 100644
index 0000000..1316be3
--- /dev/null
+++ b/net/socket/sock.c
@@ -0,0 +1,418 @@
+/*
+ * NET2Debugged, generic socket properties.
+ *
+ * This module provides the generic option control and memory handling
+ * for a socket of any kind.
+ *
+ * Version: @(#)sock.c 1.28 26/12/93
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+#include "raw.h"
+#include "icmp.h"
+
+static __inline__ int
+min(unsigned int a, unsigned int b)
+{
+ if (a < b)
+ return(a);
+ return(b);
+}
+
+#ifdef SOCK_DEBUG
+
+void print_sk(struct sock *sk)
+{
+ if (!sk)
+ {
+ printk(" print_sk(NULL)\n");
+ return;
+ }
+ printk(" wmem_alloc = %lu\n", sk->wmem_alloc);
+ printk(" rmem_alloc = %lu\n", sk->rmem_alloc);
+ printk(" send_head = %p\n", sk->send_head);
+ printk(" state = %d\n",sk->state);
+ printk(" wback = %p, rqueue = %p\n", sk->wback, sk->rqueue);
+ printk(" wfront = %p\n", sk->wfront);
+ printk(" daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr);
+ printk(" num = %d", sk->num);
+ printk(" next = %p\n", sk->next);
+ printk(" send_seq = %ld, acked_seq = %ld, copied_seq = %ld\n",
+ sk->send_seq, sk->acked_seq, sk->copied_seq);
+ printk(" rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n",
+ sk->rcv_ack_seq, sk->window_seq, sk->fin_seq);
+ printk(" prot = %p\n", sk->prot);
+ printk(" pair = %p, back_log = %p\n", sk->pair,sk->back_log);
+ printk(" inuse = %d , blog = %d\n", sk->inuse, sk->blog);
+ printk(" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks);
+ printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout);
+ printk(" cong_window = %d, packets_out = %d\n", sk->cong_window,
+ sk->packets_out);
+ printk(" urg = %d shutdown=%d\n", sk->urg, sk->shutdown);
+}
+
+
+void print_skb(struct sk_buff *skb)
+{
+ if (!skb)
+ {
+ printk(" print_skb(NULL)\n");
+ return;
+ }
+ printk(" prev = %p, next = %p\n", skb->prev, skb->next);
+ printk(" sk = %p link3 = %p\n", skb->sk, skb->link3);
+ printk(" mem_addr = %p, mem_len = %lu\n", skb->mem_addr, skb->mem_len);
+ printk(" used = %d free = %d\n", skb->used,skb->free);
+}
+
+
+#endif
+
+/*
+ * This is meant for all protocols to use and covers goings on
+ * at the socket level. Everything here is generic.
+ */
+
+int sock_setsockopt(struct sock *sk, int level, int optname,
+ char *optval, int optlen)
+{
+ int val;
+ int err;
+ struct linger ling;
+
+ if (optval == NULL)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
+ val = get_fs_long((unsigned long *)optval);
+ switch(optname)
+ {
+ case SO_TYPE:
+ case SO_ERROR:
+ return(-ENOPROTOOPT);
+
+ case SO_DEBUG:
+ sk->debug=val?1:0;
+ case SO_DONTROUTE: /* Still to be implemented */
+ return(0);
+ case SO_BROADCAST:
+ sk->broadcast=val?1:0;
+ return 0;
+ case SO_SNDBUF:
+ if(val>32767)
+ val=32767;
+ if(val<256)
+ val=256;
+ sk->sndbuf=val;
+ return 0;
+ case SO_LINGER:
+ err=verify_area(VERIFY_READ,optval,sizeof(ling));
+ if(err)
+ return err;
+ memcpy_fromfs(&ling,optval,sizeof(ling));
+ if(ling.l_onoff==0)
+ sk->linger=0;
+ else
+ {
+ sk->lingertime=ling.l_linger;
+ sk->linger=1;
+ }
+ return 0;
+ case SO_RCVBUF:
+ if(val>32767)
+ val=32767;
+ if(val<256)
+ val=256;
+ sk->rcvbuf=val;
+ return(0);
+
+ case SO_REUSEADDR:
+ if (val)
+ sk->reuse = 1;
+ else
+ sk->reuse = 0;
+ return(0);
+
+ case SO_KEEPALIVE:
+ if (val)
+ sk->keepopen = 1;
+ else
+ sk->keepopen = 0;
+ return(0);
+
+ case SO_OOBINLINE:
+ if (val)
+ sk->urginline = 1;
+ else
+ sk->urginline = 0;
+ return(0);
+
+ case SO_NO_CHECK:
+ if (val)
+ sk->no_check = 1;
+ else
+ sk->no_check = 0;
+ return(0);
+
+ case SO_PRIORITY:
+ if (val >= 0 && val < DEV_NUMBUFFS)
+ {
+ sk->priority = val;
+ }
+ else
+ {
+ return(-EINVAL);
+ }
+ return(0);
+
+ default:
+ return(-ENOPROTOOPT);
+ }
+}
+
+
+int sock_getsockopt(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ int val;
+ int err;
+ struct linger ling;
+
+ switch(optname)
+ {
+ case SO_DEBUG:
+ val = sk->debug;
+ break;
+
+ case SO_DONTROUTE: /* One last option to implement */
+ val = 0;
+ break;
+
+ case SO_BROADCAST:
+ val= sk->broadcast;
+ break;
+
+ case SO_LINGER:
+ err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
+ if(err)
+ return err;
+ err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(ling),(unsigned long *)optlen);
+ ling.l_onoff=sk->linger;
+ ling.l_linger=sk->lingertime;
+ memcpy_tofs(optval,&ling,sizeof(ling));
+ return 0;
+
+ case SO_SNDBUF:
+ val=sk->sndbuf;
+ break;
+
+ case SO_RCVBUF:
+ val =sk->rcvbuf;
+ break;
+
+ case SO_REUSEADDR:
+ val = sk->reuse;
+ break;
+
+ case SO_KEEPALIVE:
+ val = sk->keepopen;
+ break;
+
+ case SO_TYPE:
+ if (sk->prot == &tcp_prot)
+ val = SOCK_STREAM;
+ else
+ val = SOCK_DGRAM;
+ break;
+
+ case SO_ERROR:
+ val = sk->err;
+ sk->err = 0;
+ break;
+
+ case SO_OOBINLINE:
+ val = sk->urginline;
+ break;
+
+ case SO_NO_CHECK:
+ val = sk->no_check;
+ break;
+
+ case SO_PRIORITY:
+ val = sk->priority;
+ break;
+
+ default:
+ return(-ENOPROTOOPT);
+ }
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(val,(unsigned long *)optval);
+
+ return(0);
+}
+
+
+void *sock_wmalloc(struct sock *sk, unsigned long size, int force,
+ int priority)
+{
+ if (sk)
+ {
+ if (sk->wmem_alloc + size < sk->sndbuf || force)
+ {
+ cli();
+ sk->wmem_alloc+= size;
+ sti();
+ return(alloc_skb(size, priority));
+ }
+ DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n",
+ sk, size, force, priority));
+ return(NULL);
+ }
+ return(alloc_skb(size, priority));
+}
+
+
+void *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
+{
+ if (sk)
+ {
+ if (sk->rmem_alloc + size < sk->rcvbuf || force)
+ {
+ void *c = alloc_skb(size, priority);
+ cli();
+ if (c)
+ sk->rmem_alloc += size;
+ sti();
+ return(c);
+ }
+ DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n",
+ sk,size,force, priority));
+ return(NULL);
+ }
+ return(alloc_skb(size, priority));
+}
+
+
+unsigned long sock_rspace(struct sock *sk)
+{
+ int amt;
+
+ if (sk != NULL)
+ {
+ if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW)
+ return(0);
+ amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
+ if (amt < 0)
+ return(0);
+ return(amt);
+ }
+ return(0);
+}
+
+
+unsigned long sock_wspace(struct sock *sk)
+{
+ if (sk != NULL)
+ {
+ if (sk->shutdown & SEND_SHUTDOWN)
+ return(0);
+ if (sk->wmem_alloc >= sk->sndbuf)
+ return(0);
+ return(sk->sndbuf-sk->wmem_alloc );
+ }
+ return(0);
+}
+
+
+void sock_wfree(struct sock *sk, void *mem, unsigned long size)
+{
+ struct sk_buff *skb;
+ DPRINTF((DBG_INET, "sock_wfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
+
+ IS_SKB(mem);
+
+ skb=mem;
+
+ kfree_skbmem(mem, size);
+ if (sk)
+ {
+ sk->wmem_alloc -= size;
+
+ /* In case it might be waiting for more memory. */
+ if (!sk->dead)
+ sk->write_space(sk);
+ if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0)
+ {
+ DPRINTF((DBG_INET,
+ "recovered lost memory, sock = %X\n", sk));
+ }
+ return;
+ }
+}
+
+
+void sock_rfree(struct sock *sk, void *mem, unsigned long size)
+{
+ struct sk_buff *skb;
+
+ DPRINTF((DBG_INET, "sock_rfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
+
+ IS_SKB(mem);
+ skb=mem;
+
+ kfree_skbmem(mem, size);
+
+ if (sk)
+ {
+ sk->rmem_alloc -= size;
+ if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0)
+ {
+ DPRINTF((DBG_INET,"recovered lot memory, sock = %X\n", sk));
+ }
+ }
+}
+
diff --git a/net/socket/sock.h b/net/socket/sock.h
new file mode 100644
index 0000000..6f0b1d8
--- /dev/null
+++ b/net/socket/sock.h
@@ -0,0 +1,191 @@
+/*
+ * Definitions for the socket handler
+ *
+ * Version: @(#)sock.h 1.28 26/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche <flla@stud.uni-sb.de>
+ *
+ * Fixes:
+ * Alan Cox : Volatiles in skbuff pointers. See
+ * skbuff comments. May be overdone,
+ * better to prove they can be removed
+ * than the reverse.
+ * Alan Cox : Added a zapped field for tcp to note
+ * a socket is reset and must stay shut up
+ * Alan Cox : New fields for options
+ * Pauline Middelink : identd support
+ * Alan Cox : Split into sock.h and sockinet.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _SOCK_H
+#define _SOCK_H
+
+#include <linux/timer.h>
+#include <linux/ip.h> /* struct options */
+#include <linux/tcp.h> /* struct tcphdr */
+
+#include "skbuff.h" /* struct sk_buff */
+#ifdef CONFIG_AX25
+#include "ax25/ax25.h"
+#endif
+#ifdef CONFIG_IPX
+#include "ipx/ipx.h"
+#endif
+
+#define SOCK_ARRAY_SIZE 64
+
+
+/*
+ * This structure really needs to be cleaned up.
+ * Most of it is for TCP, and not used by any of
+ * the other protocols.
+ */
+struct sock {
+ struct options *opt;
+ struct options *rcv_opt;
+ volatile unsigned long wmem_alloc;
+ volatile unsigned long rmem_alloc;
+ unsigned long send_seq;
+ unsigned long acked_seq;
+ unsigned long copied_seq;
+ unsigned long rcv_ack_seq;
+ unsigned long window_seq;
+ unsigned long fin_seq;
+
+ /*
+ * Not all are volatile, but some are, so we
+ * might as well say they all are.
+ */
+ volatile char inuse,
+ dead,
+ urginline,
+ intr,
+ blog,
+ done,
+ reuse,
+ keepopen,
+ linger,
+ delay_acks,
+ destroy,
+ ack_timed,
+ no_check,
+ exp_growth,
+ zapped, /* In ax25 & ipx means not linked */
+ broadcast;
+ unsigned long lingertime;
+ int proc;
+ struct sock *next;
+ struct sock *pair;
+ struct sk_buff *volatile send_tail;
+ struct sk_buff *volatile send_head;
+ struct sk_buff *volatile back_log;
+ struct sk_buff *send_tmp;
+ long retransmits;
+ struct sk_buff *volatile wback,
+ *volatile wfront,
+ *volatile rqueue;
+ struct proto *prot;
+ struct wait_queue **sleep;
+ unsigned long daddr;
+ unsigned long saddr;
+ unsigned short max_unacked;
+ unsigned short window;
+ unsigned short bytes_rcv;
+ unsigned short mtu;
+ unsigned short num;
+ volatile unsigned short cong_window;
+ volatile unsigned short packets_out;
+ volatile unsigned short urg;
+ volatile unsigned short shutdown;
+ unsigned short mss;
+ volatile unsigned long rtt;
+ volatile unsigned long mdev;
+ volatile unsigned short backoff;
+ volatile short err;
+ unsigned char protocol;
+ volatile unsigned char state;
+ volatile unsigned char ack_backlog;
+ unsigned char max_ack_backlog;
+ unsigned char priority;
+ unsigned char debug;
+ unsigned short rcvbuf;
+ unsigned short sndbuf;
+ unsigned short type;
+#ifdef CONFIG_IPX
+ ipx_address ipx_source_addr,ipx_dest_addr;
+ unsigned short ipx_type;
+#endif
+#ifdef CONFIG_AX25
+/* Really we want to add a per protocol private area */
+ ax25_address ax25_source_addr,ax25_dest_addr;
+ struct sk_buff *volatile ax25_retxq[8];
+ char ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr;
+ char ax25_condition;
+ char ax25_retxcnt;
+ char ax25_xx;
+ char ax25_retxqi;
+ char ax25_rrtimer;
+ char ax25_timer;
+#endif
+/* IP 'private area' or will be eventually */
+ int ip_ttl; /* TTL setting */
+ int ip_tos; /* TOS */
+
+ struct tcphdr dummy_th;
+
+ /* This part is used for the timeout functions (timer.c). */
+ int timeout; /* What are we waiting for? */
+ struct timer_list timer;
+
+ /* identd */
+ struct socket *socket;
+
+ /* Event callbacks */
+
+ void (*state_change)(struct sock *sk);
+ void (*data_ready)(struct sock *sk,int bytes);
+ void (*write_space)(struct sock *sk);
+ void (*error_report)(struct sock *sk);
+};
+
+
+#define TIME_WRITE 1
+#define TIME_CLOSE 2
+#define TIME_KEEPOPEN 3
+#define TIME_DESTROY 4
+#define TIME_DONE 5 /* used to absorb those last few packets */
+#define SOCK_DESTROY_TIME 1000 /* about 10 seconds */
+
+#define PROT_SOCK 1024 /* Sockets 0-1023 can't be bound too unless you are superuser */
+
+#define SHUTDOWN_MASK 3
+#define RCV_SHUTDOWN 1
+#define SEND_SHUTDOWN 2
+
+extern void print_sk(struct sock *);
+extern void *sock_wmalloc(struct sock *sk,
+ unsigned long size, int force,
+ int priority);
+extern void *sock_rmalloc(struct sock *sk,
+ unsigned long size, int force,
+ int priority);
+extern void sock_wfree(struct sock *sk, void *mem,
+ unsigned long size);
+extern void sock_rfree(struct sock *sk, void *mem,
+ unsigned long size);
+extern unsigned long sock_rspace(struct sock *sk);
+extern unsigned long sock_wspace(struct sock *sk);
+
+extern int sock_setsockopt(struct sock *sk, int level, int optname, char *optval,
+ int optlen);
+extern int sock_getsockopt(struct sock *sk, int level, int optname, char *optval,
+ int *optlen);
+
+#endif /* _SOCK_H */
diff --git a/net/unix/proc.c b/net/unix/proc.c
index 8a80ad5..4e23976 100644
--- a/net/unix/proc.c
+++ b/net/unix/proc.c
@@ -8,7 +8,7 @@
* the PROC file system and the "unix" family of networking
* protocols. It is mainly used for debugging and statistics.
*
- * Version: @(#)proc.c 1.0.4 05/23/93
+ * Version: @(#)proc.c 1.28 25/12/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -16,12 +16,14 @@
* 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>
@@ -33,45 +35,55 @@
#include "unix.h"
-/* Called from PROCfs. */
+/*
+ * Called from PROCfs.
+ */
+
int unix_get_info(char *buffer)
{
- char *pos;
- int i;
+ char *pos;
+ int i;
- pos = buffer;
- pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
+ pos = buffer;
+ pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
- for(i = 0; i < NSOCKETS; i++) {
- if (unix_datas[i].refcnt) {
- pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
- unix_datas[i].refcnt,
- unix_datas[i].protocol,
- unix_datas[i].socket->flags,
- unix_datas[i].socket->type,
- unix_datas[i].socket->state
- );
-
- /* If socket is bound to a filename, we'll print it. */
- if(unix_datas[i].sockaddr_len>0) {
- pos += sprintf(pos, " %s\n",
- unix_datas[i].sockaddr_un.sun_path);
- } else { /* just add a newline */
- *pos='\n';
- pos++;
- *pos='\0';
- }
+ for(i = 0; i < NSOCKETS; i++)
+ {
+ if (unix_datas[i].refcnt)
+ {
+ pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
+ unix_datas[i].refcnt,
+ unix_datas[i].protocol,
+ unix_datas[i].socket->flags,
+ unix_datas[i].socket->type,
+ unix_datas[i].socket->state
+ );
+
+ /* If socket is bound to a filename, we'll print it. */
+ if(unix_datas[i].sockaddr_len>0)
+ {
+ pos += sprintf(pos, " %s\n",
+ unix_datas[i].sockaddr_un.sun_path);
+ }
+ else
+ { /* just add a newline */
+ *pos='\n';
+ pos++;
+ *pos='\0';
+ }
- /*
- * Check whether buffer _may_ overflow in the next loop.
- * Since sockets may have very very long paths, we make
- * PATH_MAX+80 the minimum space left for a new line.
- */
- if (pos > buffer+PAGE_SIZE-80-PATH_MAX) {
- printk("UNIX: netinfo: oops, too many sockets.\n");
- return(pos - buffer);
+ /*
+ * Check whether buffer _may_ overflow in the next loop.
+ * Since sockets may have very very long paths, we make
+ * PATH_MAX+80 the minimum space left for a new line.
+ */
+
+ if (pos > buffer+PAGE_SIZE-80-PATH_MAX)
+ {
+ printk("UNIX: netinfo: oops, too many sockets.\n");
+ return(pos - buffer);
+ }
}
- }
- }
- return(pos - buffer);
+ }
+ return(pos - buffer);
}
diff --git a/net/unix/sock.c b/net/unix/sock.c
index f4de8a8..7e68b24 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -4,7 +4,7 @@
* BSD Socket interface as the means of communication with
* the user level.
*
- * Version: @(#)sock.c 1.0.5 05/25/93
+ * Version: @(#)sock.c 1.28 25/12/93
*
* Authors: Orest Zborowski, <obz@Kodak.COM>
* Ross Biro, <bir7@leland.Stanford.Edu>
@@ -12,6 +12,7 @@
*
* Fixes:
* Alan Cox : Verify Area
+ * Alan Cox : Tidy up ready for release
*
* BUGS
* Page faults on read while another process reads could lose data.
@@ -93,252 +94,268 @@ static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen);
-static void
-dprintf(int level, char *fmt, ...)
+static void dprintf(int level, char *fmt, ...)
{
- va_list args;
- char *buff;
- extern int vsprintf(char * buf, const char * fmt, va_list args);
-
- if (level != unix_debug) return;
-
- buff = (char *) kmalloc(256, GFP_KERNEL);
- if (buff != NULL) {
- va_start(args, fmt);
- vsprintf(buff, fmt, args);
- va_end(args);
- printk(buff);
- kfree(buff);
- }
+ va_list args;
+ char *buff;
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+ if (level != unix_debug)
+ return;
+
+ buff = (char *) kmalloc(256, GFP_KERNEL);
+ if (buff != NULL)
+ {
+ va_start(args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end(args);
+ printk(buff);
+ kfree(buff);
+ }
}
-static inline int
-min(int a, int b)
+static inline int min(int a, int b)
{
- if (a < b) return(a);
- return(b);
+ if (a < b)
+ return(a);
+ return(b);
}
-void
-sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
+void sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
{
- char buf[sizeof(sockun->sun_path) + 1];
-
- if (unix_debug == 0) return;
-
- sockaddr_len -= UN_PATH_OFFSET;
- if (sockun->sun_family != AF_UNIX)
- printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
- else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
- printk("UNIX: Bad addr len %d>\n", sockaddr_len);
- else {
- memcpy(buf, sockun->sun_path, sockaddr_len);
- buf[sockaddr_len] = '\0';
- printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET);
- }
+ char buf[sizeof(sockun->sun_path) + 1];
+
+ if (unix_debug == 0)
+ return;
+
+ sockaddr_len -= UN_PATH_OFFSET;
+ if (sockun->sun_family != AF_UNIX)
+ printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
+ else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
+ printk("UNIX: Bad addr len %d>\n", sockaddr_len);
+ else
+ {
+ memcpy(buf, sockun->sun_path, sockaddr_len);
+ buf[sockaddr_len] = '\0';
+ printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET);
+ }
}
-/* don't have to do anything. */
-static int
-unix_proto_listen(struct socket *sock, int backlog)
+/*
+ * Don't have to do anything.
+ */
+
+static int unix_proto_listen(struct socket *sock, int backlog)
{
- return(0);
+ return(0);
}
-static int
-unix_proto_setsockopt(struct socket *sock, int level, int optname,
+static int unix_proto_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int
-unix_proto_getsockopt(struct socket *sock, int level, int optname,
+static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int
-unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
+static int unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int addr_len)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int
-unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
+static int unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int *addr_len)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int
-unix_proto_shutdown(struct socket *sock, int how)
+static int unix_proto_shutdown(struct socket *sock, int how)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-/* This error needs to be checked. */
-static int
-unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
+/*
+ * This error needs to be checked.
+ */
+
+static int unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
- if (flags != 0) return(-EINVAL);
- return(unix_proto_write(sock, (char *) buff, len, nonblock));
+ if (flags != 0)
+ return(-EINVAL);
+ return(unix_proto_write(sock, (char *) buff, len, nonblock));
}
-/* This error needs to be checked. */
-static int
-unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
+/*
+ * This error needs to be checked.
+ */
+
+static int unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
- if (flags != 0) return(-EINVAL);
- return(unix_proto_read(sock, (char *) buff, len, nonblock));
+ if (flags != 0)
+ return(-EINVAL);
+ return(unix_proto_read(sock, (char *) buff, len, nonblock));
}
-static struct unix_proto_data *
-unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
+static struct unix_proto_data * unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
struct inode *inode)
{
- struct unix_proto_data *upd;
-
- for(upd = unix_datas; upd <= last_unix_data; ++upd) {
- if (upd->refcnt && upd->socket &&
- upd->socket->state == SS_UNCONNECTED &&
- upd->sockaddr_un.sun_family == sockun->sun_family &&
- upd->inode == inode) return(upd);
- }
- return(NULL);
+ struct unix_proto_data *upd;
+
+ for(upd = unix_datas; upd <= last_unix_data; ++upd)
+ {
+ if (upd->refcnt && upd->socket &&
+ upd->socket->state == SS_UNCONNECTED &&
+ upd->sockaddr_un.sun_family == sockun->sun_family &&
+ upd->inode == inode)
+ {
+ return(upd);
+ }
+ }
+ return(NULL);
}
-static struct unix_proto_data *
-unix_data_alloc(void)
+static struct unix_proto_data *unix_data_alloc(void)
{
- struct unix_proto_data *upd;
-
- cli();
- for(upd = unix_datas; upd <= last_unix_data; ++upd) {
- if (!upd->refcnt) {
- upd->refcnt = 1;
- sti();
- upd->socket = NULL;
- upd->sockaddr_len = 0;
- upd->sockaddr_un.sun_family = 0;
- upd->buf = NULL;
- upd->bp_head = upd->bp_tail = 0;
- upd->inode = NULL;
- upd->peerupd = NULL;
- return(upd);
- }
- }
- sti();
- return(NULL);
+ struct unix_proto_data *upd;
+
+ cli();
+ for(upd = unix_datas; upd <= last_unix_data; ++upd)
+ {
+ if (!upd->refcnt)
+ {
+ upd->refcnt = 1;
+ sti();
+ upd->socket = NULL;
+ upd->sockaddr_len = 0;
+ upd->sockaddr_un.sun_family = 0;
+ upd->buf = NULL;
+ upd->bp_head = upd->bp_tail = 0;
+ upd->inode = NULL;
+ upd->peerupd = NULL;
+ return(upd);
+ }
+ }
+ sti();
+ return(NULL);
}
-static inline void
-unix_data_ref(struct unix_proto_data *upd)
+static inline void unix_data_ref(struct unix_proto_data *upd)
{
- if (!upd) {
- dprintf(1, "UNIX: data_ref: upd = NULL\n");
- return;
- }
- ++upd->refcnt;
- dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt);
+ if (!upd)
+ {
+ dprintf(1, "UNIX: data_ref: upd = NULL\n");
+ return;
+ }
+ ++upd->refcnt;
+ dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt);
}
-static void
-unix_data_deref(struct unix_proto_data *upd)
+static void unix_data_deref(struct unix_proto_data *upd)
{
- if (!upd) {
- dprintf(1, "UNIX: data_deref: upd = NULL\n");
- return;
- }
- if (upd->refcnt == 1) {
- dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
- if (upd->buf) {
- free_page((unsigned long)upd->buf);
- upd->buf = NULL;
- upd->bp_head = upd->bp_tail = 0;
- }
- }
- --upd->refcnt;
+ if (!upd)
+ {
+ dprintf(1, "UNIX: data_deref: upd = NULL\n");
+ return;
+ }
+ if (upd->refcnt == 1)
+ {
+ dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
+ if (upd->buf)
+ {
+ free_page((unsigned long)upd->buf);
+ upd->buf = NULL;
+ upd->bp_head = upd->bp_tail = 0;
+ }
+ }
+ --upd->refcnt;
}
/*
- * Upon a create, we allocate an empty protocol data,
- * and grab a page to buffer writes.
+ * Upon a create, we allocate an empty protocol data,
+ * and grab a page to buffer writes.
*/
-static int
-unix_proto_create(struct socket *sock, int protocol)
-{
- struct unix_proto_data *upd;
-
- dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
- if (protocol != 0) {
- dprintf(1, "UNIX: create: protocol != 0\n");
- return(-EINVAL);
- }
- if (!(upd = unix_data_alloc())) {
- printk("UNIX: create: can't allocate buffer\n");
- return(-ENOMEM);
- }
- if (!(upd->buf = (char*) get_free_page(GFP_USER))) {
- printk("UNIX: create: can't get page!\n");
- unix_data_deref(upd);
- return(-ENOMEM);
- }
- upd->protocol = protocol;
- upd->socket = sock;
- UN_DATA(sock) = upd;
- dprintf(1, "UNIX: create: allocated data 0x%x\n", upd);
- return(0);
+
+static int unix_proto_create(struct socket *sock, int protocol)
+{
+ struct unix_proto_data *upd;
+
+ dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
+ if (protocol != 0)
+ {
+ dprintf(1, "UNIX: create: protocol != 0\n");
+ return(-EINVAL);
+ }
+ if (!(upd = unix_data_alloc()))
+ {
+ printk("UNIX: create: can't allocate buffer\n");
+ return(-ENOMEM);
+ }
+ if (!(upd->buf = (char*) get_free_page(GFP_USER)))
+ {
+ printk("UNIX: create: can't get page!\n");
+ unix_data_deref(upd);
+ return(-ENOMEM);
+ }
+ upd->protocol = protocol;
+ upd->socket = sock;
+ UN_DATA(sock) = upd;
+ dprintf(1, "UNIX: create: allocated data 0x%x\n", upd);
+ return(0);
}
-static int
-unix_proto_dup(struct socket *newsock, struct socket *oldsock)
+static int unix_proto_dup(struct socket *newsock, struct socket *oldsock)
{
- struct unix_proto_data *upd = UN_DATA(oldsock);
+ struct unix_proto_data *upd = UN_DATA(oldsock);
- return(unix_proto_create(newsock, upd->protocol));
+ return(unix_proto_create(newsock, upd->protocol));
}
-static int
-unix_proto_release(struct socket *sock, struct socket *peer)
-{
- struct unix_proto_data *upd = UN_DATA(sock);
-
- dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
- if (!upd) return(0);
- if (upd->socket != sock) {
- printk("UNIX: release: socket link mismatch!\n");
- return(-EINVAL);
- }
- if (upd->inode) {
- dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
- iput(upd->inode);
- upd->inode = NULL;
- }
- UN_DATA(sock) = NULL;
- upd->socket = NULL;
- if (upd->peerupd) unix_data_deref(upd->peerupd);
- unix_data_deref(upd);
- return(0);
+static int unix_proto_release(struct socket *sock, struct socket *peer)
+{
+ struct unix_proto_data *upd = UN_DATA(sock);
+
+ dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
+ if (!upd)
+ return(0);
+ if (upd->socket != sock)
+ {
+ printk("UNIX: release: socket link mismatch!\n");
+ return(-EINVAL);
+ }
+ if (upd->inode)
+ {
+ dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
+ iput(upd->inode);
+ upd->inode = NULL;
+ }
+ UN_DATA(sock) = NULL;
+ upd->socket = NULL;
+ if (upd->peerupd)
+ unix_data_deref(upd->peerupd);
+ unix_data_deref(upd);
+ return(0);
}
@@ -351,54 +368,57 @@ unix_proto_release(struct socket *sock, struct socket *peer)
* Here we return EINVAL, but it may be necessary to re-bind.
* I think thats what BSD does in the case of datagram sockets...
*/
-static int
-unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
+static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
int sockaddr_len)
{
- char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
- struct unix_proto_data *upd = UN_DATA(sock);
- unsigned long old_fs;
- int i;
- int er;
-
- dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len);
- if (sockaddr_len <= UN_PATH_OFFSET ||
- sockaddr_len > sizeof(struct sockaddr_un)) {
- dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
- return(-EINVAL);
- }
- if (upd->sockaddr_len || upd->inode) {
- printk("UNIX: bind: already bound!\n");
- return(-EINVAL);
- }
- er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len);
- if(er)
- return er;
- memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
- upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
- if (upd->sockaddr_un.sun_family != AF_UNIX) {
- dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
- upd->sockaddr_un.sun_family, AF_UNIX);
- return(-EINVAL);
- }
-
- memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
- fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
- old_fs = get_fs();
- set_fs(get_ds());
- i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
- if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
- set_fs(old_fs);
- if (i < 0) {
- printk("UNIX: bind: can't open socket %s\n", fname);
- return(i);
- }
- upd->sockaddr_len = sockaddr_len; /* now its legal */
-
- dprintf(1, "UNIX: bind: bound socket address: ");
- sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
- dprintf(1, "to inode 0x%x\n", upd->inode);
- return(0);
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
+ struct unix_proto_data *upd = UN_DATA(sock);
+ unsigned long old_fs;
+ int i;
+ int er;
+
+ dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len);
+ if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un))
+ {
+ dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
+ return(-EINVAL);
+ }
+ if (upd->sockaddr_len || upd->inode)
+ {
+ printk("UNIX: bind: already bound!\n");
+ return(-EINVAL);
+ }
+ er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len);
+ if(er)
+ return er;
+ memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
+ upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ if (upd->sockaddr_un.sun_family != AF_UNIX)
+ {
+ dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
+ upd->sockaddr_un.sun_family, AF_UNIX);
+ return(-EINVAL);
+ }
+
+ memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ old_fs = get_fs();
+ set_fs(get_ds());
+ i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
+ if (i == 0)
+ i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
+ set_fs(old_fs);
+ if (i < 0)
+ {
+ printk("UNIX: bind: can't open socket %s\n", fname);
+ return(i);
+ }
+ upd->sockaddr_len = sockaddr_len; /* now its legal */
+
+ dprintf(1, "UNIX: bind: bound socket address: ");
+ sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
+ dprintf(1, "to inode 0x%x\n", upd->inode);
+ return(0);
}
@@ -407,71 +427,79 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
* (I can't for the life of me find an application where that
* wouldn't be the case!)
*/
-static int
-unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags)
-{
- char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
- struct sockaddr_un sockun;
- struct unix_proto_data *serv_upd;
- struct inode *inode;
- unsigned long old_fs;
- int i;
- int er;
-
- dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len);
-
- if (sockaddr_len <= UN_PATH_OFFSET ||
- sockaddr_len > sizeof(struct sockaddr_un)) {
- dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len);
- return(-EINVAL);
- }
- if (sock->state == SS_CONNECTING) return(-EINPROGRESS);
- if (sock->state == SS_CONNECTED) return(-EISCONN);
-
- er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
- if(er)
- return er;
- memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
- sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
- if (sockun.sun_family != AF_UNIX) {
- dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
- sockun.sun_family, AF_UNIX);
- return(-EINVAL);
- }
-
- /*
- * Try to open the name in the filesystem - this is how we
- * identify ourselves and our server. Note that we don't
- * hold onto the inode that long, just enough to find our
- * server. When we're connected, we mooch off the server.
- */
- memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
- fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
- old_fs = get_fs();
- set_fs(get_ds());
- i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
- set_fs(old_fs);
- if (i < 0) {
- dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
- return(i);
- }
- serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
- iput(inode);
- if (!serv_upd) {
- dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
- fname, inode);
- return(-EINVAL);
- }
- if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
- dprintf(1, "UNIX: connect: can't await connection\n");
- return(i);
- }
- if (sock->conn) {
- unix_data_ref(UN_DATA(sock->conn));
- UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
- }
- return(0);
+
+static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len, int flags)
+{
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
+ struct sockaddr_un sockun;
+ struct unix_proto_data *serv_upd;
+ struct inode *inode;
+ unsigned long old_fs;
+ int i;
+ int er;
+
+ dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len);
+
+ if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un))
+ {
+ dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len);
+ return(-EINVAL);
+ }
+ if (sock->state == SS_CONNECTING)
+ return(-EINPROGRESS);
+ if (sock->state == SS_CONNECTED)
+ return(-EISCONN);
+
+ er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
+ if(er)
+ return er;
+ memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
+ sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ if (sockun.sun_family != AF_UNIX)
+ {
+ dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
+ sockun.sun_family, AF_UNIX);
+ return(-EINVAL);
+ }
+
+ /*
+ * Try to open the name in the filesystem - this is how we
+ * identify ourselves and our server. Note that we don't
+ * hold onto the inode that long, just enough to find our
+ * server. When we're connected, we mooch off the server.
+ */
+
+ memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ old_fs = get_fs();
+ set_fs(get_ds());
+ i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
+ set_fs(old_fs);
+ if (i < 0)
+ {
+ dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
+ return(i);
+ }
+ serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
+ iput(inode);
+ if (!serv_upd)
+ {
+ dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
+ fname, inode);
+ return(-EINVAL);
+ }
+ if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0)
+ {
+ dprintf(1, "UNIX: connect: can't await connection\n");
+ return(i);
+ }
+ if (sock->conn)
+ {
+ unix_data_ref(UN_DATA(sock->conn));
+ UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
+ }
+ return(0);
}
@@ -481,146 +509,173 @@ unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
* for a wait area, and deadlock prevention in the case of a process
* writing to itself is, ignored, in true unix fashion!
*/
-static int
-unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
+
+static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
{
- struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
+ struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
- unix_data_ref(upd1);
- unix_data_ref(upd2);
- upd1->peerupd = upd2;
- upd2->peerupd = upd1;
- return(0);
+ unix_data_ref(upd1);
+ unix_data_ref(upd2);
+ upd1->peerupd = upd2;
+ upd2->peerupd = upd1;
+ return(0);
}
/* On accept, we ref the peer's data for safe writes. */
-static int
-unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- struct socket *clientsock;
-
- dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n",
- sock, newsock);
-
- /*
- * If there aren't any sockets awaiting connection,
- * then wait for one, unless nonblocking.
- */
- while(!(clientsock = sock->iconn)) {
- if (flags & O_NONBLOCK) return(-EAGAIN);
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked) {
- dprintf(1, "UNIX: accept: sleep was interrupted\n");
- return(-ERESTARTSYS);
- }
- }
-
- /*
- * Great. Finish the connection relative to server and client,
- * wake up the client and return the new fd to the server.
- */
- sock->iconn = clientsock->next;
- clientsock->next = NULL;
- newsock->conn = clientsock;
- clientsock->conn = newsock;
- clientsock->state = SS_CONNECTED;
- newsock->state = SS_CONNECTED;
- unix_data_ref(UN_DATA(clientsock));
- UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
- UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
- UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
- wake_up(clientsock->wait);
- return(0);
+
+static int unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ struct socket *clientsock;
+
+ dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n",
+ sock, newsock);
+
+ /*
+ * If there aren't any sockets awaiting connection,
+ * then wait for one, unless nonblocking.
+ */
+ while(!(clientsock = sock->iconn))
+ {
+ if (flags & O_NONBLOCK)
+ return(-EAGAIN);
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked)
+ {
+ dprintf(1, "UNIX: accept: sleep was interrupted\n");
+ return(-ERESTARTSYS);
+ }
+ }
+
+ /*
+ * Great. Finish the connection relative to server and client,
+ * wake up the client and return the new fd to the server.
+ */
+ sock->iconn = clientsock->next;
+ clientsock->next = NULL;
+ newsock->conn = clientsock;
+ clientsock->conn = newsock;
+ clientsock->state = SS_CONNECTED;
+ newsock->state = SS_CONNECTED;
+ unix_data_ref(UN_DATA(clientsock));
+ UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
+ UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
+ UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
+ wake_up(clientsock->wait);
+ return(0);
}
-/* Gets the current name or the name of the connected socket. */
-static int
-unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
- int *usockaddr_len, int peer)
+/*
+ * Gets the current name or the name of the connected socket.
+ */
+
+static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
+ int *usockaddr_len, int peer)
{
- struct unix_proto_data *upd;
- int len;
- int er;
-
- dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
- if (peer) {
- if (sock->state != SS_CONNECTED) {
- dprintf(1, "UNIX: getname: socket not connected\n");
- return(-EINVAL);
- }
- upd = UN_DATA(sock->conn);
- } else
- upd = UN_DATA(sock);
-
- er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
- if(er)
- return er;
- if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL);
- if (len > upd->sockaddr_len) len = upd->sockaddr_len;
- if (len) {
- er=verify_area(VERIFY_WRITE, usockaddr, len);
- if(er)
- return er;
- memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
- }
- put_fs_long(len, usockaddr_len);
- return(0);
+ struct unix_proto_data *upd;
+ int len;
+ int er;
+
+ dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
+ if (peer)
+ {
+ if (sock->state != SS_CONNECTED)
+ {
+ dprintf(1, "UNIX: getname: socket not connected\n");
+ return(-EINVAL);
+ }
+ upd = UN_DATA(sock->conn);
+ }
+ else
+ upd = UN_DATA(sock);
+
+ er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
+ if(er)
+ return er;
+ if ((len = get_fs_long(usockaddr_len)) <= 0)
+ return(-EINVAL);
+ if (len > upd->sockaddr_len)
+ len = upd->sockaddr_len;
+ if (len)
+ {
+ er=verify_area(VERIFY_WRITE, usockaddr, len);
+ if(er)
+ return er;
+ memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
+ }
+ put_fs_long(len, usockaddr_len);
+ return(0);
}
/* We read from our own buf. */
-static int
-unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
-{
- struct unix_proto_data *upd;
- int todo, avail;
- int er;
-
- if ((todo = size) <= 0) return(0);
- upd = UN_DATA(sock);
- while(!(avail = UN_BUF_AVAIL(upd))) {
- if (sock->state != SS_CONNECTED) {
- dprintf(1, "UNIX: read: socket not connected\n");
- return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
- }
- dprintf(1, "UNIX: read: no data available...\n");
- if (nonblock) return(-EAGAIN);
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked) {
- dprintf(1, "UNIX: read: interrupted\n");
- return(-ERESTARTSYS);
- }
- }
-
- /*
- * Copy from the read buffer into the user's buffer,
- * watching for wraparound. Then we wake up the writer.
- */
- do {
- int part, cando;
-
- if (avail <= 0) {
- printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
- send_sig(SIGKILL, current, 1);
- return(-EPIPE);
- }
- if ((cando = todo) > avail) cando = avail;
- if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part;
- dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
- avail, todo, cando);
- if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
- return er;
- memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
- upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
- ubuf += cando;
- todo -= cando;
- if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
- avail = UN_BUF_AVAIL(upd);
- } while(todo && avail);
- return(size - todo);
+static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+ struct unix_proto_data *upd;
+ int todo, avail;
+ int er;
+
+ if ((todo = size) <= 0)
+ return(0);
+ upd = UN_DATA(sock);
+ while(!(avail = UN_BUF_AVAIL(upd)))
+ {
+ if (sock->state != SS_CONNECTED)
+ {
+ dprintf(1, "UNIX: read: socket not connected\n");
+ return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
+ }
+ dprintf(1, "UNIX: read: no data available...\n");
+ if (nonblock)
+ return(-EAGAIN);
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked)
+ {
+ dprintf(1, "UNIX: read: interrupted\n");
+ return(-ERESTARTSYS);
+ }
+ }
+
+ /*
+ * Copy from the read buffer into the user's buffer,
+ * watching for wraparound. Then we wake up the writer.
+ */
+
+ do
+ {
+ int part, cando;
+
+ if (avail <= 0)
+ {
+ printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
+ send_sig(SIGKILL, current, 1);
+ return(-EPIPE);
+ }
+
+ if ((cando = todo) > avail)
+ cando = avail;
+ if (cando >(part = BUF_SIZE - upd->bp_tail))
+ cando = part;
+
+ dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
+ avail, todo, cando);
+
+ if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
+ return er;
+
+ memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
+ upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
+ ubuf += cando;
+ todo -= cando;
+
+ if (sock->state == SS_CONNECTED)
+ wake_up(sock->conn->wait);
+ avail = UN_BUF_AVAIL(upd);
+ }
+ while(todo && avail);
+ return(size - todo);
}
@@ -629,274 +684,308 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
* peer so we are safe that the buffer remains, even after the
* peer has disconnected, which we check other ways.
*/
-static int
-unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
-{
- struct unix_proto_data *pupd;
- int todo, space;
- int er;
-
- if ((todo = size) <= 0) return(0);
- if (sock->state != SS_CONNECTED) {
- dprintf(1, "UNIX: write: socket not connected\n");
- if (sock->state == SS_DISCONNECTING) {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- return(-EINVAL);
- }
- pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
-
- while(!(space = UN_BUF_SPACE(pupd))) {
- dprintf(1, "UNIX: write: no space left...\n");
- if (nonblock) return(-EAGAIN);
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked) {
- dprintf(1, "UNIX: write: interrupted\n");
- return(-ERESTARTSYS);
- }
- if (sock->state == SS_DISCONNECTING) {
- dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- }
-
- /*
- * Copy from the user's buffer to the write buffer,
- * watching for wraparound. Then we wake up the reader.
- */
- do {
- int part, cando;
-
- if (space <= 0) {
- printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
- send_sig(SIGKILL, current, 1);
- return(-EPIPE);
- }
+static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+ struct unix_proto_data *pupd;
+ int todo, space;
+ int er;
+
+ if ((todo = size) <= 0)
+ return(0);
+ if (sock->state != SS_CONNECTED)
+ {
+ dprintf(1, "UNIX: write: socket not connected\n");
+ if (sock->state == SS_DISCONNECTING)
+ {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ return(-EINVAL);
+ }
+ pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
+
+ while(!(space = UN_BUF_SPACE(pupd)))
+ {
+ dprintf(1, "UNIX: write: no space left...\n");
+ if (nonblock)
+ return(-EAGAIN);
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked)
+ {
+ dprintf(1, "UNIX: write: interrupted\n");
+ return(-ERESTARTSYS);
+ }
+ if (sock->state == SS_DISCONNECTING)
+ {
+ dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ }
- /*
- * We may become disconnected inside this loop, so watch
- * for it (peerupd is safe until we close).
- */
- if (sock->state == SS_DISCONNECTING) {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- if ((cando = todo) > space) cando = space;
- if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;
- dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
- space, todo, cando);
- er=verify_area(VERIFY_READ, ubuf, cando);
- if(er)
- return er;
- memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
- pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
- ubuf += cando;
- todo -= cando;
- if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
- space = UN_BUF_SPACE(pupd);
- } while(todo && space);
- return(size - todo);
+ /*
+ * Copy from the user's buffer to the write buffer,
+ * watching for wraparound. Then we wake up the reader.
+ */
+
+ do
+ {
+ int part, cando;
+
+ if (space <= 0)
+ {
+ printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
+ send_sig(SIGKILL, current, 1);
+ return(-EPIPE);
+ }
+
+ /*
+ * We may become disconnected inside this loop, so watch
+ * for it (peerupd is safe until we close).
+ */
+
+ if (sock->state == SS_DISCONNECTING)
+ {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ if ((cando = todo) > space)
+ cando = space;
+
+ if (cando >(part = BUF_SIZE - pupd->bp_head))
+ cando = part;
+
+ dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
+ space, todo, cando);
+
+ er=verify_area(VERIFY_READ, ubuf, cando);
+ if(er)
+ return er;
+ memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
+ pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
+
+ ubuf += cando;
+ todo -= cando;
+
+ if (sock->state == SS_CONNECTED)
+ wake_up(sock->conn->wait);
+ space = UN_BUF_SPACE(pupd);
+ }
+ while(todo && space);
+ return(size - todo);
}
-static int
-unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
+static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
{
- struct unix_proto_data *upd, *peerupd;
-
- /* Handle server sockets specially. */
- if (sock->flags & SO_ACCEPTCON) {
- if (sel_type == SEL_IN) {
- dprintf(1, "UNIX: select: %sconnections pending\n",
- sock->iconn ? "" : "no ");
- if (sock->iconn) return(1);
+ struct unix_proto_data *upd, *peerupd;
+
+ /* Handle server sockets specially. */
+ if (sock->flags & SO_ACCEPTCON)
+ {
+ if (sel_type == SEL_IN)
+ {
+ dprintf(1, "UNIX: select: %sconnections pending\n",
+ sock->iconn ? "" : "no ");
+ if (sock->iconn)
+ return(1);
+ select_wait(sock->wait, wait);
+ return(sock->iconn ? 1 : 0);
+ }
+ dprintf(1, "UNIX: select: nothing else for server socket\n");
select_wait(sock->wait, wait);
- return(sock->iconn ? 1 : 0);
- }
- dprintf(1, "UNIX: select: nothing else for server socket\n");
- select_wait(sock->wait, wait);
- return(0);
- }
-
- if (sel_type == SEL_IN) {
- upd = UN_DATA(sock);
- dprintf(1, "UNIX: select: there is%s data available\n",
- UN_BUF_AVAIL(upd) ? "" : " no");
- if (UN_BUF_AVAIL(upd)) /* even if disconnected */
+ return(0);
+ }
+
+ if (sel_type == SEL_IN)
+ {
+ upd = UN_DATA(sock);
+ dprintf(1, "UNIX: select: there is%s data available\n",
+ UN_BUF_AVAIL(upd) ? "" : " no");
+ if (UN_BUF_AVAIL(upd)) /* even if disconnected */
return(1);
- else if (sock->state != SS_CONNECTED) {
- dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
- return(1);
- }
- select_wait(sock->wait,wait);
- return(0);
- }
- if (sel_type == SEL_OUT) {
- if (sock->state != SS_CONNECTED) {
- dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
- return(1);
- }
- peerupd = UN_DATA(sock->conn);
- dprintf(1, "UNIX: select: there is%s space available\n",
- UN_BUF_SPACE(peerupd) ? "" : " no");
- if (UN_BUF_SPACE(peerupd) > 0) return(1);
- select_wait(sock->wait,wait);
- return(0);
- }
-
- /* SEL_EX */
- dprintf(1, "UNIX: select: there are no exceptions here?!\n");
- return(0);
+ else if (sock->state != SS_CONNECTED)
+ {
+ dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
+ return(1);
+ }
+ select_wait(sock->wait,wait);
+ return(0);
+ }
+ if (sel_type == SEL_OUT)
+ {
+ if (sock->state != SS_CONNECTED)
+ {
+ dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
+ return(1);
+ }
+ peerupd = UN_DATA(sock->conn);
+ dprintf(1, "UNIX: select: there is%s space available\n",
+ UN_BUF_SPACE(peerupd) ? "" : " no");
+ if (UN_BUF_SPACE(peerupd) > 0)
+ return(1);
+ select_wait(sock->wait,wait);
+ return(0);
+ }
+
+ /* SEL_EX */
+ dprintf(1, "UNIX: select: there are no exceptions here?!\n");
+ return(0);
}
-static int
-unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
- struct unix_proto_data *upd, *peerupd;
- int er;
-
- upd = UN_DATA(sock);
- peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
-
- switch(cmd) {
- case TIOCINQ:
- if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
- er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
- if(er)
- return er;
- if (UN_BUF_AVAIL(upd) || peerupd)
- put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
- else
- put_fs_long(0,(unsigned long *)arg);
- break;
- case TIOCOUTQ:
- if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
- er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
- if(er)
- return er;
- if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd),
- (unsigned long *)arg);
- else
- put_fs_long(0,(unsigned long *)arg);
- break;
- default:
- return(-EINVAL);
- }
- return(0);
+ struct unix_proto_data *upd, *peerupd;
+ int er;
+
+ upd = UN_DATA(sock);
+ peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
+
+ switch(cmd)
+ {
+ case TIOCINQ:
+ if (sock->flags & SO_ACCEPTCON)
+ return(-EINVAL);
+ er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
+ if(er)
+ return er;
+ if (UN_BUF_AVAIL(upd) || peerupd)
+ put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
+ else
+ put_fs_long(0,(unsigned long *)arg);
+ break;
+ case TIOCOUTQ:
+ if (sock->flags & SO_ACCEPTCON)
+ return(-EINVAL);
+ er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
+ if(er)
+ return er;
+ if (peerupd)
+ put_fs_long(UN_BUF_SPACE(peerupd), (unsigned long *)arg);
+ else
+ put_fs_long(0,(unsigned long *)arg);
+ break;
+ default:
+ return(-EINVAL);
+ }
+ return(0);
}
-static int
-unix_open(struct inode * inode, struct file * file)
+static int unix_open(struct inode * inode, struct file * file)
{
- int minor;
+ int minor;
- dprintf(1, "UNIX: open\n");
- minor = MINOR(inode->i_rdev);
- if (minor != 0) return(-ENODEV);
+ dprintf(1, "UNIX: open\n");
+ minor = MINOR(inode->i_rdev);
+
+ if (minor != 0)
+ return(-ENODEV);
- return(0);
+ return(0);
}
-static void
-unix_close(struct inode * inode, struct file * file)
+static void unix_close(struct inode * inode, struct file * file)
{
- dprintf(1, "UNIX: close\n");
+ dprintf(1, "UNIX: close\n");
}
-static int
-unix_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int unix_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- int minor, ret;
- int er;
-
- dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);
- minor = MINOR(inode->i_rdev);
- if (minor != 0) return(-ENODEV);
-
- ret = -EINVAL;
- switch(cmd) {
- case DDIOCSDBG:
- er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
- if(er)
- return er;
- unix_debug = get_fs_long((int *)arg);
- if (unix_debug != 0 && unix_debug != 1) {
- unix_debug = 0;
- return(-EINVAL);
- }
- return(0);
- case SIOCSIFLINK:
- printk("UNIX: cannot link streams!\n");
- break;
- default:
- break;
- }
- return(ret);
+ int minor, ret;
+ int er;
+
+ dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);
+ minor = MINOR(inode->i_rdev);
+
+ if (minor != 0)
+ return(-ENODEV);
+
+ ret = -EINVAL;
+ switch(cmd)
+ {
+ case DDIOCSDBG:
+ er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
+ if(er)
+ return er;
+ unix_debug = get_fs_long((int *)arg);
+ if (unix_debug != 0 && unix_debug != 1)
+ {
+ unix_debug = 0;
+ return(-EINVAL);
+ }
+ return(0);
+ case SIOCSIFLINK:
+ printk("UNIX: cannot link streams!\n");
+ break;
+ default:
+ break;
+ }
+ return(ret);
}
-static struct file_operations unix_fops = {
- NULL, /* LSEEK */
- NULL, /* READ */
- NULL, /* WRITE */
- NULL, /* READDIR */
- NULL, /* SELECT */
- unix_ioctl, /* IOCTL */
- NULL, /* MMAP */
- unix_open, /* OPEN */
- unix_close /* CLOSE */
+static struct file_operations unix_fops =
+{
+ NULL, /* LSEEK */
+ NULL, /* READ */
+ NULL, /* WRITE */
+ NULL, /* READDIR */
+ NULL, /* SELECT */
+ unix_ioctl, /* IOCTL */
+ NULL, /* MMAP */
+ unix_open, /* OPEN */
+ unix_close /* CLOSE */
};
static struct proto_ops unix_proto_ops = {
- AF_UNIX,
- unix_proto_create,
- unix_proto_dup,
- unix_proto_release,
- unix_proto_bind,
- unix_proto_connect,
- unix_proto_socketpair,
- unix_proto_accept,
- unix_proto_getname,
- unix_proto_read,
- unix_proto_write,
- unix_proto_select,
- unix_proto_ioctl,
- unix_proto_listen,
- unix_proto_send,
- unix_proto_recv,
- unix_proto_sendto,
- unix_proto_recvfrom,
- unix_proto_shutdown,
- unix_proto_setsockopt,
- unix_proto_getsockopt,
- NULL /* unix_proto_fcntl */
+ AF_UNIX,
+ unix_proto_create,
+ unix_proto_dup,
+ unix_proto_release,
+ unix_proto_bind,
+ unix_proto_connect,
+ unix_proto_socketpair,
+ unix_proto_accept,
+ unix_proto_getname,
+ unix_proto_read,
+ unix_proto_write,
+ unix_proto_select,
+ unix_proto_ioctl,
+ unix_proto_listen,
+ unix_proto_send,
+ unix_proto_recv,
+ unix_proto_sendto,
+ unix_proto_recvfrom,
+ unix_proto_shutdown,
+ unix_proto_setsockopt,
+ unix_proto_getsockopt,
+ NULL /* unix_proto_fcntl */
};
-void
-unix_proto_init(struct ddi_proto *pro)
+void unix_proto_init(struct ddi_proto *pro)
{
- struct unix_proto_data *upd;
-
- dprintf(1, "%s: init: initializing...\n", pro->name);
- if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) {
- printk("%s: cannot register major device %d!\n",
- pro->name, AF_UNIX_MAJOR);
- return;
- }
-
- /* Tell SOCKET that we are alive... */
- (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
-
- for(upd = unix_datas; upd <= last_unix_data; ++upd) {
- upd->refcnt = 0;
- }
+ struct unix_proto_data *upd;
+
+ dprintf(1, "%s: init: initializing...\n", pro->name);
+ if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0)
+ {
+ printk("%s: cannot register major device %d!\n",
+ pro->name, AF_UNIX_MAJOR);
+ return;
+ }
+
+ /* Tell SOCKET that we are alive... */
+ (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
+
+ for(upd = unix_datas; upd <= last_unix_data; ++upd)
+ {
+ upd->refcnt = 0;
+ }
}