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
b18b05fb
Commit
b18b05fb
authored
Oct 18, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-lksctp.bkbits.net/lksctp-2.5
into nuts.ninka.net:/home/davem/src/BK/sctp-2.5
parents
7e8a4852
63592fe5
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
534 additions
and
256 deletions
+534
-256
include/net/sctp/sm.h
include/net/sctp/sm.h
+35
-2
include/net/sctp/structs.h
include/net/sctp/structs.h
+7
-1
net/sctp/associola.c
net/sctp/associola.c
+1
-7
net/sctp/bind_addr.c
net/sctp/bind_addr.c
+18
-14
net/sctp/input.c
net/sctp/input.c
+50
-15
net/sctp/output.c
net/sctp/output.c
+11
-3
net/sctp/outqueue.c
net/sctp/outqueue.c
+104
-59
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+33
-34
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+4
-2
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+197
-97
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+2
-2
net/sctp/socket.c
net/sctp/socket.c
+72
-20
No files found.
include/net/sctp/sm.h
View file @
b18b05fb
...
...
@@ -139,6 +139,7 @@ sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
sctp_state_fn_t
sctp_sf_do_5_2_2_dupinit
;
sctp_state_fn_t
sctp_sf_do_5_2_4_dupcook
;
sctp_state_fn_t
sctp_sf_unk_chunk
;
sctp_state_fn_t
sctp_sf_do_8_5_1_E_sa
;
/* Prototypes for primitive event state functions. */
sctp_state_fn_t
sctp_sf_do_prm_asoc
;
...
...
@@ -329,10 +330,10 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
);
/* 4th level prototypes */
void
sctp_param2sockaddr
(
sockaddr_storage_t
*
addr
,
const
sctpParam_t
param
,
void
sctp_param2sockaddr
(
sockaddr_storage_t
*
addr
,
sctp_addr_param_t
*
,
__u16
port
);
int
sctp_addr2sockaddr
(
const
sctpParam_t
,
sockaddr_storage_t
*
);
int
sockaddr2sctp_addr
(
const
sockaddr_storage_t
*
,
sctp
Param_t
);
int
sockaddr2sctp_addr
(
const
sockaddr_storage_t
*
,
sctp
_addr_param_t
*
);
/* Extern declarations for major data structures. */
sctp_sm_table_entry_t
*
sctp_chunk_event_lookup
(
sctp_cid_t
,
sctp_state_t
);
...
...
@@ -432,4 +433,36 @@ static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_a
BUG
();
}
/* Check VTAG of the packet matches the sender's own tag OR its peer's
* tag and the T bit is set in the Chunk Flags.
*/
static
inline
int
sctp_vtag_verify_either
(
const
sctp_chunk_t
*
chunk
,
const
sctp_association_t
*
asoc
)
{
/* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2
*
* B) The receiver of a ABORT shall accept the packet if the
* Verification Tag field of the packet matches its own tag OR it
* is set to its peer's tag and the T bit is set in the Chunk
* Flags. Otherwise, the receiver MUST silently discard the packet
* and take no further action.
*
* (C) The receiver of a SHUTDOWN COMPLETE shall accept the
* packet if the Verification Tag field of the packet
* matches its own tag OR it is set to its peer's tag and
* the T bit is set in the Chunk Flags. Otherwise, the
* receiver MUST silently discard the packet and take no
* further action....
*
*/
if
((
ntohl
(
chunk
->
sctp_hdr
->
vtag
)
==
asoc
->
c
.
my_vtag
)
||
(
sctp_test_T_bit
(
chunk
)
&&
(
ntohl
(
chunk
->
sctp_hdr
->
vtag
)
==
asoc
->
c
.
peer_vtag
)))
{
return
1
;
}
return
0
;
}
#endif
/* __sctp_sm_h__ */
include/net/sctp/structs.h
View file @
b18b05fb
...
...
@@ -378,7 +378,7 @@ typedef union {
typedef
union
{
sctp_ipv4addr_param_t
v4
;
sctp_ipv6addr_param_t
v6
;
}
sctp
IpAddress
_t
;
}
sctp
_addr_param
_t
;
/* RFC 2960. Section 3.3.5 Heartbeat.
* Heartbeat Information: variable length
...
...
@@ -1044,6 +1044,9 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
const
sockaddr_storage_t
*
);
int
sctp_has_association
(
const
sockaddr_storage_t
*
laddr
,
const
sockaddr_storage_t
*
paddr
);
int
sctp_verify_init
(
const
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
sctp_init_chunk_t
*
peer_init
,
...
...
@@ -1312,6 +1315,9 @@ struct SCTP_association {
__u32
ctsn_ack_point
;
/* Highest TSN that is acknowledged by incoming SACKs. */
__u32
highest_sacked
;
/* The number of unacknowledged data chunks. Reported through
* the SCTP_STATUS sockopt.
*/
...
...
net/sctp/associola.c
View file @
b18b05fb
...
...
@@ -207,6 +207,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
->
next_tsn
=
asoc
->
c
.
initial_tsn
;
asoc
->
ctsn_ack_point
=
asoc
->
next_tsn
-
1
;
asoc
->
highest_sacked
=
asoc
->
ctsn_ack_point
;
asoc
->
unack_data
=
0
;
...
...
@@ -476,13 +477,6 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc
->
peer
.
retran_path
=
peer
;
}
/* If we do not yet have a primary path, set one. */
if
(
NULL
==
asoc
->
peer
.
primary_path
)
{
asoc
->
peer
.
primary_path
=
peer
;
asoc
->
peer
.
active_path
=
peer
;
asoc
->
peer
.
retran_path
=
peer
;
}
if
(
asoc
->
peer
.
active_path
==
asoc
->
peer
.
retran_path
)
asoc
->
peer
.
retran_path
=
peer
;
...
...
net/sctp/bind_addr.c
View file @
b18b05fb
...
...
@@ -199,11 +199,10 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr)
sctpParam_t
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
int
*
addrs_len
,
int
priority
)
{
sctpParam_t
rawaddr
;
sctpParam_t
addrparms
;
sctpParam_t
retval
;
int
addrparms_len
;
sctp
IpAddress_t
rawaddr_space
;
sctp
_addr_param_t
rawaddr
;
int
len
;
struct
sockaddr_storage_list
*
addr
;
struct
list_head
*
pos
;
...
...
@@ -214,7 +213,7 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
/* Allocate enough memory at once. */
list_for_each
(
pos
,
&
bp
->
address_list
)
{
len
+=
sizeof
(
sctp_
ipv6
addr_param_t
);
len
+=
sizeof
(
sctp_addr_param_t
);
}
addrparms
.
v
=
kmalloc
(
len
,
priority
);
...
...
@@ -222,12 +221,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
goto
end_raw
;
retval
=
addrparms
;
rawaddr
.
v4
=
&
rawaddr_space
.
v4
;
list_for_each
(
pos
,
&
bp
->
address_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
len
=
sockaddr2sctp_addr
(
&
addr
->
a
,
rawaddr
);
memcpy
(
addrparms
.
v
,
rawaddr
.
v
,
len
);
len
=
sockaddr2sctp_addr
(
&
addr
->
a
,
&
rawaddr
);
memcpy
(
addrparms
.
v
,
&
rawaddr
,
len
);
addrparms
.
v
+=
len
;
addrparms_len
+=
len
;
}
...
...
@@ -244,33 +242,39 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
int
sctp_raw_to_bind_addrs
(
sctp_bind_addr_t
*
bp
,
__u8
*
raw_addr_list
,
int
addrs_len
,
__u16
port
,
int
priority
)
{
sctpParam_t
rawaddr
;
sctp_addr_param_t
*
rawaddr
;
sctp_paramhdr_t
*
param
;
sockaddr_storage_t
addr
;
int
retval
=
0
;
int
len
;
/* Convert the raw address to standard address format */
while
(
addrs_len
)
{
rawaddr
.
v
=
raw_addr_list
;
if
(
SCTP_PARAM_IPV4_ADDRESS
==
rawaddr
.
p
->
type
||
SCTP_PARAM_IPV6_ADDRESS
==
rawaddr
.
p
->
type
)
{
param
=
(
sctp_paramhdr_t
*
)
raw_addr_list
;
rawaddr
=
(
sctp_addr_param_t
*
)
raw_addr_list
;
switch
(
param
->
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV6_ADDRESS
:
sctp_param2sockaddr
(
&
addr
,
rawaddr
,
port
);
retval
=
sctp_add_bind_addr
(
bp
,
&
addr
,
priority
);
if
(
retval
)
{
/* Can't finish building the list, clean up. */
sctp_bind_addr_clean
(
bp
);
break
;
break
;
;
}
len
=
ntohs
(
rawaddr
.
p
->
length
);
len
=
ntohs
(
param
->
length
);
addrs_len
-=
len
;
raw_addr_list
+=
len
;
}
else
{
break
;
default:
/* Corrupted raw addr list! */
retval
=
-
EINVAL
;
sctp_bind_addr_clean
(
bp
);
break
;
}
if
(
retval
)
break
;
}
return
retval
;
...
...
net/sctp/input.c
View file @
b18b05fb
...
...
@@ -522,7 +522,7 @@ void __sctp_unhash_established(sctp_association_t *asoc)
}
/* Look up an association. */
sctp_association_t
*
__sctp_
rcv_
lookup_association
(
const
sockaddr_storage_t
*
laddr
,
sctp_association_t
*
__sctp_lookup_association
(
const
sockaddr_storage_t
*
laddr
,
const
sockaddr_storage_t
*
paddr
,
sctp_transport_t
**
transportp
)
{
...
...
@@ -557,6 +557,36 @@ sctp_association_t *__sctp_rcv_lookup_association(const sockaddr_storage_t *ladd
return
asoc
;
}
/* Look up an association. BH-safe. */
sctp_association_t
*
sctp_lookup_association
(
const
sockaddr_storage_t
*
laddr
,
const
sockaddr_storage_t
*
paddr
,
sctp_transport_t
**
transportp
)
{
sctp_association_t
*
asoc
;
sctp_local_bh_disable
();
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
sctp_local_bh_enable
();
return
asoc
;
}
/* Is there an association matching the given local and peer addresses? */
int
sctp_has_association
(
const
sockaddr_storage_t
*
laddr
,
const
sockaddr_storage_t
*
paddr
)
{
sctp_association_t
*
asoc
;
sctp_transport_t
*
transport
;
if
((
asoc
=
sctp_lookup_association
(
laddr
,
paddr
,
&
transport
)))
{
sock_put
(
asoc
->
base
.
sk
);
sctp_association_put
(
asoc
);
return
1
;
}
return
0
;
}
/*
* SCTP Implementors Guide, 2.18 Handling of address
* parameters within the INIT or INIT-ACK.
...
...
@@ -584,14 +614,20 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
sctp_chunkhdr_t
*
ch
;
__u8
*
ch_end
,
*
data
;
sctp
Param_t
parm
;
sctp
_paramhdr_t
*
parm
;
ch
=
(
sctp_chunkhdr_t
*
)
skb
->
data
;
ch_end
=
((
__u8
*
)
ch
)
+
WORD_ROUND
(
ntohs
(
ch
->
length
));
if
(
SCTP_CID_INIT_ACK
!=
ch
->
type
)
/* If this is INIT/INIT-ACK look inside the chunk too. */
switch
(
ch
->
type
)
{
case
SCTP_CID_INIT
:
case
SCTP_CID_INIT_ACK
:
break
;
default:
return
NULL
;
}
/*
* This code will NOT touch anything inside the chunk--it is
...
...
@@ -609,26 +645,25 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Find the start of the TLVs and the end of the chunk. This is
* the region we search for address parameters.
*/
data
=
skb
->
data
+
sizeof
(
sctp_init_chunk_t
);
/* See sctp_process_init() for how to go thru TLVs. */
while
(
data
<
ch_end
)
{
parm
.
v
=
data
;
parm
=
(
sctp_paramhdr_t
*
)
data
;
if
(
!
parm
.
p
->
length
)
if
(
!
parm
->
length
)
break
;
data
+=
WORD_ROUND
(
ntohs
(
parm
.
p
->
length
));
data
+=
WORD_ROUND
(
ntohs
(
parm
->
length
));
/* Note: Ignoring hostname addresses. */
if
((
SCTP_PARAM_IPV4_ADDRESS
!=
parm
.
p
->
type
)
&&
(
SCTP_PARAM_IPV6_ADDRESS
!=
parm
.
p
->
type
))
if
((
SCTP_PARAM_IPV4_ADDRESS
!=
parm
->
type
)
&&
(
SCTP_PARAM_IPV6_ADDRESS
!=
parm
->
type
))
continue
;
sctp_param2sockaddr
(
paddr
,
parm
,
ntohs
(
sh
->
source
));
asoc
=
__sctp_
rcv_
lookup_association
(
laddr
,
paddr
,
transportp
);
sctp_param2sockaddr
(
paddr
,
(
sctp_addr_param_t
*
)
parm
,
ntohs
(
sh
->
source
));
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
if
(
asoc
)
return
asoc
;
}
...
...
@@ -644,7 +679,7 @@ sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
{
sctp_association_t
*
asoc
;
asoc
=
__sctp_
rcv_
lookup_association
(
laddr
,
paddr
,
transportp
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
/* Further lookup for INIT-ACK packet.
* SCTP Implementors Guide, 2.18 Handling of address
...
...
net/sctp/output.c
View file @
b18b05fb
...
...
@@ -530,10 +530,18 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
* to a given transport address if it has cwnd or more bytes
* of data outstanding to that transport address.
*/
/* RFC 7.2.4 & the Implementers Guide 2.8.
*
* 3) ...
* When a Fast Retransmit is being performed the sender SHOULD
* ignore the value of cwnd and SHOULD NOT delay retransmission.
*/
if
(
!
chunk
->
fast_retransmit
)
{
if
(
transport
->
flight_size
>=
transport
->
cwnd
)
{
retval
=
SCTP_XMIT_RWND_FULL
;
goto
finish
;
}
}
/* Keep track of how many bytes are in flight over this transport. */
transport
->
flight_size
+=
datasize
;
...
...
net/sctp/outqueue.c
View file @
b18b05fb
...
...
@@ -59,7 +59,8 @@ static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn);
static
void
sctp_check_transmitted
(
sctp_outqueue_t
*
q
,
struct
list_head
*
transmitted_queue
,
sctp_transport_t
*
transport
,
sctp_sackhdr_t
*
sack
);
sctp_sackhdr_t
*
sack
,
__u32
highest_new_tsn
);
/* Generate a new outqueue. */
sctp_outqueue_t
*
sctp_outqueue_new
(
sctp_association_t
*
asoc
)
...
...
@@ -773,6 +774,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/
if
(
packet
->
has_cookie_echo
)
goto
sctp_flush_out
;
/* Don't send new data if there is still data
* waiting to retransmit.
*/
if
(
!
list_empty
(
&
q
->
retransmit
))
goto
sctp_flush_out
;
}
/* Finally, transmit new packets. */
...
...
@@ -849,7 +856,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
/* We could not append this chunk, so put
* the chunk back on the output queue.
*/
SCTP_DEBUG_PRINTK
(
"sctp_flush_outqueue: could"
SCTP_DEBUG_PRINTK
(
"sctp_flush_outqueue: could
"
"not transmit TSN: 0x%x, status: %d
\n
"
,
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
),
status
);
...
...
@@ -971,6 +978,36 @@ static void sctp_sack_update_unack_data(sctp_association_t *assoc,
assoc
->
unack_data
=
unack_data
;
}
/* Return the highest new tsn that is acknowledged by the given SACK chunk. */
static
__u32
sctp_highest_new_tsn
(
sctp_sackhdr_t
*
sack
,
sctp_association_t
*
asoc
)
{
struct
list_head
*
ltransport
,
*
lchunk
;
sctp_transport_t
*
transport
;
sctp_chunk_t
*
chunk
;
__u32
highest_new_tsn
,
tsn
;
struct
list_head
*
transport_list
=
&
asoc
->
peer
.
transport_addr_list
;
highest_new_tsn
=
ntohl
(
sack
->
cum_tsn_ack
);
list_for_each
(
ltransport
,
transport_list
)
{
transport
=
list_entry
(
ltransport
,
sctp_transport_t
,
transports
);
list_for_each
(
lchunk
,
&
transport
->
transmitted
)
{
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
tsn
=
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
);
if
(
!
chunk
->
tsn_gap_acked
&&
TSN_lt
(
highest_new_tsn
,
tsn
)
&&
sctp_acked
(
sack
,
tsn
))
highest_new_tsn
=
tsn
;
}
}
return
highest_new_tsn
;
}
/* This is where we REALLY process a SACK.
*
* Process the sack against the outqueue. Mostly, this just frees
...
...
@@ -978,22 +1015,36 @@ static void sctp_sack_update_unack_data(sctp_association_t *assoc,
*/
int
sctp_sack_outqueue
(
sctp_outqueue_t
*
q
,
sctp_sackhdr_t
*
sack
)
{
sctp_association_t
*
asoc
=
q
->
asoc
;
sctp_transport_t
*
transport
;
sctp_chunk_t
*
tchunk
;
struct
list_head
*
lchunk
,
*
transport_list
,
*
pos
;
__u32
tsn
;
__u32
sack_ctsn
;
__u32
ctsn
;
sctp_transport_t
*
transport
;
int
outstanding
;
sctp_sack_variable_t
*
frags
=
sack
->
variable
;
__u32
sack_ctsn
,
ctsn
,
tsn
;
__u32
highest_tsn
,
highest_new_tsn
;
__u32
sack_a_rwnd
;
int
outstanding
;
/* Grab the association's destination address list. */
transport_list
=
&
q
->
asoc
->
peer
.
transport_addr_list
;
transport_list
=
&
asoc
->
peer
.
transport_addr_list
;
sack_ctsn
=
ntohl
(
sack
->
cum_tsn_ack
);
/* Get the highest TSN in the sack. */
highest_tsn
=
sack_ctsn
+
ntohs
(
frags
[
ntohs
(
sack
->
num_gap_ack_blocks
)
-
1
].
gab
.
end
);
if
(
TSN_lt
(
asoc
->
highest_sacked
,
highest_tsn
))
{
highest_new_tsn
=
highest_tsn
;
asoc
->
highest_sacked
=
highest_tsn
;
}
else
{
highest_new_tsn
=
sctp_highest_new_tsn
(
sack
,
asoc
);
}
/* Run through the retransmit queue. Credit bytes received
* and free those chunks that we can.
*/
sctp_check_transmitted
(
q
,
&
q
->
retransmit
,
NULL
,
sack
);
sctp_check_transmitted
(
q
,
&
q
->
retransmit
,
NULL
,
sack
,
highest_new_tsn
);
/* Run through the transmitted queue.
* Credit bytes received and free those chunks which we can.
...
...
@@ -1003,23 +1054,22 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
list_for_each
(
pos
,
transport_list
)
{
transport
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
sctp_check_transmitted
(
q
,
&
transport
->
transmitted
,
transport
,
sack
);
transport
,
sack
,
highest_new_tsn
);
}
/* Move the Cumulative TSN Ack Point if appropriate. */
sack_ctsn
=
ntohl
(
sack
->
cum_tsn_ack
);
if
(
TSN_lt
(
q
->
asoc
->
ctsn_ack_point
,
sack_ctsn
))
q
->
asoc
->
ctsn_ack_point
=
sack_ctsn
;
if
(
TSN_lt
(
asoc
->
ctsn_ack_point
,
sack_ctsn
))
asoc
->
ctsn_ack_point
=
sack_ctsn
;
/* Update unack_data field in the assoc. */
sctp_sack_update_unack_data
(
q
->
asoc
,
sack
);
sctp_sack_update_unack_data
(
asoc
,
sack
);
ctsn
=
q
->
asoc
->
ctsn_ack_point
;
ctsn
=
asoc
->
ctsn_ack_point
;
SCTP_DEBUG_PRINTK
(
"%s: sack Cumulative TSN Ack is 0x%x.
\n
"
,
__FUNCTION__
,
sack_ctsn
);
SCTP_DEBUG_PRINTK
(
"%s: Cumulative TSN Ack of association "
"%p is 0x%x.
\n
"
,
__FUNCTION__
,
q
->
asoc
,
ctsn
);
"%p is 0x%x.
\n
"
,
__FUNCTION__
,
asoc
,
ctsn
);
/* Throw away stuff rotting on the sack queue. */
list_for_each
(
lchunk
,
&
q
->
sacked
)
{
...
...
@@ -1045,7 +1095,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
sack_a_rwnd
=
0
;
}
q
->
asoc
->
peer
.
rwnd
=
sack_a_rwnd
;
asoc
->
peer
.
rwnd
=
sack_a_rwnd
;
/* See if all chunks are acked.
* Make sure the empty queue handler will get run later.
...
...
@@ -1092,7 +1142,8 @@ int sctp_outqueue_is_empty(const sctp_outqueue_t *q)
static
void
sctp_check_transmitted
(
sctp_outqueue_t
*
q
,
struct
list_head
*
transmitted_queue
,
sctp_transport_t
*
transport
,
sctp_sackhdr_t
*
sack
)
sctp_sackhdr_t
*
sack
,
__u32
highest_new_tsn_in_sack
)
{
struct
list_head
*
lchunk
;
sctp_chunk_t
*
tchunk
;
...
...
@@ -1100,7 +1151,6 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
__u32
tsn
;
__u32
sack_ctsn
;
__u32
rtt
;
__u32
highest_new_tsn_in_sack
;
__u8
restart_timer
=
0
;
__u8
do_fast_retransmit
=
0
;
int
bytes_acked
=
0
;
...
...
@@ -1121,7 +1171,6 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
#endif
/* SCTP_DEBUG */
sack_ctsn
=
ntohl
(
sack
->
cum_tsn_ack
);
highest_new_tsn_in_sack
=
sack_ctsn
;
INIT_LIST_HEAD
(
&
tlist
);
...
...
@@ -1194,10 +1243,6 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
if
(
!
tchunk
->
tsn_gap_acked
)
{
tchunk
->
tsn_gap_acked
=
1
;
bytes_acked
+=
sctp_data_size
(
tchunk
);
if
(
TSN_lt
(
highest_new_tsn_in_sack
,
tsn
))
{
highest_new_tsn_in_sack
=
tsn
;
}
}
list_add_tail
(
lchunk
,
&
tlist
);
}
...
...
net/sctp/sm_make_chunk.c
View file @
b18b05fb
...
...
@@ -1710,6 +1710,7 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
sctp_cid_t
cid
,
int
priority
)
{
sockaddr_storage_t
addr
;
sctp_addr_param_t
*
addrparm
;
int
j
;
int
i
;
int
retval
=
1
;
...
...
@@ -1721,24 +1722,23 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
*/
switch
(
param
.
p
->
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
if
(
SCTP_CID_INIT
!=
cid
)
{
sctp_param2sockaddr
(
&
addr
,
para
m
,
asoc
->
peer
.
port
);
addrparm
=
(
sctp_addr_param_t
*
)
param
.
v
;
sctp_param2sockaddr
(
&
addr
,
addrpar
m
,
asoc
->
peer
.
port
);
scope
=
sctp_scope
(
peer_addr
);
if
(
sctp_in_scope
(
&
addr
,
scope
))
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
);
}
break
;
case
SCTP_PARAM_IPV6_ADDRESS
:
if
(
SCTP_CID_INIT
!=
cid
)
{
/* Rethink this as we may need to keep for
* restart considerations.
*/
if
(
PF_INET6
==
asoc
->
base
.
sk
->
family
)
{
sctp_param2sockaddr
(
&
addr
,
param
,
asoc
->
peer
.
port
);
addrparm
=
(
sctp_addr_param_t
*
)
param
.
v
;
sctp_param2sockaddr
(
&
addr
,
addrparm
,
asoc
->
peer
.
port
);
scope
=
sctp_scope
(
peer_addr
);
if
(
sctp_in_scope
(
&
addr
,
scope
))
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
);
}
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
);
}
break
;
...
...
@@ -1833,7 +1833,6 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *ep)
/* Select an initial TSN to send during startup. */
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
ep
)
{
/* I believe that this random number generator complies with RFC1750. */
__u32
retval
;
get_random_bytes
(
&
retval
,
sizeof
(
__u32
));
...
...
@@ -1845,26 +1844,27 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
********************************************************************/
/* Convert from an SCTP IP parameter to a sockaddr_storage_t. */
void
sctp_param2sockaddr
(
sockaddr_storage_t
*
addr
,
sctpParam_t
param
,
__u16
port
)
void
sctp_param2sockaddr
(
sockaddr_storage_t
*
addr
,
sctp_addr_param_t
*
param
,
__u16
port
)
{
switch
(
param
.
p
->
type
)
{
switch
(
param
->
v4
.
param_hdr
.
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
addr
->
v4
.
sin_family
=
AF_INET
;
addr
->
v4
.
sin_port
=
port
;
addr
->
v4
.
sin_addr
.
s_addr
=
param
.
v4
->
addr
.
s_addr
;
addr
->
v4
.
sin_addr
.
s_addr
=
param
->
v4
.
addr
.
s_addr
;
break
;
case
SCTP_PARAM_IPV6_ADDRESS
:
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_port
=
port
;
addr
->
v6
.
sin6_flowinfo
=
0
;
/* BUG */
addr
->
v6
.
sin6_addr
=
param
.
v6
->
addr
;
addr
->
v6
.
sin6_addr
=
param
->
v6
.
addr
;
addr
->
v6
.
sin6_scope_id
=
0
;
/* BUG */
break
;
default:
SCTP_DEBUG_PRINTK
(
"Illegal address type %d
\n
"
,
ntohs
(
param
.
p
->
type
));
ntohs
(
param
->
v4
.
param_hdr
.
type
));
break
;
};
}
...
...
@@ -1904,11 +1904,9 @@ int ipver2af(__u8 ipver)
case
4
:
family
=
AF_INET
;
break
;
case
6
:
family
=
AF_INET6
;
break
;
default:
family
=
0
;
break
;
...
...
@@ -1917,25 +1915,26 @@ int ipver2af(__u8 ipver)
return
family
;
}
/* Convert a sockaddr_in to IP address in an SCTP para. */
/* Returns true if a valid conversion was possible. */
int
sockaddr2sctp_addr
(
const
sockaddr_storage_t
*
sa
,
sctpParam_t
p
)
/* Convert a sockaddr_in to an IP address in an SCTP param.
* Returns len if a valid conversion was possible.
*/
int
sockaddr2sctp_addr
(
const
sockaddr_storage_t
*
sa
,
sctp_addr_param_t
*
p
)
{
int
len
=
0
;
switch
(
sa
->
v4
.
sin_family
)
{
case
AF_INET
:
p
.
p
->
type
=
SCTP_PARAM_IPV4_ADDRESS
;
p
.
p
->
length
=
ntohs
(
sizeof
(
sctp_ipv4addr_param_t
));
p
->
v4
.
param_hdr
.
type
=
SCTP_PARAM_IPV4_ADDRESS
;
p
->
v4
.
param_hdr
.
length
=
ntohs
(
sizeof
(
sctp_ipv4addr_param_t
));
len
=
sizeof
(
sctp_ipv4addr_param_t
);
p
.
v4
->
addr
.
s_addr
=
sa
->
v4
.
sin_addr
.
s_addr
;
p
->
v4
.
addr
.
s_addr
=
sa
->
v4
.
sin_addr
.
s_addr
;
break
;
case
AF_INET6
:
p
.
p
->
type
=
SCTP_PARAM_IPV6_ADDRESS
;
p
.
p
->
length
=
ntohs
(
sizeof
(
sctp_ipv6addr_param_t
));
p
->
v6
.
param_hdr
.
type
=
SCTP_PARAM_IPV6_ADDRESS
;
p
->
v6
.
param_hdr
.
length
=
ntohs
(
sizeof
(
sctp_ipv6addr_param_t
));
len
=
sizeof
(
sctp_ipv6addr_param_t
);
p
.
v6
->
addr
=
*
(
&
sa
->
v6
.
sin6_addr
);
p
->
v6
.
addr
=
*
(
&
sa
->
v6
.
sin6_addr
);
break
;
default:
...
...
net/sctp/sm_sideeffect.c
View file @
b18b05fb
...
...
@@ -1118,7 +1118,8 @@ void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
}
/* Helper function to handle the reception of an HEARTBEAT ACK. */
static
void
sctp_cmd_transport_on
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
static
void
sctp_cmd_transport_on
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_transport_t
*
t
,
sctp_chunk_t
*
chunk
)
{
sctp_sender_hb_info_t
*
hbinfo
;
...
...
@@ -1164,7 +1165,8 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
}
/* Helper function to process the process SACK command. */
static
int
sctp_cmd_process_sack
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
static
int
sctp_cmd_process_sack
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_sackhdr_t
*
sackh
)
{
int
err
;
...
...
net/sctp/sm_statefuns.c
View file @
b18b05fb
...
...
@@ -110,18 +110,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
if
(
!
chunk
->
singleton
)
return
SCTP_DISPOSITION_VIOLATION
;
/* RFC 2960 8.5.1 Exceptions in Verification Tag Rules
*
* (C) The receiver of a SHUTDOWN COMPLETE shall accept the
* packet if the Verification Tag field of the packet
* matches its own tag OR it is set to its peer's tag and
* the T bit is set in the Chunk Flags. Otherwise, the
* receiver MUST silently discard the packet and take no
* further action....
*/
if
((
ntohl
(
chunk
->
sctp_hdr
->
vtag
)
!=
asoc
->
c
.
my_vtag
)
&&
!
(
sctp_test_T_bit
(
chunk
)
||
(
ntohl
(
chunk
->
sctp_hdr
->
vtag
)
!=
asoc
->
peer
.
i
.
init_tag
)))
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
/* RFC 2960 10.2 SCTP-to-ULP
...
...
@@ -873,6 +862,105 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_CONSUME
;
}
/* Helper function to send out an abort for the restart
* condition.
*/
static
int
sctp_sf_send_restart_abort
(
sockaddr_storage_t
*
ssa
,
sctp_chunk_t
*
init
,
sctp_cmd_seq_t
*
commands
)
{
int
len
;
sctp_packet_t
*
pkt
;
sctp_addr_param_t
*
addrparm
;
sctp_errhdr_t
*
errhdr
;
sctp_endpoint_t
*
ep
;
char
buffer
[
sizeof
(
sctp_errhdr_t
)
+
sizeof
(
sctp_addr_param_t
)];
/* Build the error on the stack. We are way to malloc
* malloc crazy throughout the code today.
*/
errhdr
=
(
sctp_errhdr_t
*
)
buffer
;
addrparm
=
(
sctp_addr_param_t
*
)
errhdr
->
variable
;
/* Copy into a parm format. */
len
=
sockaddr2sctp_addr
(
ssa
,
addrparm
);
len
+=
sizeof
(
sctp_errhdr_t
);
errhdr
->
cause
=
SCTP_ERROR_RESTART
;
errhdr
->
length
=
htons
(
len
);
/* Assign to the control socket. */
ep
=
sctp_sk
((
sctp_get_ctl_sock
()))
->
ep
;
/* Association is NULL since this may be a restart attack and we
* want to send back the attacker's vtag.
*/
pkt
=
sctp_abort_pkt_new
(
ep
,
NULL
,
init
,
errhdr
,
len
);
if
(
!
pkt
)
goto
out
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
pkt
));
/* Discard the rest of the inbound packet. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
out:
/* Even if there is no memory, treat as a failure so
* the packet will get dropped.
*/
return
0
;
}
/* A restart is occuring, check to make sure no new addresses
* are being added as we may be under a takeover attack.
*/
static
int
sctp_sf_check_restart_addrs
(
const
sctp_association_t
*
new_asoc
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
init
,
sctp_cmd_seq_t
*
commands
)
{
sctp_transport_t
*
new_addr
,
*
addr
;
struct
list_head
*
pos
,
*
pos2
;
int
found
;
/* Implementor's Guide - Sectin 5.2.2
* ...
* Before responding the endpoint MUST check to see if the
* unexpected INIT adds new addresses to the association. If new
* addresses are added to the association, the endpoint MUST respond
* with an ABORT..
*/
/* Search through all current addresses and make sure
* we aren't adding any new ones.
*/
new_addr
=
0
;
found
=
0
;
list_for_each
(
pos
,
&
new_asoc
->
peer
.
transport_addr_list
)
{
new_addr
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
found
=
0
;
list_for_each
(
pos2
,
&
asoc
->
peer
.
transport_addr_list
)
{
addr
=
list_entry
(
pos2
,
sctp_transport_t
,
transports
);
if
(
sctp_cmp_addr_exact
(
&
new_addr
->
ipaddr
,
&
addr
->
ipaddr
))
{
found
=
1
;
break
;
}
}
if
(
!
found
)
break
;
}
/* If a new address was added, ABORT the sender. */
if
(
!
found
&&
new_addr
)
{
sctp_sf_send_restart_abort
(
&
new_addr
->
ipaddr
,
init
,
commands
);
}
/* Return success if all addresses were found. */
return
found
;
}
/* Populate the verification/tie tags based on overlapping INIT
* scenario.
*
...
...
@@ -969,6 +1057,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_disposition_t
retval
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
repl
;
sctp_association_t
*
new_asoc
;
...
...
@@ -1006,15 +1095,14 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
));
sctp_free_chunk
(
err_chunk
);
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
ret
urn
SCTP_DISPOSITION_CONSUME
;
ret
val
=
SCTP_DISPOSITION_CONSUME
;
}
else
{
ret
urn
SCTP_DISPOSITION_NOMEM
;
ret
val
=
SCTP_DISPOSITION_NOMEM
;
}
goto
cleanup
;
}
else
{
return
sctp_sf_tabort_8_4_8
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
...
@@ -1039,6 +1127,19 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
GFP_ATOMIC
);
/* Make sure no new addresses are being added during the
* restart. Do not do this check for COOKIE-WAIT state,
* since there are no peer addresses to check against.
* Upon return an ABORT will have been sent if needed.
*/
if
(
asoc
->
state
!=
SCTP_STATE_COOKIE_WAIT
)
{
if
(
!
sctp_sf_check_restart_addrs
(
new_asoc
,
asoc
,
chunk
,
commands
))
{
retval
=
SCTP_DISPOSITION_CONSUME
;
goto
cleanup_asoc
;
}
}
sctp_tietags_populate
(
new_asoc
,
asoc
);
/* B) "Z" shall respond immediately with an INIT ACK chunk. */
...
...
@@ -1086,13 +1187,18 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* Otherwise, "Z" will be vulnerable to resource attacks.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
ret
urn
SCTP_DISPOSITION_CONSUME
;
ret
val
=
SCTP_DISPOSITION_CONSUME
;
nomem
:
cleanup
:
if
(
err_chunk
)
sctp_free_chunk
(
err_chunk
);
return
SCTP_DISPOSITION_NOMEM
;
return
retval
;
nomem:
retval
=
SCTP_DISPOSITION_NOMEM
;
goto
cleanup
;
cleanup_asoc:
sctp_association_free
(
new_asoc
);
goto
cleanup
;
}
/*
...
...
@@ -1198,6 +1304,8 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep,
return
sctp_sf_do_unexpected_init
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
/* Unexpected COOKIE-ECHO handlerfor peer restart (Table 2, action 'A')
*
* Section 5.2.4
...
...
@@ -1212,9 +1320,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
sctp_init_chunk_t
*
peer_init
;
sctp_ulpevent_t
*
ev
;
sctp_chunk_t
*
repl
;
sctp_transport_t
*
new_addr
,
*
addr
;
struct
list_head
*
pos
,
*
pos2
,
*
temp
;
int
found
,
error
;
/* new_asoc is a brand-new association, so these are not yet
* side effects--it is safe to run them here.
...
...
@@ -1223,56 +1328,13 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
);
/* Make sure peer is not adding new addresses. */
found
=
0
;
new_addr
=
NULL
;
list_for_each
(
pos
,
&
new_asoc
->
peer
.
transport_addr_list
)
{
new_addr
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
found
=
1
;
list_for_each_safe
(
pos2
,
temp
,
&
asoc
->
peer
.
transport_addr_list
)
{
addr
=
list_entry
(
pos2
,
sctp_transport_t
,
transports
);
if
(
!
sctp_cmp_addr_exact
(
&
new_addr
->
ipaddr
,
&
addr
->
ipaddr
))
{
found
=
0
;
break
;
}
}
if
(
!
found
)
break
;
}
if
(
!
found
)
{
sctp_bind_addr_t
*
bp
;
sctpParam_t
rawaddr
;
int
len
;
bp
=
sctp_bind_addr_new
(
GFP_ATOMIC
);
if
(
!
bp
)
goto
nomem
;
error
=
sctp_add_bind_addr
(
bp
,
&
new_addr
->
ipaddr
,
GFP_ATOMIC
);
if
(
error
)
goto
nomem_add
;
rawaddr
=
sctp_bind_addrs_to_raw
(
bp
,
&
len
,
GFP_ATOMIC
);
if
(
!
rawaddr
.
v
)
goto
nomem_raw
;
repl
=
sctp_make_abort
(
asoc
,
chunk
,
len
+
sizeof
(
sctp_errhdr_t
));
if
(
!
repl
)
goto
nomem_abort
;
sctp_init_cause
(
repl
,
SCTP_ERROR_RESTART
,
rawaddr
.
v
,
len
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
/* Make sure no new addresses are being added during the
* restart. Though this is a pretty complicated attack
* since you'd have to get inside the cookie.
*/
if
(
!
sctp_sf_check_restart_addrs
(
new_asoc
,
asoc
,
chunk
,
commands
))
{
printk
(
"cookie echo check
\n
"
);
return
SCTP_DISPOSITION_CONSUME
;
nomem_abort:
kfree
(
rawaddr
.
v
);
nomem_raw:
nomem_add:
sctp_bind_addr_free
(
bp
);
goto
nomem
;
}
/* For now, fail any unsent/unacked data. Consider the optional
...
...
@@ -1302,7 +1364,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
nomem_ev:
sctp_free_chunk
(
repl
);
nomem:
return
SCTP_DISPOSITION_NOMEM
;
}
...
...
@@ -1564,6 +1625,10 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
...
...
@@ -1583,6 +1648,10 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
/* Stop the T2-shutdown timer. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
...
...
@@ -1754,6 +1823,11 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
/* ASSOC_FAILED will DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
...
...
@@ -1772,8 +1846,10 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
/* Check the verification tag. */
/* BUG: WRITE ME. */
sctp_chunk_t
*
chunk
=
arg
;
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
...
...
@@ -2699,13 +2775,6 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
* the Verification Tag received in the SHUTDOWN ACK and set the
* T-bit in the Chunk Flags to indicate that no TCB was found.
*
* Verification Tag: 8.5.1 E) Rules for packet carrying a SHUTDOWN ACK
* If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state the
* procedures in section 8.4 SHOULD be followed, in other words it
* should be treated as an Out Of The Blue packet.
* [This means that we do NOT check the Verification Tag on these
* chunks. --piggy ]
*
* Inputs
* (endpoint, asoc, type, arg, commands)
*
...
...
@@ -2750,6 +2819,31 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_NOMEM
;
}
/*
* Handle SHUTDOWN ACK in COOKIE_ECHOED or COOKIE_WAIT state.
*
* Verification Tag: 8.5.1 E) Rules for packet carrying a SHUTDOWN ACK
* If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state the
* procedures in section 8.4 SHOULD be followed, in other words it
* should be treated as an Out Of The Blue packet.
* [This means that we do NOT check the Verification Tag on these
* chunks. --piggy ]
*
*/
sctp_disposition_t
sctp_sf_do_8_5_1_E_sa
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
/* Although we do have an association in this case, it corresponds
* to a restarted association. So the packet is treated as an OOTB
* packet and the state function that handles OOTB SHUTDOWN_ACK is
* called with a NULL association.
*/
return
sctp_sf_shut_8_4_5
(
ep
,
NULL
,
type
,
arg
,
commands
);
}
/*
* Process an unknown chunk.
*
...
...
@@ -2881,8 +2975,7 @@ sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep,
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t
sctp_sf_pdiscard
(
const
sctp_endpoint_t
*
ep
,
sctp_disposition_t
sctp_sf_pdiscard
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
...
...
@@ -4143,9 +4236,16 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
*/
if
(
asoc
)
{
vtag
=
asoc
->
peer
.
i
.
init_tag
;
}
else
{
/* Special case the INIT as there is no vtag yet. */
if
(
SCTP_CID_INIT
==
chunk
->
chunk_hdr
->
type
)
{
sctp_init_chunk_t
*
init
;
init
=
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
;
vtag
=
ntohl
(
init
->
init_hdr
.
init_tag
);
}
else
{
vtag
=
ntohl
(
chunk
->
sctp_hdr
->
vtag
);
}
}
/* Make a transport for the bucket, Eliza... */
transport
=
sctp_transport_new
(
sctp_source
(
chunk
),
GFP_ATOMIC
);
...
...
net/sctp/sm_statetable.c
View file @
b18b05fb
...
...
@@ -271,9 +271,9 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_
ootb, .name = "sctp_sf_ootb
"}, \
{.fn = sctp_sf_
do_8_5_1_E_sa, .name = "sctp_sf_do_8_5_1_E_sa
"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_d
iscard_chunk, .name = "sctp_sf_discard_chunk
"}, \
{.fn = sctp_sf_d
o_8_5_1_E_sa, .name = "sctp_sf_do_8_5_1_E_sa
"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_violation, .name = "sctp_sf_violation"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
...
...
net/sctp/socket.c
View file @
b18b05fb
...
...
@@ -726,9 +726,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
* flags - flags sent or received with the user message, see Section
* 5 for complete description of the flags.
*
* NB: The argument 'msg' is a user space address.
* Note: This function could use a rewrite especially when explicit
* connect support comes in.
*/
/* BUG: We do not implement timeouts. */
/* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */
SCTP_STATIC
int
sctp_msghdr_parse
(
const
struct
msghdr
*
,
sctp_cmsgs_t
*
);
...
...
@@ -738,7 +738,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
{
sctp_opt_t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
=
NULL
;
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
sctp_transport_t
*
transport
;
sctp_chunk_t
*
chunk
=
NULL
;
sockaddr_storage_t
to
;
...
...
@@ -821,7 +821,32 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* If a msg_name has been specified, assume this is to be used. */
if
(
msg_name
)
{
/* Look for a matching association on the endpoint. */
asoc
=
sctp_endpoint_lookup_assoc
(
ep
,
&
to
,
&
transport
);
if
(
!
asoc
)
{
struct
list_head
*
pos
;
struct
sockaddr_storage_list
*
addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_read_lock
(
&
ep
->
base
.
addr_lock
);
/* If we could not find a matching association on
* the endpoint, make sure that there is no peeled-
* off association.
*/
list_for_each
(
pos
,
&
bp
->
address_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
(
sctp_has_association
(
&
addr
->
a
,
&
to
))
{
err
=
-
EINVAL
;
sctp_read_unlock
(
&
ep
->
base
.
addr_lock
);
goto
out_unlock
;
}
}
sctp_read_unlock
(
&
ep
->
base
.
addr_lock
);
}
}
else
{
/* For a peeled-off socket, ignore any associd specified by
* the user with SNDRCVINFO.
...
...
@@ -907,11 +932,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
scope
=
sctp_scope
(
&
to
);
asoc
=
sctp_association_new
(
ep
,
sk
,
scope
,
GFP_KERNEL
);
if
(
!
asoc
)
{
new_
asoc
=
sctp_association_new
(
ep
,
sk
,
scope
,
GFP_KERNEL
);
if
(
!
new_
asoc
)
{
err
=
-
ENOMEM
;
goto
out_unlock
;
}
asoc
=
new_asoc
;
/* If the SCTP_INIT ancillary data is specified, set all
* the association init values accordingly.
...
...
@@ -946,7 +972,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
/* ASSERT: we have a valid association at this point. */
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
/* API 7.1.7, the sndbuf size per association bounds the
* maximum size of data that can be sent in a single send call.
...
...
@@ -1054,10 +1080,16 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
err
=
msg_len
;
goto
out_unlock
;
}
/* If we are already past ASSOCIATE, the lower
* layers are responsible for its cleanup.
*/
goto
out_free_chunk
;
out_free:
if
(
SCTP_STATE_CLOSED
==
asoc
->
state
)
if
(
new_asoc
)
sctp_association_free
(
asoc
);
out_free_chunk:
if
(
chunk
)
sctp_free_chunk
(
chunk
);
...
...
@@ -1577,6 +1609,8 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
sctp_endpoint_t
*
newep
;
sctp_opt_t
*
oldsp
=
sctp_sk
(
oldsk
);
sctp_opt_t
*
newsp
;
struct
sk_buff
*
skb
,
*
tmp
;
sctp_ulpevent_t
*
event
;
int
err
=
0
;
/* An association cannot be branched off from an already peeled-off
...
...
@@ -1606,6 +1640,17 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
*/
newsp
->
ep
=
newep
;
/* Move any messages in the old socket's receive queue that are for the
* peeled off association to the new socket's receive queue.
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
/* Set the type of socket to indicate that it is peeled off from the
* original socket.
*/
...
...
@@ -1623,39 +1668,46 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
{
sctp_peeloff_arg_t
peeloff
;
struct
socket
*
newsock
;
int
err
,
sd
;
int
retval
=
0
;
sctp_association_t
*
assoc
;
if
(
len
!=
sizeof
(
sctp_peeloff_arg_t
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
peeloff
,
optval
,
len
))
return
-
EFAULT
;
sctp_lock_sock
(
sk
);
assoc
=
sctp_id2assoc
(
sk
,
peeloff
.
associd
);
if
(
NULL
==
assoc
)
return
-
EINVAL
;
if
(
NULL
==
assoc
)
{
retval
=
-
EINVAL
;
goto
out_unlock
;
}
SCTP_DEBUG_PRINTK
(
"%s: sk: %p assoc: %p
\n
"
,
__FUNCTION__
,
sk
,
assoc
);
err
=
sctp_do_peeloff
(
assoc
,
&
newsock
);
if
(
err
<
0
)
return
err
;
retval
=
sctp_do_peeloff
(
assoc
,
&
newsock
);
if
(
retval
<
0
)
goto
out_unlock
;
/* Map the socket to an unused fd that can be returned to the user. */
sd
=
sock_map_fd
(
newsock
);
if
(
sd
<
0
)
{
retval
=
sock_map_fd
(
newsock
);
if
(
retval
<
0
)
{
sock_release
(
newsock
);
return
sd
;
goto
out_unlock
;
}
SCTP_DEBUG_PRINTK
(
"%s: sk: %p assoc: %p newsk: %p sd: %d
\n
"
,
__FUNCTION__
,
sk
,
assoc
,
newsock
->
sk
,
sd
);
__FUNCTION__
,
sk
,
assoc
,
newsock
->
sk
,
retval
);
/* Return the fd mapped to the new socket. */
peeloff
.
sd
=
sd
;
peeloff
.
sd
=
retval
;
if
(
copy_to_user
(
optval
,
&
peeloff
,
len
))
ret
urn
-
EFAULT
;
ret
val
=
-
EFAULT
;
return
0
;
out_unlock:
sctp_release_sock
(
sk
);
return
retval
;
}
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
...
...
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