Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
36f4514a
Commit
36f4514a
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 0.99.14p
parent
ddd9ed00
Changes
47
Hide whitespace changes
Inline
Side-by-side
Showing
47 changed files
with
1201 additions
and
691 deletions
+1201
-691
Makefile
Makefile
+1
-1
drivers/FPU-emu/Makefile
drivers/FPU-emu/Makefile
+3
-2
drivers/FPU-emu/README
drivers/FPU-emu/README
+4
-3
drivers/FPU-emu/errors.c
drivers/FPU-emu/errors.c
+4
-2
drivers/FPU-emu/fpu_trig.c
drivers/FPU-emu/fpu_trig.c
+25
-1
drivers/FPU-emu/reg_norm.S
drivers/FPU-emu/reg_norm.S
+23
-1
drivers/FPU-emu/version.h
drivers/FPU-emu/version.h
+2
-2
drivers/block/cdu31a.c
drivers/block/cdu31a.c
+259
-135
drivers/char/Makefile
drivers/char/Makefile
+1
-1
drivers/char/mouse.c
drivers/char/mouse.c
+2
-2
drivers/char/psaux.c
drivers/char/psaux.c
+1
-1
drivers/char/serial.c
drivers/char/serial.c
+2
-2
drivers/char/tty_io.c
drivers/char/tty_io.c
+7
-1
drivers/net/slip.c
drivers/net/slip.c
+32
-0
fs/binfmt_coff.c
fs/binfmt_coff.c
+16
-1
fs/ext2/CHANGES
fs/ext2/CHANGES
+1
-2
fs/ext2/dir.c
fs/ext2/dir.c
+0
-9
fs/ext2/file.c
fs/ext2/file.c
+3
-10
fs/ext2/super.c
fs/ext2/super.c
+1
-1
fs/sysv/README
fs/sysv/README
+3
-8
fs/sysv/ialloc.c
fs/sysv/ialloc.c
+2
-1
fs/sysv/inode.c
fs/sysv/inode.c
+1
-1
include/linux/ext2_fs.h
include/linux/ext2_fs.h
+1
-1
include/linux/if_ether.h
include/linux/if_ether.h
+2
-1
include/linux/socket.h
include/linux/socket.h
+21
-0
include/linux/sockios.h
include/linux/sockios.h
+1
-1
init/main.c
init/main.c
+1
-1
net/inet/arp.c
net/inet/arp.c
+35
-8
net/inet/arp.h
net/inet/arp.h
+1
-0
net/inet/datagram.c
net/inet/datagram.c
+40
-35
net/inet/dev.c
net/inet/dev.c
+18
-51
net/inet/eth.c
net/inet/eth.c
+3
-2
net/inet/icmp.c
net/inet/icmp.c
+4
-3
net/inet/ip.c
net/inet/ip.c
+77
-3
net/inet/ip.h
net/inet/ip.h
+4
-1
net/inet/packet.c
net/inet/packet.c
+3
-0
net/inet/raw.c
net/inet/raw.c
+17
-5
net/inet/route.c
net/inet/route.c
+14
-8
net/inet/skbuff.c
net/inet/skbuff.c
+82
-82
net/inet/skbuff.h
net/inet/skbuff.h
+1
-0
net/inet/sock.c
net/inet/sock.c
+231
-171
net/inet/sock.h
net/inet/sock.h
+18
-1
net/inet/tcp.c
net/inet/tcp.c
+170
-112
net/inet/timer.c
net/inet/timer.c
+4
-4
net/inet/udp.c
net/inet/udp.c
+14
-10
net/unix/sock.c
net/unix/sock.c
+44
-4
net/unix/unix.h
net/unix/unix.h
+2
-0
No files found.
Makefile
View file @
36f4514a
VERSION
=
0.99
PATCHLEVEL
=
14
ALPHA
=
o
ALPHA
=
p
all
:
Version zImage
...
...
drivers/FPU-emu/Makefile
View file @
36f4514a
...
...
@@ -4,14 +4,15 @@
#DEBUG = -DDEBUGGING
DEBUG
=
PARANOID
=
-DPARANOID
REENTRANT
=
-DREENTRANT_FPU
CFLAGS
:=
$(CFLAGS)
-DPARANOID
$(DEBUG)
-fno-builtin
CFLAGS
:=
$(CFLAGS)
$(PARANOID)
$(DEBUG)
-fno-builtin
.c.o
:
$(CC)
$(CFLAGS)
$(MATH_EMULATION)
-c
$<
.S.o
:
$(CC)
-D__ASSEMBLER__
$(REENTRANT)
-c
$<
$(CC)
-D__ASSEMBLER__
$(
PARANOID)
$(
REENTRANT)
-c
$<
.s.o
:
$(CC)
-c
$<
...
...
drivers/FPU-emu/README
View file @
36f4514a
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen
Sept 1993
Jan 1994
----------------------- Internals of wm-FPU-emu -----------------------
...
...
@@ -305,7 +305,8 @@ Daniel Carosone, danielce@ee.mu.oz.au
cae@jpmorgan.com
Hamish Coleman, t933093@minyos.xx.rmit.oz.au
Bruce Evans, bde@kralizec.zeta.org.au
Timo Korvola, Timo.Korvola@hut.fi
...and numerous others who responded to my request for help with
a real 80486.
drivers/FPU-emu/errors.c
View file @
36f4514a
...
...
@@ -3,7 +3,7 @@
| |
| The error handling functions for wm-FPU-emu |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -208,7 +208,7 @@ static struct {
0x125 in fpu_trig.c
0x126 in fpu_entry.c
0x127 in poly_2xm1.c
0x2nn in an *.
s
file:
0x2nn in an *.
S
file:
0x201 in reg_u_add.S, reg_round.S
0x202 in reg_u_div.S
0x203 in reg_u_div.S
...
...
@@ -227,6 +227,8 @@ static struct {
0x216 in reg_round.S
0x217 in reg_round.S
0x218 in reg_round.S
0x220 in reg_norm.S
0x221 in reg_norm.S
*/
void
exception
(
int
n
)
...
...
drivers/FPU-emu/fpu_trig.c
View file @
36f4514a
...
...
@@ -3,7 +3,7 @@
| |
| Implementation of the FPU "transcendental" functions. |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
...
...
@@ -88,9 +88,19 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */
significand
(
&
tmp
)
=
q
+
1
;
tmp
.
exp
=
EXP_BIAS
+
63
;
tmp
.
tag
=
TW_Valid
;
normalize
(
&
tmp
);
reg_mul
(
&
CONST_PI2extra
,
&
tmp
,
&
tmp
,
FULL_PRECISION
);
reg_add
(
X
,
&
tmp
,
X
,
FULL_PRECISION
);
if
(
X
->
sign
==
SIGN_NEG
)
{
/* CONST_PI2extra is negative, so the result of the addition
can be negative. This means that the argument is actually
in a different quadrant. The correction is always < pi/2,
so it can't overflow into yet another quadrant. */
X
->
sign
=
SIGN_POS
;
q
++
;
}
}
#endif BETTER_THAN_486
}
...
...
@@ -107,9 +117,23 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */
significand
(
&
tmp
)
=
q
;
tmp
.
exp
=
EXP_BIAS
+
63
;
tmp
.
tag
=
TW_Valid
;
normalize
(
&
tmp
);
reg_mul
(
&
CONST_PI2extra
,
&
tmp
,
&
tmp
,
FULL_PRECISION
);
reg_sub
(
X
,
&
tmp
,
X
,
FULL_PRECISION
);
if
(
(
X
->
exp
==
CONST_PI2
.
exp
)
&&
((
X
->
sigh
>
CONST_PI2
.
sigh
)
||
((
X
->
sigh
==
CONST_PI2
.
sigh
)
&&
(
X
->
sigl
>
CONST_PI2
.
sigl
)))
)
{
/* CONST_PI2extra is negative, so the result of the
subtraction can be larger than pi/2. This means
that the argument is actually in a different quadrant.
The correction is always < pi/2, so it can't overflow
into yet another quadrant. */
reg_sub
(
&
CONST_PI
,
X
,
X
,
FULL_PRECISION
);
q
++
;
}
}
}
#endif BETTER_THAN_486
...
...
drivers/FPU-emu/reg_norm.S
View file @
36f4514a
/*---------------------------------------------------------------------------+
|
reg_norm
.
S
|
|
|
|
Copyright
(
C
)
1992
,
1993
|
|
Copyright
(
C
)
1992
,
1993
,
1994
|
|
W
.
Metzenthen
,
22
Parker
St
,
Ormond
,
Vic
3163
,
|
|
Australia
.
E
-
mail
billm
@
vaxc
.
cc
.
monash
.
edu
.
au
|
|
|
...
...
@@ -29,6 +29,17 @@ _normalize:
movl
PARAM1
,%
ebx
#ifdef PARANOID
cmpb
TW_Valid
,
TAG
(%
ebx
)
je
L_ok
pushl
$
0x220
call
_exception
addl
$
4
,%
esp
L_ok
:
#endif PARANOID
movl
SIGH
(%
ebx
),%
edx
movl
SIGL
(%
ebx
),%
eax
...
...
@@ -98,6 +109,17 @@ _normalize_nuo:
movl
PARAM1
,%
ebx
#ifdef PARANOID
cmpb
TW_Valid
,
TAG
(%
ebx
)
je
L_ok_nuo
pushl
$
0x221
call
_exception
addl
$
4
,%
esp
L_ok_nuo
:
#endif PARANOID
movl
SIGH
(%
ebx
),%
edx
movl
SIGL
(%
ebx
),%
eax
...
...
drivers/FPU-emu/version.h
View file @
36f4514a
...
...
@@ -2,12 +2,12 @@
| version.h |
| |
| |
| Copyright (C) 1992,1993
|
| Copyright (C) 1992,1993
,1994
|
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version B
ETA 1.6
"
#define FPU_VERSION "wm-FPU-emu version B
eta 1.7
"
drivers/block/cdu31a.c
View file @
36f4514a
...
...
@@ -80,11 +80,13 @@
#define MAJOR_NR CDU31A_CDROM_MAJOR
#include "blk.h"
#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
static
unsigned
short
cdu31a_addresses
[]
=
{
0x340
,
/* Standard configuration Sony Interface */
0x1f88
,
/* Fusion CD-16 */
0x230
,
/* SoundBlaster 16 card */
0x360
,
/* Secondary standard Sony Interface */
0x320
,
/* Secondary standard Sony Interface */
0x330
,
/* Secondary standard Sony Interface */
...
...
@@ -96,6 +98,13 @@ static int handle_sony_cd_attention(void);
static
int
read_subcode
(
void
);
static
void
sony_get_toc
(
void
);
static
int
scd_open
(
struct
inode
*
inode
,
struct
file
*
filp
);
static
void
do_sony_cd_cmd
(
unsigned
char
cmd
,
unsigned
char
*
params
,
unsigned
int
num_params
,
unsigned
char
*
result_buffer
,
unsigned
int
*
result_size
);
static
void
size_to_buf
(
unsigned
int
size
,
unsigned
char
*
buf
);
/* The base I/O address of the Sony Interface. This is a variable (not a
...
...
@@ -116,7 +125,6 @@ static volatile unsigned short sony_cd_read_reg;
static
volatile
unsigned
short
sony_cd_fifost_reg
;
static
int
initialized
=
0
;
/* Has the drive been initialized? */
static
int
sony_disc_changed
=
1
;
/* Has the disk been changed
since the last check? */
static
int
sony_toc_read
=
0
;
/* Has the table of contents been
...
...
@@ -306,6 +314,71 @@ write_cmd(unsigned char cmd)
outb
(
SONY_RES_RDY_INT_EN_BIT
,
sony_cd_control_reg
);
}
/*
* Set the drive parameters so the drive will auto-spin-up when a
* disk is inserted.
*/
static
void
set_drive_params
(
void
)
{
unsigned
char
res_reg
[
2
];
unsigned
int
res_size
;
unsigned
char
params
[
3
];
params
[
0
]
=
SONY_SD_MECH_CONTROL
;
params
[
1
]
=
0x03
;
do_sony_cd_cmd
(
SONY_SET_DRIVE_PARAM_CMD
,
params
,
2
,
res_reg
,
&
res_size
);
if
((
res_size
<
2
)
||
((
res_reg
[
0
]
&
0x20
)
==
0x20
))
{
printk
(
" Unable to set mechanical parameters: 0x%2.2x
\n
"
,
res_reg
[
1
]);
}
}
/*
* This code will reset the drive and attempt to restore sane parameters.
*/
static
void
restart_on_error
(
void
)
{
unsigned
char
res_reg
[
2
];
unsigned
int
res_size
;
unsigned
int
retry_count
;
printk
(
"cdu31a: Resetting drive on error
\n
"
);
reset_drive
();
retry_count
=
jiffies
+
SONY_RESET_TIMEOUT
;
while
((
retry_count
>
jiffies
)
&&
(
!
is_attention
()))
{
sony_sleep
();
}
set_drive_params
();
do_sony_cd_cmd
(
SONY_SPIN_UP_CMD
,
NULL
,
0
,
res_reg
,
&
res_size
);
if
((
res_size
<
2
)
||
((
res_reg
[
0
]
&
0x20
)
==
0x20
))
{
printk
(
"cdu31a: Unable to spin up drive: 0x%2.2x
\n
"
,
res_reg
[
1
]);
}
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
200
;
schedule
();
do_sony_cd_cmd
(
SONY_READ_TOC_CMD
,
NULL
,
0
,
res_reg
,
&
res_size
);
if
((
res_size
<
2
)
||
((
res_reg
[
0
]
&
0x20
)
==
0x20
))
{
printk
(
"cdu31a: Unable to read TOC: 0x%2.2x
\n
"
,
res_reg
[
1
]);
}
sony_get_toc
();
if
(
!
sony_toc_read
)
{
printk
(
"cdu31a: Unable to get TOC data
\n
"
);
}
}
/*
* This routine writes data to the parameter register. Since this should
...
...
@@ -459,6 +532,39 @@ get_result(unsigned char *result_buffer,
}
}
/*
* Read in a 2048 byte block of data.
*/
static
void
read_data_block
(
unsigned
char
*
data
,
unsigned
char
*
result_buffer
,
unsigned
int
*
result_size
)
{
int
i
;
unsigned
int
retry_count
;
for
(
i
=
0
;
i
<
2048
;
i
++
)
{
retry_count
=
jiffies
+
SONY_JIFFIES_TIMEOUT
;
while
((
retry_count
>
jiffies
)
&&
(
!
is_data_requested
()))
{
while
(
handle_sony_cd_attention
())
;
sony_sleep
();
}
if
(
!
is_data_requested
())
{
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_TIMEOUT_OP_ERR
;
*
result_size
=
2
;
return
;
}
*
data
=
read_data_register
();
data
++
;
}
}
/*
* This routine issues a read data command and gets the data. I don't
...
...
@@ -469,35 +575,37 @@ get_result(unsigned char *result_buffer,
* received at any time and should be handled immediately (at least
* between every 2048 byte block) to check for errors, we can't wait
* until all the data is read.
*
* This routine returns the total number of sectors read. It will
* not return an error if it reads at least one sector successfully.
*/
static
void
get_data
(
unsigned
char
*
data
,
static
unsigned
int
get_data
(
unsigned
char
*
orig_
data
,
unsigned
char
*
params
,
/* 6 bytes with the MSF start address
and number of sectors to read. */
unsigned
int
data_size
,
unsigned
int
orig_
data_size
,
unsigned
char
*
result_buffer
,
unsigned
int
*
result_size
)
{
int
i
;
unsigned
int
cur_offset
;
unsigned
int
retry_count
;
int
result_read
;
int
num_retries
;
unsigned
int
num_sectors_read
=
0
;
unsigned
char
*
data
=
orig_data
;
unsigned
int
data_size
=
orig_data_size
;
cli
();
if
(
current
!=
has_cd_task
)
/* Allow recursive calls to this routine */
while
(
sony_inuse
)
{
while
(
sony_inuse
)
interruptible_sleep_on
(
&
sony_wait
);
if
(
current
->
signal
&
~
current
->
blocked
)
{
interruptible_sleep_on
(
&
sony_wait
);
if
(
current
->
signal
&
~
current
->
blocked
)
{
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_SIGNAL_OP_ERR
;
*
result_size
=
2
;
return
;
}
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_SIGNAL_OP_ERR
;
*
result_size
=
2
;
return
0
;
}
}
sony_inuse
=
1
;
...
...
@@ -506,6 +614,8 @@ get_data(unsigned char *data,
num_retries
=
0
;
retry_data_operation:
result_buffer
[
0
]
=
0
;
result_buffer
[
1
]
=
0
;
/*
* Clear any outstanding attentions and wait for the drive to
...
...
@@ -522,115 +632,120 @@ get_data(unsigned char *data,
while
(
handle_sony_cd_attention
())
;
}
if
(
is_busy
())
{
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_TIMEOUT_OP_ERR
;
*
result_size
=
2
;
goto
get_data_end
;
}
else
{
/* Issue the command */
clear_result_ready
();
clear_param_reg
();
/* Issue the command */
clear_result_ready
();
clear_param_reg
();
write_params
(
params
,
6
);
write_cmd
(
SONY_READ_CMD
);
write_params
(
params
,
6
);
write_cmd
(
SONY_READ_CMD
);
/*
* Read the data from the drive one 2048 byte sector at a time. Handle
* any results received between sectors, if an error result is returned
* terminate the operation immediately.
*/
cur_offset
=
0
;
result_read
=
0
;
while
(
data_size
>
0
)
{
/* Wait for the drive to tell us we have something */
retry_count
=
jiffies
+
SONY_JIFFIES_TIMEOUT
;
while
((
retry_count
>
jiffies
)
&&
(
!
(
is_result_ready
()
||
is_data_ready
())))
{
while
(
handle_sony_cd_attention
())
;
sony_sleep
();
}
if
(
!
(
is_result_ready
()
||
is_data_ready
()))
/*
* Read the data from the drive one 2048 byte sector at a time. Handle
* any results received between sectors, if an error result is returned
* terminate the operation immediately.
*/
cur_offset
=
0
;
result_read
=
0
;
while
((
data_size
>
0
)
&&
(
result_buffer
[
0
]
==
0
))
{
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_TIMEOUT_OP_ERR
;
*
result_size
=
2
;
goto
get_data_end
;
}
/* Wait for the drive to tell us we have something */
retry_count
=
jiffies
+
SONY_JIFFIES_TIMEOUT
;
while
((
retry_count
>
jiffies
)
&&
(
!
(
is_result_ready
()
||
is_data_ready
())))
{
while
(
handle_sony_cd_attention
())
;
sony_sleep
();
}
if
(
!
(
is_result_ready
()
||
is_data_ready
()))
{
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_TIMEOUT_OP_ERR
;
*
result_size
=
2
;
}
/* Handle results first */
if
(
is_result_ready
())
{
result_read
=
1
;
get_result
(
result_buffer
,
result_size
);
if
((
*
result_size
<
2
)
||
(
result_buffer
[
0
]
!=
0
))
/* Handle results first */
else
if
(
is_result_ready
())
{
goto
get_data_end
;
result_read
=
1
;
get_result
(
result_buffer
,
result_size
);
}
}
else
/* Handle data next */
{
/*
* The drive has to be polled for status on a byte-by-byte basis
* to know if the data is ready. Yuck. I really wish I could use DMA.
*/
clear_data_ready
();
for
(
i
=
0
;
i
<
2048
;
i
++
)
else
/* Handle data next */
{
retry_count
=
jiffies
+
SONY_JIFFIES_TIMEOUT
;
while
((
retry_count
>
jiffies
)
&&
(
!
is_data_requested
()))
{
while
(
handle_sony_cd_attention
())
;
sony_sleep
();
}
if
(
!
is_data_requested
())
{
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_TIMEOUT_OP_ERR
;
*
result_size
=
2
;
goto
get_data_end
;
}
*
data
=
read_data_register
();
data
++
;
data_size
--
;
/*
* The drive has to be polled for status on a byte-by-byte basis
* to know if the data is ready. Yuck. I really wish I could use DMA.
*/
clear_data_ready
();
read_data_block
(
data
,
result_buffer
,
result_size
);
data
+=
2048
;
data_size
-=
2048
;
cur_offset
=
cur_offset
+
2048
;
num_sectors_read
++
;
}
cur_offset
=
cur_offset
+
2048
;
}
}
/* Make sure the result has been read */
if
(
!
result_read
)
{
get_result
(
result_buffer
,
result_size
);
/* Make sure the result has been read */
if
(
!
result_read
)
{
get_result
(
result_buffer
,
result_size
);
}
}
get_data_end:
if
(
((
result_buffer
[
0
]
&
0x20
)
==
0x20
)
&&
(
result_buffer
[
1
]
!=
SONY_NOT_SPIN_ERR
)
/* No retry when not spin */
&&
(
num_retries
<
MAX_CDU31A_RETRIES
))
{
/*
* If an error occurs, go back and only read one sector at the
* given location. Hopefully the error occurred on an unused
* sector after the first one. It is hard to say which sector
* the error occurred on because the drive returns status before
* the data transfer is finished and doesn't say which sector.
*/
data_size
=
2048
;
data
=
orig_data
;
num_sectors_read
=
0
;
size_to_buf
(
1
,
&
params
[
3
]);
num_retries
++
;
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
10
;
/* Wait .1 seconds on retries */
schedule
();
/* Issue a reset on an error (the second time), othersize just delay */
if
(
num_retries
==
2
)
{
restart_on_error
();
}
else
{
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
10
;
schedule
();
}
/* Restart the operation. */
goto
retry_data_operation
;
}
has_cd_task
=
NULL
;
sony_inuse
=
0
;
wake_up_interruptible
(
&
sony_wait
);
return
(
num_sectors_read
);
}
/*
* Do a command that does not involve data transfer.
* Do a command that does not involve data transfer. This routine must
* be re-entrant from the same task to support being called from the
* data operation code when an error occurs.
*/
static
void
do_sony_cd_cmd
(
unsigned
char
cmd
,
...
...
@@ -641,6 +756,7 @@ do_sony_cd_cmd(unsigned char cmd,
{
unsigned
int
retry_count
;
int
num_retries
;
int
recursive_call
;
cli
();
...
...
@@ -657,9 +773,14 @@ do_sony_cd_cmd(unsigned char cmd,
return
;
}
}
sony_inuse
=
1
;
has_cd_task
=
current
;
recursive_call
=
0
;
}
else
{
recursive_call
=
1
;
}
sony_inuse
=
1
;
has_cd_task
=
current
;
sti
();
num_retries
=
0
;
...
...
@@ -681,18 +802,18 @@ do_sony_cd_cmd(unsigned char cmd,
result_buffer
[
0
]
=
0x20
;
result_buffer
[
1
]
=
SONY_TIMEOUT_OP_ERR
;
*
result_size
=
2
;
goto
do_cmd_end
;
}
else
{
clear_result_ready
();
clear_param_reg
();
clear_result_ready
();
clear_param_reg
();
write_params
(
params
,
num_params
);
write_cmd
(
cmd
);
write_params
(
params
,
num_params
);
write_cmd
(
cmd
);
get_result
(
result_buffer
,
result_size
);
get_result
(
result_buffer
,
result_size
);
}
do_cmd_end:
if
(
((
result_buffer
[
0
]
&
0x20
)
==
0x20
)
&&
(
num_retries
<
MAX_CDU31A_RETRIES
))
{
...
...
@@ -703,26 +824,41 @@ do_sony_cd_cmd(unsigned char cmd,
goto
retry_cd_operation
;
}
has_cd_task
=
NULL
;
sony_inuse
=
0
;
wake_up_interruptible
(
&
sony_wait
);
if
(
!
recursive_call
)
{
has_cd_task
=
NULL
;
sony_inuse
=
0
;
wake_up_interruptible
(
&
sony_wait
);
}
}
/*
* Handle an attention from the drive. This will return 1 if it found one
* or 0 if not (if one is found, the caller might want to call again).
*
* This routine counts the number of consecutive times it is called
* (since this is always called from a while loop until it returns
* a 0), and returns a 0 if it happens too many times. This will help
* prevent a lockup.
*/
static
int
handle_sony_cd_attention
(
void
)
{
unsigned
char
atten_code
;
unsigned
char
res_reg
[
2
];
unsigned
int
res_size
;
static
int
num_consecutive_attentions
=
0
;
if
(
is_attention
())
{
if
(
num_consecutive_attentions
>
CDU31A_MAX_CONSECUTIVE_ATTENTIONS
)
{
printk
(
"cdu31a: Too many consecutive attentions: %d
\n
"
,
num_consecutive_attentions
);
num_consecutive_attentions
=
0
;
return
(
0
);
}
clear_attention
();
atten_code
=
read_result_register
();
...
...
@@ -735,11 +871,6 @@ handle_sony_cd_attention(void)
sony_audio_status
=
CDROM_AUDIO_NO_STATUS
;
sony_first_block
=
-
1
;
sony_last_block
=
-
1
;
if
(
initialized
)
{
do_sony_cd_cmd
(
SONY_SPIN_UP_CMD
,
NULL
,
0
,
res_reg
,
&
res_size
);
sony_get_toc
();
}
break
;
case
SONY_AUDIO_PLAY_DONE_ATTN
:
...
...
@@ -758,9 +889,12 @@ handle_sony_cd_attention(void)
sony_audio_status
=
CDROM_AUDIO_ERROR
;
break
;
}
num_consecutive_attentions
++
;
return
(
1
);
}
num_consecutive_attentions
=
0
;
return
(
0
);
}
...
...
@@ -862,6 +996,7 @@ do_cdu31a_request(void)
while
(
1
)
{
cdu31a_request_startover:
/*
* The beginning here is stolen from the hard disk driver. I hope
* its right.
...
...
@@ -878,7 +1013,7 @@ do_cdu31a_request(void)
if
(
dev
!=
0
)
{
end_request
(
0
);
continue
;
goto
cdu31a_request_startover
;
}
switch
(
CURRENT
->
cmd
)
...
...
@@ -891,12 +1026,12 @@ do_cdu31a_request(void)
if
((
block
/
4
)
>=
sony_toc
->
lead_out_start_lba
)
{
end_request
(
0
);
return
;
goto
cdu31a_request_startover
;
}
if
(((
block
+
nsect
)
/
4
)
>=
sony_toc
->
lead_out_start_lba
)
{
end_request
(
0
);
return
;
goto
cdu31a_request_startover
;
}
while
(
nsect
>
0
)
...
...
@@ -916,12 +1051,10 @@ do_cdu31a_request(void)
*/
if
(((
block
/
4
)
+
sony_buffer_sectors
)
>=
sony_toc
->
lead_out_start_lba
)
{
sony_last_block
=
(
sony_toc
->
lead_out_start_lba
*
4
)
-
1
;
read_size
=
sony_toc
->
lead_out_start_lba
-
(
block
/
4
);
}
else
{
sony_last_block
=
sony_first_block
+
(
sony_buffer_sectors
*
4
)
-
1
;
read_size
=
sony_buffer_sectors
;
}
size_to_buf
(
read_size
,
&
params
[
3
]);
...
...
@@ -932,7 +1065,12 @@ do_cdu31a_request(void)
*/
spin_up_retry
=
0
;
try_read_again:
get_data
(
sony_buffer
,
params
,
(
read_size
*
2048
),
res_reg
,
&
res_size
);
sony_last_block
=
sony_first_block
+
(
get_data
(
sony_buffer
,
params
,
(
read_size
*
2048
),
res_reg
,
&
res_size
)
*
4
)
-
1
;
if
((
res_size
<
2
)
||
(
res_reg
[
0
]
!=
0
))
{
if
((
res_reg
[
1
]
==
SONY_NOT_SPIN_ERR
)
&&
(
!
spin_up_retry
))
...
...
@@ -946,7 +1084,7 @@ do_cdu31a_request(void)
sony_first_block
=
-
1
;
sony_last_block
=
-
1
;
end_request
(
0
);
return
;
goto
cdu31a_request_startover
;
}
}
...
...
@@ -1569,7 +1707,7 @@ static char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };
/* Read-ahead buffer sizes for different drives. These are just arbitrary
values, I don't know what is really optimum. */
static
unsigned
int
mem_size
[]
=
{
4096
,
8192
,
16384
,
2048
};
static
unsigned
int
mem_size
[]
=
{
16384
,
16384
,
16384
,
2048
};
void
get_drive_configuration
(
unsigned
short
base_io
,
...
...
@@ -1640,8 +1778,6 @@ unsigned long
cdu31a_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
)
{
struct
s_sony_drive_config
drive_config
;
unsigned
char
params
[
3
];
unsigned
char
res_reg
[
2
];
unsigned
int
res_size
;
int
i
;
int
drive_found
;
...
...
@@ -1695,17 +1831,7 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
}
printk
(
"
\n
"
);
params
[
0
]
=
SONY_SD_MECH_CONTROL
;
params
[
1
]
=
0x03
;
do_sony_cd_cmd
(
SONY_SET_DRIVE_PARAM_CMD
,
params
,
2
,
res_reg
,
&
res_size
);
if
((
res_size
<
2
)
||
((
res_reg
[
0
]
&
0x20
)
==
0x20
))
{
printk
(
" Unable to set mechanical parameters: 0x%2.2x
\n
"
,
res_reg
[
1
]);
}
set_drive_params
();
blk_dev
[
MAJOR_NR
].
request_fn
=
DEVICE_REQUEST
;
read_ahead
[
MAJOR_NR
]
=
8
;
/* 8 sector (4kB) read-ahead */
...
...
@@ -1716,8 +1842,6 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
mem_start
+=
sizeof
(
*
last_sony_subcode
);
sony_buffer
=
(
unsigned
char
*
)
mem_start
;
mem_start
+=
sony_buffer_size
;
initialized
=
1
;
}
i
++
;
...
...
drivers/char/Makefile
View file @
36f4514a
...
...
@@ -48,7 +48,7 @@ OBJS := $(OBJS) msbusmouse.o
SRCS
:=
$(SRCS)
msbusmouse.c
endif
ifdef
CONFIG_
QUICKPORT
_MOUSE
ifdef
CONFIG_
82C710
_MOUSE
CONFIG_PSMOUSE
=
CONFIG_PSMOUSE
endif
...
...
drivers/char/mouse.c
View file @
36f4514a
...
...
@@ -45,7 +45,7 @@ static int mouse_open(struct inode * inode, struct file * file)
file
->
f_op
=
&
bus_mouse_fops
;
break
;
#endif
#if defined CONFIG_PSMOUSE || defined CONFIG_
QUICKPORT
_MOUSE
#if defined CONFIG_PSMOUSE || defined CONFIG_
82C710
_MOUSE
case
PSMOUSE_MINOR
:
file
->
f_op
=
&
psaux_fops
;
break
;
...
...
@@ -83,7 +83,7 @@ unsigned long mouse_init(unsigned long kmem_start)
#ifdef CONFIG_BUSMOUSE
kmem_start
=
bus_mouse_init
(
kmem_start
);
#endif
#if defined CONFIG_PSMOUSE || defined CONFIG_
QUICKPORT
_MOUSE
#if defined CONFIG_PSMOUSE || defined CONFIG_
82C710
_MOUSE
kmem_start
=
psaux_init
(
kmem_start
);
#endif
#ifdef CONFIG_MS_BUSMOUSE
...
...
drivers/char/psaux.c
View file @
36f4514a
...
...
@@ -68,7 +68,7 @@
#define AUX_DISABLE_DEV 0xf5
/* disable aux device */
#define AUX_RESET 0xff
/* reset aux device */
#define MAX_RETRIES
3
0
/* some aux operations take long time*/
#define MAX_RETRIES
6
0
/* some aux operations take long time*/
#define AUX_IRQ 12
#define AUX_BUF_SIZE 2048
...
...
drivers/char/serial.c
View file @
36f4514a
...
...
@@ -1574,7 +1574,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if
(
info
->
flags
&
ASYNC_CLOSING
)
{
interruptible_sleep_on
(
&
info
->
close_wait
);
return
-
E
AGAIN
;
return
-
E
RESTARTSYS
;
}
/*
...
...
@@ -1632,7 +1632,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
current
->
state
=
TASK_INTERRUPTIBLE
;
if
(
tty_hung_up_p
(
filp
)
||
!
(
info
->
flags
&
ASYNC_INITIALIZED
))
{
retval
=
-
E
AGAIN
;
retval
=
-
E
RESTARTSYS
;
break
;
}
if
(
!
(
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
&&
...
...
drivers/char/tty_io.c
View file @
36f4514a
...
...
@@ -1315,6 +1315,7 @@ static int tty_open(struct inode * inode, struct file * filp)
int
major
,
minor
;
int
noctty
,
retval
;
retry_open:
minor
=
MINOR
(
inode
->
i_rdev
);
major
=
MAJOR
(
inode
->
i_rdev
);
noctty
=
filp
->
f_flags
&
O_NOCTTY
;
...
...
@@ -1372,7 +1373,12 @@ static int tty_open(struct inode * inode, struct file * filp)
#endif
release_dev
(
minor
,
filp
);
return
retval
;
if
(
retval
!=
-
ERESTARTSYS
)
return
retval
;
if
(
current
->
signal
&
~
current
->
blocked
)
return
retval
;
schedule
();
goto
retry_open
;
}
if
(
!
noctty
&&
current
->
leader
&&
...
...
drivers/net/slip.c
View file @
36f4514a
...
...
@@ -881,6 +881,37 @@ slip_open(struct tty_struct *tty)
return
(
sl
->
line
);
}
static
struct
enet_statistics
*
sl_get_stats
(
struct
device
*
dev
)
{
static
struct
enet_statistics
stats
;
struct
slip
*
sl
;
struct
slcompress
*
comp
;
/* Find the correct SLIP channel to use. */
sl
=
&
sl_ctrl
[
dev
->
base_addr
];
if
(
!
sl
)
return
NULL
;
memset
(
&
stats
,
0
,
sizeof
(
struct
enet_statistics
));
stats
.
rx_packets
=
sl
->
rpacket
;
stats
.
rx_over_errors
=
sl
->
roverrun
;
stats
.
tx_packets
=
sl
->
spacket
;
stats
.
tx_dropped
=
sl
->
sbusy
;
stats
.
rx_errors
=
sl
->
errors
;
comp
=
sl
->
slcomp
;
if
(
comp
)
{
stats
.
rx_fifo_errors
=
comp
->
sls_i_compressed
;
stats
.
rx_dropped
=
comp
->
sls_i_tossed
;
stats
.
tx_fifo_errors
=
comp
->
sls_o_compressed
;
stats
.
collisions
=
comp
->
sls_o_misses
;
}
return
(
&
stats
);
}
/*
* Close down a SLIP channel.
...
...
@@ -1193,6 +1224,7 @@ slip_init(struct device *dev)
dev
->
hard_header
=
sl_header
;
dev
->
add_arp
=
sl_add_arp
;
dev
->
type_trans
=
sl_type_trans
;
dev
->
get_stats
=
sl_get_stats
;
#ifdef HAVE_SET_MAC_ADDR
#ifdef CONFIG_AX25
dev
->
set_mac_address
=
sl_set_mac_address
;
...
...
fs/binfmt_coff.c
View file @
36f4514a
...
...
@@ -38,6 +38,12 @@
* Al Longyear (longyear@sii.com)
* Removed erroneous code which mistakenly folded .data with .bss for
* a shared library.
*
* 8 Janurary 1994
* Al Longyear (longyear@sii.com)
* Corrected problem with read of library section returning the byte
* count rather than zero. This was a change between the pl12 and
* pl14 kernels which slipped by me.
*/
#include <linux/fs.h>
...
...
@@ -650,12 +656,21 @@ preload_library (struct linux_binprm *exe_bprm,
buffer
,
/* Buffer for read */
nbytes
);
/* Byte count reqd. */
set_fs
(
old_fs
);
/* Restore the selector */
/*
* Check the result. The value returned is the byte count actaully read.
*/
if
(
status
>=
0
&&
status
!=
nbytes
)
{
#ifdef COFF_DEBUG
printk
(
"read of lib section was short
\n
"
);
#endif
status
=
-
ENOEXEC
;
}
}
/*
* At this point, go through the list of libraries in the data area.
*/
phdr
=
(
COFF_SLIBHD
*
)
buffer
;
while
(
status
=
=
0
&&
nbytes
>
COFF_SLIBSZ
)
{
while
(
status
>
=
0
&&
nbytes
>
COFF_SLIBSZ
)
{
int
entry_size
=
COFF_LONG
(
phdr
->
sl_entsz
)
*
sizeof
(
long
);
int
header_size
=
COFF_LONG
(
phdr
->
sl_pathndx
)
*
sizeof
(
long
);
/*
...
...
fs/ext2/CHANGES
View file @
36f4514a
...
...
@@ -4,8 +4,7 @@ Changes from version 0.4a to version 0.4b
- 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.
- Direct reads of directories disallowed.
- Readahead implemented in readdir by Stephen Tweedie.
- Bugs in block and inodes allocation fixed.
- Readahead implemented in ext2_find_entry by Chip Salzenberg.
...
...
fs/ext2/dir.c
View file @
36f4514a
...
...
@@ -16,32 +16,23 @@
#include <asm/segment.h>
#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
#ifndef CONFIG_EXT2_FS_DIR_READ
static
int
ext2_dir_read
(
struct
inode
*
inode
,
struct
file
*
filp
,
char
*
buf
,
int
count
)
{
return
-
EISDIR
;
}
#else
int
ext2_file_read
(
struct
inode
*
,
struct
file
*
,
char
*
,
int
);
#endif
static
int
ext2_readdir
(
struct
inode
*
,
struct
file
*
,
struct
dirent
*
,
int
);
static
struct
file_operations
ext2_dir_operations
=
{
NULL
,
/* lseek - default */
#ifdef CONFIG_EXT2_FS_DIR_READ
ext2_file_read
,
/* read */
#else
ext2_dir_read
,
/* read */
#endif
NULL
,
/* write - bad */
ext2_readdir
,
/* readdir */
NULL
,
/* select - default */
...
...
fs/ext2/file.c
View file @
36f4514a
...
...
@@ -17,7 +17,6 @@
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
...
...
@@ -34,10 +33,7 @@
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#ifndef CONFIG_EXT2_FS_DIR_READ
static
#endif
int
ext2_file_read
(
struct
inode
*
,
struct
file
*
,
char
*
,
int
);
static
int
ext2_file_read
(
struct
inode
*
,
struct
file
*
,
char
*
,
int
);
static
int
ext2_file_write
(
struct
inode
*
,
struct
file
*
,
char
*
,
int
);
static
void
ext2_release_file
(
struct
inode
*
,
struct
file
*
);
...
...
@@ -76,10 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
ext2_permission
/* permission */
};
#ifndef CONFIG_EXT2_FS_DIR_READ
static
#endif
int
ext2_file_read
(
struct
inode
*
inode
,
struct
file
*
filp
,
static
int
ext2_file_read
(
struct
inode
*
inode
,
struct
file
*
filp
,
char
*
buf
,
int
count
)
{
int
read
,
left
,
chars
;
...
...
@@ -97,7 +90,7 @@ int ext2_file_read (struct inode * inode, struct file * filp,
return
-
EINVAL
;
}
sb
=
inode
->
i_sb
;
if
(
!
S_ISREG
(
inode
->
i_mode
)
&&
!
S_ISDIR
(
inode
->
i_mode
)
)
{
if
(
!
S_ISREG
(
inode
->
i_mode
))
{
ext2_warning
(
sb
,
"ext2_file_read"
,
"mode = %07o"
,
inode
->
i_mode
);
return
-
EINVAL
;
...
...
fs/ext2/super.c
View file @
36f4514a
...
...
@@ -274,7 +274,7 @@ static void ext2_setup_super (struct super_block * sb,
printk
(
"EXT2-fs warning: mounting fs with errors, "
"running e2fsck is recommended
\n
"
);
else
if
(
es
->
s_max_mnt_count
>=
0
&&
es
->
s_mnt_count
>=
es
->
s_max_mnt_count
)
es
->
s_mnt_count
>=
(
unsigned
short
)
es
->
s_max_mnt_count
)
printk
(
"EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended
\n
"
);
if
(
!
(
sb
->
s_flags
&
MS_RDONLY
))
{
...
...
fs/sysv/README
View file @
36f4514a
...
...
@@ -4,16 +4,11 @@ It implements all of
- SystemV/386 FS,
- Coherent FS.
This is version
alpha 5
.
This is version
beta 1
.
To install:
* You need Linux 0.99.14.
* Go to /usr/src/linux, unpack the tar file there, and patch the Linux source:
patch -p1 < sysvfs.cdif
To build the Linux kernel with the patches:
make config
make depend
make
* Answer the 'System V and Coherent filesystem support' question with 'y'
when configuring the kernel.
* To mount a disk or a partition, use
mount [-r] -t sysv device mountpoint
The file system type names
...
...
fs/sysv/ialloc.c
View file @
36f4514a
...
...
@@ -65,7 +65,8 @@ void sysv_free_inode(struct inode * inode)
return
;
}
if
(
!
(
bh
=
sysv_bread
(
sb
,
inode
->
i_dev
,
sb
->
sv_firstinodezone
+
((
ino
-
1
)
>>
sb
->
sv_inodes_per_block_bits
),
&
bh_data
)))
{
panic
(
"sysv_free_inode: unable to read inode block"
);
/* FIXME: too severe? */
printk
(
"sysv_free_inode: unable to read inode block on device %d/%d
\n
"
,
MAJOR
(
inode
->
i_dev
),
MINOR
(
inode
->
i_dev
));
clear_inode
(
inode
);
return
;
}
raw_inode
=
(
struct
sysv_inode
*
)
bh_data
+
((
ino
-
1
)
&
sb
->
sv_inodes_per_block_1
);
...
...
fs/sysv/inode.c
View file @
36f4514a
...
...
@@ -316,7 +316,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb
->
s_dev
=
0
;
unlock_super
(
sb
);
if
(
!
silent
)
printk
(
"VFS: unable to read Xenix/SystemV/Coherent superblock
\n
"
);
printk
(
"VFS: unable to read Xenix/SystemV/Coherent superblock
on device %d/%d
\n
"
,
MAJOR
(
dev
),
MINOR
(
dev
)
);
return
NULL
;
ok:
...
...
include/linux/ext2_fs.h
View file @
36f4514a
...
...
@@ -52,7 +52,7 @@
/*
* The second extended file system version
*/
#define EXT2FS_DATE "94/01/0
5
"
#define EXT2FS_DATE "94/01/0
8
"
#define EXT2FS_VERSION "0.4b"
/*
...
...
include/linux/if_ether.h
View file @
36f4514a
...
...
@@ -31,7 +31,8 @@
#define ETH_P_PUP 0x0400
/* Xerox PUP packet */
#define ETH_P_IP 0x0800
/* Internet Protocol packet */
#define ETH_P_ARP 0x0806
/* Address Resolution packet */
#define ETH_P_RARP 0x0835
/* Reverse Addr Res packet */
#define ETH_P_RARP 0x8035
/* Reverse Addr Res packet */
#define ETH_P_X25 0x0805
/* CCITT X.25 */
#define ETH_P_IPX 0x8137
/* IPX over DIX */
#define ETH_P_802_3 0x0001
/* Dummy type for 802.3 frames */
#define ETH_P_AX25 0x0002
/* Dummy protocol id for AX.25 */
...
...
include/linux/socket.h
View file @
36f4514a
...
...
@@ -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
...
...
include/linux/sockios.h
View file @
36f4514a
...
...
@@ -28,7 +28,7 @@ struct ip_config {
unsigned
long
paddr
;
unsigned
long
router
;
unsigned
long
net
;
unsigned
int
up
:
1
,
destroy
:
1
;
unsigned
long
up
:
1
,
destroy
:
1
;
};
#endif
/* FIXME: */
...
...
init/main.c
View file @
36f4514a
...
...
@@ -235,7 +235,7 @@ static void calibrate_delay(void)
"r"
(
ticks
),
"0"
(
loops_per_sec
)
:
"dx"
);
printk
(
"ok - %lu.%02lu BogoMips
(tm)
\n
"
,
printk
(
"ok - %lu.%02lu BogoMips
\n
"
,
loops_per_sec
/
500000
,
(
loops_per_sec
/
5000
)
%
100
);
return
;
...
...
net/inet/arp.c
View file @
36f4514a
...
...
@@ -36,6 +36,9 @@
* 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 : ATF_PERM was backwards! - might be useful now (sigh)
*
* To Fix:
* : arp response allocates an skbuff to send. However there is a perfectly
...
...
@@ -386,7 +389,7 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
/* Delete an ARP mapping entry in the cache. */
void
arp_destr
oy
(
unsigned
long
paddr
)
arp_destr
uctor
(
unsigned
long
paddr
,
int
force
)
{
struct
arp_table
*
apt
;
struct
arp_table
**
lapt
;
...
...
@@ -406,6 +409,8 @@ arp_destroy(unsigned long paddr)
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
--
;
...
...
@@ -418,6 +423,23 @@ arp_destroy(unsigned long paddr)
sti
();
}
/*
* Kill an entry - eg for ioctl()
*/
void
arp_destroy
(
unsigned
long
paddr
)
{
arp_destructor
(
paddr
,
1
);
}
/*
* Delete a possibly invalid entry (see timer.c)
*/
void
arp_destroy_maybe
(
unsigned
long
paddr
)
{
arp_destructor
(
paddr
,
0
);
}
/* Create an ARP entry. The caller should check for duplicates! */
static
struct
arp_table
*
...
...
@@ -536,16 +558,16 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return
(
0
);
}
/*
* A broadcast arp, ignore it
*/
/*
* A broadcast arp, ignore it
*/
if
(
(
dst
&
0xFF
)
==
0xFF
)
if
(
chk_addr
(
dst
)
==
IS_BROADCAST
)
{
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
"
));
...
...
@@ -654,8 +676,8 @@ arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
* 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
))
{
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
);
...
...
@@ -814,6 +836,11 @@ arp_req_set(struct arpreq *req)
htype
=
ARPHRD_ETHER
;
hlen
=
ETH_ALEN
;
break
;
case
ARPHRD_AX25
:
htype
=
ARPHRD_AX25
;
hlen
=
7
;
break
;
default:
return
(
-
EPFNOSUPPORT
);
}
...
...
net/inet/arp.h
View file @
36f4514a
...
...
@@ -59,5 +59,6 @@ extern void arp_add_broad(unsigned long addr, struct device *dev);
extern
void
arp_queue
(
struct
sk_buff
*
skb
);
extern
int
arp_get_info
(
char
*
buffer
);
extern
int
arp_ioctl
(
unsigned
int
cmd
,
void
*
arg
);
extern
void
arp_destroy_maybe
(
unsigned
long
paddr
);
#endif
/* _ARP_H */
net/inet/datagram.c
View file @
36f4514a
...
...
@@ -2,7 +2,7 @@
* 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-).
* 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.
*
...
...
@@ -13,6 +13,7 @@
* 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 : Fixed write select of non IP protocol crash.
*/
#include <linux/config.h>
...
...
@@ -35,7 +36,7 @@
#include "udp.h"
#include "skbuff.h"
#include "sock.h"
/*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
...
...
@@ -46,16 +47,16 @@
*/
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
)
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
;
...
...
@@ -69,7 +70,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
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
)
{
...
...
@@ -77,24 +78,24 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
*
err
=-
ENOTCONN
;
return
NULL
;
}
/* User doesn't want to wait */
if
(
noblock
)
if
(
noblock
)
{
release_sock
(
sk
);
*
err
=-
EAGAIN
;
return
NULL
;
}
release_sock
(
sk
);
/* Interrupts off so that no packet arrives before we begin sleeping.
/* Interrupts off so that no packet arrives before we begin sleeping.
Otherwise we might miss our wake up */
cli
();
if
(
sk
->
rqueue
==
NULL
)
if
(
sk
->
rqueue
==
NULL
)
{
interruptible_sleep_on
(
sk
->
sleep
);
/* Signals may need a restart of the syscall */
if
(
current
->
signal
&
~
current
->
blocked
)
if
(
current
->
signal
&
~
current
->
blocked
)
{
sti
();
*
err
=-
ERESTARTSYS
;
...
...
@@ -115,26 +116,26 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
}
/* Again only user level code calls this function, so nothing interrupt level
will suddenely eat the rqueue */
if
(
!
(
flags
&
MSG_PEEK
))
if
(
!
(
flags
&
MSG_PEEK
))
{
skb
=
skb_dequeue
(
&
sk
->
rqueue
);
if
(
skb
!=
NULL
)
skb
->
users
++
;
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
;
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
)
{
...
...
@@ -156,7 +157,7 @@ void skb_free_datagram(struct sk_buff *skb)
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
/* We will know all about the fraglist options to allow >4K receives
but not this release */
memcpy_tofs
(
to
,
skb
->
h
.
raw
+
offset
,
size
);
}
...
...
@@ -165,11 +166,11 @@ void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int 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
)
switch
(
sel_type
)
{
case
SEL_IN
:
if
(
sk
->
type
==
SOCK_SEQPACKET
&&
sk
->
state
==
TCP_CLOSE
)
...
...
@@ -177,7 +178,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
/* Connection closed: Wake up */
return
(
1
);
}
if
(
sk
->
rqueue
!=
NULL
||
sk
->
err
!=
0
)
if
(
sk
->
rqueue
!=
NULL
||
sk
->
err
!=
0
)
{
/* This appears to be consistent
with other stacks */
return
(
1
);
...
...
@@ -185,16 +186,20 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return
(
0
);
case
SEL_OUT
:
if
(
sk
->
prot
->
wspace
(
sk
)
>=
MIN_WRITE_SPACE
)
if
(
sk
->
prot
->
wspace
(
sk
)
>=
MIN_WRITE_SPACE
)
{
return
(
1
);
}
if
(
sk
->
prot
==
NULL
&&
sk
->
sndbuf
-
sk
->
wmem_alloc
>=
MIN_WRITE_SPACE
)
{
return
(
1
);
}
return
(
0
);
case
SEL_EX
:
if
(
sk
->
err
)
return
(
1
);
/* Socket has gone into error state (eg icmp error) */
return
(
0
);
}
return
(
0
);
}
return
(
0
);
}
net/inet/dev.c
View file @
36f4514a
...
...
@@ -26,6 +26,10 @@
* a) actually works for all A/B nets
* b) doesn't forward off the same interface.
* Alan Cox: Multiple extra protocols
* Alan Cox: Fixed ifconfig up of dud device setting the up flag
* Alan Cox: Fixed verify_area errors
* Alan Cox: Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give
* anything away 8)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -709,9 +713,12 @@ dev_ifconf(char *arg)
struct
device
*
dev
;
char
*
pos
;
int
len
;
int
err
;
/* Fetch the caller's info block. */
verify_area
(
VERIFY_WRITE
,
arg
,
sizeof
(
struct
ifconf
));
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
;
...
...
@@ -800,7 +807,9 @@ dev_ifsioc(void *arg, unsigned int getset)
int
ret
;
/* Fetch the caller's info block. */
verify_area
(
VERIFY_WRITE
,
arg
,
sizeof
(
struct
ifreq
));
int
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. */
...
...
@@ -827,8 +836,12 @@ dev_ifsioc(void *arg, unsigned int getset)
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
;
/* Didnt open so down the if */
}
}
break
;
case
SIOCGIFADDR
:
...
...
@@ -946,55 +959,9 @@ dev_ioctl(unsigned int cmd, void *arg)
int
ret
;
switch
(
cmd
)
{
case
IP_SET_DEV
:
{
/* Maintain backwards-compatibility, to be deleted for 1.00. */
struct
device
*
dev
;
/* The old 'struct ip_config'. */
struct
ip_config
{
char
name
[
MAX_IP_NAME
];
unsigned
long
paddr
,
router
,
net
,
up
:
1
,
destroy
:
1
;
}
ipc
;
int
retval
,
loopback
;
printk
(
"INET: Warning: old-style ioctl(IP_SET_DEV) called!
\n
"
);
if
(
!
suser
())
return
(
-
EPERM
);
verify_area
(
VERIFY_WRITE
,
arg
,
sizeof
(
ipc
));
memcpy_fromfs
(
&
ipc
,
arg
,
sizeof
(
ipc
));
ipc
.
name
[
MAX_IP_NAME
-
1
]
=
0
;
loopback
=
(
strcmp
(
ipc
.
name
,
"loopback"
)
==
0
);
dev
=
dev_get
(
loopback
?
"lo"
:
ipc
.
name
);
if
(
dev
==
NULL
)
return
-
EINVAL
;
ipc
.
destroy
=
0
;
dev
->
pa_addr
=
ipc
.
paddr
;
dev
->
family
=
AF_INET
;
dev
->
pa_mask
=
get_mask
(
dev
->
pa_addr
);
dev
->
pa_brdaddr
=
dev
->
pa_addr
|
~
dev
->
pa_mask
;
if
(
ipc
.
net
!=
0xffffffff
)
{
dev
->
flags
|=
IFF_BROADCAST
;
dev
->
pa_brdaddr
=
ipc
.
net
;
}
/* To be proper we should delete the route here. */
if
(
ipc
.
up
==
0
)
return
(
dev
->
flags
&
IFF_UP
!=
0
)
?
dev_close
(
dev
)
:
0
;
if
((
dev
->
flags
&
IFF_UP
)
==
0
&&
(
retval
=
dev_open
(
dev
))
!=
0
)
return
retval
;
printk
(
"%s: adding HOST route of %8.8lx.
\n
"
,
dev
->
name
,
htonl
(
ipc
.
paddr
));
rt_add
(
RTF_HOST
,
ipc
.
paddr
,
0
,
0
,
dev
);
if
(
ipc
.
router
!=
0
&&
ipc
.
router
!=
-
1
)
{
rt_add
(
RTF_GATEWAY
,
ipc
.
paddr
,
0
,
ipc
.
router
,
dev
);
printk
(
"%s: adding GATEWAY route of %8.8lx.
\n
"
,
dev
->
name
,
htonl
(
ipc
.
paddr
));
}
return
0
;
}
case
IP_SET_DEV
:
printk
(
"Your network configuration program needs upgrading.
\n
"
);
return
-
EINVAL
;
case
SIOCGIFCONF
:
(
void
)
dev_ifconf
((
char
*
)
arg
);
ret
=
0
;
...
...
net/inet/eth.c
View file @
36f4514a
...
...
@@ -17,6 +17,7 @@
* Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and
* minor other things.
* Tegge : Arp bug fixes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -124,7 +125,7 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
cli
();
memcpy
(
eth
->
h_source
,
&
saddr
,
4
);
/* No. Ask ARP to resolve the Ethernet address. */
if
(
arp_find
(
eth
->
h_dest
,
daddr
,
dev
,
s
addr
))
if
(
arp_find
(
eth
->
h_dest
,
daddr
,
dev
,
dev
->
pa_
addr
))
{
sti
();
if
(
type
!=
ETH_P_IP
)
...
...
@@ -155,7 +156,7 @@ eth_rebuild_header(void *buff, struct device *dev)
DPRINTF
((
DBG_DEV
,
"ETH: RebuildHeader: SRC=%s "
,
in_ntoa
(
src
)));
DPRINTF
((
DBG_DEV
,
"DST=%s
\n
"
,
in_ntoa
(
dst
)));
if
(
eth
->
h_proto
!=
htons
(
ETH_P_ARP
))
/* This ntohs kind of helps a bit! */
if
(
arp_find
(
eth
->
h_dest
,
dst
,
dev
,
src
))
return
(
1
);
if
(
arp_find
(
eth
->
h_dest
,
dst
,
dev
,
dev
->
pa_addr
/* src */
))
return
(
1
);
memcpy
(
eth
->
h_source
,
dev
->
dev_addr
,
dev
->
addr_len
);
return
(
0
);
}
...
...
net/inet/icmp.c
View file @
36f4514a
...
...
@@ -14,6 +14,7 @@
* Fixes:
* Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected
* Alan Cox : Use tos/ttl settings
*
*
* This program is free software; you can redistribute it and/or
...
...
@@ -108,7 +109,7 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
/* Build Layer 2-3 headers for message back to source. */
offset
=
ip_build_header
(
skb
,
dev
->
pa_addr
,
iph
->
saddr
,
&
dev
,
IPPROTO_ICMP
,
NULL
,
len
);
&
dev
,
IPPROTO_ICMP
,
NULL
,
len
,
skb_in
->
ip_hdr
->
tos
,
255
);
if
(
offset
<
0
)
{
skb
->
sk
=
NULL
;
kfree_skb
(
skb
,
FREE_READ
);
...
...
@@ -255,7 +256,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Build Layer 2-3 headers for message back to source */
offset
=
ip_build_header
(
skb2
,
daddr
,
saddr
,
&
dev
,
IPPROTO_ICMP
,
opt
,
len
);
IPPROTO_ICMP
,
opt
,
len
,
skb
->
ip_hdr
->
tos
,
255
);
if
(
offset
<
0
)
{
printk
(
"ICMP: Could not build IP Header for ICMP ECHO Response
\n
"
);
kfree_skb
(
skb2
,
FREE_WRITE
);
...
...
@@ -319,7 +320,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Build Layer 2-3 headers for message back to source */
offset
=
ip_build_header
(
skb2
,
daddr
,
saddr
,
&
dev
,
IPPROTO_ICMP
,
opt
,
len
);
IPPROTO_ICMP
,
opt
,
len
,
skb
->
ip_hdr
->
tos
,
255
);
if
(
offset
<
0
)
{
printk
(
"ICMP: Could not build IP Header for ICMP ADDRESS Response
\n
"
);
kfree_skb
(
skb2
,
FREE_WRITE
);
...
...
net/inet/ip.c
View file @
36f4514a
...
...
@@ -31,6 +31,9 @@
* 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 : Save IP header pointer for later
* Alan Cox : ip option setting
* Alan Cox : Use ip_tos/ip_ttl settings
*
* To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules
...
...
@@ -198,7 +201,7 @@ ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
*/
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
device
**
dev
,
int
type
,
struct
options
*
opt
,
int
len
,
int
tos
,
int
ttl
)
{
static
struct
options
optmem
;
struct
iphdr
*
iph
;
...
...
@@ -256,9 +259,9 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
iph
=
(
struct
iphdr
*
)
buff
;
iph
->
version
=
4
;
iph
->
tos
=
0
;
iph
->
tos
=
tos
;
iph
->
frag_off
=
0
;
iph
->
ttl
=
32
;
iph
->
ttl
=
ttl
;
iph
->
daddr
=
daddr
;
iph
->
saddr
=
saddr
;
iph
->
protocol
=
type
;
...
...
@@ -1267,6 +1270,8 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
}
/* 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
);
for
(
ipprot
=
(
struct
inet_protocol
*
)
inet_protos
[
hash
];
...
...
@@ -1504,3 +1509,72 @@ 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
);
}
net/inet/ip.h
View file @
36f4514a
...
...
@@ -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,7 @@ 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 */
net/inet/packet.c
View file @
36f4514a
...
...
@@ -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 : Added NULL's for socket options.
*
*
* This program is free software; you can redistribute it and/or
...
...
@@ -264,6 +265,8 @@ struct proto packet_prot = {
NULL
,
packet_init
,
NULL
,
NULL
,
/* No set/get socket options */
NULL
,
128
,
0
,
{
NULL
,},
...
...
net/inet/raw.c
View file @
36f4514a
...
...
@@ -19,6 +19,10 @@
* Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too
* Alan Cox : Setsocketopt added
* Alan Cox : Fixed error return for broadcasts
* Alan Cox : Removed wake_up calls
* Alan Cox : Use ttl/tos
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -76,7 +80,7 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
}
sk
->
err
=
icmp_err_convert
[
err
&
0xff
].
errno
;
wake_up
(
sk
->
sleep
);
sk
->
error_report
(
sk
);
return
;
}
...
...
@@ -123,7 +127,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
}
sk
->
rmem_alloc
+=
skb
->
mem_len
;
skb_queue_tail
(
&
sk
->
rqueue
,
skb
);
wake_up
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
skb
->
len
);
release_sock
(
sk
);
return
(
0
);
}
...
...
@@ -169,7 +173,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
if
(
sin
.
sin_port
==
0
)
sin
.
sin_port
=
sk
->
protocol
;
if
(
sk
->
broadcast
==
0
&&
chk_addr
(
sin
.
sin_addr
.
s_addr
)
==
IS_BROADCAST
)
return
-
E
NETUNREACH
;
return
-
E
ACCES
;
sk
->
inuse
=
1
;
skb
=
NULL
;
...
...
@@ -214,7 +218,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp
=
sk
->
prot
->
build_header
(
skb
,
sk
->
saddr
,
sin
.
sin_addr
.
s_addr
,
&
dev
,
sk
->
protocol
,
sk
->
opt
,
skb
->
mem_len
);
sk
->
protocol
,
sk
->
opt
,
skb
->
mem_len
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
DPRINTF
((
DBG_RAW
,
"raw_sendto: error building ip header.
\n
"
));
kfree_skb
(
skb
,
FREE_WRITE
);
...
...
@@ -330,6 +334,13 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
return
err
;
put_fs_long
(
sizeof
(
*
sin
),
addr_len
);
}
if
(
sin
)
{
err
=
verify_area
(
VERIFY_WRITE
,
sin
,
sizeof
(
*
sin
));
if
(
err
)
return
err
;
}
err
=
verify_area
(
VERIFY_WRITE
,
to
,
len
);
if
(
err
)
return
err
;
...
...
@@ -348,7 +359,6 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
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
));
}
...
...
@@ -390,6 +400,8 @@ struct proto raw_prot = {
NULL
,
raw_init
,
NULL
,
ip_setsockopt
,
ip_getsockopt
,
128
,
0
,
{
NULL
,},
...
...
net/inet/route.c
View file @
36f4514a
...
...
@@ -121,21 +121,27 @@ void rt_flush(struct device *dev)
* number of zero 8-bit net numbers, otherwise we use the "default"
* masks judging by the destination address and our device netmask.
*/
static
inline
unsigned
long
default_mask
(
unsigned
long
dst
)
{
dst
=
ntohl
(
dst
);
if
(
IN_CLASSA
(
dst
))
return
htonl
(
IN_CLASSA_NET
);
if
(
IN_CLASSB
(
dst
))
return
htonl
(
IN_CLASSB_NET
);
return
htonl
(
IN_CLASSC_NET
);
}
static
unsigned
long
guess_mask
(
unsigned
long
dst
,
struct
device
*
dev
)
{
unsigned
long
mask
=
0xffffffff
;
/* this is a rather ugly optimization: works only on little-endian machines */
while
(
mask
&
dst
)
mask
>>
=
8
;
mask
<<
=
8
;
if
(
mask
)
return
~
mask
;
dst
=
ntohl
(
dst
);
if
(
IN_CLASSA
(
dst
))
mask
=
htonl
(
IN_CLASSA_NET
);
else
if
(
IN_CLASSB
(
dst
))
mask
=
htonl
(
IN_CLASSB_NET
);
else
mask
=
htonl
(
IN_CLASSC_NET
);
/* ok, no more hacks.. */
mask
=
default_mask
(
dst
);
if
(
dev
->
flags
&
IFF_POINTOPOINT
)
return
mask
;
if
((
dst
^
dev
->
pa_addr
)
&
mask
)
...
...
net/inet/skbuff.c
View file @
36f4514a
...
...
@@ -13,7 +13,7 @@
* and memory leak hunting.
* Alan Cox : More generic kfree handler
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
...
...
@@ -44,14 +44,14 @@
/*
* 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
)
...
...
@@ -81,20 +81,20 @@ void skb_check(struct sk_buff *skb, int line, char *file)
/*
* 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
);
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
...
...
@@ -110,14 +110,14 @@ void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
/*
* 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
();
...
...
@@ -137,7 +137,7 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
*
list
=
newsk
;
}
IS_SKB
(
newsk
->
prev
);
IS_SKB
(
newsk
->
next
);
IS_SKB
(
newsk
->
next
);
restore_flags
(
flags
);
}
...
...
@@ -146,21 +146,21 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
* 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
;
...
...
@@ -173,7 +173,7 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
IS_SKB
(
result
);
restore_flags
(
flags
);
if
(
result
->
list
!=
list
)
printk
(
"Dequeued packet has invalid list pointer
\n
"
);
...
...
@@ -186,19 +186,19 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
/*
* 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
;
...
...
@@ -206,18 +206,18 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
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
);
...
...
@@ -225,7 +225,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
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
;
...
...
@@ -233,7 +233,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
newsk
->
next
=
old
->
next
;
newsk
->
next
->
prev
=
newsk
;
newsk
->
prev
->
next
=
newsk
;
restore_flags
(
flags
);
}
...
...
@@ -243,7 +243,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
* MUST EXIST when you unlink. Thus a list must have its contents unlinked
* _FIRST_.
*/
void
skb_unlink
(
struct
sk_buff
*
skb
)
{
unsigned
long
flags
;
...
...
@@ -251,7 +251,7 @@ void skb_unlink(struct sk_buff *skb)
cli
();
IS_SKB
(
skb
);
if
(
skb
->
list
)
{
skb
->
next
->
prev
=
skb
->
prev
;
...
...
@@ -290,7 +290,7 @@ void skb_new_list_head(struct sk_buff *volatile* list)
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
...
...
@@ -310,14 +310,14 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list)
* 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
);
...
...
@@ -336,7 +336,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
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 */
...
...
@@ -349,7 +349,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
kfree_skb
(
newsk
,
FREE_WRITE
);
continue
;
}
IS_SKB
(
orig
);
IS_SKB
(
newsk
);
memcpy
(
newsk
,
orig
,
len
);
...
...
@@ -364,11 +364,11 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
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.
...
...
@@ -376,68 +376,68 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
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
);
if
(
skb
==
NULL
)
{
printk
(
"kfree_skb: skb = NULL
\n
"
);
return
;
}
else
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
)
{
/* Non INET - default wmalloc/rmalloc handler */
if
(
rw
)
skb
->
sk
->
rmem_alloc
-=
skb
->
mem_len
;
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
skb
->
sk
->
wmem_alloc
-=
skb
->
mem_len
;
if
(
!
skb
->
sk
->
dead
)
{
/* 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
);
kfree_skbmem
(
skb
->
mem_addr
,
skb
->
mem_len
);
}
}
}
else
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
;
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
)
{
...
...
@@ -451,4 +451,4 @@ void kfree_skbmem(void *mem,unsigned size)
net_memory
-=
size
;
}
}
net/inet/skbuff.h
View file @
36f4514a
...
...
@@ -60,6 +60,7 @@ struct sk_buff {
ipx_packet
*
ipx
;
#endif
}
h
;
struct
iphdr
*
ip_hdr
;
/* For IPPROTO_RAW */
unsigned
long
mem_len
;
unsigned
long
len
;
unsigned
long
fraglen
;
...
...
net/inet/sock.c
View file @
36f4514a
...
...
@@ -48,6 +48,9 @@
* Alan Cox : SO_LINGER supported
* Alan Cox : Error reporting fixes
* Anonymous : inet_create tidied up (sk->reuse setting)
* Alan Cox : inet sockets don't set sk->type!
* Alan Cox : Split socket option code
* Alan Cox : Callbacks
*
* To Fix:
*
...
...
@@ -312,7 +315,7 @@ destroy_sock(struct sock *sk)
/* Incase it's sleeping somewhere. */
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
sk
->
write_space
(
sk
);
remove_sock
(
sk
);
...
...
@@ -471,205 +474,236 @@ inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
}
static
int
inet_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
/*
* 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
;
int
val
;
int
err
;
struct
linger
ling
;
/* This should really pass things on to the other levels. */
if
(
level
!=
SOL_SOCKET
)
return
(
-
EOPNOTSUPP
);
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
);
}
sk
=
(
struct
sock
*
)
sock
->
data
;
if
(
sk
==
NULL
)
{
printk
(
"Warning: sock->data = NULL: %d
\n
"
,
__LINE__
);
return
(
0
);
}
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
);
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
);
}
case
SO_OOBINLINE
:
if
(
val
)
sk
->
urginline
=
1
;
else
sk
->
urginline
=
0
;
return
(
0
);
/*
* This is meant for all protocols to use and covers goings on
* at the socket level. Everything here is generic.
*/
case
SO_NO_CHECK
:
if
(
val
)
sk
->
no_check
=
1
;
else
sk
->
no_check
=
0
;
return
(
0
);
int
sock_setsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
optlen
)
{
int
val
;
int
err
;
struct
linger
ling
;
case
SO_PRIORITY
:
if
(
val
>=
0
&&
val
<
DEV_NUMBUFFS
)
{
sk
->
priority
=
val
;
}
else
{
return
(
-
EINVAL
);
}
return
(
0
);
if
(
optval
==
NULL
)
return
(
-
EINVAL
);
default:
return
(
-
ENOPROTOOPT
);
}
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
);
}
}
static
int
inet_getsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
{
struct
sock
*
sk
;
int
val
;
int
err
;
struct
linger
ling
;
/* This should really pass things on to the other levels. */
if
(
level
!=
SOL_SOCKET
)
return
(
-
EOPNOTSUPP
);
int
sock_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
{
int
val
;
int
err
;
struct
linger
ling
;
sk
=
(
struct
sock
*
)
sock
->
data
;
if
(
sk
==
NULL
)
{
printk
(
"Warning: sock->data = NULL: %d
\n
"
,
__LINE__
);
return
(
0
);
}
switch
(
optname
)
{
case
SO_DEBUG
:
val
=
sk
->
debug
;
break
;
case
SO_DONTROUTE
:
/* One last option to implement */
val
=
0
;
break
;
switch
(
optname
)
{
case
SO_DEBUG
:
val
=
sk
->
debug
;
break
;
case
SO_BROADCAST
:
val
=
sk
->
broadcast
;
break
;
case
SO_DONTROUTE
:
/* One last option to implement */
val
=
0
;
break
;
case
SO_LINGER
:
case
SO_BROADCAST
:
val
=
sk
->
broadcast
;
break
;
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_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_SNDBUF
:
val
=
sk
->
sndbuf
;
break
;
case
SO_RCVBUF
:
val
=
sk
->
rcvbuf
;
break
;
case
SO_REUSEADDR
:
val
=
sk
->
reuse
;
break
;
case
SO_RCVBUF
:
val
=
sk
->
rcvbuf
;
break
;
case
SO_KEEPALIVE
:
val
=
sk
->
keepopen
;
break
;
case
SO_REUSEADDR
:
val
=
sk
->
reuse
;
break
;
case
SO_TYPE
:
if
(
sk
->
prot
==
&
tcp_prot
)
val
=
SOCK_STREAM
;
else
val
=
SOCK_DGRAM
;
break
;
case
SO_KEEPALIVE
:
val
=
sk
->
keepopen
;
break
;
case
SO_ERROR
:
val
=
sk
->
err
;
sk
->
err
=
0
;
break
;
case
SO_TYPE
:
if
(
sk
->
prot
==
&
tcp_prot
)
val
=
SOCK_STREAM
;
else
val
=
SOCK_DGRAM
;
break
;
case
SO_OOBINLINE
:
val
=
sk
->
urginline
;
break
;
case
SO_ERROR
:
val
=
sk
->
err
;
sk
->
err
=
0
;
break
;
case
SO_NO_CHECK
:
val
=
sk
->
no_check
;
break
;
case
SO_OOBINLINE
:
val
=
sk
->
urginline
;
break
;
case
SO_NO_CHECK
:
val
=
sk
->
no_check
;
break
;
case
SO_PRIORITY
:
val
=
sk
->
priority
;
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
);
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
);
err
=
verify_area
(
VERIFY_WRITE
,
optval
,
sizeof
(
int
));
if
(
err
)
return
err
;
put_fs_long
(
val
,(
unsigned
long
*
)
optval
);
return
(
0
);
return
(
0
);
}
static
int
inet_listen
(
struct
socket
*
sock
,
int
backlog
)
{
...
...
@@ -698,6 +732,23 @@ inet_listen(struct socket *sock, int backlog)
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
);
}
static
int
inet_create
(
struct
socket
*
sock
,
int
protocol
)
...
...
@@ -773,6 +824,7 @@ inet_create(struct socket *sock, int protocol)
return
(
-
ESOCKTNOSUPPORT
);
}
sk
->
socket
=
sock
;
sk
->
type
=
sock
->
type
;
sk
->
protocol
=
protocol
;
sk
->
wmem_alloc
=
0
;
sk
->
rmem_alloc
=
0
;
...
...
@@ -853,6 +905,14 @@ inet_create(struct socket *sock, int protocol)
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
...
...
@@ -893,7 +953,7 @@ inet_release(struct socket *sock, struct socket *peer)
if
(
sk
==
NULL
)
return
(
0
);
DPRINTF
((
DBG_INET
,
"inet_release(sock = %X, peer = %X)
\n
"
,
sock
,
peer
));
wake_up
(
sk
->
sleep
);
sk
->
state_change
(
sk
);
/* Start closing the connection. This may take a while. */
/*
...
...
@@ -1579,7 +1639,7 @@ sock_wfree(struct sock *sk, void *mem, unsigned long size)
sk
->
wmem_alloc
-=
size
;
/* In case it might be waiting for more memory. */
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
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
));
...
...
net/inet/sock.h
View file @
36f4514a
...
...
@@ -136,7 +136,11 @@ struct sock {
char
ax25_retxqi
;
char
ax25_rrtimer
;
char
ax25_timer
;
ax25_digi
*
ax25_digipeat
;
#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). */
...
...
@@ -145,6 +149,13 @@ struct sock {
/* identd */
struct
socket
*
socket
;
/* 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
);
};
struct
proto
{
...
...
@@ -177,7 +188,7 @@ struct proto {
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
);
int
(
*
connect
)(
struct
sock
*
sk
,
struct
sockaddr_in
*
usin
,
int
addr_len
);
struct
sock
*
(
*
accept
)
(
struct
sock
*
sk
,
int
flags
);
...
...
@@ -197,6 +208,10 @@ struct proto {
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
];
...
...
@@ -238,6 +253,8 @@ extern void sock_rfree(struct sock *sk, void *mem,
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
op
,
char
*
optval
,
int
optlen
);
extern
int
sock_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
op
,
char
*
optval
,
int
*
optlen
);
/* declarations from timer.c */
extern
struct
sock
*
timer_base
;
...
...
net/inet/tcp.c
View file @
36f4514a
...
...
@@ -47,6 +47,13 @@
* 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 : Added socket option proto entries. Also added awareness of them to accept.
* Alan Cox : Added TCP options (SOL_TCP)
* Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets.
* Alan Cox : Use ip_tos/ip_ttl settings.
* Alan Cox : Handle FIN (more) properly (we hope).
* Alan Cox : RST frames sent on unsynchronised state ack error/
* Alan Cox : Put in missing check for SYN bit.
*
*
* To Fix:
...
...
@@ -155,7 +162,7 @@ static void tcp_time_wait(struct sock *sk)
sk
->
state
=
TCP_TIME_WAIT
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
sk
->
state_change
(
sk
);
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
}
...
...
@@ -213,7 +220,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
if
(
err
<
0
)
{
sk
->
err
=
-
err
;
wake_up
(
sk
->
sleep
);
sk
->
error_report
(
sk
);
return
;
}
...
...
@@ -237,7 +244,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
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) */
sk
->
error_report
(
sk
);
/* Wake people up to see the error (see connect in sock.c) */
}
}
return
;
...
...
@@ -558,7 +565,20 @@ tcp_send_partial(struct sock *sk)
if
(
sk
==
NULL
||
sk
->
send_tmp
==
NULL
)
return
;
skb
=
sk
->
send_tmp
;
/* If we have queued a header size packet.. */
if
(
skb
->
len
-
(
unsigned
long
)
skb
->
h
.
th
+
(
unsigned
long
)(
skb
+
1
)
==
sizeof
(
struct
tcphdr
))
{
/* If its got a syn or fin its notionally included in the size..*/
if
(
!
skb
->
h
.
th
->
syn
&&
!
skb
->
h
.
th
->
fin
)
{
printk
(
"tcp_send_partial: attempt to queue a bogon.
\n
"
);
kfree_skb
(
skb
,
FREE_WRITE
);
sk
->
send_tmp
=
NULL
;
return
;
}
}
/* We need to complete and send the packet. */
tcp_send_check
(
skb
->
h
.
th
,
sk
->
saddr
,
sk
->
daddr
,
skb
->
len
-
(
unsigned
long
)
skb
->
h
.
th
+
...
...
@@ -622,7 +642,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
/* 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
);
IPPROTO_TCP
,
sk
->
opt
,
MAX_ACK_SIZE
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
buff
->
free
=
1
;
sk
->
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
...
...
@@ -887,7 +907,7 @@ tcp_write(struct sock *sk, unsigned char *from,
* Perhaps some hints here would be good.
*/
tmp
=
prot
->
build_header
(
skb
,
sk
->
saddr
,
sk
->
daddr
,
&
dev
,
IPPROTO_TCP
,
sk
->
opt
,
skb
->
mem_len
);
IPPROTO_TCP
,
sk
->
opt
,
skb
->
mem_len
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
prot
->
wfree
(
sk
,
skb
->
mem_addr
,
skb
->
mem_len
);
release_sock
(
sk
);
...
...
@@ -1008,7 +1028,7 @@ tcp_read_wakeup(struct sock *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
);
IPPROTO_TCP
,
sk
->
opt
,
MAX_ACK_SIZE
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
buff
->
free
=
1
;
sk
->
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
...
...
@@ -1484,7 +1504,7 @@ tcp_shutdown(struct sock *sk, int how)
/* 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
));
sizeof
(
struct
tcphdr
)
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
buff
->
free
=
1
;
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
...
...
@@ -1569,7 +1589,7 @@ tcp_recvfrom(struct sock *sk, unsigned char *to,
/* 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
proto
*
prot
,
struct
options
*
opt
,
struct
device
*
dev
,
int
tos
,
int
ttl
)
{
struct
sk_buff
*
buff
;
struct
tcphdr
*
t1
;
...
...
@@ -1594,7 +1614,7 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
/* Put in the IP header and routing stuff. */
tmp
=
prot
->
build_header
(
buff
,
saddr
,
daddr
,
&
dev
,
IPPROTO_TCP
,
opt
,
sizeof
(
struct
tcphdr
));
sizeof
(
struct
tcphdr
)
,
tos
,
ttl
);
if
(
tmp
<
0
)
{
buff
->
free
=
1
;
prot
->
wfree
(
NULL
,
buff
->
mem_addr
,
buff
->
mem_len
);
...
...
@@ -1714,10 +1734,10 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* If the socket is dead, don't accept the connection. */
if
(
!
sk
->
dead
)
{
wake_up
(
sk
->
sleep
);
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
);
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
kfree_skb
(
skb
,
FREE_READ
);
return
;
}
...
...
@@ -1802,21 +1822,12 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
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
/* Grab the ttl and tos values and use them */
newsk
->
ip_ttl
=
sk
->
ip_ttl
;
newsk
->
ip_tos
=
skb
->
ip_hdr
->
tos
;
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
;
...
...
@@ -1835,7 +1846,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* 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
);
IPPROTO_TCP
,
NULL
,
MAX_SYN_SIZE
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
/* Something went wrong. */
if
(
tmp
<
0
)
{
...
...
@@ -1912,25 +1923,13 @@ tcp_close(struct sock *sk, int timeout)
sk
->
keepopen
=
1
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
/* 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
)
...
...
@@ -1941,7 +1940,6 @@ tcp_close(struct sock *sk, int timeout)
}
if
(
sk
->
debug
)
printk
(
"Cleaned.
\n
"
);
#endif
}
sk
->
rqueue
=
NULL
;
...
...
@@ -1999,7 +1997,7 @@ tcp_close(struct sock *sk, int timeout)
/* 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
));
sizeof
(
struct
tcphdr
)
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
kfree_skb
(
buff
,
FREE_WRITE
);
DPRINTF
((
DBG_TCP
,
"Unable to build header for fin.
\n
"
));
...
...
@@ -2088,7 +2086,7 @@ tcp_write_xmit(struct sock *sk)
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
);
if
(
!
sk
->
dead
)
sk
->
write_space
(
sk
);
}
else
{
sk
->
prot
->
queue_xmit
(
sk
,
skb
->
dev
,
skb
,
skb
->
free
);
}
...
...
@@ -2185,30 +2183,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
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
;
}
for
(
i
=
0
;
i
<
DEV_NUMBUFFS
;
i
++
)
{
if
(
skb
->
dev
->
buffs
[
i
]
==
skb
)
{
if
(
skb
->
next
==
skb
)
skb
->
dev
->
buffs
[
i
]
=
NULL
;
else
skb
->
dev
->
buffs
[
i
]
=
skb
->
next
;
break
;
}
}
if
(
arp_q
==
skb
)
{
if
(
skb
->
next
==
skb
)
arp_q
=
NULL
;
else
arp_q
=
skb
->
next
;
}
#else
skb_unlink
(
skb
);
#endif
}
/* Now add it to the write_queue. */
skb
->
magic
=
TCP_WRITE_QUEUE_MAGIC
;
...
...
@@ -2272,7 +2247,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
sk
->
send_head
,
sk
->
send_head
->
h
.
seq
,
ack
));
/* Wake up the process, it can probably write more. */
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
write_space
(
sk
);
oskb
=
sk
->
send_head
;
...
...
@@ -2310,7 +2285,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
sti
();
oskb
->
magic
=
0
;
kfree_skb
(
oskb
,
FREE_WRITE
);
/* write. */
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
write_space
(
sk
);
}
else
{
break
;
}
...
...
@@ -2330,7 +2305,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
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
);
if
(
!
sk
->
dead
)
sk
->
write_space
(
sk
);
if
(
sk
->
keepopen
)
reset_timer
(
sk
,
TIME_KEEPOPEN
,
TCP_TIMEOUT_LEN
);
...
...
@@ -2355,7 +2330,8 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
/* See if we are done. */
if
(
sk
->
state
==
TCP_TIME_WAIT
)
{
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
if
(
sk
->
rcv_ack_seq
==
sk
->
send_seq
&&
sk
->
acked_seq
==
sk
->
fin_seq
)
{
flag
|=
1
;
sk
->
state
=
TCP_CLOSE
;
...
...
@@ -2364,7 +2340,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
}
if
(
sk
->
state
==
TCP_LAST_ACK
||
sk
->
state
==
TCP_FIN_WAIT2
)
{
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
if
(
sk
->
rcv_ack_seq
==
sk
->
send_seq
)
{
flag
|=
1
;
if
(
sk
->
acked_seq
!=
sk
->
fin_seq
)
{
...
...
@@ -2421,13 +2397,13 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
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
->
prot
,
NULL
,
skb
->
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
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
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
return
(
0
);
}
...
...
@@ -2523,7 +2499,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
/* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
if
(
skb
->
h
.
th
->
fin
)
{
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
sk
->
shutdown
|=
RCV_SHUTDOWN
;
}
...
...
@@ -2541,7 +2517,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
*/
if
(
skb2
->
h
.
th
->
fin
)
{
sk
->
shutdown
|=
RCV_SHUTDOWN
;
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
}
/* Force an immediate ack. */
...
...
@@ -2614,7 +2590,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
if
(
!
sk
->
dead
)
{
if
(
sk
->
debug
)
printk
(
"Data wakeup.
\n
"
);
wake_up
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
0
);
}
else
{
DPRINTF
((
DBG_TCP
,
"data received on dead socket.
\n
"
));
}
...
...
@@ -2626,7 +2602,7 @@ tcp_data(struct sk_buff *skb, struct sock *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
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
}
return
(
0
);
...
...
@@ -2639,7 +2615,8 @@ 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
);
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
data_ready
(
sk
,
0
);
if
(
sk
->
urginline
)
{
th
->
urg
=
0
;
...
...
@@ -2662,7 +2639,7 @@ tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
}
/* This deals with incoming fins. */
/* This deals with incoming fins.
'Linus at 9 O'clock' 8-)
*/
static
int
tcp_fin
(
struct
sock
*
sk
,
struct
tcphdr
*
th
,
unsigned
long
saddr
,
struct
device
*
dev
)
...
...
@@ -2671,7 +2648,7 @@ tcp_fin(struct sock *sk, struct tcphdr *th,
sk
,
th
,
saddr
,
dev
));
if
(
!
sk
->
dead
)
{
wake_up
(
sk
->
sleep
);
sk
->
state_change
(
sk
);
}
switch
(
sk
->
state
)
{
...
...
@@ -2813,7 +2790,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* 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
);
IPPROTO_TCP
,
NULL
,
MAX_SYN_SIZE
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
sk
->
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
release_sock
(
sk
);
...
...
@@ -2862,7 +2839,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* 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
options
*
opt
,
unsigned
long
saddr
,
struct
device
*
dev
)
{
/*
* This isn't quite right. sk->acked_seq could be more recent
...
...
@@ -2882,6 +2859,19 @@ tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
}
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
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
return
(
1
);
}
/*
* If it's too far ahead, send an ack to let the
* other end know what we expect.
...
...
@@ -2969,7 +2959,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
{
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
);
tcp_reset
(
daddr
,
saddr
,
th
,
&
tcp_prot
,
opt
,
dev
,
skb
->
ip_hdr
->
tos
,
255
);
}
skb
->
sk
=
NULL
;
kfree_skb
(
skb
,
FREE_READ
);
...
...
@@ -3042,7 +3032,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
if
(
!
sk
->
dead
)
{
wake_up
(
sk
->
sleep
);
sk
->
state_change
(
sk
);
}
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
...
...
@@ -3054,7 +3044,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
case
TCP_FIN_WAIT1
:
case
TCP_FIN_WAIT2
:
case
TCP_TIME_WAIT
:
if
(
!
tcp_sequence
(
sk
,
th
,
len
,
opt
,
saddr
))
{
if
(
!
tcp_sequence
(
sk
,
th
,
len
,
opt
,
saddr
,
dev
))
{
if
(
inet_debug
==
DBG_SLIP
)
printk
(
"
\r
tcp_rcv: not in seq
\n
"
);
if
(
!
th
->
rst
)
tcp_send_ack
(
sk
->
send_seq
,
sk
->
acked_seq
,
...
...
@@ -3077,33 +3067,32 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
* A reset with a fin just means that
* the data was not all read.
*/
/* The comment above appears completely bogus --clh */
/* if (!th->fin) { */
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
if
(
!
sk
->
dead
)
{
wake_up
(
sk
->
sleep
);
}
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
/* } */
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
);
}
if
(
#if 0
if (opt && (opt->security != 0 ||
opt->compartment != 0 || th->syn)) {
if ((opt && (opt->security != 0 ||
opt->compartment != 0)) ||
#endif
th
->
syn
)
{
sk
->
err
=
ECONNRESET
;
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
!
sk
->
dead
)
{
wake_up(sk->sleep
);
sk
->
state_change
(
sk
);
}
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
}
#endif
if
(
th
->
ack
)
{
if
(
!
tcp_ack
(
sk
,
th
,
saddr
,
len
))
{
kfree_skb
(
skb
,
FREE_READ
);
...
...
@@ -3119,13 +3108,14 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
}
}
if
(
t
h
->
fin
&&
tcp_fin
(
sk
,
th
,
saddr
,
dev
))
{
if
(
t
cp_data
(
skb
,
sk
,
saddr
,
len
))
{
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
}
if
(
tcp_data
(
skb
,
sk
,
saddr
,
len
))
{
/* Moved: you must do data then fin bit */
if
(
th
->
fin
&&
tcp_fin
(
sk
,
th
,
saddr
,
dev
))
{
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
...
...
@@ -3145,7 +3135,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
if
(
!
th
->
rst
)
{
if
(
!
th
->
ack
)
th
->
ack_seq
=
0
;
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
);
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
}
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
...
...
@@ -3158,7 +3148,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
return
(
0
);
}
if
(
th
->
ack
)
{
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
);
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
...
...
@@ -3189,7 +3179,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
return
(
0
);
default:
if
(
!
tcp_sequence
(
sk
,
th
,
len
,
opt
,
saddr
))
{
if
(
!
tcp_sequence
(
sk
,
th
,
len
,
opt
,
saddr
,
dev
))
{
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
...
...
@@ -3202,7 +3192,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
sk
->
shutdown
=
SHUTDOWN_MASK
;
sk
->
zapped
=
1
;
if
(
!
sk
->
dead
)
{
wake_up
(
sk
->
sleep
);
sk
->
state_change
(
sk
);
}
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
...
...
@@ -3236,7 +3226,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
case
TCP_SYN_SENT
:
if
(
!
tcp_ack
(
sk
,
th
,
saddr
,
len
))
{
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
);
sk
->
prot
,
opt
,
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
...
...
@@ -3261,7 +3251,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
case
TCP_SYN_RECV
:
if
(
!
tcp_ack
(
sk
,
th
,
saddr
,
len
))
{
tcp_reset
(
daddr
,
saddr
,
th
,
sk
->
prot
,
opt
,
dev
);
sk
->
prot
,
opt
,
dev
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
return
(
0
);
...
...
@@ -3277,7 +3267,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
sk
->
dummy_th
.
dest
=
th
->
source
;
sk
->
copied_seq
=
sk
->
acked_seq
-
1
;
if
(
!
sk
->
dead
)
{
wake_up
(
sk
->
sleep
);
sk
->
state_change
(
sk
);
}
/*
...
...
@@ -3354,7 +3344,7 @@ tcp_write_wakeup(struct sock *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
);
IPPROTO_TCP
,
sk
->
opt
,
MAX_ACK_SIZE
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
if
(
tmp
<
0
)
{
sk
->
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
return
;
...
...
@@ -3389,6 +3379,72 @@ tcp_write_wakeup(struct sock *sk)
sk
->
prot
->
queue_xmit
(
sk
,
dev
,
buff
,
1
);
}
/*
* Socket option code for TCP.
*/
int
tcp_setsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
optlen
)
{
int
val
,
err
;
if
(
level
!=
SOL_TCP
)
return
ip_setsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
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
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
);
return
(
0
);
}
struct
proto
tcp_prot
=
{
sock_wmalloc
,
...
...
@@ -3414,6 +3470,8 @@ struct proto tcp_prot = {
tcp_ioctl
,
NULL
,
tcp_shutdown
,
tcp_setsockopt
,
tcp_getsockopt
,
128
,
0
,
{
NULL
,},
...
...
net/inet/timer.c
View file @
36f4514a
...
...
@@ -141,7 +141,7 @@ net_timer (unsigned long data)
sk
->
state
=
TCP_CLOSE
;
delete_timer
(
sk
);
/* Kill the ARP entry in case the hardware has changed. */
arp_destroy
(
sk
->
daddr
);
arp_destroy
_maybe
(
sk
->
daddr
);
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
sk
->
shutdown
=
SHUTDOWN_MASK
;
...
...
@@ -167,7 +167,7 @@ net_timer (unsigned long data)
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
);
arp_destroy
_maybe
(
sk
->
daddr
);
ip_route_check
(
sk
->
daddr
);
}
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
sk
->
retransmits
>
TCP_RETR2
)
{
...
...
@@ -198,14 +198,14 @@ net_timer (unsigned long data)
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
);
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
(
sk
->
daddr
);
arp_destroy
_maybe
(
sk
->
daddr
);
sk
->
err
=
ETIMEDOUT
;
if
(
sk
->
state
==
TCP_FIN_WAIT1
||
sk
->
state
==
TCP_FIN_WAIT2
)
{
sk
->
state
=
TCP_TIME_WAIT
;
...
...
net/inet/udp.c
View file @
36f4514a
...
...
@@ -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 : Added get/set sockopt support.
* Alan Cox : Broadcasting without option set returns EACCES.
* Alan Cox : No wakeup calls. Instead we now use the callbacks.
* Alan Cox : Use ip_tos and ip_ttl
*
* 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
...
...
@@ -114,7 +115,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
if
(
err
<
0
)
/* As per the calling spec */
{
sk
->
err
=
-
err
;
wake_up
(
sk
->
sleep
);
/* User process wakes to see error */
sk
->
error_report
(
sk
);
/* User process wakes to see error */
return
;
}
...
...
@@ -130,7 +131,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
if
(
icmp_err_convert
[
err
&
0xff
].
fatal
&&
sk
->
state
==
TCP_ESTABLISHED
)
{
sk
->
err
=
ECONNREFUSED
;
}
wake_up
(
sk
->
sleep
);
sk
->
error_report
(
sk
);
}
...
...
@@ -249,7 +250,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
DPRINTF
((
DBG_UDP
,
"UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d
\n
"
,
saddr
,
sin
->
sin_addr
.
s_addr
,
dev
,
IPPROTO_UDP
,
skb
->
mem_len
));
tmp
=
sk
->
prot
->
build_header
(
skb
,
saddr
,
sin
->
sin_addr
.
s_addr
,
&
dev
,
IPPROTO_UDP
,
sk
->
opt
,
skb
->
mem_len
);
&
dev
,
IPPROTO_UDP
,
sk
->
opt
,
skb
->
mem_len
,
sk
->
ip_tos
,
sk
->
ip_ttl
);
skb
->
sk
=
sk
;
/* So memory is freed correctly */
if
(
tmp
<
0
)
{
...
...
@@ -335,7 +336,7 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
}
if
(
!
sk
->
broadcast
&&
chk_addr
(
sin
.
sin_addr
.
s_addr
)
==
IS_BROADCAST
)
return
-
E
NETUNREACH
;
/* Must turn broadcast on first */
return
-
E
ACCES
;
/* Must turn broadcast on first */
sk
->
inuse
=
1
;
/* Send the packet. */
...
...
@@ -522,7 +523,7 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return
(
-
EAFNOSUPPORT
);
if
(
!
sk
->
broadcast
&&
chk_addr
(
sin
.
sin_addr
.
s_addr
)
==
IS_BROADCAST
)
return
-
E
NETUNREACH
;
/* Must turn broadcast on first */
return
-
E
ACCES
;
/* Must turn broadcast on first */
sk
->
daddr
=
sin
.
sin_addr
.
s_addr
;
sk
->
dummy_th
.
dest
=
sin
.
sin_port
;
...
...
@@ -604,8 +605,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb
->
len
=
len
-
sizeof
(
*
uh
);
if
(
!
sk
->
dead
)
wake_up
(
sk
->
sleep
);
if
(
!
sk
->
dead
)
sk
->
data_ready
(
sk
,
skb
->
len
);
release_sock
(
sk
);
return
(
0
);
}
...
...
@@ -635,6 +637,8 @@ struct proto udp_prot = {
udp_ioctl
,
NULL
,
NULL
,
ip_setsockopt
,
ip_getsockopt
,
128
,
0
,
{
NULL
,},
...
...
net/unix/sock.c
View file @
36f4514a
...
...
@@ -12,11 +12,12 @@
*
* Fixes:
* Alan Cox : Verify Area
* NET2E Team : Page fault locks
*
*
BUGS
*
Page faults on read while another process reads could lose data.
*
Page faults on write happen to interleave data (probably not allowed)
*
with any other simultaneous writers on the socket but dont cause harm
.
*
To Do:
*
*
Change to the NET2E3 code for Unix domain sockets in general. The
*
read/write logic is much better and cleaner
.
*
*
* This program is free software; you can redistribute it and/or
...
...
@@ -141,6 +142,29 @@ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
}
/* Support routines doing anti page fault locking
* FvK & Matt Dillon (borrowed From NET2E3)
*/
/*
* Locking for unix-domain sockets. We don't use the socket structure's
* wait queue because it is allowed to 'go away' outside of our control,
* whereas unix_proto_data structures stick around.
*/
void
unix_lock
(
struct
unix_proto_data
*
upd
)
{
while
(
upd
->
lock_flag
)
sleep_on
(
&
upd
->
wait
);
upd
->
lock_flag
=
1
;
}
void
unix_unlock
(
struct
unix_proto_data
*
upd
)
{
upd
->
lock_flag
=
0
;
wake_up
(
&
upd
->
wait
);
}
/* don't have to do anything. */
static
int
unix_proto_listen
(
struct
socket
*
sock
,
int
backlog
)
...
...
@@ -598,6 +622,8 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
* Copy from the read buffer into the user's buffer,
* watching for wraparound. Then we wake up the writer.
*/
unix_lock
(
upd
);
do
{
int
part
,
cando
;
...
...
@@ -612,7 +638,10 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
dprintf
(
1
,
"UNIX: read: avail=%d, todo=%d, cando=%d
\n
"
,
avail
,
todo
,
cando
);
if
((
er
=
verify_area
(
VERIFY_WRITE
,
ubuf
,
cando
))
<
0
)
{
unix_unlock
(
upd
);
return
er
;
}
memcpy_tofs
(
ubuf
,
upd
->
buf
+
upd
->
bp_tail
,
cando
);
upd
->
bp_tail
=
(
upd
->
bp_tail
+
cando
)
&
(
BUF_SIZE
-
1
);
ubuf
+=
cando
;
...
...
@@ -620,6 +649,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
if
(
sock
->
state
==
SS_CONNECTED
)
wake_up
(
sock
->
conn
->
wait
);
avail
=
UN_BUF_AVAIL
(
upd
);
}
while
(
todo
&&
avail
);
unix_unlock
(
upd
);
return
(
size
-
todo
);
}
...
...
@@ -666,6 +696,9 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
* Copy from the user's buffer to the write buffer,
* watching for wraparound. Then we wake up the reader.
*/
unix_lock
(
pupd
);
do
{
int
part
,
cando
;
...
...
@@ -681,6 +714,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
*/
if
(
sock
->
state
==
SS_DISCONNECTING
)
{
send_sig
(
SIGPIPE
,
current
,
1
);
unix_unlock
(
pupd
);
return
(
-
EPIPE
);
}
if
((
cando
=
todo
)
>
space
)
cando
=
space
;
...
...
@@ -689,7 +723,10 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
space
,
todo
,
cando
);
er
=
verify_area
(
VERIFY_READ
,
ubuf
,
cando
);
if
(
er
)
{
unix_unlock
(
pupd
);
return
er
;
}
memcpy_fromfs
(
pupd
->
buf
+
pupd
->
bp_head
,
ubuf
,
cando
);
pupd
->
bp_head
=
(
pupd
->
bp_head
+
cando
)
&
(
BUF_SIZE
-
1
);
ubuf
+=
cando
;
...
...
@@ -697,6 +734,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if
(
sock
->
state
==
SS_CONNECTED
)
wake_up
(
sock
->
conn
->
wait
);
space
=
UN_BUF_SPACE
(
pupd
);
}
while
(
todo
&&
space
);
unix_unlock
(
pupd
);
return
(
size
-
todo
);
}
...
...
@@ -842,6 +880,8 @@ unix_ioctl(struct inode *inode, struct file *file,
}
static
struct
file_operations
unix_fops
=
{
NULL
,
/* LSEEK */
NULL
,
/* READ */
...
...
net/unix/unix.h
View file @
36f4514a
...
...
@@ -35,6 +35,8 @@ struct unix_proto_data {
int
bp_head
,
bp_tail
;
struct
inode
*
inode
;
struct
unix_proto_data
*
peerupd
;
struct
wait_queue
*
wait
;
/* Lock across page faults (FvK) */
int
lock_flag
;
};
extern
struct
unix_proto_data
unix_datas
[
NSOCKETS
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment