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
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
Expand all
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
This diff is collapsed.
Click to expand it.
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