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
e10e81fb
Commit
e10e81fb
authored
Nov 23, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Plain Diff
Merge us.ibm.com:/home/sridhar/BK/lksctp-2.5.work
into us.ibm.com:/home/sridhar/BK/lksctp-2.6.0-test10
parents
a3d93eb3
b896b82b
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
716 additions
and
71 deletions
+716
-71
include/linux/sctp.h
include/linux/sctp.h
+2
-1
include/linux/sysctl.h
include/linux/sysctl.h
+1
-0
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
net/sctp/associola.c
net/sctp/associola.c
+47
-0
net/sctp/input.c
net/sctp/input.c
+3
-6
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
+4
-3
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+119
-16
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+8
-6
net/sctp/socket.c
net/sctp/socket.c
+75
-17
net/sctp/sysctl.c
net/sctp/sysctl.c
+8
-0
No files found.
include/linux/sctp.h
View file @
e10e81fb
...
...
@@ -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 @
e10e81fb
...
...
@@ -577,6 +577,7 @@ enum {
NET_SCTP_HB_INTERVAL
=
10
,
NET_SCTP_PRESERVE_ENABLE
=
11
,
NET_SCTP_MAX_BURST
=
12
,
NET_SCTP_ADDIP_ENABLE
=
13
,
};
/* CTL_PROC names: */
...
...
include/net/sctp/constants.h
View file @
e10e81fb
/* 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 @
e10e81fb
...
...
@@ -116,8 +116,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 @
e10e81fb
...
...
@@ -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 @
e10e81fb
...
...
@@ -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
);
...
...
net/sctp/associola.c
View file @
e10e81fb
...
...
@@ -361,6 +361,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
);
}
...
...
@@ -524,6 +532,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 @
e10e81fb
...
...
@@ -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/outqueue.c
View file @
e10e81fb
...
...
@@ -149,7 +149,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 @
e10e81fb
...
...
@@ -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 @
e10e81fb
...
...
@@ -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
;
}
struct
sctp_chunk
*
sctp_process_asconf
(
struct
sctp_association
*
asoc
,
/* 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
,
int
vparam_len
)
sctp_addip_param_t
*
asconf_param
)
{
// FIXME: process asconf chunk
return
NULL
;
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
)
{
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 @
e10e81fb
...
...
@@ -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
);
...
...
net/sctp/sm_statefuns.c
View file @
e10e81fb
...
...
@@ -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
)
{
// 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
;
}
...
...
@@ -3092,8 +3131,72 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
// FIXME: Handle the ASCONF-ACK chunk
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_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
)
{
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
;
}
/*
...
...
net/sctp/sm_statetable.c
View file @
e10e81fb
/* 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 @
e10e81fb
...
...
@@ -99,6 +99,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
*
,
...
...
@@ -299,6 +301,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.
*
...
...
@@ -379,6 +416,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
;
...
...
@@ -388,10 +428,13 @@ 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
...
...
@@ -432,7 +475,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
goto
out
;
}
retval
=
sctp_
primitive_ASCONF
(
asoc
,
chunk
);
retval
=
sctp_
send_asconf
(
asoc
,
chunk
);
if
(
retval
)
{
sctp_chunk_free
(
chunk
);
goto
out
;
...
...
@@ -564,6 +607,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
;
...
...
@@ -573,10 +619,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
...
...
@@ -621,7 +670,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
goto
out
;
}
retval
=
sctp_
primitive_ASCONF
(
asoc
,
chunk
);
retval
=
sctp_
send_asconf
(
asoc
,
chunk
);
if
(
retval
)
{
sctp_chunk_free
(
chunk
);
goto
out
;
...
...
@@ -1919,6 +1968,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
;
...
...
@@ -1929,6 +1981,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
;
...
...
@@ -1941,7 +1999,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
if
(
!
chunk
)
return
-
ENOMEM
;
err
=
sctp_
primitive_ASCONF
(
asoc
,
chunk
);
err
=
sctp_
send_asconf
(
asoc
,
chunk
);
if
(
err
)
{
sctp_chunk_free
(
chunk
);
return
err
;
...
...
net/sctp/sysctl.c
View file @
e10e81fb
...
...
@@ -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
}
};
...
...
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