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
3940ed85
Commit
3940ed85
authored
Jan 19, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/davem/net-2.6
into home.osdl.org:/home/torvalds/v2.5/linux
parents
4d53a003
4705cae7
Changes
36
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
1171 additions
and
300 deletions
+1171
-300
drivers/net/Kconfig
drivers/net/Kconfig
+1
-1
include/linux/sctp.h
include/linux/sctp.h
+2
-1
include/linux/sysctl.h
include/linux/sysctl.h
+3
-0
include/net/neighbour.h
include/net/neighbour.h
+0
-2
include/net/sctp/constants.h
include/net/sctp/constants.h
+1
-3
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+4
-2
include/net/sctp/sm.h
include/net/sctp/sm.h
+21
-6
include/net/sctp/structs.h
include/net/sctp/structs.h
+11
-0
kernel/sysctl.c
kernel/sysctl.c
+205
-122
net/ax25/af_ax25.c
net/ax25/af_ax25.c
+6
-1
net/bridge/br_netfilter.c
net/bridge/br_netfilter.c
+2
-0
net/core/dst.c
net/core/dst.c
+1
-1
net/core/neighbour.c
net/core/neighbour.c
+5
-4
net/core/pktgen.c
net/core/pktgen.c
+13
-3
net/ipv4/Kconfig
net/ipv4/Kconfig
+1
-1
net/ipv6/addrconf.c
net/ipv6/addrconf.c
+4
-1
net/ipv6/af_inet6.c
net/ipv6/af_inet6.c
+51
-35
net/ipv6/datagram.c
net/ipv6/datagram.c
+23
-7
net/ipv6/raw.c
net/ipv6/raw.c
+28
-15
net/ipv6/route.c
net/ipv6/route.c
+1
-0
net/ipv6/sit.c
net/ipv6/sit.c
+4
-2
net/irda/af_irda.c
net/irda/af_irda.c
+15
-3
net/netrom/af_netrom.c
net/netrom/af_netrom.c
+6
-1
net/rose/af_rose.c
net/rose/af_rose.c
+9
-3
net/sctp/associola.c
net/sctp/associola.c
+47
-0
net/sctp/input.c
net/sctp/input.c
+3
-6
net/sctp/output.c
net/sctp/output.c
+1
-2
net/sctp/outqueue.c
net/sctp/outqueue.c
+1
-1
net/sctp/protocol.c
net/sctp/protocol.c
+3
-0
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+408
-10
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+8
-7
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+175
-19
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+8
-6
net/sctp/socket.c
net/sctp/socket.c
+86
-32
net/sctp/sysctl.c
net/sctp/sysctl.c
+8
-0
net/sunrpc/sysctl.c
net/sunrpc/sysctl.c
+6
-3
No files found.
drivers/net/Kconfig
View file @
3940ed85
...
...
@@ -1697,7 +1697,7 @@ config NET_POCKET
<file:Documentation/Changes>) and you can say N here.
Laptop users should read the Linux Laptop home page at
<http://www.
cs.utexas.edu/users/kharker/linux-laptop
/>.
<http://www.
linux-on-laptops.com
/>.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
...
...
include/linux/sctp.h
View file @
3940ed85
...
...
@@ -439,12 +439,13 @@ typedef enum {
* 0x0101 Operation Refused Due to Resource Shortage.
* 0x0102 Request to Delete Source IP Address.
* 0x0103 Association Aborted due to illegal ASCONF-ACK
* 0x0104 Request refused - no authorization.
*/
SCTP_ERROR_DEL_LAST_IP
=
__constant_htons
(
0x0100
),
SCTP_ERROR_RSRC_LOW
=
__constant_htons
(
0x0101
),
SCTP_ERROR_DEL_SRC_IP
=
__constant_htons
(
0x0102
),
SCTP_ERROR_ASCONF_ACK
=
__constant_htons
(
0x0103
),
SCTP_ERROR_REQ_REFUSED
=
__constant_htons
(
0x0104
)
}
sctp_error_t
;
...
...
include/linux/sysctl.h
View file @
3940ed85
...
...
@@ -580,6 +580,7 @@ enum {
NET_SCTP_HB_INTERVAL
=
10
,
NET_SCTP_PRESERVE_ENABLE
=
11
,
NET_SCTP_MAX_BURST
=
12
,
NET_SCTP_ADDIP_ENABLE
=
13
,
};
/* /proc/sys/net/bridge */
...
...
@@ -737,6 +738,8 @@ extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
void
__user
*
,
size_t
*
);
extern
int
proc_dointvec_jiffies
(
ctl_table
*
,
int
,
struct
file
*
,
void
__user
*
,
size_t
*
);
extern
int
proc_dointvec_userhz_jiffies
(
ctl_table
*
,
int
,
struct
file
*
,
void
__user
*
,
size_t
*
);
extern
int
proc_doulongvec_minmax
(
ctl_table
*
,
int
,
struct
file
*
,
void
__user
*
,
size_t
*
);
extern
int
proc_doulongvec_ms_jiffies_minmax
(
ctl_table
*
table
,
int
,
...
...
include/net/neighbour.h
View file @
3940ed85
...
...
@@ -47,9 +47,7 @@
#include <linux/skbuff.h>
#include <linux/err.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
#define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE)
#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
...
...
include/net/sctp/constants.h
View file @
3940ed85
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -75,8 +75,6 @@ enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
#define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1)
#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2)
#define SCTP_CID_ADDIP_MIN SCTP_CID_ASCONF
#define SCTP_CID_ADDIP_MAX SCTP_CID_ASCONF_ACK
#define SCTP_NUM_ADDIP_CHUNK_TYPES 2
/* These are the different flavours of event. */
...
...
include/net/sctp/sctp.h
View file @
3940ed85
...
...
@@ -115,8 +115,10 @@
#define SCTP_STATIC static
#endif
#define MSECS_TO_JIFFIES(msec) (msec * HZ / 1000)
#define JIFFIES_TO_MSECS(jiff) (jiff * 1000 / HZ)
#define MSECS_TO_JIFFIES(msec) \
(((msec / 1000) * HZ) + ((msec % 1000) * HZ) / 1000)
#define JIFFIES_TO_MSECS(jiff) \
(((jiff / HZ) * 1000) + ((jiff % HZ) * 1000) / HZ)
/*
* Function declarations.
...
...
include/net/sctp/sm.h
View file @
3940ed85
...
...
@@ -268,15 +268,15 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
struct
sctp_chunk
*
sctp_make_asconf_update_ip
(
struct
sctp_association
*
,
union
sctp_addr
*
,
struct
sockaddr
*
,
int
,
int
);
int
,
__u16
);
struct
sctp_chunk
*
sctp_make_asconf_set_prim
(
struct
sctp_association
*
asoc
,
union
sctp_addr
*
addr
);
struct
sctp_chunk
*
sctp_make_asconf_ack
(
struct
sctp_association
*
asoc
,
int
serial
,
int
vparam_len
);
struct
sctp_chunk
*
sctp_make_asconf_ack
(
const
struct
sctp_association
*
asoc
,
__u32
serial
,
int
vparam_len
);
struct
sctp_chunk
*
sctp_process_asconf
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
int
vparam_len
);
struct
sctp_chunk
*
asconf
);
int
sctp_process_asconf_ack
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf_ack
);
void
sctp_chunk_assign_tsn
(
struct
sctp_chunk
*
);
void
sctp_chunk_assign_ssn
(
struct
sctp_chunk
*
);
...
...
@@ -431,6 +431,21 @@ static inline int SSN_lte(__u16 s, __u16 t)
return
(((
s
)
==
(
t
))
||
(((
s
)
-
(
t
))
&
SSN_SIGN_BIT
));
}
/*
* ADDIP 3.1.1
* The valid range of Serial Number is from 0 to 4294967295 (2**32 - 1). Serial
* Numbers wrap back to 0 after reaching 4294967295.
*/
enum
{
ADDIP_SERIAL_SIGN_BIT
=
(
1
<<
31
)
};
static
inline
int
ADDIP_SERIAL_gte
(
__u16
s
,
__u16
t
)
{
return
(((
s
)
==
(
t
))
||
(((
t
)
-
(
s
))
&
ADDIP_SERIAL_SIGN_BIT
));
}
/* Run sctp_add_cmd() generating a BUG() if there is a failure. */
static
inline
void
sctp_add_cmd_sf
(
sctp_cmd_seq_t
*
seq
,
sctp_verb_t
verb
,
sctp_arg_t
obj
)
{
...
...
include/net/sctp/structs.h
View file @
3940ed85
...
...
@@ -190,6 +190,9 @@ extern struct sctp_globals {
*/
struct
list_head
local_addr_list
;
spinlock_t
local_addr_lock
;
/* Flag to indicate if addip is enabled. */
int
addip_enable
;
}
sctp_globals
;
#define sctp_rto_initial (sctp_globals.rto_initial)
...
...
@@ -217,6 +220,7 @@ extern struct sctp_globals {
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.local_addr_lock)
#define sctp_addip_enable (sctp_globals.addip_enable)
/* SCTP Socket type: UDP or TCP style. */
typedef
enum
{
...
...
@@ -1397,6 +1401,11 @@ struct sctp_association {
/* Does peer support ADDIP? */
__u8
asconf_capable
;
/* This mask is used to disable sending the ASCONF chunk
* with specified parameter to peer.
*/
__u16
addip_disabled_mask
;
struct
sctp_inithdr
i
;
int
cookie_len
;
void
*
cookie
;
...
...
@@ -1708,6 +1717,8 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
struct
sctp_transport
*
sctp_assoc_add_peer
(
struct
sctp_association
*
,
const
union
sctp_addr
*
address
,
const
int
gfp
);
void
sctp_assoc_del_peer
(
struct
sctp_association
*
asoc
,
const
union
sctp_addr
*
addr
);
void
sctp_assoc_control_transport
(
struct
sctp_association
*
,
struct
sctp_transport
*
,
sctp_transport_cmd_t
,
sctp_sn_error_t
);
...
...
kernel/sysctl.c
View file @
3940ed85
...
...
@@ -37,6 +37,7 @@
#include <linux/hugetlb.h>
#include <linux/security.h>
#include <linux/initrd.h>
#include <linux/times.h>
#include <asm/uaccess.h>
#ifdef CONFIG_ROOT_NFS
...
...
@@ -1070,8 +1071,8 @@ int do_sysctl_strategy (ctl_table *table,
* cover common cases -
*
* proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
* proc_dointvec_
minmax(), proc_doulongvec_ms_jiffies_minmax(),
* proc_doulongvec_minmax()
* proc_dointvec_
userhz_jiffies(), proc_dointvec_minmax(),
* proc_doulongvec_m
s_jiffies_minmax(), proc_doulongvec_m
inmax()
*
* It is the handler's job to read the input buffer from user memory
* and process it. The handler should return 0 on success.
...
...
@@ -1342,19 +1343,36 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
return
r
;
}
#define OP_SET 0
#define OP_AND 1
#define OP_OR 2
#define OP_MAX 3
#define OP_MIN 4
static
int
do_proc_dointvec_conv
(
int
*
negp
,
unsigned
long
*
lvalp
,
int
*
valp
,
int
write
,
void
*
data
)
{
if
(
write
)
{
*
valp
=
*
negp
?
-*
lvalp
:
*
lvalp
;
}
else
{
int
val
=
*
valp
;
if
(
val
<
0
)
{
*
negp
=
-
1
;
*
lvalp
=
(
unsigned
long
)
-
val
;
}
else
{
*
negp
=
0
;
*
lvalp
=
(
unsigned
long
)
val
;
}
}
return
0
;
}
static
int
do_proc_dointvec
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
,
int
conv
,
int
op
)
void
__user
*
buffer
,
size_t
*
lenp
,
int
(
*
conv
)(
int
*
negp
,
unsigned
long
*
lvalp
,
int
*
valp
,
int
write
,
void
*
data
),
void
*
data
)
{
#define TMPBUFLEN 20
int
*
i
,
vleft
,
first
=
1
,
neg
,
val
;
unsigned
long
lval
;
size_t
left
,
len
;
#define TMPBUFLEN 20
char
buf
[
TMPBUFLEN
],
*
p
;
if
(
!
table
->
data
||
!
table
->
maxlen
||
!*
lenp
||
...
...
@@ -1364,9 +1382,12 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
}
i
=
(
int
*
)
table
->
data
;
vleft
=
table
->
maxlen
/
sizeof
(
int
);
vleft
=
table
->
maxlen
/
sizeof
(
*
i
);
left
=
*
lenp
;
if
(
!
conv
)
conv
=
do_proc_dointvec_conv
;
for
(;
left
&&
vleft
--
;
i
++
,
first
=
0
)
{
if
(
write
)
{
while
(
left
)
{
...
...
@@ -1382,8 +1403,8 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
break
;
neg
=
0
;
len
=
left
;
if
(
len
>
TMPBUFLEN
-
1
)
len
=
TMPBUFLEN
-
1
;
if
(
len
>
sizeof
(
buf
)
-
1
)
len
=
sizeof
(
buf
)
-
1
;
if
(
copy_from_user
(
buf
,
buffer
,
len
))
return
-
EFAULT
;
buf
[
len
]
=
0
;
...
...
@@ -1394,7 +1415,9 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
}
if
(
*
p
<
'0'
||
*
p
>
'9'
)
break
;
val
=
simple_strtoul
(
p
,
&
p
,
0
)
*
conv
;
lval
=
simple_strtoul
(
p
,
&
p
,
0
);
len
=
p
-
buf
;
if
((
len
<
left
)
&&
*
p
&&
!
isspace
(
*
p
))
break
;
...
...
@@ -1402,22 +1425,18 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
val
=
-
val
;
buffer
+=
len
;
left
-=
len
;
switch
(
op
)
{
case
OP_SET
:
*
i
=
val
;
break
;
case
OP_AND
:
*
i
&=
val
;
break
;
case
OP_OR
:
*
i
|=
val
;
break
;
case
OP_MAX
:
if
(
*
i
<
val
)
*
i
=
val
;
break
;
case
OP_MIN
:
if
(
*
i
>
val
)
*
i
=
val
;
break
;
}
if
(
conv
(
&
neg
,
&
lval
,
i
,
1
,
data
))
break
;
}
else
{
p
=
buf
;
if
(
!
first
)
*
p
++
=
'\t'
;
sprintf
(
p
,
"%d"
,
(
*
i
)
/
conv
);
if
(
conv
(
&
neg
,
&
lval
,
i
,
0
,
data
))
break
;
sprintf
(
p
,
"%s%lu"
,
neg
?
"-"
:
""
,
lval
);
len
=
strlen
(
buf
);
if
(
len
>
left
)
len
=
left
;
...
...
@@ -1449,6 +1468,7 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
*
lenp
-=
left
;
filp
->
f_pos
+=
*
lenp
;
return
0
;
#undef TMPBUFLEN
}
/**
...
...
@@ -1467,7 +1487,45 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
int
proc_dointvec
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
)
{
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
1
,
OP_SET
);
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
NULL
,
NULL
);
}
#define OP_SET 0
#define OP_AND 1
#define OP_OR 2
#define OP_MAX 3
#define OP_MIN 4
static
int
do_proc_dointvec_bset_conv
(
int
*
negp
,
unsigned
long
*
lvalp
,
int
*
valp
,
int
write
,
void
*
data
)
{
int
op
=
*
(
int
*
)
data
;
if
(
write
)
{
int
val
=
*
negp
?
-*
lvalp
:
*
lvalp
;
switch
(
op
)
{
case
OP_SET
:
*
valp
=
val
;
break
;
case
OP_AND
:
*
valp
&=
val
;
break
;
case
OP_OR
:
*
valp
|=
val
;
break
;
case
OP_MAX
:
if
(
*
valp
<
val
)
*
valp
=
val
;
break
;
case
OP_MIN
:
if
(
*
valp
>
val
)
*
valp
=
val
;
break
;
}
}
else
{
int
val
=
*
valp
;
if
(
val
<
0
)
{
*
negp
=
-
1
;
*
lvalp
=
(
unsigned
long
)
-
val
;
}
else
{
*
negp
=
0
;
*
lvalp
=
(
unsigned
long
)
val
;
}
}
return
0
;
}
/*
...
...
@@ -1477,11 +1535,44 @@ int proc_dointvec(ctl_table *table, int write, struct file *filp,
int
proc_dointvec_bset
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
)
{
int
op
;
if
(
!
capable
(
CAP_SYS_MODULE
))
{
return
-
EPERM
;
}
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
1
,
(
current
->
pid
==
1
)
?
OP_SET
:
OP_AND
);
op
=
(
current
->
pid
==
1
)
?
OP_SET
:
OP_AND
;
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
do_proc_dointvec_bset_conv
,
&
op
);
}
struct
do_proc_dointvec_minmax_conv_param
{
int
*
min
;
int
*
max
;
};
static
int
do_proc_dointvec_minmax_conv
(
int
*
negp
,
unsigned
long
*
lvalp
,
int
*
valp
,
int
write
,
void
*
data
)
{
struct
do_proc_dointvec_minmax_conv_param
*
param
=
data
;
if
(
write
)
{
int
val
=
*
negp
?
-*
lvalp
:
*
lvalp
;
if
((
param
->
min
&&
*
param
->
min
>
val
)
||
(
param
->
max
&&
*
param
->
max
<
val
))
return
-
EINVAL
;
*
valp
=
val
;
}
else
{
int
val
=
*
valp
;
if
(
val
<
0
)
{
*
negp
=
-
1
;
*
lvalp
=
(
unsigned
long
)
-
val
;
}
else
{
*
negp
=
0
;
*
lvalp
=
(
unsigned
long
)
val
;
}
}
return
0
;
}
/**
...
...
@@ -1503,98 +1594,12 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
int
proc_dointvec_minmax
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
)
{
int
*
i
,
*
min
,
*
max
,
vleft
,
first
=
1
,
neg
,
val
;
size_t
len
,
left
;
#define TMPBUFLEN 20
char
buf
[
TMPBUFLEN
],
*
p
;
if
(
!
table
->
data
||
!
table
->
maxlen
||
!*
lenp
||
(
filp
->
f_pos
&&
!
write
))
{
*
lenp
=
0
;
return
0
;
}
i
=
(
int
*
)
table
->
data
;
min
=
(
int
*
)
table
->
extra1
;
max
=
(
int
*
)
table
->
extra2
;
vleft
=
table
->
maxlen
/
sizeof
(
int
);
left
=
*
lenp
;
for
(;
left
&&
vleft
--
;
i
++
,
min
++
,
max
++
,
first
=
0
)
{
if
(
write
)
{
while
(
left
)
{
char
c
;
if
(
get_user
(
c
,
(
char
*
)
buffer
))
return
-
EFAULT
;
if
(
!
isspace
(
c
))
break
;
left
--
;
buffer
++
;
}
if
(
!
left
)
break
;
neg
=
0
;
len
=
left
;
if
(
len
>
TMPBUFLEN
-
1
)
len
=
TMPBUFLEN
-
1
;
if
(
copy_from_user
(
buf
,
buffer
,
len
))
return
-
EFAULT
;
buf
[
len
]
=
0
;
p
=
buf
;
if
(
*
p
==
'-'
&&
left
>
1
)
{
neg
=
1
;
left
--
,
p
++
;
}
if
(
*
p
<
'0'
||
*
p
>
'9'
)
break
;
val
=
simple_strtoul
(
p
,
&
p
,
0
);
len
=
p
-
buf
;
if
((
len
<
left
)
&&
*
p
&&
!
isspace
(
*
p
))
break
;
if
(
neg
)
val
=
-
val
;
buffer
+=
len
;
left
-=
len
;
if
((
min
&&
val
<
*
min
)
||
(
max
&&
val
>
*
max
))
continue
;
*
i
=
val
;
}
else
{
p
=
buf
;
if
(
!
first
)
*
p
++
=
'\t'
;
sprintf
(
p
,
"%d"
,
*
i
);
len
=
strlen
(
buf
);
if
(
len
>
left
)
len
=
left
;
if
(
copy_to_user
(
buffer
,
buf
,
len
))
return
-
EFAULT
;
left
-=
len
;
buffer
+=
len
;
}
}
if
(
!
write
&&
!
first
&&
left
)
{
if
(
put_user
(
'\n'
,
(
char
*
)
buffer
))
return
-
EFAULT
;
left
--
,
buffer
++
;
}
if
(
write
)
{
p
=
(
char
*
)
buffer
;
while
(
left
)
{
char
c
;
if
(
get_user
(
c
,
p
++
))
return
-
EFAULT
;
if
(
!
isspace
(
c
))
break
;
left
--
;
}
}
if
(
write
&&
first
)
return
-
EINVAL
;
*
lenp
-=
left
;
filp
->
f_pos
+=
*
lenp
;
return
0
;
struct
do_proc_dointvec_minmax_conv_param
param
=
{
.
min
=
(
int
*
)
table
->
extra1
,
.
max
=
(
int
*
)
table
->
extra2
,
};
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
do_proc_dointvec_minmax_conv
,
&
param
);
}
static
int
do_proc_doulongvec_minmax
(
ctl_table
*
table
,
int
write
,
...
...
@@ -1749,6 +1754,48 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
}
static
int
do_proc_dointvec_jiffies_conv
(
int
*
negp
,
unsigned
long
*
lvalp
,
int
*
valp
,
int
write
,
void
*
data
)
{
if
(
write
)
{
*
valp
=
*
negp
?
-
(
*
lvalp
*
HZ
)
:
(
*
lvalp
*
HZ
);
}
else
{
int
val
=
*
valp
;
unsigned
long
lval
;
if
(
val
<
0
)
{
*
negp
=
-
1
;
lval
=
(
unsigned
long
)
-
val
;
}
else
{
*
negp
=
0
;
lval
=
(
unsigned
long
)
val
;
}
*
lvalp
=
lval
/
HZ
;
}
return
0
;
}
static
int
do_proc_dointvec_userhz_jiffies_conv
(
int
*
negp
,
unsigned
long
*
lvalp
,
int
*
valp
,
int
write
,
void
*
data
)
{
if
(
write
)
{
*
valp
=
clock_t_to_jiffies
(
*
negp
?
-*
lvalp
:
*
lvalp
);
}
else
{
int
val
=
*
valp
;
unsigned
long
lval
;
if
(
val
<
0
)
{
*
negp
=
-
1
;
lval
=
(
unsigned
long
)
-
val
;
}
else
{
*
negp
=
0
;
lval
=
(
unsigned
long
)
val
;
}
*
lvalp
=
jiffies_to_clock_t
(
lval
);
}
return
0
;
}
/**
* proc_dointvec_jiffies - read a vector of integers as seconds
* @table: the sysctl table
...
...
@@ -1767,7 +1814,30 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
int
proc_dointvec_jiffies
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
)
{
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
HZ
,
OP_SET
);
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
do_proc_dointvec_jiffies_conv
,
NULL
);
}
/**
* proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds
* @table: the sysctl table
* @write: %TRUE if this is a write to the sysctl file
* @filp: the file structure
* @buffer: the user buffer
* @lenp: the size of the user buffer
*
* Reads/writes up to table->maxlen/sizeof(unsigned int) integer
* values from/to the user buffer, treated as an ASCII string.
* The values read are assumed to be in 1/USER_HZ seconds, and
* are converted into jiffies.
*
* Returns 0 on success.
*/
int
proc_dointvec_userhz_jiffies
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
)
{
return
do_proc_dointvec
(
table
,
write
,
filp
,
buffer
,
lenp
,
do_proc_dointvec_userhz_jiffies_conv
,
NULL
);
}
#else
/* CONFIG_PROC_FS */
...
...
@@ -1808,6 +1878,12 @@ int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
return
-
ENOSYS
;
}
int
proc_dointvec_userhz_jiffies
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
*
buffer
,
size_t
*
lenp
)
{
return
-
ENOSYS
;
}
int
proc_doulongvec_minmax
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
*
buffer
,
size_t
*
lenp
)
{
...
...
@@ -1995,6 +2071,12 @@ int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
return
-
ENOSYS
;
}
int
proc_dointvec_userhz_jiffies
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
*
buffer
,
size_t
*
lenp
)
{
return
-
ENOSYS
;
}
int
proc_doulongvec_minmax
(
ctl_table
*
table
,
int
write
,
struct
file
*
filp
,
void
__user
*
buffer
,
size_t
*
lenp
)
{
...
...
@@ -2027,6 +2109,7 @@ void unregister_sysctl_table(struct ctl_table_header * table)
EXPORT_SYMBOL
(
proc_dointvec
);
EXPORT_SYMBOL
(
proc_dointvec_jiffies
);
EXPORT_SYMBOL
(
proc_dointvec_minmax
);
EXPORT_SYMBOL
(
proc_dointvec_userhz_jiffies
);
EXPORT_SYMBOL
(
proc_dostring
);
EXPORT_SYMBOL
(
proc_doulongvec_minmax
);
EXPORT_SYMBOL
(
proc_doulongvec_ms_jiffies_minmax
);
...
...
net/ax25/af_ax25.c
View file @
3940ed85
...
...
@@ -1526,7 +1526,12 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
SOCK_DEBUG
(
sk
,
"AX.25: Appending user data
\n
"
);
/* User data follows immediately after the AX.25 data */
memcpy_fromiovec
(
skb_put
(
skb
,
len
),
msg
->
msg_iov
,
len
);
if
(
memcpy_fromiovec
(
skb_put
(
skb
,
len
),
msg
->
msg_iov
,
len
))
{
err
=
-
EFAULT
;
kfree_skb
(
skb
);
goto
out
;
}
skb
->
nh
.
raw
=
skb
->
data
;
/* Add the PID if one is not supplied by the user in the skb */
...
...
net/bridge/br_netfilter.c
View file @
3940ed85
...
...
@@ -435,8 +435,10 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
struct
vlan_ethhdr
*
hdr
=
(
struct
vlan_ethhdr
*
)(
skb
->
mac
.
ethernet
);
struct
net_device
**
d
=
(
struct
net_device
**
)(
skb
->
cb
);
#ifdef CONFIG_SYSCTL
if
(
!
brnf_call_arptables
)
return
NF_ACCEPT
;
#endif
if
(
skb
->
protocol
!=
__constant_htons
(
ETH_P_ARP
))
{
if
(
!
IS_VLAN_ARP
)
...
...
net/core/dst.c
View file @
3940ed85
...
...
@@ -40,7 +40,7 @@ static void dst_run_gc(unsigned long);
static
void
___dst_free
(
struct
dst_entry
*
dst
);
static
struct
timer_list
dst_gc_timer
=
TIMER_INITIALIZER
(
dst_run_gc
,
0
,
DST_GC_MIN
);
TIMER_INITIALIZER
(
dst_run_gc
,
DST_GC_MIN
,
0
);
static
void
dst_run_gc
(
unsigned
long
dummy
)
{
...
...
net/core/neighbour.c
View file @
3940ed85
...
...
@@ -24,6 +24,7 @@
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
#include <linux/times.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/sock.h>
...
...
@@ -1510,7 +1511,7 @@ struct neigh_sysctl_table {
.
procname
=
"retrans_time"
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
,
.
proc_handler
=
&
proc_dointvec
_userhz_jiffies
,
},
{
.
ctl_name
=
NET_NEIGH_REACHABLE_TIME
,
...
...
@@ -1555,21 +1556,21 @@ struct neigh_sysctl_table {
.
procname
=
"anycast_delay"
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
,
.
proc_handler
=
&
proc_dointvec
_userhz_jiffies
,
},
{
.
ctl_name
=
NET_NEIGH_PROXY_DELAY
,
.
procname
=
"proxy_delay"
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
,
.
proc_handler
=
&
proc_dointvec
_userhz_jiffies
,
},
{
.
ctl_name
=
NET_NEIGH_LOCKTIME
,
.
procname
=
"locktime"
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
,
.
proc_handler
=
&
proc_dointvec
_userhz_jiffies
,
},
{
.
ctl_name
=
NET_NEIGH_GC_INTERVAL
,
...
...
net/core/pktgen.c
View file @
3940ed85
...
...
@@ -88,7 +88,7 @@
#define cycles() ((u32)get_cycles())
#define VERSION "pktgen version 1.3"
#define VERSION "pktgen version 1.3
1
"
static
char
version
[]
__initdata
=
"pktgen.c: v1.3: Packet Generator for packet performance testing.
\n
"
;
...
...
@@ -720,8 +720,18 @@ static void inject(struct pktgen_info* info)
{
char
*
p
=
info
->
result
;
__u64
pps
=
(
__u32
)(
info
->
sofar
*
1000
)
/
((
__u32
)(
total
)
/
1000
);
__u64
bps
=
pps
*
8
*
(
info
->
pkt_size
+
4
);
/* take 32bit ethernet CRC into account */
__u64
bps
,
pps
=
0
;
if
(
total
>
1000
)
pps
=
(
__u32
)(
info
->
sofar
*
1000
)
/
((
__u32
)(
total
)
/
1000
);
else
if
(
total
>
100
)
pps
=
(
__u32
)(
info
->
sofar
*
10000
)
/
((
__u32
)(
total
)
/
100
);
else
if
(
total
>
10
)
pps
=
(
__u32
)(
info
->
sofar
*
100000
)
/
((
__u32
)(
total
)
/
10
);
else
if
(
total
>
1
)
pps
=
(
__u32
)(
info
->
sofar
*
1000000
)
/
(
__u32
)
total
;
bps
=
pps
*
8
*
(
info
->
pkt_size
+
4
);
/* take 32bit ethernet CRC into account */
p
+=
sprintf
(
p
,
"OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps) errors: %llu"
,
(
unsigned
long
long
)
total
,
(
unsigned
long
long
)
(
total
-
idle
),
...
...
net/ipv4/Kconfig
View file @
3940ed85
...
...
@@ -90,7 +90,7 @@ config IP_ROUTE_NAT
destination addresses of packets that pass through it, in a manner
you specify. General information about Network Address Translation
can be gotten from the document
<http://www.
csn.tu-chemnitz.de/~mha
/linux-ip-nat/diplom/nat.html>.
<http://www.
hasenstein.com
/linux-ip-nat/diplom/nat.html>.
config IP_ROUTE_MULTIPATH
bool "IP: equal cost multipath"
...
...
net/ipv6/addrconf.c
View file @
3940ed85
...
...
@@ -3039,7 +3039,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
static
struct
addrconf_sysctl_table
{
struct
ctl_table_header
*
sysctl_header
;
ctl_table
addrconf_vars
[
1
6
];
ctl_table
addrconf_vars
[
1
7
];
ctl_table
addrconf_dev
[
2
];
ctl_table
addrconf_conf_dir
[
2
];
ctl_table
addrconf_proto_dir
[
2
];
...
...
@@ -3180,6 +3180,9 @@ static struct addrconf_sysctl_table
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
,
},
{
.
ctl_name
=
0
,
/* sentinel */
}
},
.
addrconf_dev
=
{
{
...
...
net/ipv6/af_inet6.c
View file @
3940ed85
...
...
@@ -294,6 +294,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
__u32
v4addr
=
0
;
unsigned
short
snum
;
int
addr_type
=
0
;
int
err
=
0
;
/* If the socket has its own bind function then use it. */
if
(
sk
->
sk_prot
->
bind
)
...
...
@@ -305,24 +306,6 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if
((
addr_type
&
IPV6_ADDR_MULTICAST
)
&&
sock
->
type
==
SOCK_STREAM
)
return
-
EINVAL
;
/* Check if the address belongs to the host. */
if
(
addr_type
==
IPV6_ADDR_MAPPED
)
{
v4addr
=
addr
->
sin6_addr
.
s6_addr32
[
3
];
if
(
inet_addr_type
(
v4addr
)
!=
RTN_LOCAL
)
return
-
EADDRNOTAVAIL
;
}
else
{
if
(
addr_type
!=
IPV6_ADDR_ANY
)
{
/* ipv4 addr of the socket is invalid. Only the
* unspecified and mapped address have a v4 equivalent.
*/
v4addr
=
LOOPBACK4_IPV6
;
if
(
!
(
addr_type
&
IPV6_ADDR_MULTICAST
))
{
if
(
!
ipv6_chk_addr
(
&
addr
->
sin6_addr
,
NULL
))
return
-
EADDRNOTAVAIL
;
}
}
}
snum
=
ntohs
(
addr
->
sin6_port
);
if
(
snum
&&
snum
<
PROT_SOCK
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
return
-
EACCES
;
...
...
@@ -331,23 +314,56 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Check these errors (active socket, double bind). */
if
(
sk
->
sk_state
!=
TCP_CLOSE
||
inet
->
num
)
{
release_sock
(
sk
)
;
return
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
;
}
if
(
addr_type
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
addr_len
>=
sizeof
(
struct
sockaddr_in6
)
&&
addr
->
sin6_scope_id
)
{
/* Override any existing binding, if another one
* is supplied by user.
*/
sk
->
sk_bound_dev_if
=
addr
->
sin6_scope_id
;
/* Check if the address belongs to the host. */
if
(
addr_type
==
IPV6_ADDR_MAPPED
)
{
v4addr
=
addr
->
sin6_addr
.
s6_addr32
[
3
];
if
(
inet_addr_type
(
v4addr
)
!=
RTN_LOCAL
)
{
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
}
else
{
if
(
addr_type
!=
IPV6_ADDR_ANY
)
{
struct
net_device
*
dev
=
NULL
;
if
(
addr_type
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
addr_len
>=
sizeof
(
struct
sockaddr_in6
)
&&
addr
->
sin6_scope_id
)
{
/* Override any existing binding, if another one
* is supplied by user.
*/
sk
->
sk_bound_dev_if
=
addr
->
sin6_scope_id
;
}
/* Binding to link-local address requires an interface */
if
(
!
sk
->
sk_bound_dev_if
)
{
err
=
-
EINVAL
;
goto
out
;
}
dev
=
dev_get_by_index
(
sk
->
sk_bound_dev_if
);
if
(
!
dev
)
{
err
=
-
ENODEV
;
goto
out
;
}
}
/* Binding to link-local address requires an interface */
if
(
!
sk
->
sk_bound_dev_if
)
{
release_sock
(
sk
);
return
-
EINVAL
;
/* ipv4 addr of the socket is invalid. Only the
* unspecified and mapped address have a v4 equivalent.
*/
v4addr
=
LOOPBACK4_IPV6
;
if
(
!
(
addr_type
&
IPV6_ADDR_MULTICAST
))
{
if
(
!
ipv6_chk_addr
(
&
addr
->
sin6_addr
,
dev
))
{
if
(
dev
)
dev_put
(
dev
);
err
=
-
EADDRNOTAVAIL
;
goto
out
;
}
}
if
(
dev
)
dev_put
(
dev
);
}
}
...
...
@@ -362,8 +378,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Make sure we are allowed to bind here. */
if
(
sk
->
sk_prot
->
get_port
(
sk
,
snum
))
{
inet_reset_saddr
(
sk
);
release_sock
(
sk
)
;
return
-
EADDRINUSE
;
err
=
-
EADDRINUSE
;
goto
out
;
}
if
(
addr_type
!=
IPV6_ADDR_ANY
)
...
...
@@ -373,9 +389,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
inet
->
sport
=
ntohs
(
inet
->
num
);
inet
->
dport
=
0
;
inet
->
daddr
=
0
;
out:
release_sock
(
sk
);
return
0
;
return
err
;
}
int
inet6_release
(
struct
socket
*
sock
)
...
...
net/ipv6/datagram.c
View file @
3940ed85
...
...
@@ -265,6 +265,8 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
int
err
=
0
;
for
(
cmsg
=
CMSG_FIRSTHDR
(
msg
);
cmsg
;
cmsg
=
CMSG_NXTHDR
(
msg
,
cmsg
))
{
int
addr_type
;
struct
net_device
*
dev
=
NULL
;
if
(
cmsg
->
cmsg_len
<
sizeof
(
struct
cmsghdr
)
||
(
unsigned
long
)(((
char
*
)
cmsg
-
(
char
*
)
msg
->
msg_control
)
...
...
@@ -291,16 +293,30 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
fl
->
oif
=
src_info
->
ipi6_ifindex
;
}
if
(
!
ipv6_addr_any
(
&
src_info
->
ipi6_addr
))
{
if
(
!
ipv6_chk_addr
(
&
src_info
->
ipi6_addr
,
NULL
))
{
err
=
-
EINVAL
;
goto
exit_f
;
}
addr_type
=
ipv6_addr_type
(
&
src_info
->
ipi6_addr
);
ipv6_addr_copy
(
&
fl
->
fl6_src
,
&
src_info
->
ipi6_addr
);
if
(
ipv6_addr_type
==
IPV6_ADDR_ANY
)
break
;
if
(
addr_type
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
!
src_info
->
ipi6_ifindex
)
return
-
EINVAL
;
else
{
dev
=
dev_get_by_index
(
src_info
->
ipi6_ifindex
);
if
(
!
dev
)
return
-
ENODEV
;
}
}
if
(
!
ipv6_chk_addr
(
&
src_info
->
ipi6_addr
,
dev
))
{
if
(
dev
)
dev_put
(
dev
);
err
=
-
EINVAL
;
goto
exit_f
;
}
if
(
dev
)
dev_put
(
dev
);
ipv6_addr_copy
(
&
fl
->
fl6_src
,
&
src_info
->
ipi6_addr
);
break
;
case
IPV6_FLOWINFO
:
...
...
net/ipv6/raw.c
View file @
3940ed85
...
...
@@ -197,31 +197,44 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if
(
sk
->
sk_state
!=
TCP_CLOSE
)
goto
out
;
if
(
addr_type
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
addr_len
>=
sizeof
(
struct
sockaddr_in6
)
&&
addr
->
sin6_scope_id
)
{
/* Override any existing binding, if another one
* is supplied by user.
*/
sk
->
sk_bound_dev_if
=
addr
->
sin6_scope_id
;
}
/* Binding to link-local address requires an interface */
if
(
!
sk
->
sk_bound_dev_if
)
goto
out
;
}
/* Check if the address belongs to the host. */
if
(
addr_type
!=
IPV6_ADDR_ANY
)
{
struct
net_device
*
dev
=
NULL
;
if
(
addr_type
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
addr_len
>=
sizeof
(
struct
sockaddr_in6
)
&&
addr
->
sin6_scope_id
)
{
/* Override any existing binding, if another
* one is supplied by user.
*/
sk
->
sk_bound_dev_if
=
addr
->
sin6_scope_id
;
}
/* Binding to link-local address requires an interface */
if
(
!
sk
->
sk_bound_dev_if
)
goto
out
;
dev
=
dev_get_by_index
(
sk
->
sk_bound_dev_if
);
if
(
!
dev
)
{
err
=
-
ENODEV
;
goto
out
;
}
}
/* ipv4 addr of the socket is invalid. Only the
* unpecified and mapped address have a v4 equivalent.
*/
v4addr
=
LOOPBACK4_IPV6
;
if
(
!
(
addr_type
&
IPV6_ADDR_MULTICAST
))
{
err
=
-
EADDRNOTAVAIL
;
if
(
!
ipv6_chk_addr
(
&
addr
->
sin6_addr
,
NULL
))
if
(
!
ipv6_chk_addr
(
&
addr
->
sin6_addr
,
dev
))
{
if
(
dev
)
dev_put
(
dev
);
goto
out
;
}
}
if
(
dev
)
dev_put
(
dev
);
}
inet
->
rcv_saddr
=
inet
->
saddr
=
v4addr
;
...
...
net/ipv6/route.c
View file @
3940ed85
...
...
@@ -1974,6 +1974,7 @@ ctl_table ipv6_route_table[] = {
.
proc_handler
=
&
proc_dointvec_jiffies
,
.
strategy
=
&
sysctl_jiffies
,
},
{
.
ctl_name
=
0
}
};
#endif
...
...
net/ipv6/sit.c
View file @
3940ed85
...
...
@@ -485,7 +485,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
.
daddr
=
dst
,
.
saddr
=
tiph
->
saddr
,
.
tos
=
RT_TOS
(
tos
)
}
},
.
oif
=
tunnel
->
parms
.
link
};
.
oif
=
tunnel
->
parms
.
link
,
.
proto
=
IPPROTO_IPV6
};
if
(
ip_route_output_key
(
&
rt
,
&
fl
))
{
tunnel
->
stat
.
tx_carrier_errors
++
;
goto
tx_error_icmp
;
...
...
@@ -757,7 +758,8 @@ static int ipip6_tunnel_init(struct net_device *dev)
{
.
daddr
=
iph
->
daddr
,
.
saddr
=
iph
->
saddr
,
.
tos
=
RT_TOS
(
iph
->
tos
)
}
},
.
oif
=
tunnel
->
parms
.
link
};
.
oif
=
tunnel
->
parms
.
link
,
.
proto
=
IPPROTO_IPV6
};
struct
rtable
*
rt
;
if
(
!
ip_route_output_key
(
&
rt
,
&
fl
))
{
tdev
=
rt
->
u
.
dst
.
dev
;
...
...
net/irda/af_irda.c
View file @
3940ed85
...
...
@@ -1307,7 +1307,11 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_reserve
(
skb
,
self
->
max_header_size
+
16
);
asmptr
=
skb
->
h
.
raw
=
skb_put
(
skb
,
len
);
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
err
=
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
if
(
err
)
{
kfree_skb
(
skb
);
return
err
;
}
/*
* Just send the message to TinyTP, and let it deal with possible
...
...
@@ -1550,7 +1554,11 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG
(
4
,
"%s(), appending user data
\n
"
,
__FUNCTION__
);
asmptr
=
skb
->
h
.
raw
=
skb_put
(
skb
,
len
);
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
err
=
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
if
(
err
)
{
kfree_skb
(
skb
);
return
err
;
}
/*
* Just send the message to TinyTP, and let it deal with possible
...
...
@@ -1613,7 +1621,11 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG
(
4
,
"%s(), appending user data
\n
"
,
__FUNCTION__
);
asmptr
=
skb
->
h
.
raw
=
skb_put
(
skb
,
len
);
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
err
=
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
if
(
err
)
{
kfree_skb
(
skb
);
return
err
;
}
err
=
irlmp_connless_data_request
(
self
->
lsap
,
skb
);
if
(
err
)
{
...
...
net/netrom/af_netrom.c
View file @
3940ed85
...
...
@@ -1101,7 +1101,12 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
SOCK_DEBUG
(
sk
,
"NET/ROM: Appending user data
\n
"
);
/* User data follows immediately after the NET/ROM transport header */
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
if
(
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
))
{
kfree_skb
(
skb
);
err
=
-
EFAULT
;
goto
out
;
}
SOCK_DEBUG
(
sk
,
"NET/ROM: Transmitting buffer
\n
"
);
if
(
sk
->
sk_state
!=
TCP_ESTABLISHED
)
{
...
...
net/rose/af_rose.c
View file @
3940ed85
...
...
@@ -1083,7 +1083,11 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
asmptr
=
skb
->
h
.
raw
=
skb_put
(
skb
,
len
);
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
err
=
memcpy_fromiovec
(
asmptr
,
msg
->
msg_iov
,
len
);
if
(
err
)
{
kfree_skb
(
skb
);
return
err
;
}
/*
* If the Q BIT Include socket option is in force, the first
...
...
@@ -1133,8 +1137,10 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
frontlen
=
skb_headroom
(
skb
);
while
(
skb
->
len
>
0
)
{
if
((
skbn
=
sock_alloc_send_skb
(
sk
,
frontlen
+
ROSE_PACLEN
,
0
,
&
err
))
==
NULL
)
if
((
skbn
=
sock_alloc_send_skb
(
sk
,
frontlen
+
ROSE_PACLEN
,
0
,
&
err
))
==
NULL
)
{
kfree_skb
(
skb
);
return
err
;
}
skbn
->
sk
=
sk
;
skbn
->
free
=
1
;
...
...
@@ -1159,7 +1165,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
}
skb
->
free
=
1
;
kfree_skb
(
skb
,
FREE_WRITE
);
kfree_skb
(
skb
);
}
else
{
skb_queue_tail
(
&
sk
->
sk_write_queue
,
skb
);
/* Throw it on the queue */
}
...
...
net/sctp/associola.c
View file @
3940ed85
...
...
@@ -362,6 +362,14 @@ void sctp_association_free(struct sctp_association *asoc)
asoc
->
eyecatcher
=
0
;
/* Free any cached ASCONF_ACK chunk. */
if
(
asoc
->
addip_last_asconf_ack
)
sctp_chunk_free
(
asoc
->
addip_last_asconf_ack
);
/* Free any cached ASCONF chunk. */
if
(
asoc
->
addip_last_asconf
)
sctp_chunk_free
(
asoc
->
addip_last_asconf
);
sctp_association_put
(
asoc
);
}
...
...
@@ -525,6 +533,45 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
return
peer
;
}
/* Delete a transport address from an association. */
void
sctp_assoc_del_peer
(
struct
sctp_association
*
asoc
,
const
union
sctp_addr
*
addr
)
{
struct
list_head
*
pos
;
struct
list_head
*
temp
;
struct
sctp_transport
*
peer
=
NULL
;
struct
sctp_transport
*
transport
;
list_for_each_safe
(
pos
,
temp
,
&
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
sctp_cmp_addr_exact
(
addr
,
&
transport
->
ipaddr
))
{
peer
=
transport
;
list_del
(
pos
);
break
;
}
}
/* The address we want delete is not in the association. */
if
(
!
peer
)
return
;
/* Get the first transport of asoc. */
pos
=
asoc
->
peer
.
transport_addr_list
.
next
;
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
/* Update any entries that match the peer to be deleted. */
if
(
asoc
->
peer
.
primary_path
==
peer
)
sctp_assoc_set_primary
(
asoc
,
transport
);
if
(
asoc
->
peer
.
active_path
==
peer
)
asoc
->
peer
.
active_path
=
transport
;
if
(
asoc
->
peer
.
retran_path
==
peer
)
asoc
->
peer
.
retran_path
=
transport
;
if
(
asoc
->
peer
.
last_data_from
==
peer
)
asoc
->
peer
.
last_data_from
=
transport
;
sctp_transport_free
(
peer
);
}
/* Lookup a transport by address. */
struct
sctp_transport
*
sctp_assoc_lookup_paddr
(
const
struct
sctp_association
*
asoc
,
...
...
net/sctp/input.c
View file @
3940ed85
...
...
@@ -124,16 +124,16 @@ int sctp_rcv(struct sk_buff *skb)
/* Pull up the IP and SCTP headers. */
__skb_pull
(
skb
,
skb
->
h
.
raw
-
skb
->
data
);
if
(
skb
->
len
<
sizeof
(
struct
sctphdr
))
goto
bad_packe
t
;
goto
discard_i
t
;
if
(
sctp_rcv_checksum
(
skb
)
<
0
)
goto
bad_packe
t
;
goto
discard_i
t
;
skb_pull
(
skb
,
sizeof
(
struct
sctphdr
));
family
=
ipver2af
(
skb
->
nh
.
iph
->
version
);
af
=
sctp_get_af_specific
(
family
);
if
(
unlikely
(
!
af
))
goto
bad_packe
t
;
goto
discard_i
t
;
/* Initialize local addresses for lookups. */
af
->
from_skb
(
&
src
,
skb
,
1
);
...
...
@@ -223,9 +223,6 @@ int sctp_rcv(struct sk_buff *skb)
sock_put
(
sk
);
return
ret
;
bad_packet:
SCTP_INC_STATS
(
SctpChecksumErrors
);
discard_it:
kfree_skb
(
skb
);
return
ret
;
...
...
net/sctp/output.c
View file @
3940ed85
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -350,7 +350,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/
SCTP_DEBUG_PRINTK
(
"***sctp_transmit_packet***
\n
"
);
while
((
chunk
=
(
struct
sctp_chunk
*
)
__skb_dequeue
(
&
packet
->
chunks
)))
{
if
(
sctp_chunk_is_data
(
chunk
))
{
if
(
!
chunk
->
has_tsn
)
{
...
...
net/sctp/outqueue.c
View file @
3940ed85
...
...
@@ -150,7 +150,7 @@ static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary,
if
(
!
primary
->
cacc
.
cycling_changeover
)
{
if
(
sctp_cacc_skip_3_1_d
(
primary
,
transport
,
count_of_newacks
))
return
1
;
if
(
sctp_cacc_skip_3_1_f
(
transport
,
count_of_newacks
))
;
if
(
sctp_cacc_skip_3_1_f
(
transport
,
count_of_newacks
))
return
1
;
return
0
;
}
...
...
net/sctp/protocol.c
View file @
3940ed85
...
...
@@ -1115,6 +1115,9 @@ __init int sctp_init(void)
"(established %d bind %d)
\n
"
,
sctp_assoc_hashsize
,
sctp_port_hashsize
);
/* Disable ADDIP by default. */
sctp_addip_enable
=
0
;
sctp_sysctl_register
();
INIT_LIST_HEAD
(
&
sctp_address_families
);
...
...
net/sctp/sm_make_chunk.c
View file @
3940ed85
...
...
@@ -1441,6 +1441,7 @@ struct sctp_association *sctp_unpack_cookie(
retval
->
next_tsn
=
retval
->
c
.
initial_tsn
;
retval
->
ctsn_ack_point
=
retval
->
next_tsn
-
1
;
retval
->
addip_serial
=
retval
->
c
.
initial_tsn
;
/* The INIT stuff will be done by the side effects. */
return
retval
;
...
...
@@ -2035,7 +2036,7 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
if
(
!
retval
)
return
NULL
;
asconf
.
serial
=
asoc
->
addip_serial
++
;
asconf
.
serial
=
htonl
(
asoc
->
addip_serial
++
)
;
retval
->
subh
.
addip_hdr
=
sctp_addto_chunk
(
retval
,
sizeof
(
asconf
),
&
asconf
);
...
...
@@ -2073,7 +2074,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
union
sctp_addr
*
laddr
,
struct
sockaddr
*
addrs
,
int
addrcnt
,
int
flags
)
__u16
flags
)
{
sctp_addip_param_t
param
;
struct
sctp_chunk
*
retval
;
...
...
@@ -2112,7 +2113,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
addr_param_len
=
af
->
to_addr_param
(
addr
,
&
addr_param
);
param
.
param_hdr
.
type
=
flags
;
param
.
param_hdr
.
length
=
htons
(
paramlen
+
addr_param_len
);
param
.
crr_id
=
htonl
(
i
)
;
param
.
crr_id
=
i
;
sctp_addto_chunk
(
retval
,
paramlen
,
&
param
);
sctp_addto_chunk
(
retval
,
addr_param_len
,
&
addr_param
);
...
...
@@ -2185,8 +2186,8 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
*
* Create an ASCONF_ACK chunk with enough space for the parameter responses.
*/
struct
sctp_chunk
*
sctp_make_asconf_ack
(
struct
sctp_association
*
asoc
,
int
serial
,
int
vparam_len
)
struct
sctp_chunk
*
sctp_make_asconf_ack
(
const
struct
sctp_association
*
asoc
,
__u32
serial
,
int
vparam_len
)
{
sctp_addiphdr_t
asconf
;
struct
sctp_chunk
*
retval
;
...
...
@@ -2197,7 +2198,7 @@ struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
if
(
!
retval
)
return
NULL
;
asconf
.
serial
=
serial
;
asconf
.
serial
=
htonl
(
serial
)
;
retval
->
subh
.
addip_hdr
=
sctp_addto_chunk
(
retval
,
sizeof
(
asconf
),
&
asconf
);
...
...
@@ -2205,10 +2206,407 @@ struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
return
retval
;
}
/* Add response parameters to an ASCONF_ACK chunk. */
static
void
sctp_add_asconf_response
(
struct
sctp_chunk
*
chunk
,
__u32
crr_id
,
__u16
err_code
,
sctp_addip_param_t
*
asconf_param
)
{
sctp_addip_param_t
ack_param
;
sctp_errhdr_t
err_param
;
int
asconf_param_len
=
0
;
int
err_param_len
=
0
;
__u16
response_type
;
if
(
SCTP_ERROR_NO_ERROR
==
err_code
)
{
response_type
=
SCTP_PARAM_SUCCESS_REPORT
;
}
else
{
response_type
=
SCTP_PARAM_ERR_CAUSE
;
err_param_len
=
sizeof
(
err_param
);
if
(
asconf_param
)
asconf_param_len
=
ntohs
(
asconf_param
->
param_hdr
.
length
);
}
/* Add Success Indication or Error Cause Indication parameter. */
ack_param
.
param_hdr
.
type
=
response_type
;
ack_param
.
param_hdr
.
length
=
htons
(
sizeof
(
ack_param
)
+
err_param_len
+
asconf_param_len
);
ack_param
.
crr_id
=
crr_id
;
sctp_addto_chunk
(
chunk
,
sizeof
(
ack_param
),
&
ack_param
);
if
(
SCTP_ERROR_NO_ERROR
==
err_code
)
return
;
/* Add Error Cause parameter. */
err_param
.
cause
=
err_code
;
err_param
.
length
=
htons
(
err_param_len
+
asconf_param_len
);
sctp_addto_chunk
(
chunk
,
err_param_len
,
&
err_param
);
/* Add the failed TLV copied from ASCONF chunk. */
if
(
asconf_param
)
sctp_addto_chunk
(
chunk
,
asconf_param_len
,
asconf_param
);
}
/* Process a asconf parameter. */
static
__u16
sctp_process_asconf_param
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
sctp_addip_param_t
*
asconf_param
)
{
struct
sctp_transport
*
peer
;
struct
sctp_af
*
af
;
union
sctp_addr
addr
;
struct
list_head
*
pos
;
union
sctp_addr_param
*
addr_param
;
addr_param
=
(
union
sctp_addr_param
*
)
((
void
*
)
asconf_param
+
sizeof
(
sctp_addip_param_t
));
af
=
sctp_get_af_specific
(
param_type2af
(
addr_param
->
v4
.
param_hdr
.
type
));
if
(
unlikely
(
!
af
))
return
SCTP_ERROR_INV_PARAM
;
af
->
from_addr_param
(
&
addr
,
addr_param
,
asoc
->
peer
.
port
,
0
);
switch
(
asconf_param
->
param_hdr
.
type
)
{
case
SCTP_PARAM_ADD_IP
:
/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
* request and does not have the local resources to add this
* new address to the association, it MUST return an Error
* Cause TLV set to the new error code 'Operation Refused
* Due to Resource Shortage'.
*/
peer
=
sctp_assoc_add_peer
(
asoc
,
&
addr
,
GFP_ATOMIC
);
if
(
!
peer
)
return
SCTP_ERROR_RSRC_LOW
;
/* Start the heartbeat timer. */
if
(
!
mod_timer
(
&
peer
->
hb_timer
,
sctp_transport_timeout
(
peer
)))
sctp_transport_hold
(
peer
);
break
;
case
SCTP_PARAM_DEL_IP
:
/* ADDIP 4.3 D7) If a request is received to delete the
* last remaining IP address of a peer endpoint, the receiver
* MUST send an Error Cause TLV with the error cause set to the
* new error code 'Request to Delete Last Remaining IP Address'.
*/
pos
=
asoc
->
peer
.
transport_addr_list
.
next
;
if
(
pos
->
next
==
&
asoc
->
peer
.
transport_addr_list
)
return
SCTP_ERROR_DEL_LAST_IP
;
/* ADDIP 4.3 D8) If a request is received to delete an IP
* address which is also the source address of the IP packet
* which contained the ASCONF chunk, the receiver MUST reject
* this request. To reject the request the receiver MUST send
* an Error Cause TLV set to the new error code 'Request to
* Delete Source IP Address'
*/
if
(
sctp_cmp_addr_exact
(
sctp_source
(
asconf
),
&
addr
))
return
SCTP_ERROR_DEL_SRC_IP
;
sctp_assoc_del_peer
(
asoc
,
&
addr
);
break
;
case
SCTP_PARAM_SET_PRIMARY
:
peer
=
sctp_assoc_lookup_paddr
(
asoc
,
&
addr
);
if
(
!
peer
)
return
SCTP_ERROR_INV_PARAM
;
sctp_assoc_set_primary
(
asoc
,
peer
);
break
;
default:
return
SCTP_ERROR_INV_PARAM
;
break
;
}
return
SCTP_ERROR_NO_ERROR
;
}
/* Process an incoming ASCONF chunk with the next expected serial no. and
* return an ASCONF_ACK chunk to be sent in response.
*/
struct
sctp_chunk
*
sctp_process_asconf
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
int
vparam_len
)
struct
sctp_chunk
*
asconf
)
{
// FIXME: process asconf chunk
return
NULL
;
sctp_addiphdr_t
*
hdr
;
union
sctp_addr_param
*
addr_param
;
sctp_addip_param_t
*
asconf_param
;
struct
sctp_chunk
*
asconf_ack
;
__u16
err_code
;
int
length
=
0
;
int
chunk_len
=
asconf
->
skb
->
len
;
__u32
serial
;
int
all_param_pass
=
1
;
hdr
=
(
sctp_addiphdr_t
*
)
asconf
->
skb
->
data
;
serial
=
ntohl
(
hdr
->
serial
);
/* Skip the addiphdr and store a pointer to address parameter. */
length
=
sizeof
(
sctp_addiphdr_t
);
addr_param
=
(
union
sctp_addr_param
*
)(
asconf
->
skb
->
data
+
length
);
chunk_len
-=
length
;
/* Skip the address parameter and store a pointer to the first
* asconf paramter.
*/
length
=
ntohs
(
addr_param
->
v4
.
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)((
void
*
)
addr_param
+
length
);
chunk_len
-=
length
;
/* create an ASCONF_ACK chunk.
* Based on the definitions of parameters, we know that the size of
* ASCONF_ACK parameters are less than or equal to the twice of ASCONF
* paramters.
*/
asconf_ack
=
sctp_make_asconf_ack
(
asoc
,
serial
,
chunk_len
*
2
);
if
(
!
asconf_ack
)
goto
done
;
/* Process the TLVs contained within the ASCONF chunk. */
while
(
chunk_len
>
0
)
{
err_code
=
sctp_process_asconf_param
(
asoc
,
asconf
,
asconf_param
);
/* ADDIP 4.1 A7)
* If an error response is received for a TLV parameter,
* all TLVs with no response before the failed TLV are
* considered successful if not reported. All TLVs after
* the failed response are considered unsuccessful unless
* a specific success indication is present for the parameter.
*/
if
(
SCTP_ERROR_NO_ERROR
!=
err_code
)
all_param_pass
=
0
;
if
(
!
all_param_pass
)
sctp_add_asconf_response
(
asconf_ack
,
asconf_param
->
crr_id
,
err_code
,
asconf_param
);
/* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add
* an IP address sends an 'Out of Resource' in its response, it
* MUST also fail any subsequent add or delete requests bundled
* in the ASCONF.
*/
if
(
SCTP_ERROR_RSRC_LOW
==
err_code
)
goto
done
;
/* Move to the next ASCONF param. */
length
=
ntohs
(
asconf_param
->
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)((
void
*
)
asconf_param
+
length
);
chunk_len
-=
length
;
}
done:
asoc
->
peer
.
addip_serial
++
;
/* If we are sending a new ASCONF_ACK hold a reference to it in assoc
* after freeing the reference to old asconf ack if any.
*/
if
(
asconf_ack
)
{
if
(
asoc
->
addip_last_asconf_ack
)
sctp_chunk_free
(
asoc
->
addip_last_asconf_ack
);
sctp_chunk_hold
(
asconf_ack
);
asoc
->
addip_last_asconf_ack
=
asconf_ack
;
}
return
asconf_ack
;
}
/* Process a asconf parameter that is successfully acked. */
static
int
sctp_asconf_param_success
(
struct
sctp_association
*
asoc
,
sctp_addip_param_t
*
asconf_param
)
{
struct
sctp_af
*
af
;
union
sctp_addr
addr
;
struct
sctp_bind_addr
*
bp
=
&
asoc
->
base
.
bind_addr
;
union
sctp_addr_param
*
addr_param
;
int
retval
=
0
;
addr_param
=
(
union
sctp_addr_param
*
)
((
void
*
)
asconf_param
+
sizeof
(
sctp_addip_param_t
));
/* We have checked the packet before, so we do not check again. */
af
=
sctp_get_af_specific
(
param_type2af
(
addr_param
->
v4
.
param_hdr
.
type
));
af
->
from_addr_param
(
&
addr
,
addr_param
,
bp
->
port
,
0
);
switch
(
asconf_param
->
param_hdr
.
type
)
{
case
SCTP_PARAM_ADD_IP
:
sctp_local_bh_disable
();
sctp_write_lock
(
&
asoc
->
base
.
addr_lock
);
retval
=
sctp_add_bind_addr
(
bp
,
&
addr
,
GFP_ATOMIC
);
sctp_write_unlock
(
&
asoc
->
base
.
addr_lock
);
sctp_local_bh_enable
();
break
;
case
SCTP_PARAM_DEL_IP
:
sctp_local_bh_disable
();
sctp_write_lock
(
&
asoc
->
base
.
addr_lock
);
retval
=
sctp_del_bind_addr
(
bp
,
&
addr
);
sctp_write_unlock
(
&
asoc
->
base
.
addr_lock
);
sctp_local_bh_enable
();
break
;
default:
break
;
}
return
retval
;
}
/* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk
* for the given asconf parameter. If there is no response for this parameter,
* return the error code based on the third argument 'no_err'.
* ADDIP 4.1
* A7) If an error response is received for a TLV parameter, all TLVs with no
* response before the failed TLV are considered successful if not reported.
* All TLVs after the failed response are considered unsuccessful unless a
* specific success indication is present for the parameter.
*/
static
__u16
sctp_get_asconf_response
(
struct
sctp_chunk
*
asconf_ack
,
sctp_addip_param_t
*
asconf_param
,
int
no_err
)
{
sctp_addip_param_t
*
asconf_ack_param
;
sctp_errhdr_t
*
err_param
;
int
length
;
int
asconf_ack_len
=
asconf_ack
->
skb
->
len
;
__u16
err_code
;
if
(
no_err
)
err_code
=
SCTP_ERROR_NO_ERROR
;
else
err_code
=
SCTP_ERROR_REQ_REFUSED
;
/* Skip the addiphdr from the asconf_ack chunk and store a pointer to
* the first asconf_ack parameter.
*/
length
=
sizeof
(
sctp_addiphdr_t
);
asconf_ack_param
=
(
sctp_addip_param_t
*
)(
asconf_ack
->
skb
->
data
+
length
);
asconf_ack_len
-=
length
;
while
(
asconf_ack_len
>
0
)
{
if
(
asconf_ack_param
->
crr_id
==
asconf_param
->
crr_id
)
{
switch
(
asconf_ack_param
->
param_hdr
.
type
)
{
case
SCTP_PARAM_SUCCESS_REPORT
:
return
SCTP_ERROR_NO_ERROR
;
case
SCTP_PARAM_ERR_CAUSE
:
length
=
sizeof
(
sctp_addip_param_t
);
err_param
=
(
sctp_errhdr_t
*
)
((
void
*
)
asconf_ack_param
+
length
);
asconf_ack_len
-=
length
;
if
(
asconf_ack_len
>
0
)
return
err_param
->
cause
;
else
return
SCTP_ERROR_INV_PARAM
;
break
;
default:
return
SCTP_ERROR_INV_PARAM
;
}
}
length
=
ntohs
(
asconf_ack_param
->
param_hdr
.
length
);
asconf_ack_param
=
(
sctp_addip_param_t
*
)
((
void
*
)
asconf_ack_param
+
length
);
asconf_ack_len
-=
length
;
}
return
err_code
;
}
/* Process an incoming ASCONF_ACK chunk against the cached last ASCONF chunk. */
int
sctp_process_asconf_ack
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf_ack
)
{
struct
sctp_chunk
*
asconf
=
asoc
->
addip_last_asconf
;
union
sctp_addr_param
*
addr_param
;
sctp_addip_param_t
*
asconf_param
;
int
length
=
0
;
int
asconf_len
=
asconf
->
skb
->
len
;
int
all_param_pass
=
0
;
int
no_err
=
1
;
int
retval
=
0
;
__u16
err_code
=
SCTP_ERROR_NO_ERROR
;
/* Skip the chunkhdr and addiphdr from the last asconf sent and store
* a pointer to address parameter.
*/
length
=
sizeof
(
sctp_addip_chunk_t
);
addr_param
=
(
union
sctp_addr_param
*
)(
asconf
->
skb
->
data
+
length
);
asconf_len
-=
length
;
/* Skip the address parameter in the last asconf sent and store a
* pointer to the first asconf paramter.
*/
length
=
ntohs
(
addr_param
->
v4
.
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)((
void
*
)
addr_param
+
length
);
asconf_len
-=
length
;
/* ADDIP 4.1
* A8) If there is no response(s) to specific TLV parameter(s), and no
* failures are indicated, then all request(s) are considered
* successful.
*/
if
(
asconf_ack
->
skb
->
len
==
sizeof
(
sctp_addiphdr_t
))
all_param_pass
=
1
;
/* Process the TLVs contained in the last sent ASCONF chunk. */
while
(
asconf_len
>
0
)
{
if
(
all_param_pass
)
err_code
=
SCTP_ERROR_NO_ERROR
;
else
{
err_code
=
sctp_get_asconf_response
(
asconf_ack
,
asconf_param
,
no_err
);
if
(
no_err
&&
(
SCTP_ERROR_NO_ERROR
!=
err_code
))
no_err
=
0
;
}
switch
(
err_code
)
{
case
SCTP_ERROR_NO_ERROR
:
retval
=
sctp_asconf_param_success
(
asoc
,
asconf_param
);
break
;
case
SCTP_ERROR_RSRC_LOW
:
retval
=
1
;
break
;
case
SCTP_ERROR_INV_PARAM
:
/* Disable sending this type of asconf parameter in
* future.
*/
asoc
->
peer
.
addip_disabled_mask
|=
asconf_param
->
param_hdr
.
type
;
break
;
case
SCTP_ERROR_REQ_REFUSED
:
case
SCTP_ERROR_DEL_LAST_IP
:
case
SCTP_ERROR_DEL_SRC_IP
:
default:
break
;
}
/* Skip the processed asconf parameter and move to the next
* one.
*/
length
=
ntohs
(
asconf_param
->
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)((
void
*
)
asconf_param
+
length
);
asconf_len
-=
length
;
}
/* Free the cached last sent asconf chunk. */
sctp_chunk_free
(
asconf
);
asoc
->
addip_last_asconf
=
NULL
;
/* Send the next asconf chunk from the addip chunk queue. */
asconf
=
(
struct
sctp_chunk
*
)
__skb_dequeue
(
&
asoc
->
addip_chunks
);
if
(
asconf
)
{
/* Hold the chunk until an ASCONF_ACK is received. */
sctp_chunk_hold
(
asconf
);
if
(
sctp_primitive_ASCONF
(
asoc
,
asconf
))
sctp_chunk_free
(
asconf
);
else
asoc
->
addip_last_asconf
=
asconf
;
}
return
retval
;
}
net/sctp/sm_sideeffect.c
View file @
3940ed85
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 200
3
* (C) Copyright IBM Corp. 2001, 200
4
* Copyright (c) 1999 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
*
...
...
@@ -663,10 +663,11 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
struct
sock
*
sk
=
asoc
->
base
.
sk
;
/* If it is a non-temporary association belonging to a TCP-style
* listening socket
, do not free it so that accept() can pick it
* up later.
* listening socket
that is not closed, do not free it so that accept()
*
can pick it
up later.
*/
if
(
sctp_style
(
sk
,
TCP
)
&&
sctp_sstate
(
sk
,
LISTENING
)
&&
(
!
asoc
->
temp
))
if
(
sctp_style
(
sk
,
TCP
)
&&
sctp_sstate
(
sk
,
LISTENING
)
&&
(
!
asoc
->
temp
)
&&
(
sk
->
sk_shutdown
!=
SHUTDOWN_MASK
))
return
;
sctp_unhash_established
(
asoc
);
...
...
@@ -676,8 +677,8 @@ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
/*
* ADDIP Section 4.1 ASCONF Chunk Procedures
* A4) Start a T-4 RTO timer, using the RTO value of the selected
* destination address (
normally the primary path; see RFC2960
*
section 6.4 for details).
* destination address (
we use active path instead of primary path just
*
because primary path may be inactive.
*/
static
void
sctp_cmd_setup_t4
(
sctp_cmd_seq_t
*
cmds
,
struct
sctp_association
*
asoc
,
...
...
@@ -685,7 +686,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
{
struct
sctp_transport
*
t
;
t
=
asoc
->
peer
.
primary
_path
;
t
=
asoc
->
peer
.
active
_path
;
asoc
->
timeouts
[
SCTP_EVENT_TIMEOUT_T4_RTO
]
=
t
->
rto
;
chunk
->
transport
=
t
;
}
...
...
net/sctp/sm_statefuns.c
View file @
3940ed85
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 200
3
* (C) Copyright IBM Corp. 2001, 200
4
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 Intel Corp.
...
...
@@ -46,6 +46,7 @@
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -3066,19 +3067,57 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
return
sctp_sf_shut_8_4_5
(
ep
,
NULL
,
type
,
arg
,
commands
);
}
/*
* ADDIP Section 4.2 Upon reception of an ASCONF Chunk
* When an endpoint receive an ASCONF Chunk from the remote peer
* special procedures MAY be needed to identify the association the
* ASCONF Chunk is associated with. To properly find the association
* the following procedures should be L1 to L4 and C1 to C5
*/
/* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. */
sctp_disposition_t
sctp_sf_do_asconf
(
const
struct
sctp_endpoint
*
ep
,
const
struct
sctp_association
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
const
struct
sctp_association
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
// FIXME: Handle the ASCONF chunk
struct
sctp_chunk
*
chunk
=
arg
;
struct
sctp_chunk
*
asconf_ack
=
NULL
;
sctp_addiphdr_t
*
hdr
;
__u32
serial
;
hdr
=
(
sctp_addiphdr_t
*
)
chunk
->
skb
->
data
;
serial
=
ntohl
(
hdr
->
serial
);
/* ADDIP 4.2 C1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable
* 'Peer-Serial-Number'.
*/
if
(
serial
==
asoc
->
peer
.
addip_serial
+
1
)
{
/* ADDIP 4.2 C2) If the value found in the serial number is
* equal to the ('Peer-Serial-Number' + 1), the endpoint MUST
* do V1-V5.
*/
asconf_ack
=
sctp_process_asconf
((
struct
sctp_association
*
)
asoc
,
chunk
);
if
(
!
asconf_ack
)
return
SCTP_DISPOSITION_NOMEM
;
}
else
if
(
serial
==
asoc
->
peer
.
addip_serial
)
{
/* ADDIP 4.2 C3) If the value found in the serial number is
* equal to the value stored in the 'Peer-Serial-Number'
* IMPLEMENTATION NOTE: As an optimization a receiver may wish
* to save the last ASCONF-ACK for some predetermined period of * time and instead of re-processing the ASCONF (with the same
* serial number) it may just re-transmit the ASCONF-ACK.
*/
if
(
asoc
->
addip_last_asconf_ack
)
asconf_ack
=
asoc
->
addip_last_asconf_ack
;
else
return
SCTP_DISPOSITION_DISCARD
;
}
else
{
/* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since
* it must be either a stale packet or from an attacker.
*/
return
SCTP_DISPOSITION_DISCARD
;
}
/* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent
* back to the source address contained in the IP header of the ASCONF
* being responded to.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
asconf_ack
));
return
SCTP_DISPOSITION_CONSUME
;
}
...
...
@@ -3088,12 +3127,81 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
* delete IP addresses the D0 to D13 rules should be applied:
*/
sctp_disposition_t
sctp_sf_do_asconf_ack
(
const
struct
sctp_endpoint
*
ep
,
const
struct
sctp_association
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
const
struct
sctp_association
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
// FIXME: Handle the ASCONF-ACK chunk
return
SCTP_DISPOSITION_CONSUME
;
struct
sctp_chunk
*
asconf_ack
=
arg
;
struct
sctp_chunk
*
last_asconf
=
asoc
->
addip_last_asconf
;
struct
sctp_chunk
*
abort
;
sctp_addiphdr_t
*
addip_hdr
;
__u32
sent_serial
,
rcvd_serial
;
addip_hdr
=
(
sctp_addiphdr_t
*
)
asconf_ack
->
skb
->
data
;
rcvd_serial
=
ntohl
(
addip_hdr
->
serial
);
if
(
last_asconf
)
{
addip_hdr
=
(
sctp_addiphdr_t
*
)
last_asconf
->
subh
.
addip_hdr
;
sent_serial
=
ntohl
(
addip_hdr
->
serial
);
}
else
{
sent_serial
=
asoc
->
addip_serial
-
1
;
}
/* D0) If an endpoint receives an ASCONF-ACK that is greater than or
* equal to the next serial number to be used but no ASCONF chunk is
* outstanding the endpoint MUST ABORT the association. Note that a
* sequence number is greater than if it is no more than 2^^31-1
* larger than the current sequence number (using serial arithmetic).
*/
if
(
ADDIP_SERIAL_gte
(
rcvd_serial
,
sent_serial
+
1
)
&&
!
(
asoc
->
addip_last_asconf
))
{
abort
=
sctp_make_abort
(
asoc
,
asconf_ack
,
sizeof
(
sctp_errhdr_t
));
if
(
abort
)
{
sctp_init_cause
(
abort
,
SCTP_ERROR_ASCONF_ACK
,
NULL
,
0
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
abort
));
}
/* We are going to ABORT, so we might as well stop
* processing the rest of the chunks in the packet.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T4_RTO
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_ASCONF_ACK
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_ABORT
;
}
if
((
rcvd_serial
==
sent_serial
)
&&
asoc
->
addip_last_asconf
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T4_RTO
));
if
(
!
sctp_process_asconf_ack
((
struct
sctp_association
*
)
asoc
,
asconf_ack
))
return
SCTP_DISPOSITION_CONSUME
;
abort
=
sctp_make_abort
(
asoc
,
asconf_ack
,
sizeof
(
sctp_errhdr_t
));
if
(
abort
)
{
sctp_init_cause
(
abort
,
SCTP_ERROR_RSRC_LOW
,
NULL
,
0
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
abort
));
}
/* We are going to ABORT, so we might as well stop
* processing the rest of the chunks in the packet.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_ASCONF_ACK
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_ABORT
;
}
return
SCTP_DISPOSITION_DISCARD
;
}
/*
...
...
@@ -4269,7 +4377,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
/*
* ADDIP Section 4.1 ASCONF CHunk Procedures
* If the T
-
4 RTO timer expires the endpoint should do B1 to B5
* If the T4 RTO timer expires the endpoint should do B1 to B5
*/
sctp_disposition_t
sctp_sf_t4_timer_expire
(
const
struct
sctp_endpoint
*
ep
,
...
...
@@ -4278,7 +4386,55 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
// FIXME: need to handle t4 expire
struct
sctp_chunk
*
chunk
=
asoc
->
addip_last_asconf
;
struct
sctp_transport
*
transport
=
chunk
->
transport
;
/* ADDIP 4.1 B1) Increment the error counters and perform path failure
* detection on the appropriate destination address as defined in
* RFC2960 [5] section 8.1 and 8.2.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_STRIKE
,
SCTP_TRANSPORT
(
transport
));
/* Reconfig T4 timer and transport. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SETUP_T4
,
SCTP_CHUNK
(
chunk
));
/* ADDIP 4.1 B2) Increment the association error counters and perform
* endpoint failure detection on the association as defined in
* RFC2960 [5] section 8.1 and 8.2.
* association error counter is incremented in SCTP_CMD_STRIKE.
*/
if
(
asoc
->
overall_error_count
>=
asoc
->
max_retrans
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T4_RTO
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_ABORT
;
}
/* ADDIP 4.1 B3) Back-off the destination address RTO value to which
* the ASCONF chunk was sent by doubling the RTO timer value.
* This is done in SCTP_CMD_STRIKE.
*/
/* ADDIP 4.1 B4) Re-transmit the ASCONF Chunk last sent and if possible
* choose an alternate destination address (please refer to RFC2960
* [5] section 6.4.1). An endpoint MUST NOT add new parameters to this
* chunk, it MUST be the same (including its serial number) as the last
* ASCONF sent.
*/
sctp_chunk_hold
(
asoc
->
addip_last_asconf
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
asoc
->
addip_last_asconf
));
/* ADDIP 4.1 B5) Restart the T-4 RTO timer. Note that if a different
* destination is selected, then the RTO used will be that of the new
* destination address.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_RESTART
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T4_RTO
));
return
SCTP_DISPOSITION_CONSUME
;
}
...
...
net/sctp/sm_statetable.c
View file @
3940ed85
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
*
...
...
@@ -921,13 +921,15 @@ const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
if
(
state
>
SCTP_STATE_MAX
)
return
&
bug
;
if
(
cid
>=
0
&&
cid
<=
SCTP_CID_BASE_MAX
)
{
if
(
cid
>=
0
&&
cid
<=
SCTP_CID_BASE_MAX
)
return
&
chunk_event_table
[
cid
][
state
];
}
if
(
cid
>=
SCTP_CID_ADDIP_MIN
&&
cid
<=
SCTP_CID_ADDIP_MAX
)
{
return
&
addip_chunk_event_table
[
cid
-
SCTP_CID_ADDIP_MIN
][
state
];
if
(
sctp_addip_enable
)
{
if
(
cid
==
SCTP_CID_ASCONF
)
return
&
addip_chunk_event_table
[
0
][
state
];
if
(
cid
==
SCTP_CID_ASCONF_ACK
)
return
&
addip_chunk_event_table
[
1
][
state
];
}
return
&
chunk_event_table_unknown
[
state
];
...
...
net/sctp/socket.c
View file @
3940ed85
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 200
3
* (C) Copyright IBM Corp. 2001, 200
4
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 Intel Corp.
...
...
@@ -100,6 +100,8 @@ static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr
*
,
int
);
static
int
sctp_send_asconf_add_ip
(
struct
sock
*
,
struct
sockaddr
*
,
int
);
static
int
sctp_send_asconf_del_ip
(
struct
sock
*
,
struct
sockaddr
*
,
int
);
static
int
sctp_send_asconf
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
);
static
int
sctp_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
static
void
sctp_sock_migrate
(
struct
sock
*
,
struct
sock
*
,
...
...
@@ -150,10 +152,14 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
{
struct
sctp_association
*
addr_asoc
=
NULL
,
*
id_asoc
=
NULL
;
struct
sctp_transport
*
transport
;
union
sctp_addr
*
laddr
=
(
union
sctp_addr
*
)
addr
;
laddr
->
v4
.
sin_port
=
ntohs
(
laddr
->
v4
.
sin_port
);
addr_asoc
=
sctp_endpoint_lookup_assoc
(
sctp_sk
(
sk
)
->
ep
,
(
union
sctp_addr
*
)
addr
,
&
transport
);
laddr
->
v4
.
sin_port
=
htons
(
laddr
->
v4
.
sin_port
);
if
(
!
addr_asoc
)
return
NULL
;
...
...
@@ -300,6 +306,41 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
return
ret
;
}
/* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
*
* R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged
* at any one time. If a sender, after sending an ASCONF chunk, decides
* it needs to transfer another ASCONF Chunk, it MUST wait until the
* ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a
* subsequent ASCONF. Note this restriction binds each side, so at any
* time two ASCONF may be in-transit on any given association (one sent
* from each endpoint).
*/
static
int
sctp_send_asconf
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
)
{
int
retval
=
0
;
/* If there is an outstanding ASCONF chunk, queue it for later
* transmission.
*/
if
(
asoc
->
addip_last_asconf
)
{
__skb_queue_tail
(
&
asoc
->
addip_chunks
,
(
struct
sk_buff
*
)
chunk
);
goto
out
;
}
/* Hold the chunk until an ASCONF_ACK is received. */
sctp_chunk_hold
(
chunk
);
retval
=
sctp_primitive_ASCONF
(
asoc
,
chunk
);
if
(
retval
)
sctp_chunk_free
(
chunk
);
else
asoc
->
addip_last_asconf
=
chunk
;
out:
return
retval
;
}
/* Add a list of addresses as bind addresses to local endpoint or
* association.
*
...
...
@@ -380,6 +421,9 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
int
i
;
int
retval
=
0
;
if
(
!
sctp_addip_enable
)
return
retval
;
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
...
...
@@ -389,12 +433,15 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
list_for_each
(
pos
,
&
ep
->
asocs
)
{
asoc
=
list_entry
(
pos
,
struct
sctp_association
,
asocs
);
if
(
!
sctp_state
(
asoc
,
ESTABLISHED
)
)
if
(
!
asoc
->
peer
.
asconf_capable
)
continue
;
if
(
!
asoc
->
peer
.
asconf_capable
)
if
(
asoc
->
peer
.
addip_disabled_mask
&
SCTP_PARAM_ADD_IP
)
continue
;
if
(
!
sctp_state
(
asoc
,
ESTABLISHED
))
continue
;
/* Check if any address in the packed array of addresses is
* in the bind address list of the association. If so,
* do not send the asconf chunk to its peer, but continue with
...
...
@@ -409,9 +456,9 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
goto
out
;
}
if
(
sctp_assoc_lookup_laddr
(
asoc
,
addr
))
if
(
sctp_assoc_lookup_laddr
(
asoc
,
addr
))
break
;
addr_buf
+=
af
->
sockaddr_len
;
}
if
(
i
<
addrcnt
)
...
...
@@ -433,14 +480,10 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
goto
out
;
}
retval
=
sctp_primitive_ASCONF
(
asoc
,
chunk
);
if
(
retval
)
{
sctp_chunk_free
(
chunk
);
goto
out
;
}
retval
=
sctp_send_asconf
(
asoc
,
chunk
);
/* FIXME: After sending the add address ASCONF chunk, we
* cannot append the address to the association's binding
/* FIXME: After sending the add address ASCONF chunk, we
* cannot append the address to the association's binding
* address list, because the new address may be used as the
* source of a message sent to the peer before the ASCONF
* chunk is received by the peer. So we should wait until
...
...
@@ -565,6 +608,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
int
i
;
int
retval
=
0
;
if
(
!
sctp_addip_enable
)
return
retval
;
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
...
...
@@ -574,10 +620,13 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
list_for_each
(
pos
,
&
ep
->
asocs
)
{
asoc
=
list_entry
(
pos
,
struct
sctp_association
,
asocs
);
if
(
!
sctp_state
(
asoc
,
ESTABLISHED
)
)
if
(
!
asoc
->
peer
.
asconf_capable
)
continue
;
if
(
!
asoc
->
peer
.
asconf_capable
)
if
(
asoc
->
peer
.
addip_disabled_mask
&
SCTP_PARAM_DEL_IP
)
continue
;
if
(
!
sctp_state
(
asoc
,
ESTABLISHED
))
continue
;
/* Check if any address in the packed array of addresses is
...
...
@@ -594,9 +643,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
goto
out
;
}
if
(
!
sctp_assoc_lookup_laddr
(
asoc
,
laddr
))
if
(
!
sctp_assoc_lookup_laddr
(
asoc
,
laddr
))
break
;
addr_buf
+=
af
->
sockaddr_len
;
}
if
(
i
<
addrcnt
)
...
...
@@ -611,27 +660,23 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
bp
=
&
asoc
->
base
.
bind_addr
;
laddr
=
sctp_find_unmatch_addr
(
bp
,
(
union
sctp_addr
*
)
addrs
,
addrcnt
,
sp
);
sctp_read_unlock
(
&
asoc
->
base
.
addr_lock
);
sctp_read_unlock
(
&
asoc
->
base
.
addr_lock
);
if
(
!
laddr
)
continue
;
chunk
=
sctp_make_asconf_update_ip
(
asoc
,
laddr
,
addrs
,
addrcnt
,
chunk
=
sctp_make_asconf_update_ip
(
asoc
,
laddr
,
addrs
,
addrcnt
,
SCTP_PARAM_DEL_IP
);
if
(
!
chunk
)
{
retval
=
-
ENOMEM
;
goto
out
;
}
retval
=
sctp_primitive_ASCONF
(
asoc
,
chunk
);
if
(
retval
)
{
sctp_chunk_free
(
chunk
);
goto
out
;
}
retval
=
sctp_send_asconf
(
asoc
,
chunk
);
/* FIXME: After sending the delete address ASCONF chunk, we
* cannot remove the addresses from the association's bind
* address list, because there maybe some packet send to
* the delete addresses, so we should wait until ASCONF_ACK
* the delete addresses, so we should wait until ASCONF_ACK
* packet is received.
*/
}
...
...
@@ -1920,6 +1965,9 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
if
(
!
sctp_addip_enable
)
return
-
EPERM
;
if
(
optlen
!=
sizeof
(
struct
sctp_setpeerprim
))
return
-
EINVAL
;
...
...
@@ -1930,6 +1978,12 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
if
(
!
asoc
)
return
-
EINVAL
;
if
(
!
asoc
->
peer
.
asconf_capable
)
return
-
EPERM
;
if
(
asoc
->
peer
.
addip_disabled_mask
&
SCTP_PARAM_SET_PRIMARY
)
return
-
EPERM
;
if
(
!
sctp_state
(
asoc
,
ESTABLISHED
))
return
-
ENOTCONN
;
...
...
@@ -1942,15 +1996,11 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
if
(
!
chunk
)
return
-
ENOMEM
;
err
=
sctp_primitive_ASCONF
(
asoc
,
chunk
);
if
(
err
)
{
sctp_chunk_free
(
chunk
);
return
err
;
}
err
=
sctp_send_asconf
(
asoc
,
chunk
);
SCTP_DEBUG_PRINTK
(
"We set peer primary addr primitively.
\n
"
);
return
0
;
return
err
;
}
...
...
@@ -2962,9 +3012,13 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
if
(
!
asoc
->
peer
.
primary_path
)
return
-
ENOTCONN
;
asoc
->
peer
.
primary_path
->
ipaddr
.
v4
.
sin_port
=
htons
(
asoc
->
peer
.
primary_path
->
ipaddr
.
v4
.
sin_port
);
memcpy
(
&
prim
.
ssp_addr
,
&
asoc
->
peer
.
primary_path
->
ipaddr
,
sizeof
(
union
sctp_addr
));
asoc
->
peer
.
primary_path
->
ipaddr
.
v4
.
sin_port
=
ntohs
(
asoc
->
peer
.
primary_path
->
ipaddr
.
v4
.
sin_port
);
sctp_get_pf_specific
(
sk
->
sk_family
)
->
addr_v4map
(
sp
,
(
union
sctp_addr
*
)
&
prim
.
ssp_addr
);
...
...
net/sctp/sysctl.c
View file @
3940ed85
...
...
@@ -162,6 +162,14 @@ static ctl_table sctp_table[] = {
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
},
{
.
ctl_name
=
NET_SCTP_ADDIP_ENABLE
,
.
procname
=
"addip_enable"
,
.
data
=
&
sctp_addip_enable
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
},
{
.
ctl_name
=
0
}
};
...
...
net/sunrpc/sysctl.c
View file @
3940ed85
...
...
@@ -81,7 +81,8 @@ proc_dodebug(ctl_table *table, int write, struct file *file,
if
(
left
>
sizeof
(
tmpbuf
)
-
1
)
return
-
EINVAL
;
copy_from_user
(
tmpbuf
,
p
,
left
);
if
(
copy_from_user
(
tmpbuf
,
p
,
left
))
return
-
EFAULT
;
tmpbuf
[
left
]
=
'\0'
;
for
(
p
=
tmpbuf
,
value
=
0
;
'0'
<=
*
p
&&
*
p
<=
'9'
;
p
++
,
left
--
)
...
...
@@ -101,9 +102,11 @@ proc_dodebug(ctl_table *table, int write, struct file *file,
len
=
sprintf
(
tmpbuf
,
"%d"
,
*
(
unsigned
int
*
)
table
->
data
);
if
(
len
>
left
)
len
=
left
;
__copy_to_user
(
buffer
,
tmpbuf
,
len
);
if
(
__copy_to_user
(
buffer
,
tmpbuf
,
len
))
return
-
EFAULT
;
if
((
left
-=
len
)
>
0
)
{
put_user
(
'\n'
,
(
char
*
)
buffer
+
len
);
if
(
put_user
(
'\n'
,
(
char
*
)
buffer
+
len
))
return
-
EFAULT
;
left
--
;
}
}
...
...
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