Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
b896b82b
Commit
b896b82b
authored
Nov 20, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.
parent
c4fdf856
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
385 additions
and
57 deletions
+385
-57
include/linux/sctp.h
include/linux/sctp.h
+2
-1
include/net/sctp/sm.h
include/net/sctp/sm.h
+17
-0
include/net/sctp/structs.h
include/net/sctp/structs.h
+5
-0
net/sctp/associola.c
net/sctp/associola.c
+4
-0
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+218
-34
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+70
-5
net/sctp/socket.c
net/sctp/socket.c
+69
-17
No files found.
include/linux/sctp.h
View file @
b896b82b
...
...
@@ -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/net/sctp/sm.h
View file @
b896b82b
...
...
@@ -275,6 +275,8 @@ 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
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
*
);
...
...
@@ -429,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 @
b896b82b
...
...
@@ -1401,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
;
...
...
net/sctp/associola.c
View file @
b896b82b
...
...
@@ -365,6 +365,10 @@ void sctp_association_free(struct sctp_association *asoc)
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
);
}
...
...
net/sctp/sm_make_chunk.c
View file @
b896b82b
...
...
@@ -2207,7 +2207,7 @@ struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
}
/* Add response parameters to an ASCONF_ACK chunk. */
void
sctp_add_asconf_response
(
struct
sctp_chunk
*
chunk
,
__u32
crr_id
,
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
;
...
...
@@ -2248,16 +2248,19 @@ void sctp_add_asconf_response(struct sctp_chunk *chunk, __u32 crr_id,
}
/* Process a asconf parameter. */
__u16
sctp_process_asconf_param
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
sctp_addip_param_t
*
asconf_param
,
union
sctp_addr_param
*
addr_param
)
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
;
...
...
@@ -2330,33 +2333,29 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
__u16
err_code
;
int
length
=
0
;
int
chunk_len
=
ntohs
(
asconf
->
chunk_hdr
->
length
);
int
asconf_param_len
;
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 chunkhdr. */
chunk_len
-=
sizeof
(
sctp_chunkhdr_t
);
/* Skip the addiphdr and store a pointer to address parameter. */
/* Skip the addiphdr and store a pointer to address parameter. */
length
=
sizeof
(
sctp_addiphdr_t
);
addr_param
=
(
union
sctp_addr_param
*
)
skb_pull
(
asconf
->
skb
,
length
);
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
*
)
skb_pull
(
asconf
->
skb
,
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
* paramter.
* paramter
s
.
*/
asconf_ack
=
sctp_make_asconf_ack
(
asoc
,
serial
,
chunk_len
*
2
);
if
(
!
asconf_ack
)
...
...
@@ -2364,22 +2363,8 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
/* Process the TLVs contained within the ASCONF chunk. */
while
(
chunk_len
>
0
)
{
asconf_param_len
=
ntohs
(
asconf_param
->
param_hdr
.
length
);
length
=
sizeof
(
sctp_addip_param_t
);
/* Unrecognized or unsupported paramter. */
if
(
asconf_param_len
<=
length
)
{
sctp_add_asconf_response
(
asconf_ack
,
0
,
SCTP_ERROR_UNKNOWN_PARAM
,
NULL
);
goto
done
;
}
addr_param
=
(
union
sctp_addr_param
*
)
skb_pull
(
asconf
->
skb
,
length
);
err_code
=
sctp_process_asconf_param
(
asoc
,
asconf
,
asconf_param
,
addr_param
);
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
...
...
@@ -2404,10 +2389,10 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
goto
done
;
/* Move to the next ASCONF param. */
length
=
ntohs
(
a
ddr_param
->
v4
.
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)
skb_pull
(
asconf
->
skb
,
length
);
chunk_len
-=
asconf_param_len
;
length
=
ntohs
(
a
sconf_param
->
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)
((
void
*
)
asconf_param
+
length
);
chunk_len
-=
length
;
}
done:
...
...
@@ -2426,3 +2411,202 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
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_statefuns.c
View file @
b896b82b
...
...
@@ -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.
...
...
@@ -3126,12 +3127,76 @@ 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_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/socket.c
View file @
b896b82b
...
...
@@ -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.
*
...
...
@@ -391,12 +428,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
...
...
@@ -411,9 +451,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
)
...
...
@@ -435,14 +475,14 @@ 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
;
}
/* 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
...
...
@@ -579,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
...
...
@@ -599,9 +642,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
)
...
...
@@ -616,18 +659,18 @@ 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
);
retval
=
sctp_
send_asconf
(
asoc
,
chunk
);
if
(
retval
)
{
sctp_chunk_free
(
chunk
);
goto
out
;
...
...
@@ -636,7 +679,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
/* 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.
*/
}
...
...
@@ -1925,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
;
...
...
@@ -1935,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
;
...
...
@@ -1947,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
;
...
...
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