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
nexedi
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