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
a0065b2f
Commit
a0065b2f
authored
Feb 09, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Plain Diff
Merge us.ibm.com:/home/sridhar/BK/linux-2.5.60
into us.ibm.com:/home/sridhar/BK/lksctp-2.5.60
parents
f2478c00
9d6d6cb3
Changes
31
Show whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
2039 additions
and
1473 deletions
+2039
-1473
include/net/sctp/command.h
include/net/sctp/command.h
+17
-17
include/net/sctp/constants.h
include/net/sctp/constants.h
+38
-58
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+29
-4
include/net/sctp/sm.h
include/net/sctp/sm.h
+6
-1
include/net/sctp/structs.h
include/net/sctp/structs.h
+163
-107
include/net/sctp/ulpqueue.h
include/net/sctp/ulpqueue.h
+34
-49
include/net/sctp/user.h
include/net/sctp/user.h
+17
-0
net/sctp/Kconfig
net/sctp/Kconfig
+1
-1
net/sctp/Makefile
net/sctp/Makefile
+1
-1
net/sctp/adler32.c
net/sctp/adler32.c
+15
-1
net/sctp/associola.c
net/sctp/associola.c
+191
-62
net/sctp/command.c
net/sctp/command.c
+2
-2
net/sctp/crc32c.c
net/sctp/crc32c.c
+22
-6
net/sctp/debug.c
net/sctp/debug.c
+0
-14
net/sctp/endpointola.c
net/sctp/endpointola.c
+6
-8
net/sctp/input.c
net/sctp/input.c
+148
-15
net/sctp/ipv6.c
net/sctp/ipv6.c
+106
-34
net/sctp/objcnt.c
net/sctp/objcnt.c
+2
-0
net/sctp/output.c
net/sctp/output.c
+23
-19
net/sctp/outqueue.c
net/sctp/outqueue.c
+137
-95
net/sctp/primitive.c
net/sctp/primitive.c
+0
-20
net/sctp/protocol.c
net/sctp/protocol.c
+127
-44
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+269
-122
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+67
-81
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+70
-79
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+12
-318
net/sctp/socket.c
net/sctp/socket.c
+262
-87
net/sctp/ssnmap.c
net/sctp/ssnmap.c
+113
-0
net/sctp/transport.c
net/sctp/transport.c
+72
-93
net/sctp/ulpevent.c
net/sctp/ulpevent.c
+14
-58
net/sctp/ulpqueue.c
net/sctp/ulpqueue.c
+75
-77
No files found.
include/net/sctp/command.h
View file @
a0065b2f
...
...
@@ -69,11 +69,11 @@ typedef enum {
SCTP_CMD_INIT_FAILED
,
/* High level, do init failure work. */
SCTP_CMD_REPORT_DUP
,
/* Report a duplicate TSN. */
SCTP_CMD_REPORT_BIGGAP
,
/* Narc on a TSN (it was too high). */
SCTP_CMD_SET_BIND_ADDR
,
/* Set the association bind_addr. */
SCTP_CMD_STRIKE
,
/* Mark a strike against a transport. */
SCTP_CMD_TRANSMIT
,
/* Transmit the outqueue. */
SCTP_CMD_HB_TIMERS_START
,
/* Start the heartbeat timers. */
SCTP_CMD_HB_TIMERS_UPDATE
,
/* Update the heartbeat timers. */
SCTP_CMD_HB_TIMER_UPDATE
,
/* Update a heartbeat timers. */
SCTP_CMD_HB_TIMERS_STOP
,
/* Stop the heartbeat timers. */
SCTP_CMD_TRANSPORT_RESET
,
/* Reset the status of a transport. */
SCTP_CMD_TRANSPORT_ON
,
/* Mark the transport as active. */
SCTP_CMD_REPORT_ERROR
,
/* Pass this error back out of the sm. */
...
...
@@ -112,7 +112,7 @@ typedef union {
void
*
ptr
;
sctp_chunk_t
*
chunk
;
sctp_association_t
*
asoc
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_bind_addr_t
*
bp
;
sctp_init_chunk_t
*
init
;
sctp_ulpevent_t
*
ulpevent
;
...
...
@@ -160,7 +160,7 @@ SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to)
SCTP_ARG_CONSTRUCTOR
(
PTR
,
void
*
,
ptr
)
SCTP_ARG_CONSTRUCTOR
(
CHUNK
,
sctp_chunk_t
*
,
chunk
)
SCTP_ARG_CONSTRUCTOR
(
ASOC
,
sctp_association_t
*
,
asoc
)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
s
ctp_transport_
t
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
s
truct
sctp_transpor
t
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
BA
,
sctp_bind_addr_t
*
,
bp
)
SCTP_ARG_CONSTRUCTOR
(
PEER_INIT
,
sctp_init_chunk_t
*
,
init
)
SCTP_ARG_CONSTRUCTOR
(
ULPEVENT
,
sctp_ulpevent_t
*
,
ulpevent
)
...
...
include/net/sctp/constants.h
View file @
a0065b2f
...
...
@@ -56,17 +56,10 @@
#include <linux/ipv6.h>
/* For ipv6hdr. */
#include <net/sctp/user.h>
/* What a hack! Jiminy Cricket! */
enum
{
SCTP_MAX_STREAM
=
10
};
/* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating
* for ipv6 headers, but this seems worth the simplicity.
*/
#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\
+ sizeof(struct ipv6hdr)\
+ MAX_HEADER))
/* Value used for stream negotiation. */
enum
{
SCTP_MAX_STREAM
=
0xffff
};
enum
{
SCTP_DEFAULT_OUTSTREAMS
=
10
};
enum
{
SCTP_DEFAULT_INSTREAMS
=
SCTP_MAX_STREAM
};
/* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating
...
...
@@ -105,57 +98,37 @@ typedef enum {
*/
typedef
enum
{
SCTP_EVENT_TIMEOUT_NONE
=
0
,
SCTP_EVENT_TIMEOUT_T1_COOKIE
,
SCTP_EVENT_TIMEOUT_T1_INIT
,
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
,
SCTP_EVENT_TIMEOUT_T3_RTX
,
SCTP_EVENT_TIMEOUT_T4_RTO
,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD
,
SCTP_EVENT_TIMEOUT_HEARTBEAT
,
SCTP_EVENT_TIMEOUT_SACK
,
SCTP_EVENT_TIMEOUT_AUTOCLOSE
,
SCTP_EVENT_TIMEOUT_PMTU_RAISE
,
}
sctp_event_timeout_t
;
#define SCTP_EVENT_TIMEOUT_MAX SCTP_EVENT_TIMEOUT_
PMTU_RAI
SE
#define SCTP_EVENT_TIMEOUT_MAX SCTP_EVENT_TIMEOUT_
AUTOCLO
SE
#define SCTP_NUM_TIMEOUT_TYPES (SCTP_EVENT_TIMEOUT_MAX + 1)
typedef
enum
{
SCTP_EVENT_NO_PENDING_TSN
=
0
,
SCTP_EVENT_ICMP_UNREACHFRAG
,
}
sctp_event_other_t
;
#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_
ICMP_UNREACHFRAG
#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_
NO_PENDING_TSN
#define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1)
/* These are primitive requests from the ULP. */
typedef
enum
{
SCTP_PRIMITIVE_INITIALIZE
=
0
,
SCTP_PRIMITIVE_ASSOCIATE
,
SCTP_PRIMITIVE_ASSOCIATE
=
0
,
SCTP_PRIMITIVE_SHUTDOWN
,
SCTP_PRIMITIVE_ABORT
,
SCTP_PRIMITIVE_SEND
,
SCTP_PRIMITIVE_SETPRIMARY
,
SCTP_PRIMITIVE_RECEIVE
,
SCTP_PRIMITIVE_STATUS
,
SCTP_PRIMITIVE_CHANGEHEARTBEAT
,
SCTP_PRIMITIVE_REQUESTHEARTBEAT
,
SCTP_PRIMITIVE_GETSRTTREPORT
,
SCTP_PRIMITIVE_SETFAILURETHRESHOLD
,
SCTP_PRIMITIVE_SETPROTOPARAMETERS
,
SCTP_PRIMITIVE_RECEIVE_UNSENT
,
SCTP_PRIMITIVE_RECEIVE_UNACKED
,
SCTP_PRIMITIVE_DESTROY
,
}
sctp_event_primitive_t
;
#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_
DESTROY
#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_
REQUESTHEARTBEAT
#define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1)
/* We define here a utility type for manipulating subtypes.
...
...
@@ -268,8 +241,13 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[];
#define SCTP_ADDR_REACHABLE 2
#define SCTP_ADDR_NOT_REACHABLE 1
/* Maximum chunk length considering padding requirements. */
enum
{
SCTP_MAX_CHUNK_LEN
=
((
1
<<
16
)
-
sizeof
(
__u32
))
};
/* Encourage Cookie-Echo bundling by pre-fragmenting chunks a little
* harder (until reaching ESTABLISHED state).
*/
enum
{
SCTP_ARBITRARY_COOKIE_ECHO_LEN
=
200
};
/* Guess at how big to make the TSN mapping array.
* We guarantee that we can handle at least this big a gap between the
...
...
@@ -289,7 +267,8 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[];
* is enough room for 131 duplicate reports. Round down to the
* nearest power of 2.
*/
#define SCTP_MAX_DUP_TSNS 128
enum
{
SCTP_MIN_PMTU
=
576
};
enum
{
SCTP_MAX_DUP_TSNS
=
128
};
typedef
enum
{
SCTP_COUNTER_INIT_ERROR
,
...
...
@@ -298,7 +277,6 @@ typedef enum {
/* How many counters does an association need? */
#define SCTP_NUMBER_COUNTERS 5
/* Here we define the default timers. */
/* cookie timer def = ? seconds */
...
...
@@ -317,10 +295,6 @@ typedef enum {
#define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000)
#define SCTP_DEFAULT_TIMEOUT_SACK_MAX ((500 * HZ) / 1000)
/* 500 ms */
/* How long do we wait before attempting to raise the PMTU? */
#define SCTP_DEFAULT_TIMEOUT_PMTU_RAISE (10 * 60 * HZ)
/* 10 Minutes */
#define SCTP_DEFAULT_TIMEOUT_PMTU_RAISE_MIN (10 * 60 * HZ)
/* 10 Minutes */
/* RTO.Initial - 3 seconds
* RTO.Min - 1 second
* RTO.Max - 60 seconds
...
...
@@ -439,6 +413,13 @@ typedef enum {
#define SCTP_ADDR6_PEERSUPP 0x00000004
/* IPv6 address is supported by
peer */
/* Reasons to retransmit. */
typedef
enum
{
SCTP_RETRANSMIT_T3_RTX
,
SCTP_RETRANSMIT_FAST_RTX
,
SCTP_RETRANSMIT_PMTU_DISCOVERY
,
}
sctp_retransmit_reason_t
;
/* Reasons to lower cwnd. */
typedef
enum
{
SCTP_LOWER_CWND_T3_RTX
,
...
...
@@ -448,4 +429,3 @@ typedef enum {
}
sctp_lower_cwnd_t
;
#endif
/* __sctp_constants_h__ */
include/net/sctp/sctp.h
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-200
2
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-200
3
International Business Machines, Corp.
* Copyright (c) 2001
-2003
Intel Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -37,6 +37,8 @@
* Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -147,7 +149,9 @@ extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
/*
* sctp_crc32c.c
*/
extern
__u32
count_crc
(
__u8
*
ptr
,
__u16
count
);
extern
__u32
sctp_start_cksum
(
__u8
*
ptr
,
__u16
count
);
extern
__u32
sctp_update_cksum
(
__u8
*
ptr
,
__u16
count
,
__u32
cksum
);
extern
__u32
sctp_end_cksum
(
__u32
cksum
);
/*
* sctp_input.c
...
...
@@ -162,6 +166,9 @@ extern void sctp_hash_endpoint(sctp_endpoint_t *);
extern
void
__sctp_hash_endpoint
(
sctp_endpoint_t
*
);
extern
void
sctp_unhash_endpoint
(
sctp_endpoint_t
*
);
extern
void
__sctp_unhash_endpoint
(
sctp_endpoint_t
*
);
extern
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
struct
sctp_transport
**
);
/*
* sctp_hashdriver.c
...
...
@@ -266,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_transport;
extern
atomic_t
sctp_dbg_objcnt_chunk
;
extern
atomic_t
sctp_dbg_objcnt_bind_addr
;
extern
atomic_t
sctp_dbg_objcnt_addr
;
extern
atomic_t
sctp_dbg_objcnt_ssnmap
;
/* Macros to atomically increment/decrement objcnt counters. */
#define SCTP_DBG_OBJCNT_INC(name) \
...
...
@@ -418,6 +426,23 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
return
retval
;
}
/* Generate a random jitter in the range of -50% ~ +50% of input RTO. */
static
inline
__s32
sctp_jitter
(
__u32
rto
)
{
static
__u32
sctp_rand
;
__s32
ret
;
sctp_rand
+=
jiffies
;
sctp_rand
^=
(
sctp_rand
<<
12
);
sctp_rand
^=
(
sctp_rand
>>
20
);
/* Choose random number from 0 to rto, then move to -50% ~ +50%
* of rto.
*/
ret
=
sctp_rand
%
rto
-
(
rto
>>
1
);
return
ret
;
}
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
...
...
include/net/sctp/sm.h
View file @
a0065b2f
...
...
@@ -256,7 +256,7 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *,
const
sctp_chunk_t
*
,
const
struct
msghdr
*
);
sctp_chunk_t
*
sctp_make_heartbeat
(
const
sctp_association_t
*
,
const
s
ctp_transport_
t
*
,
const
s
truct
sctp_transpor
t
*
,
const
void
*
payload
,
const
size_t
paylen
);
sctp_chunk_t
*
sctp_make_heartbeat_ack
(
const
sctp_association_t
*
,
...
...
@@ -269,6 +269,11 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *,
const
void
*
payload
,
size_t
paylen
);
void
sctp_chunk_assign_tsn
(
sctp_chunk_t
*
);
void
sctp_chunk_assign_ssn
(
sctp_chunk_t
*
);
int
sctp_datachunks_from_user
(
sctp_association_t
*
,
const
struct
sctp_sndrcvinfo
*
,
struct
msghdr
*
,
int
len
,
struct
sk_buff_head
*
);
/* Prototypes for statetable processing. */
...
...
include/net/sctp/structs.h
View file @
a0065b2f
...
...
@@ -104,27 +104,26 @@ union sctp_addr {
/* Forward declarations for data structures. */
struct
SCTP
_protocol
;
struct
sctp
_protocol
;
struct
SCTP_endpoint
;
struct
SCTP_association
;
struct
SCTP
_transport
;
struct
sctp
_transport
;
struct
SCTP_packet
;
struct
SCTP_chunk
;
struct
SCTP_inqueue
;
struct
SCTP_outqueue
;
struct
sctp_outq
;
struct
SCTP_bind_addr
;
struct
sctp_ulpq
;
struct
sctp_opt
;
struct
sctp_endpoint_common
;
struct
sctp_ssnmap
;
typedef
struct
SCTP_protocol
sctp_protocol_t
;
typedef
struct
sctp_protocol
sctp_protocol_t
;
typedef
struct
SCTP_endpoint
sctp_endpoint_t
;
typedef
struct
SCTP_association
sctp_association_t
;
typedef
struct
SCTP_transport
sctp_transport_t
;
typedef
struct
SCTP_packet
sctp_packet_t
;
typedef
struct
SCTP_chunk
sctp_chunk_t
;
typedef
struct
SCTP_inqueue
sctp_inqueue_t
;
typedef
struct
SCTP_outqueue
sctp_outqueue_t
;
typedef
struct
SCTP_bind_addr
sctp_bind_addr_t
;
typedef
struct
sctp_opt
sctp_opt_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
...
...
@@ -133,7 +132,6 @@ typedef struct sctp_endpoint_common sctp_endpoint_common_t;
#include <net/sctp/ulpevent.h>
#include <net/sctp/ulpqueue.h>
/* Structures useful for managing bind/connect. */
typedef
struct
sctp_bind_bucket
{
...
...
@@ -157,7 +155,7 @@ typedef struct sctp_hashbucket {
/* The SCTP protocol structure. */
struct
SCTP
_protocol
{
struct
sctp
_protocol
{
/* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
*
* The following protocol parameters are RECOMMENDED:
...
...
@@ -239,7 +237,9 @@ struct SCTP_protocol {
* (i.e. things that depend on the address family.)
*/
struct
sctp_af
{
int
(
*
queue_xmit
)
(
struct
sk_buff
*
skb
);
int
(
*
sctp_xmit
)
(
struct
sk_buff
*
skb
,
struct
sctp_transport
*
,
int
ipfragok
);
int
(
*
setsockopt
)
(
struct
sock
*
sk
,
int
level
,
int
optname
,
...
...
@@ -250,12 +250,18 @@ struct sctp_af {
int
optname
,
char
*
optval
,
int
*
optlen
);
struct
dst_entry
*
(
*
get_dst
)
(
union
sctp_addr
*
daddr
,
struct
dst_entry
*
(
*
get_dst
)
(
sctp_association_t
*
asoc
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
void
(
*
get_saddr
)
(
sctp_association_t
*
asoc
,
struct
dst_entry
*
dst
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
void
(
*
copy_addrlist
)
(
struct
list_head
*
,
struct
net_device
*
);
void
(
*
dst_saddr
)
(
union
sctp_addr
*
saddr
,
struct
dst_entry
*
dst
);
struct
dst_entry
*
dst
,
unsigned
short
port
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
);
void
(
*
addr_copy
)
(
union
sctp_addr
*
dst
,
...
...
@@ -282,7 +288,7 @@ struct sctp_af *sctp_get_af_specific(sa_family_t);
int
sctp_register_af
(
struct
sctp_af
*
);
/* Protocol family functions. */
typedef
struct
sctp_pf
{
struct
sctp_pf
{
void
(
*
event_msgname
)(
sctp_ulpevent_t
*
,
char
*
,
int
*
);
void
(
*
skb_msgname
)
(
struct
sk_buff
*
,
char
*
,
int
*
);
int
(
*
af_supported
)
(
sa_family_t
);
...
...
@@ -291,7 +297,7 @@ typedef struct sctp_pf {
struct
sctp_opt
*
);
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
struct
sctp_af
*
af
;
}
sctp_pf_t
;
};
/* SCTP Socket type: UDP or TCP style. */
typedef
enum
{
...
...
@@ -318,7 +324,7 @@ struct sctp_opt {
__u32
autoclose
;
__u8
nodelay
;
__u8
disable_fragments
;
s
ctp_pf_t
*
pf
;
s
truct
sctp_pf
*
pf
;
};
...
...
@@ -360,7 +366,8 @@ typedef struct sctp_cookie {
struct
timeval
expiration
;
/* Number of inbound/outbound streams which are set
* and negotiated during the INIT process. */
* and negotiated during the INIT process.
*/
__u16
sinit_num_ostreams
;
__u16
sinit_max_instreams
;
...
...
@@ -426,6 +433,49 @@ typedef struct sctp_sender_hb_info {
unsigned
long
sent_at
;
}
sctp_sender_hb_info_t
__attribute__
((
packed
));
/*
* RFC 2960 1.3.2 Sequenced Delivery within Streams
*
* The term "stream" is used in SCTP to refer to a sequence of user
* messages that are to be delivered to the upper-layer protocol in
* order with respect to other messages within the same stream. This is
* in contrast to its usage in TCP, where it refers to a sequence of
* bytes (in this document a byte is assumed to be eight bits).
* ...
*
* This is the structure we use to track both our outbound and inbound
* SSN, or Stream Sequence Numbers.
*/
struct
sctp_stream
{
__u16
*
ssn
;
unsigned
int
len
;
};
struct
sctp_ssnmap
{
struct
sctp_stream
in
;
struct
sctp_stream
out
;
int
malloced
;
};
struct
sctp_ssnmap
*
sctp_ssnmap_init
(
struct
sctp_ssnmap
*
,
__u16
,
__u16
);
struct
sctp_ssnmap
*
sctp_ssnmap_new
(
__u16
in
,
__u16
out
,
int
priority
);
void
sctp_ssnmap_free
(
struct
sctp_ssnmap
*
map
);
void
sctp_ssnmap_clear
(
struct
sctp_ssnmap
*
map
);
/* What is the current SSN number for this stream? */
static
inline
__u16
sctp_ssn_peek
(
struct
sctp_stream
*
stream
,
__u16
id
)
{
return
stream
->
ssn
[
id
];
}
/* Return the next SSN number for this stream. */
static
inline
__u16
sctp_ssn_next
(
struct
sctp_stream
*
stream
,
__u16
id
)
{
return
stream
->
ssn
[
id
]
++
;
}
/* RFC2960 1.4 Key Terms
*
* o Chunk: A unit of information within an SCTP packet, consisting of
...
...
@@ -499,6 +549,7 @@ struct SCTP_chunk {
__u8
rtt_in_progress
;
/* Is this chunk used for RTT calculation? */
__u8
num_times_sent
;
/* How man times did we send this? */
__u8
has_tsn
;
/* Does this chunk have a TSN yet? */
__u8
has_ssn
;
/* Does this chunk have a SSN yet? */
__u8
singleton
;
/* Was this the only chunk in the packet? */
__u8
end_of_packet
;
/* Was this the last chunk in the packet? */
__u8
ecn_ce_done
;
/* Have we processed the ECN CE bit? */
...
...
@@ -516,15 +567,13 @@ struct SCTP_chunk {
* For an outbound chunk, it tells us where we'd like it to
* go. It is NULL if we have no preference.
*/
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
};
sctp_chunk_t
*
sctp_make_chunk
(
const
sctp_association_t
*
,
__u8
type
,
__u8
flags
,
int
size
);
void
sctp_free_chunk
(
sctp_chunk_t
*
);
sctp_chunk_t
*
sctp_copy_chunk
(
sctp_chunk_t
*
,
int
flags
);
void
*
sctp_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
const
void
*
data
);
int
sctp_user_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
struct
iovec
*
data
);
sctp_chunk_t
*
sctp_chunkify
(
struct
sk_buff
*
,
const
sctp_association_t
*
,
struct
sock
*
);
void
sctp_init_addrs
(
sctp_chunk_t
*
,
union
sctp_addr
*
,
union
sctp_addr
*
);
...
...
@@ -560,7 +609,7 @@ struct SCTP_packet {
* The function we finally use to pass down to the next lower
* layer lives in the transport structure.
*/
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
/* Allow a callback for getting a high priority chunk
* bundled early into the packet (This is used for ECNE).
...
...
@@ -575,30 +624,33 @@ struct SCTP_packet {
/* This packet contains a COOKIE-ECHO chunk. */
int
has_cookie_echo
;
/* SCTP cannot fragment this packet. So let ip fragment it. */
int
ipfragok
;
int
malloced
;
};
typedef
int
(
sctp_outq
ueue_thandler_t
)(
sctp_outqueue_t
*
,
void
*
);
typedef
int
(
sctp_outq
ueue_ehandler_t
)(
sctp_outqueue_t
*
);
typedef
sctp_packet_t
*
(
sctp_outq
ueue
_ohandler_init_t
)
typedef
int
(
sctp_outq
_thandler_t
)(
struct
sctp_outq
*
,
void
*
);
typedef
int
(
sctp_outq
_ehandler_t
)(
struct
sctp_outq
*
);
typedef
sctp_packet_t
*
(
sctp_outq_ohandler_init_t
)
(
sctp_packet_t
*
,
s
ctp_transport_
t
*
,
s
truct
sctp_transpor
t
*
,
__u16
sport
,
__u16
dport
);
typedef
sctp_packet_t
*
(
sctp_outq
ueue
_ohandler_config_t
)
typedef
sctp_packet_t
*
(
sctp_outq_ohandler_config_t
)
(
sctp_packet_t
*
,
__u32
vtag
,
int
ecn_capable
,
sctp_packet_phandler_t
*
get_prepend_chunk
);
typedef
sctp_xmit_t
(
sctp_outq
ueue
_ohandler_t
)(
sctp_packet_t
*
,
typedef
sctp_xmit_t
(
sctp_outq_ohandler_t
)(
sctp_packet_t
*
,
sctp_chunk_t
*
);
typedef
int
(
sctp_outq
ueue
_ohandler_force_t
)(
sctp_packet_t
*
);
typedef
int
(
sctp_outq_ohandler_force_t
)(
sctp_packet_t
*
);
sctp_outq
ueue
_ohandler_init_t
sctp_packet_init
;
sctp_outq
ueue
_ohandler_config_t
sctp_packet_config
;
sctp_outq
ueue
_ohandler_t
sctp_packet_append_chunk
;
sctp_outq
ueue
_ohandler_t
sctp_packet_transmit_chunk
;
sctp_outq
ueue
_ohandler_force_t
sctp_packet_transmit
;
sctp_outq_ohandler_init_t
sctp_packet_init
;
sctp_outq_ohandler_config_t
sctp_packet_config
;
sctp_outq_ohandler_t
sctp_packet_append_chunk
;
sctp_outq_ohandler_t
sctp_packet_transmit_chunk
;
sctp_outq_ohandler_force_t
sctp_packet_transmit
;
void
sctp_packet_free
(
sctp_packet_t
*
);
...
...
@@ -622,7 +674,7 @@ void sctp_packet_free(sctp_packet_t *);
* period.
*
*/
struct
SCTP
_transport
{
struct
sctp
_transport
{
/* A list of transports. */
struct
list_head
transports
;
...
...
@@ -692,6 +744,8 @@ struct SCTP_transport {
/* Destination */
struct
dst_entry
*
dst
;
/* Source address. */
union
sctp_addr
saddr
;
/* When was the last time(in jiffies) that a data packet was sent on
* this transport? This is used to adjust the cwnd when the transport
...
...
@@ -771,24 +825,26 @@ struct SCTP_transport {
int
malloced
;
/* Is this structure kfree()able? */
};
extern
sctp_transport_
t
*
sctp_transport_new
(
const
union
sctp_addr
*
,
int
);
extern
sctp_transport_t
*
sctp_transport_init
(
sctp_transport_
t
*
,
struct
sctp_transpor
t
*
sctp_transport_new
(
const
union
sctp_addr
*
,
int
);
struct
sctp_transport
*
sctp_transport_init
(
struct
sctp_transpor
t
*
,
const
union
sctp_addr
*
,
int
);
extern
void
sctp_transport_set_owner
(
sctp_transport_
t
*
,
sctp_association_t
*
);
extern
void
sctp_transport_route
(
sctp_transport_
t
*
,
union
sctp_addr
*
,
void
sctp_transport_set_owner
(
struct
sctp_transpor
t
*
,
sctp_association_t
*
);
void
sctp_transport_route
(
struct
sctp_transpor
t
*
,
union
sctp_addr
*
,
struct
sctp_opt
*
);
extern
void
sctp_transport_free
(
sctp_transport_t
*
);
extern
void
sctp_transport_destroy
(
sctp_transport_t
*
);
extern
void
sctp_transport_reset_timers
(
sctp_transport_t
*
);
extern
void
sctp_transport_hold
(
sctp_transport_t
*
);
extern
void
sctp_transport_put
(
sctp_transport_t
*
);
extern
void
sctp_transport_update_rto
(
sctp_transport_t
*
,
__u32
);
extern
void
sctp_transport_raise_cwnd
(
sctp_transport_t
*
,
__u32
,
__u32
);
extern
void
sctp_transport_lower_cwnd
(
sctp_transport_t
*
,
sctp_lower_cwnd_t
);
void
sctp_transport_pmtu
(
struct
sctp_transport
*
);
void
sctp_transport_free
(
struct
sctp_transport
*
);
void
sctp_transport_destroy
(
struct
sctp_transport
*
);
void
sctp_transport_reset_timers
(
struct
sctp_transport
*
);
void
sctp_transport_hold
(
struct
sctp_transport
*
);
void
sctp_transport_put
(
struct
sctp_transport
*
);
void
sctp_transport_update_rto
(
struct
sctp_transport
*
,
__u32
);
void
sctp_transport_raise_cwnd
(
struct
sctp_transport
*
,
__u32
,
__u32
);
void
sctp_transport_lower_cwnd
(
struct
sctp_transport
*
,
sctp_lower_cwnd_t
);
unsigned
long
sctp_transport_timeout
(
struct
sctp_transport
*
);
/* This is the structure we use to queue packets as they come into
* SCTP. We write packets to it and read chunks from it. It handles
* fragment reassembly and chunk unbundling.
* SCTP. We write packets to it and read chunks from it.
*/
struct
SCTP_inqueue
{
/* This is actually a queue of sctp_chunk_t each
...
...
@@ -835,7 +891,7 @@ void sctp_inqueue_set_th_handler(sctp_inqueue_t *,
*
* When free()'d, it empties itself out via output_handler().
*/
struct
SCTP_outqueue
{
struct
sctp_outq
{
sctp_association_t
*
asoc
;
/* BUG: This really should be an array of streams.
...
...
@@ -861,11 +917,11 @@ struct SCTP_outqueue {
* layer. This is always SCTP_packet, but we separate the two
* structures to make testing simpler.
*/
sctp_outq
ueue
_ohandler_init_t
*
init_output
;
sctp_outq
ueue
_ohandler_config_t
*
config_output
;
sctp_outq
ueue
_ohandler_t
*
append_output
;
sctp_outq
ueue
_ohandler_t
*
build_output
;
sctp_outq
ueue
_ohandler_force_t
*
force_output
;
sctp_outq_ohandler_init_t
*
init_output
;
sctp_outq_ohandler_config_t
*
config_output
;
sctp_outq_ohandler_t
*
append_output
;
sctp_outq_ohandler_t
*
build_output
;
sctp_outq_ohandler_force_t
*
force_output
;
/* How many unackd bytes do we have in-flight? */
__u32
outstanding_bytes
;
...
...
@@ -877,24 +933,24 @@ struct SCTP_outqueue {
int
malloced
;
};
s
ctp_outqueue_t
*
sctp_outqueue
_new
(
sctp_association_t
*
);
void
sctp_outq
ueue_init
(
sctp_association_t
*
,
sctp_outqueue_t
*
);
void
sctp_outq
ueue_teardown
(
sctp_outqueue_t
*
);
void
sctp_outq
ueue_free
(
sctp_outqueue_t
*
);
void
sctp_force_outqueue
(
sctp_outqueue_t
*
);
int
sctp_
push_outqueue
(
sctp_outqueue_t
*
,
sctp_chunk_t
*
chunk
);
int
sctp_
flush_outqueue
(
sctp_outqueue_t
*
,
int
);
int
sctp_
sack_outqueue
(
sctp_outqueue_t
*
,
sctp_sackhdr_t
*
);
int
sctp_outq
ueue_is_empty
(
const
sctp_outqueue_t
*
);
int
sctp_outqueue_set_output_handlers
(
sctp_outqueue_t
*
,
sctp_outqueue_ohandler_init_t
init
,
sctp_outqueue_ohandler_config_t
config
,
sctp_outqueue_ohandler_t
appen
d
,
sctp_outqueue_ohandler_t
build
,
sctp_outqueue_ohandler_force_t
force
);
void
sctp_
outqueue_restart
(
sctp_outqueue_t
*
);
void
sctp_retransmit
(
sctp_outqueue_t
*
,
sctp_transport_t
*
,
__u8
);
void
sctp_retransmit_mark
(
s
ctp_outqueue_t
*
,
sctp_transport_
t
*
,
__u8
);
s
truct
sctp_outq
*
sctp_outq
_new
(
sctp_association_t
*
);
void
sctp_outq
_init
(
sctp_association_t
*
,
struct
sctp_outq
*
);
void
sctp_outq
_teardown
(
struct
sctp_outq
*
);
void
sctp_outq
_free
(
struct
sctp_outq
*
);
int
sctp_outq_tail
(
struct
sctp_outq
*
,
sctp_chunk_t
*
chunk
);
int
sctp_
outq_flush
(
struct
sctp_outq
*
,
int
);
int
sctp_
outq_sack
(
struct
sctp_outq
*
,
sctp_sackhdr_t
*
);
int
sctp_
outq_is_empty
(
const
struct
sctp_outq
*
);
int
sctp_outq
_set_output_handlers
(
struct
sctp_outq
*
,
sctp_outq_ohandler_init_t
init
,
sctp_outq_ohandler_config_t
config
,
sctp_outq_ohandler_t
append
,
sctp_outq_ohandler_t
buil
d
,
sctp_outq_ohandler_force_t
force
);
void
sctp_outq_restart
(
struct
sctp_outq
*
);
void
sctp_
retransmit
(
struct
sctp_outq
*
,
struct
sctp_transport
*
,
sctp_retransmit_reason_t
);
void
sctp_retransmit_mark
(
s
truct
sctp_outq
*
,
struct
sctp_transpor
t
*
,
__u8
);
/* These bind address data fields common between endpoints and associations */
...
...
@@ -1027,7 +1083,7 @@ struct SCTP_endpoint {
/* These are the system-wide defaults and other stuff which is
* endpoint-independent.
*/
s
ctp_protocol_t
*
proto
;
s
truct
sctp_protocol
*
proto
;
/* Associations: A list of current associations and mappings
* to the data consumers for each association. This
...
...
@@ -1066,10 +1122,7 @@ static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base)
{
sctp_endpoint_t
*
ep
;
/* We are not really a list, but the list_entry() macro is
* really quite generic to find the address of an outter struct.
*/
ep
=
list_entry
(
base
,
sctp_endpoint_t
,
base
);
ep
=
container_of
(
base
,
sctp_endpoint_t
,
base
);
return
ep
;
}
...
...
@@ -1083,7 +1136,7 @@ void sctp_endpoint_hold(sctp_endpoint_t *);
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
,
sctp_association_t
*
asoc
);
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
const
union
sctp_addr
*
paddr
,
s
ctp_transport_
t
**
);
s
truct
sctp_transpor
t
**
);
int
sctp_endpoint_is_peeled_off
(
sctp_endpoint_t
*
,
const
union
sctp_addr
*
);
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
const
union
sctp_addr
*
);
...
...
@@ -1184,7 +1237,7 @@ struct SCTP_association {
* designate the connection we are currently using to
* transmit new data and most control chunks.
*/
s
ctp_transport_
t
*
primary_path
;
s
truct
sctp_transpor
t
*
primary_path
;
/* Cache the primary path address here, when we
* need a an address for msg_name.
...
...
@@ -1195,7 +1248,7 @@ struct SCTP_association {
* The path that we are currently using to
* transmit new data and most control chunks.
*/
s
ctp_transport_
t
*
active_path
;
s
truct
sctp_transpor
t
*
active_path
;
/* retran_path
*
...
...
@@ -1207,13 +1260,13 @@ struct SCTP_association {
* different from the last destination address to
* which the DATA chunk was sent.
*/
s
ctp_transport_
t
*
retran_path
;
s
truct
sctp_transpor
t
*
retran_path
;
/* Pointer to last transport I have sent on. */
s
ctp_transport_
t
*
last_sent_to
;
s
truct
sctp_transpor
t
*
last_sent_to
;
/* This is the last transport I have recieved DATA on. */
s
ctp_transport_
t
*
last_data_from
;
s
truct
sctp_transpor
t
*
last_data_from
;
/*
* Mapping An array of bits or bytes indicating which out of
...
...
@@ -1325,7 +1378,7 @@ struct SCTP_association {
struct
timer_list
timers
[
SCTP_NUM_TIMEOUT_TYPES
];
/* Transport to which SHUTDOWN chunk was last sent. */
s
ctp_transport_
t
*
shutdown_last_sent_to
;
s
truct
sctp_transpor
t
*
shutdown_last_sent_to
;
/* Next TSN : The next TSN number to be assigned to a new
* : DATA chunk. This is sent in the INIT or INIT
...
...
@@ -1408,18 +1461,15 @@ struct SCTP_association {
}
defaults
;
/* This tracks outbound ssn for a given stream. */
__u16
ssn
[
SCTP_MAX_STREAM
]
;
struct
sctp_ssnmap
*
ssnmap
;
/* All outbound chunks go through this structure. */
s
ctp_outqueue_t
outqueue
;
s
truct
sctp_outq
outqueue
;
/* A smart pipe that will handle reordering and fragmentation,
* as well as handle passing events up to the ULP.
* In the future, we should make this at least dynamic, if
* not also some sparse structure.
*/
sctp_ulpqueue_t
ulpq
;
__u8
_ssnmap
[
sctp_ulpqueue_storage_size
(
SCTP_MAX_STREAM
)];
struct
sctp_ulpq
ulpq
;
/* Need to send an ECNE Chunk? */
int
need_ecne
;
...
...
@@ -1505,7 +1555,7 @@ struct SCTP_association {
*
*
* [I really think this is EXACTLY the sort of intelligence
* which already resides in
SCTP_outqueue
. Please move this
* which already resides in
sctp_outq
. Please move this
* queue and its supporting logic down there. --piggy]
*/
struct
sk_buff_head
addip_chunks
;
...
...
@@ -1546,10 +1596,7 @@ static inline sctp_association_t *sctp_assoc(sctp_endpoint_common_t *base)
{
sctp_association_t
*
asoc
;
/* We are not really a list, but the list_entry() macro is
* really quite generic find the address of an outter struct.
*/
asoc
=
list_entry
(
base
,
sctp_association_t
,
base
);
asoc
=
container_of
(
base
,
sctp_association_t
,
base
);
return
asoc
;
}
...
...
@@ -1567,16 +1614,17 @@ void sctp_association_free(sctp_association_t *);
void
sctp_association_put
(
sctp_association_t
*
);
void
sctp_association_hold
(
sctp_association_t
*
);
s
ctp_transport_
t
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
s
ctp_transport_
t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
s
truct
sctp_transpor
t
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
s
truct
sctp_transpor
t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
const
union
sctp_addr
*
);
s
ctp_transport_
t
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
s
truct
sctp_transpor
t
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
const
union
sctp_addr
*
address
,
const
int
priority
);
void
sctp_assoc_control_transport
(
sctp_association_t
*
,
sctp_transport_t
*
,
void
sctp_assoc_control_transport
(
sctp_association_t
*
,
struct
sctp_transport
*
,
sctp_transport_cmd_t
,
sctp_sn_error_t
);
s
ctp_transport_
t
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
,
__u32
);
s
ctp_transport_
t
*
sctp_assoc_is_match
(
sctp_association_t
*
,
s
truct
sctp_transpor
t
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
,
__u32
);
s
truct
sctp_transpor
t
*
sctp_assoc_is_match
(
sctp_association_t
*
,
const
union
sctp_addr
*
,
const
union
sctp_addr
*
);
void
sctp_assoc_migrate
(
sctp_association_t
*
,
struct
sock
*
);
...
...
@@ -1586,6 +1634,14 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *);
__u32
__sctp_association_get_tsn_block
(
sctp_association_t
*
,
int
);
__u16
__sctp_association_get_next_ssn
(
sctp_association_t
*
,
__u16
sid
);
void
sctp_assoc_sync_pmtu
(
sctp_association_t
*
);
void
sctp_assoc_rwnd_increase
(
sctp_association_t
*
,
int
);
void
sctp_assoc_rwnd_decrease
(
sctp_association_t
*
,
int
);
int
sctp_assoc_set_bind_addr_from_ep
(
sctp_association_t
*
,
int
);
int
sctp_assoc_set_bind_addr_from_cookie
(
sctp_association_t
*
,
sctp_cookie_t
*
,
int
);
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
const
union
sctp_addr
*
ss2
);
sctp_chunk_t
*
sctp_get_ecne_prepend
(
sctp_association_t
*
asoc
);
...
...
include/net/sctp/ulpqueue.h
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2003
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
* These are the definitions needed for the sctp_ulpq
ueue type. The
* sctp_ulpq
ueue
is the interface between the Upper Layer Protocol, or ULP,
* These are the definitions needed for the sctp_ulpq
type. The
* sctp_ulpq is the interface between the Upper Layer Protocol, or ULP,
* and the core SCTP state machine. This is the component which handles
* reassembly and ordering.
*
...
...
@@ -28,9 +28,14 @@
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to one of the
* following email addresses:
* Please send any bug reports or fixes you make to the
* email addresses:
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
*
...
...
@@ -42,46 +47,26 @@
#define __sctp_ulpqueue_h__
/* A structure to carry information to the ULP (e.g. Sockets API) */
typedef
struct
sctp_ulpqueue
{
struct
sctp_ulpq
{
int
malloced
;
spinlock_t
lock
;
sctp_association_t
*
asoc
;
struct
sk_buff_head
reasm
;
struct
sk_buff_head
lobby
;
__u16
ssn
[
0
];
}
sctp_ulpqueue_t
;
/* This macro assists in creation of external storage for variable length
* internal buffers.
*/
#define sctp_ulpqueue_storage_size(inbound) (sizeof(__u16) * (inbound))
sctp_ulpqueue_t
*
sctp_ulpqueue_new
(
sctp_association_t
*
asoc
,
__u16
inbound
,
int
priority
);
sctp_ulpqueue_t
*
sctp_ulpqueue_init
(
sctp_ulpqueue_t
*
ulpq
,
sctp_association_t
*
asoc
,
__u16
inbound
);
void
sctp_ulpqueue_free
(
sctp_ulpqueue_t
*
);
};
/* Prototypes. */
struct
sctp_ulpq
*
sctp_ulpq_new
(
sctp_association_t
*
asoc
,
int
priority
);
struct
sctp_ulpq
*
sctp_ulpq_init
(
struct
sctp_ulpq
*
,
sctp_association_t
*
);
void
sctp_ulpq_free
(
struct
sctp_ulpq
*
);
/* Add a new DATA chunk for processing. */
int
sctp_ulpqueue_tail_data
(
sctp_ulpqueue_t
*
,
sctp_chunk_t
*
chunk
,
int
priority
);
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
,
sctp_chunk_t
*
chunk
,
int
priority
);
/* Add a new event for propogation to the ULP. */
int
sctp_ulpqueue_tail_event
(
sctp_ulpqueue_t
*
,
sctp_ulpevent_t
*
event
);
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
ev
);
/* Is the ulpqueue empty. */
int
sctp_ulpqueue_is_empty
(
sctp_ulpqueue_t
*
);
int
sctp_ulpqueue_is_data_empty
(
sctp_ulpqueue_t
*
);
int
sctp_ulpqueue_is_empty
(
struct
sctp_ulpq
*
);
#endif
/* __sctp_ulpqueue_h__ */
...
...
include/net/sctp/user.h
View file @
a0065b2f
...
...
@@ -100,6 +100,14 @@ enum sctp_optname {
#define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM
SCTP_SOCKOPT_PEELOFF
,
/* peel off association. */
#define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF
SCTP_GET_PEER_ADDRS_NUM
,
/* Get number of peer addresss. */
#define SCTP_GET_PEER_ADDRS_NUM SCTP_GET_PEER_ADDRS_NUM
SCTP_GET_PEER_ADDRS
,
/* Get all peer addresss. */
#define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS
SCTP_GET_LOCAL_ADDRS_NUM
,
/* Get number of local addresss. */
#define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM
SCTP_GET_LOCAL_ADDRS
,
/* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
};
...
...
@@ -576,6 +584,15 @@ struct sctp_setstrm_timeout {
__u16
ssto_streamid_end
;
};
/*
* 8.3 8.5 get all peer/local addresses on a socket
* This parameter struct is for getsockopt
*/
struct
sctp_getaddrs
{
sctp_assoc_t
assoc_id
;
int
addr_num
;
struct
sockaddr_storage
*
addrs
;
};
/* These are bit fields for msghdr->msg_flags. See section 5.1. */
/* On user space Linux, these live in <bits/socket.h> as an enum. */
...
...
net/sctp/Kconfig
View file @
a0065b2f
...
...
@@ -6,7 +6,7 @@ menu "SCTP Configuration (EXPERIMENTAL)"
depends on INET && EXPERIMENTAL
config IPV6_SCTP__
bool
tristate
default y if IPV6=n
default IPV6 if IPV6
...
...
net/sctp/Makefile
View file @
a0065b2f
...
...
@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
inqueue.o outqueue.o ulpqueue.o command.o
\
tsnmap.o bind_addr.o socket.o primitive.o
\
output.o input.o hashdriver.o sla1.o
\
debug.o
debug.o
ssnmap.o
ifeq
($(CONFIG_SCTP_ADLER32), y)
sctp-y
+=
adler32.o
...
...
net/sctp/adler32.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -36,6 +37,7 @@
* Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -122,7 +124,7 @@ unsigned long update_adler32(unsigned long adler,
return
(
s2
<<
16
)
+
s1
;
}
__u32
count_crc
(
__u8
*
ptr
,
__u16
count
)
__u32
sctp_start_cksum
(
__u8
*
ptr
,
__u16
count
)
{
/*
* Update a running Adler-32 checksum with the bytes
...
...
@@ -146,3 +148,15 @@ __u32 count_crc(__u8 *ptr, __u16 count)
return
adler
;
}
__u32
sctp_update_cksum
(
__u8
*
ptr
,
__u16
count
,
__u32
adler
)
{
adler
=
update_adler32
(
adler
,
ptr
,
count
);
return
adler
;
}
__u32
sctp_end_cksum
(
__u32
adler
)
{
return
adler
;
}
net/sctp/associola.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-200
2
International Business Machines Corp.
* Copyright (c) 2001-200
3
International Business Machines Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
...
...
@@ -166,15 +166,10 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
->
max_init_attempts
=
sp
->
initmsg
.
sinit_max_attempts
;
asoc
->
max_init_timeo
=
sp
->
initmsg
.
sinit_max_init_timeo
*
HZ
;
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
*
* The stream sequence number in all the streams shall start
* from 0 when the association is established. Also, when the
* stream sequence number reaches the value 65535 the next
* stream sequence number shall be set to 0.
/* Allocate storage for the ssnmap after the inbound and outbound
* streams have been negotiated during Init.
*/
for
(
i
=
0
;
i
<
SCTP_MAX_STREAM
;
i
++
)
asoc
->
ssn
[
i
]
=
0
;
asoc
->
ssnmap
=
NULL
;
/* Set the local window size for receive.
* This is also the rcvbuf space per association.
...
...
@@ -252,15 +247,15 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
);
/* Create an output queue. */
sctp_outq
ueue
_init
(
asoc
,
&
asoc
->
outqueue
);
sctp_outq
ueue
_set_output_handlers
(
&
asoc
->
outqueue
,
sctp_outq_init
(
asoc
,
&
asoc
->
outqueue
);
sctp_outq_set_output_handlers
(
&
asoc
->
outqueue
,
sctp_packet_init
,
sctp_packet_config
,
sctp_packet_append_chunk
,
sctp_packet_transmit_chunk
,
sctp_packet_transmit
);
if
(
NULL
==
sctp_ulpq
ueue_init
(
&
asoc
->
ulpq
,
asoc
,
SCTP_MAX_STREAM
))
if
(
NULL
==
sctp_ulpq
_init
(
&
asoc
->
ulpq
,
asoc
))
goto
fail_init
;
/* Set up the tsn tracking. */
...
...
@@ -296,7 +291,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
*/
void
sctp_association_free
(
sctp_association_t
*
asoc
)
{
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_endpoint_t
*
ep
;
struct
list_head
*
pos
,
*
temp
;
int
i
;
...
...
@@ -310,14 +305,17 @@ void sctp_association_free(sctp_association_t *asoc)
asoc
->
base
.
dead
=
1
;
/* Dispose of any data lying around in the outqueue. */
sctp_outq
ueue
_free
(
&
asoc
->
outqueue
);
sctp_outq_free
(
&
asoc
->
outqueue
);
/* Dispose of any pending messages for the upper layer. */
sctp_ulpq
ueue
_free
(
&
asoc
->
ulpq
);
sctp_ulpq_free
(
&
asoc
->
ulpq
);
/* Dispose of any pending chunks on the inqueue. */
sctp_inqueue_free
(
&
asoc
->
base
.
inqueue
);
/* Free ssnmap storage. */
sctp_ssnmap_free
(
asoc
->
ssnmap
);
/* Clean up the bound address list. */
sctp_bind_addr_free
(
&
asoc
->
base
.
bind_addr
);
...
...
@@ -339,7 +337,7 @@ void sctp_association_free(sctp_association_t *asoc)
/* Release the transport structures. */
list_for_each_safe
(
pos
,
temp
,
&
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
transport
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
list_del
(
pos
);
sctp_transport_free
(
transport
);
}
...
...
@@ -365,11 +363,11 @@ static void sctp_association_destroy(sctp_association_t *asoc)
/* Add a transport address to an association. */
s
ctp_transport_
t
*
sctp_assoc_add_peer
(
sctp_association_t
*
asoc
,
s
truct
sctp_transpor
t
*
sctp_assoc_add_peer
(
sctp_association_t
*
asoc
,
const
union
sctp_addr
*
addr
,
int
priority
)
{
s
ctp_transport_
t
*
peer
;
s
truct
sctp_transpor
t
*
peer
;
sctp_opt_t
*
sp
;
unsigned
short
port
;
...
...
@@ -392,8 +390,8 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
sctp_transport_set_owner
(
peer
,
asoc
);
/*
Cache a route for
the transport. */
sctp_transport_
route
(
peer
,
NULL
,
sctp_sk
(
asoc
->
base
.
sk
)
);
/*
Initialize the pmtu of
the transport. */
sctp_transport_
pmtu
(
peer
);
/* If this is the first transport addr on this association,
* initialize the association PMTU to the peer's PMTU.
...
...
@@ -478,16 +476,16 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
}
/* Lookup a transport by address. */
s
ctp_transport_
t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
asoc
,
s
truct
sctp_transpor
t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
asoc
,
const
union
sctp_addr
*
address
)
{
s
ctp_transport_
t
*
t
;
s
truct
sctp_transpor
t
*
t
;
struct
list_head
*
pos
;
/* Cycle through all transports searching for a peer address. */
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
t
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
if
(
sctp_cmp_addr_exact
(
address
,
&
t
->
ipaddr
))
return
t
;
}
...
...
@@ -500,13 +498,13 @@ sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *asoc,
* Select and update the new active and retran paths.
*/
void
sctp_assoc_control_transport
(
sctp_association_t
*
asoc
,
s
ctp_transport_
t
*
transport
,
s
truct
sctp_transpor
t
*
transport
,
sctp_transport_cmd_t
command
,
sctp_sn_error_t
error
)
{
s
ctp_transport_
t
*
t
=
NULL
;
s
ctp_transport_
t
*
first
;
s
ctp_transport_
t
*
second
;
s
truct
sctp_transpor
t
*
t
=
NULL
;
s
truct
sctp_transpor
t
*
first
;
s
truct
sctp_transpor
t
*
second
;
sctp_ulpevent_t
*
event
;
struct
list_head
*
pos
;
int
spc_state
=
0
;
...
...
@@ -524,7 +522,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
break
;
default:
BUG
()
;
return
;
};
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
...
...
@@ -534,7 +532,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
(
struct
sockaddr_storage
*
)
&
transport
->
ipaddr
,
0
,
spc_state
,
error
,
GFP_ATOMIC
);
if
(
event
)
sctp_ulpq
ueue
_tail_event
(
&
asoc
->
ulpq
,
event
);
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
event
);
/* Select new active and retran paths. */
...
...
@@ -547,7 +545,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
first
=
NULL
;
second
=
NULL
;
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
t
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
if
(
!
t
->
active
)
continue
;
...
...
@@ -631,11 +629,6 @@ __u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
return
retval
;
}
/* Fetch the next Stream Sequence Number for stream number 'sid'. */
__u16
__sctp_association_get_next_ssn
(
sctp_association_t
*
asoc
,
__u16
sid
)
{
return
asoc
->
ssn
[
sid
]
++
;
}
/* Compare two addresses to see if they match. Wildcard addresses
* only match themselves.
...
...
@@ -695,12 +688,12 @@ sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc)
/*
* Find which transport this TSN was sent on.
*/
s
ctp_transport_
t
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
asoc
,
__u32
tsn
)
s
truct
sctp_transpor
t
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
asoc
,
__u32
tsn
)
{
s
ctp_transport_
t
*
active
;
s
ctp_transport_
t
*
match
;
s
truct
sctp_transpor
t
*
active
;
s
truct
sctp_transpor
t
*
match
;
struct
list_head
*
entry
,
*
pos
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_chunk_t
*
chunk
;
__u32
key
=
htonl
(
tsn
);
...
...
@@ -734,7 +727,7 @@ sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn)
/* If not found, go search all the other transports. */
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
transport
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
if
(
transport
==
active
)
break
;
...
...
@@ -752,11 +745,11 @@ sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn)
}
/* Is this the association we are looking for? */
s
ctp_transport_
t
*
sctp_assoc_is_match
(
sctp_association_t
*
asoc
,
s
truct
sctp_transpor
t
*
sctp_assoc_is_match
(
sctp_association_t
*
asoc
,
const
union
sctp_addr
*
laddr
,
const
union
sctp_addr
*
paddr
)
{
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_read_lock
(
&
asoc
->
base
.
addr_lock
);
...
...
@@ -852,8 +845,6 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
/* Update an association (possibly from unexpected COOKIE-ECHO processing). */
void
sctp_assoc_update
(
sctp_association_t
*
asoc
,
sctp_association_t
*
new
)
{
int
i
;
/* Copy in new parameters of peer. */
asoc
->
c
=
new
->
c
;
asoc
->
peer
.
rwnd
=
new
->
peer
.
rwnd
;
...
...
@@ -872,23 +863,28 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
/* If the case is A (association restart), use
* initial_tsn as next_tsn. If the case is B, use
* current next_tsn in case
there is
data sent to peer
* current next_tsn in case data sent to peer
* has been discarded and needs retransmission.
*/
if
(
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
{
asoc
->
next_tsn
=
new
->
next_tsn
;
asoc
->
ctsn_ack_point
=
new
->
ctsn_ack_point
;
/* Reinitialize SSN for both local streams
* and peer's streams.
*/
for
(
i
=
0
;
i
<
SCTP_MAX_STREAM
;
i
++
)
{
asoc
->
ssn
[
i
]
=
0
;
asoc
->
ulpq
.
ssn
[
i
]
=
0
;
}
sctp_ssnmap_clear
(
asoc
->
ssnmap
);
}
else
{
asoc
->
ctsn_ack_point
=
asoc
->
next_tsn
-
1
;
if
(
!
asoc
->
ssnmap
)
{
/* Move the ssnmap. */
asoc
->
ssnmap
=
new
->
ssnmap
;
new
->
ssnmap
=
NULL
;
}
}
}
/* Choose the transport for sending a shutdown packet.
...
...
@@ -896,9 +892,9 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
* through the inactive transports as this is the next best thing
* we can try.
*/
s
ctp_transport_
t
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
asoc
)
s
truct
sctp_transpor
t
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
asoc
)
{
s
ctp_transport_
t
*
t
,
*
next
;
s
truct
sctp_transpor
t
*
t
,
*
next
;
struct
list_head
*
head
=
&
asoc
->
peer
.
transport_addr_list
;
struct
list_head
*
pos
;
...
...
@@ -921,7 +917,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
else
pos
=
pos
->
next
;
t
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
t
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
/* Try to find an active transport. */
...
...
@@ -947,3 +943,136 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
return
t
;
}
/* Update the association's pmtu and frag_point by going through all the
* transports. This routine is called when a transport's PMTU has changed.
*/
void
sctp_assoc_sync_pmtu
(
sctp_association_t
*
asoc
)
{
struct
sctp_transport
*
t
;
struct
list_head
*
pos
;
__u32
pmtu
=
0
;
if
(
!
asoc
)
return
;
/* Get the lowest pmtu of all the transports. */
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
!
pmtu
||
(
t
->
pmtu
<
pmtu
))
pmtu
=
t
->
pmtu
;
}
if
(
pmtu
)
{
asoc
->
pmtu
=
pmtu
;
asoc
->
frag_point
=
pmtu
-
(
SCTP_IP_OVERHEAD
+
sizeof
(
sctp_data_chunk_t
));
}
SCTP_DEBUG_PRINTK
(
"%s: asoc:%p, pmtu:%d, frag_point:%d
\n
"
,
__FUNCTION__
,
asoc
,
asoc
->
pmtu
,
asoc
->
frag_point
);
}
/* Increase asoc's rwnd by len and send any window update SACK if needed. */
void
sctp_assoc_rwnd_increase
(
sctp_association_t
*
asoc
,
int
len
)
{
sctp_chunk_t
*
sack
;
struct
timer_list
*
timer
;
if
(
asoc
->
rwnd_over
)
{
if
(
asoc
->
rwnd_over
>=
len
)
{
asoc
->
rwnd_over
-=
len
;
}
else
{
asoc
->
rwnd
+=
(
len
-
asoc
->
rwnd_over
);
asoc
->
rwnd_over
=
0
;
}
}
else
{
asoc
->
rwnd
+=
len
;
}
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd increased by %d to (%u, %u) - %u
\n
"
,
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
,
asoc
->
a_rwnd
);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in
* Section 4.2.3.3 of RFC 1122.
*/
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
(
asoc
->
rwnd
>
asoc
->
a_rwnd
)
&&
((
asoc
->
rwnd
-
asoc
->
a_rwnd
)
>=
min_t
(
__u32
,
(
asoc
->
base
.
sk
->
rcvbuf
>>
1
),
asoc
->
pmtu
)))
{
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
"rwnd: %u a_rwnd: %u
\n
"
,
__FUNCTION__
,
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
return
;
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
/* Stop the SACK timer. */
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
}
}
/* Decrease asoc's rwnd by len. */
void
sctp_assoc_rwnd_decrease
(
sctp_association_t
*
asoc
,
int
len
)
{
SCTP_ASSERT
(
asoc
->
rwnd
,
"rwnd zero"
,
return
);
SCTP_ASSERT
(
!
asoc
->
rwnd_over
,
"rwnd_over not zero"
,
return
);
if
(
asoc
->
rwnd
>=
len
)
{
asoc
->
rwnd
-=
len
;
}
else
{
asoc
->
rwnd_over
=
len
-
asoc
->
rwnd
;
asoc
->
rwnd
=
0
;
}
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd decreased by %d to (%u, %u)
\n
"
,
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
);
}
/* Build the bind address list for the association based on info from the
* local endpoint and the remote peer.
*/
int
sctp_assoc_set_bind_addr_from_ep
(
sctp_association_t
*
asoc
,
int
priority
)
{
sctp_scope_t
scope
;
int
flags
;
/* Use scoping rules to determine the subset of addresses from
* the endpoint.
*/
scope
=
sctp_scope
(
&
asoc
->
peer
.
active_path
->
ipaddr
);
flags
=
(
PF_INET6
==
asoc
->
base
.
sk
->
family
)
?
SCTP_ADDR6_ALLOWED
:
0
;
if
(
asoc
->
peer
.
ipv4_address
)
flags
|=
SCTP_ADDR4_PEERSUPP
;
if
(
asoc
->
peer
.
ipv6_address
)
flags
|=
SCTP_ADDR6_PEERSUPP
;
return
sctp_bind_addr_copy
(
&
asoc
->
base
.
bind_addr
,
&
asoc
->
ep
->
base
.
bind_addr
,
scope
,
priority
,
flags
);
}
/* Build the association's bind address list from the cookie. */
int
sctp_assoc_set_bind_addr_from_cookie
(
sctp_association_t
*
asoc
,
sctp_cookie_t
*
cookie
,
int
priority
)
{
int
var_size2
=
ntohs
(
cookie
->
peer_init
->
chunk_hdr
.
length
);
int
var_size3
=
cookie
->
raw_addr_list_len
;
__u8
*
raw_addr_list
=
(
__u8
*
)
cookie
+
sizeof
(
sctp_cookie_t
)
+
var_size2
;
return
sctp_raw_to_bind_addrs
(
&
asoc
->
base
.
bind_addr
,
raw_addr_list
,
var_size3
,
asoc
->
ep
->
base
.
bind_addr
.
port
,
priority
);
}
net/sctp/command.c
View file @
a0065b2f
...
...
@@ -47,7 +47,7 @@ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority)
{
sctp_cmd_seq_t
*
retval
=
t_new
(
sctp_cmd_seq_t
,
priority
);
/* XXX Check for NULL? -DaveM */
if
(
retval
)
sctp_init_cmd_seq
(
retval
);
return
retval
;
...
...
net/sctp/crc32c.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2003
International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -33,6 +33,7 @@
* Written or modified by:
* Dinakaran Joseph
* Jon Grimm <jgrimm@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -135,11 +136,10 @@ __u32 crc_c[256] = {
0xBE2DA0A5
,
0x4C4623A6
,
0x5F16D052
,
0xAD7D5351
,
};
__u32
count_crc
(
__u8
*
buffer
,
__u16
length
)
__u32
sctp_start_cksum
(
__u8
*
buffer
,
__u16
length
)
{
__u32
crc32
=
~
(
__u32
)
0
;
__u32
i
,
result
;
__u8
byte0
,
byte1
,
byte2
,
byte3
;
__u32
i
;
/* Optimize this routine to be SCTP specific, knowing how
* to skip the checksum field of the SCTP header.
...
...
@@ -157,6 +157,24 @@ __u32 count_crc(__u8 *buffer, __u16 length)
for
(
i
=
sizeof
(
struct
sctphdr
);
i
<
length
;
i
++
)
CRC32C
(
crc32
,
buffer
[
i
]);
return
crc32
;
}
__u32
sctp_update_cksum
(
__u8
*
buffer
,
__u16
length
,
__u32
crc32
)
{
__u32
i
;
for
(
i
=
0
;
i
<
length
;
i
++
)
CRC32C
(
crc32
,
buffer
[
i
]);
return
crc32
;
}
__u32
sctp_end_cksum
(
__u32
crc32
)
{
__u32
result
;
__u8
byte0
,
byte1
,
byte2
,
byte3
;
result
=
~
crc32
;
/* result now holds the negated polynomial remainder;
...
...
@@ -183,5 +201,3 @@ __u32 count_crc(__u8 *buffer, __u16 length)
byte3
);
return
crc32
;
}
net/sctp/debug.c
View file @
a0065b2f
...
...
@@ -148,22 +148,11 @@ const char *sctp_status_tbl[] = {
/* Printable forms of primitives */
static
const
char
*
sctp_primitive_tbl
[
SCTP_NUM_PRIMITIVE_TYPES
]
=
{
"PRIMITIVE_INITIALIZE"
,
"PRIMITIVE_ASSOCIATE"
,
"PRIMITIVE_SHUTDOWN"
,
"PRIMITIVE_ABORT"
,
"PRIMITIVE_SEND"
,
"PRIMITIVE_SETPRIMARY"
,
"PRIMITIVE_RECEIVE"
,
"PRIMITIVE_STATUS"
,
"PRIMITIVE_CHANGEHEARTBEAT"
,
"PRIMITIVE_REQUESTHEARTBEAT"
,
"PRIMITIVE_GETSRTTREPORT"
,
"PRIMITIVE_SETFAILURETHRESHOLD"
,
"PRIMITIVE_SETPROTOPARAMETERS"
,
"PRIMITIVE_RECEIVE_UNSENT"
,
"PRIMITIVE_RECEIVE_UNACKED"
,
"PRIMITIVE_DESTROY"
};
/* Lookup primitive debug name. */
...
...
@@ -178,7 +167,6 @@ const char *sctp_pname(const sctp_subtype_t id)
static
const
char
*
sctp_other_tbl
[]
=
{
"NO_PENDING_TSN"
,
"ICMP_UNREACHFRAG"
};
/* Lookup "other" debug name. */
...
...
@@ -197,12 +185,10 @@ static const char *sctp_timer_tbl[] = {
"TIMEOUT_T1_INIT"
,
"TIMEOUT_T2_SHUTDOWN"
,
"TIMEOUT_T3_RTX"
,
"TIMEOUT_T4_RTO"
,
"TIMEOUT_T5_SHUTDOWN_GUARD"
,
"TIMEOUT_HEARTBEAT"
,
"TIMEOUT_SACK"
,
"TIMEOUT_AUTOCLOSE"
,
"TIMEOUT_PMTU_RAISE"
,
};
/* Lookup timer debug name. */
...
...
net/sctp/endpointola.c
View file @
a0065b2f
...
...
@@ -137,7 +137,6 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep
->
timeouts
[
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
]
=
sp
->
rtoinfo
.
srto_initial
;
ep
->
timeouts
[
SCTP_EVENT_TIMEOUT_T3_RTX
]
=
0
;
ep
->
timeouts
[
SCTP_EVENT_TIMEOUT_T4_RTO
]
=
0
;
/* sctpimpguide-05 Section 2.12.2
* If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the
...
...
@@ -152,8 +151,6 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
SCTP_DEFAULT_TIMEOUT_SACK
;
ep
->
timeouts
[
SCTP_EVENT_TIMEOUT_AUTOCLOSE
]
=
sp
->
autoclose
*
HZ
;
ep
->
timeouts
[
SCTP_EVENT_TIMEOUT_PMTU_RAISE
]
=
SCTP_DEFAULT_TIMEOUT_PMTU_RAISE
;
/* Set up the default send/receive buffer space. */
...
...
@@ -264,7 +261,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
sctp_association_t
*
__sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
endpoint
,
const
union
sctp_addr
*
paddr
,
s
ctp_transport_
t
**
transport
)
s
truct
sctp_transpor
t
**
transport
)
{
int
rport
;
sctp_association_t
*
asoc
;
...
...
@@ -289,9 +286,10 @@ sctp_association_t *__sctp_endpoint_lookup_assoc(
}
/* Lookup association on an endpoint based on a peer address. BH-safe. */
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
const
union
sctp_addr
*
paddr
,
sctp_transport_
t
**
transport
)
struct
sctp_transpor
t
**
transport
)
{
sctp_association_t
*
asoc
;
...
...
@@ -333,7 +331,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
{
sctp_association_t
*
asoc
;
struct
sock
*
sk
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_chunk_t
*
chunk
;
sctp_inqueue_t
*
inqueue
;
sctp_subtype_t
subtype
;
...
...
net/sctp/input.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2003
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
...
...
@@ -53,6 +53,9 @@
#include <linux/socket.h>
#include <linux/ip.h>
#include <linux/time.h>
/* For struct timeval */
#include <net/ip.h>
#include <net/icmp.h>
#include <net/snmp.h>
#include <net/sock.h>
#include <net/xfrm.h>
#include <net/sctp/sctp.h>
...
...
@@ -63,7 +66,7 @@ static int sctp_rcv_ootb(struct sk_buff *);
sctp_association_t
*
__sctp_rcv_lookup
(
struct
sk_buff
*
skb
,
const
union
sctp_addr
*
laddr
,
const
union
sctp_addr
*
paddr
,
s
ctp_transport_
t
**
transportp
);
s
truct
sctp_transpor
t
**
transportp
);
sctp_endpoint_t
*
__sctp_rcv_lookup_endpoint
(
const
union
sctp_addr
*
laddr
);
...
...
@@ -72,10 +75,19 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
{
struct
sctphdr
*
sh
;
__u32
cmp
,
val
;
struct
sk_buff
*
list
=
skb_shinfo
(
skb
)
->
frag_list
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
cmp
=
ntohl
(
sh
->
checksum
);
val
=
count_crc
((
__u8
*
)
sh
,
skb
->
len
);
val
=
sctp_start_cksum
((
__u8
*
)
sh
,
skb_headlen
(
skb
));
for
(;
list
;
list
=
list
->
next
)
val
=
sctp_update_cksum
((
__u8
*
)
list
->
data
,
skb_headlen
(
list
),
val
);
val
=
sctp_end_cksum
(
val
);
if
(
val
!=
cmp
)
{
/* CRC failure, dump it. */
return
-
1
;
...
...
@@ -92,7 +104,7 @@ int sctp_rcv(struct sk_buff *skb)
sctp_association_t
*
asoc
;
sctp_endpoint_t
*
ep
=
NULL
;
sctp_endpoint_common_t
*
rcvr
;
s
ctp_transport_
t
*
transport
=
NULL
;
s
truct
sctp_transpor
t
*
transport
=
NULL
;
sctp_chunk_t
*
chunk
;
struct
sctphdr
*
sh
;
union
sctp_addr
src
;
...
...
@@ -248,6 +260,27 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
return
0
;
}
/* Handle icmp frag needed error. */
static
inline
void
sctp_icmp_frag_needed
(
struct
sock
*
sk
,
sctp_association_t
*
asoc
,
struct
sctp_transport
*
transport
,
__u32
pmtu
)
{
if
(
unlikely
(
pmtu
<
SCTP_DEFAULT_MINSEGMENT
))
{
printk
(
KERN_WARNING
"%s: Reported pmtu %d too low, "
"using default minimum of %d
\n
"
,
__FUNCTION__
,
pmtu
,
SCTP_DEFAULT_MINSEGMENT
);
pmtu
=
SCTP_DEFAULT_MINSEGMENT
;
}
if
(
!
sock_owned_by_user
(
sk
)
&&
transport
&&
(
transport
->
pmtu
!=
pmtu
))
{
transport
->
pmtu
=
pmtu
;
sctp_assoc_sync_pmtu
(
asoc
);
sctp_retransmit
(
&
asoc
->
outqueue
,
transport
,
SCTP_RETRANSMIT_PMTU_DISCOVERY
);
}
}
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
...
...
@@ -263,9 +296,109 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
* is probably better.
*
*/
void
sctp_v4_err
(
struct
sk_buff
*
skb
,
u32
info
)
void
sctp_v4_err
(
struct
sk_buff
*
skb
,
__
u32
info
)
{
/* This should probably involve a call to SCTPhandleICMP(). */
struct
iphdr
*
iph
=
(
struct
iphdr
*
)
skb
->
data
;
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)(
skb
->
data
+
(
iph
->
ihl
<<
2
));
int
type
=
skb
->
h
.
icmph
->
type
;
int
code
=
skb
->
h
.
icmph
->
code
;
union
sctp_addr
saddr
,
daddr
;
struct
inet_opt
*
inet
;
struct
sock
*
sk
=
NULL
;
sctp_endpoint_t
*
ep
=
NULL
;
sctp_association_t
*
asoc
=
NULL
;
struct
sctp_transport
*
transport
;
int
err
;
if
(
skb
->
len
<
((
iph
->
ihl
<<
2
)
+
8
))
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
return
;
}
saddr
.
v4
.
sin_family
=
AF_INET
;
saddr
.
v4
.
sin_port
=
ntohs
(
sh
->
source
);
memcpy
(
&
saddr
.
v4
.
sin_addr
.
s_addr
,
&
iph
->
saddr
,
sizeof
(
struct
in_addr
));
daddr
.
v4
.
sin_family
=
AF_INET
;
daddr
.
v4
.
sin_port
=
ntohs
(
sh
->
dest
);
memcpy
(
&
daddr
.
v4
.
sin_addr
.
s_addr
,
&
iph
->
daddr
,
sizeof
(
struct
in_addr
));
/* Look for an association that matches the incoming ICMP error
* packet.
*/
asoc
=
__sctp_lookup_association
(
&
saddr
,
&
daddr
,
&
transport
);
if
(
!
asoc
)
{
/* If there is no matching association, see if it matches any
* endpoint. This may happen for an ICMP error generated in
* response to an INIT_ACK.
*/
ep
=
__sctp_rcv_lookup_endpoint
(
&
daddr
);
if
(
!
ep
)
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
return
;
}
}
if
(
asoc
)
{
if
(
ntohl
(
sh
->
vtag
)
!=
asoc
->
c
.
peer_vtag
)
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
goto
out
;
}
sk
=
asoc
->
base
.
sk
;
}
else
sk
=
ep
->
base
.
sk
;
sctp_bh_lock_sock
(
sk
);
/* If too many ICMPs get dropped on busy
* servers this needs to be solved differently.
*/
if
(
sock_owned_by_user
(
sk
))
NET_INC_STATS_BH
(
LockDroppedIcmps
);
switch
(
type
)
{
case
ICMP_PARAMETERPROB
:
err
=
EPROTO
;
break
;
case
ICMP_DEST_UNREACH
:
if
(
code
>
NR_ICMP_UNREACH
)
goto
out_unlock
;
/* PMTU discovery (RFC1191) */
if
(
ICMP_FRAG_NEEDED
==
code
)
{
sctp_icmp_frag_needed
(
sk
,
asoc
,
transport
,
info
);
goto
out_unlock
;
}
err
=
icmp_err_convert
[
code
].
errno
;
break
;
case
ICMP_TIME_EXCEEDED
:
/* Ignore any time exceeded errors due to fragment reassembly
* timeouts.
*/
if
(
ICMP_EXC_FRAGTIME
==
code
)
goto
out_unlock
;
err
=
EHOSTUNREACH
;
break
;
default:
goto
out_unlock
;
}
inet
=
inet_sk
(
sk
);
if
(
!
sock_owned_by_user
(
sk
)
&&
inet
->
recverr
)
{
sk
->
err
=
err
;
sk
->
error_report
(
sk
);
}
else
{
/* Only an error on timeout */
sk
->
err_soft
=
err
;
}
out_unlock:
sctp_bh_unlock_sock
(
sk
);
out:
sock_put
(
sk
);
if
(
asoc
)
sctp_association_put
(
asoc
);
if
(
ep
)
sctp_endpoint_put
(
ep
);
}
/*
...
...
@@ -303,17 +436,17 @@ int sctp_rcv_ootb(struct sk_buff *skb)
* chunk, the receiver should silently discard the packet
* and take no further action.
*/
if
(
ch
->
type
==
SCTP_CID_SHUTDOWN_COMPLETE
)
if
(
SCTP_CID_SHUTDOWN_COMPLETE
==
ch
->
type
)
goto
discard
;
/* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
* or a COOKIE ACK the SCTP Packet should be silently
* discarded.
*/
if
(
ch
->
type
==
SCTP_CID_COOKIE_ACK
)
if
(
SCTP_CID_COOKIE_ACK
==
ch
->
type
)
goto
discard
;
if
(
ch
->
type
==
SCTP_CID_ERROR
)
{
if
(
SCTP_CID_ERROR
==
ch
->
type
)
{
err
=
(
sctp_errhdr_t
*
)(
ch
+
sizeof
(
sctp_chunkhdr_t
));
if
(
SCTP_ERROR_STALE_COOKIE
==
err
->
cause
)
goto
discard
;
...
...
@@ -485,12 +618,12 @@ void __sctp_unhash_established(sctp_association_t *asoc)
/* Look up an association. */
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
laddr
,
const
union
sctp_addr
*
paddr
,
s
ctp_transport_
t
**
transportp
)
s
truct
sctp_transpor
t
**
transportp
)
{
sctp_hashbucket_t
*
head
;
sctp_endpoint_common_t
*
epb
;
sctp_association_t
*
asoc
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
int
hash
;
/* Optimize here for direct hit, only listening connections can
...
...
@@ -521,7 +654,7 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
/* Look up an association. BH-safe. */
sctp_association_t
*
sctp_lookup_association
(
const
union
sctp_addr
*
laddr
,
const
union
sctp_addr
*
paddr
,
s
ctp_transport_
t
**
transportp
)
s
truct
sctp_transpor
t
**
transportp
)
{
sctp_association_t
*
asoc
;
...
...
@@ -537,7 +670,7 @@ int sctp_has_association(const union sctp_addr *laddr,
const
union
sctp_addr
*
paddr
)
{
sctp_association_t
*
asoc
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
if
((
asoc
=
sctp_lookup_association
(
laddr
,
paddr
,
&
transport
)))
{
sock_put
(
asoc
->
base
.
sk
);
...
...
@@ -567,7 +700,7 @@ int sctp_has_association(const union sctp_addr *laddr,
*
*/
static
sctp_association_t
*
__sctp_rcv_init_lookup
(
struct
sk_buff
*
skb
,
const
union
sctp_addr
*
laddr
,
s
ctp_transport_
t
**
transportp
)
const
union
sctp_addr
*
laddr
,
s
truct
sctp_transpor
t
**
transportp
)
{
sctp_association_t
*
asoc
;
union
sctp_addr
addr
;
...
...
@@ -627,7 +760,7 @@ static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
sctp_association_t
*
__sctp_rcv_lookup
(
struct
sk_buff
*
skb
,
const
union
sctp_addr
*
paddr
,
const
union
sctp_addr
*
laddr
,
s
ctp_transport_
t
**
transportp
)
s
truct
sctp_transpor
t
**
transportp
)
{
sctp_association_t
*
asoc
;
...
...
net/sctp/ipv6.c
View file @
a0065b2f
...
...
@@ -98,43 +98,22 @@ static inline void sctp_v6_err(struct sk_buff *skb,
}
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
static
inline
int
sctp_v6_xmit
(
struct
sk_buff
*
skb
)
static
inline
int
sctp_v6_xmit
(
struct
sk_buff
*
skb
,
struct
sctp_transport
*
transport
,
int
ipfragok
)
{
struct
sock
*
sk
=
skb
->
sk
;
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
flowi
fl
;
struct
dst_entry
*
dst
=
skb
->
dst
;
struct
rt6_info
*
rt6
=
(
struct
rt6_info
*
)
dst
;
struct
in6_addr
saddr
;
int
err
;
fl
.
proto
=
sk
->
protocol
;
fl
.
fl6_dst
=
&
rt6
->
rt6i_dst
.
addr
;
/* FIXME: Currently, ip6_route_output() doesn't fill in the source
* address in the returned route entry. So we call ipv6_get_saddr()
* to get an appropriate source address. It is possible that this address
* may not be part of the bind address list of the association.
* Once ip6_route_ouput() is fixed so that it returns a route entry
* with an appropriate source address, the following if condition can
* be removed. With ip6_route_output() returning a source address filled
* route entry, sctp_transport_route() can do real source address
* selection for v6.
/* Fill in the dest address from the route entry passed with the skb
* and the source address from the transport.
*/
if
(
ipv6_addr_any
(
&
rt6
->
rt6i_src
.
addr
))
{
err
=
ipv6_get_saddr
(
dst
,
fl
.
fl6_dst
,
&
saddr
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: No saddr available for "
"DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
__FUNCTION__
,
NIP6
(
fl
.
fl6_src
));
return
err
;
}
fl
.
fl6_src
=
&
saddr
;
}
else
{
fl
.
fl6_src
=
&
rt6
->
rt6i_src
.
addr
;
}
fl
.
fl6_dst
=
&
rt6
->
rt6i_dst
.
addr
;
fl
.
fl6_src
=
&
transport
->
saddr
.
v6
.
sin6_addr
;
fl
.
fl6_flowlabel
=
np
->
flow_label
;
IP6_ECN_flow_xmit
(
sk
,
fl
.
fl6_flowlabel
);
...
...
@@ -147,20 +126,26 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
fl
.
nl_u
.
ip6_u
.
daddr
=
rt0
->
addr
;
}
SCTP_DEBUG_PRINTK
(
"%s: skb:%p, len:%d, "
"src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
"dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
__FUNCTION__
,
skb
,
skb
->
len
,
NIP6
(
fl
.
fl6_src
),
NIP6
(
fl
.
fl6_dst
));
return
ip6_xmit
(
sk
,
skb
,
&
fl
,
np
->
opt
);
}
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
struct
dst_entry
*
sctp_v6_get_dst
(
union
sctp_addr
*
daddr
,
struct
dst_entry
*
sctp_v6_get_dst
(
sctp_association_t
*
asoc
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
)
{
struct
dst_entry
*
dst
;
struct
flowi
fl
=
{
.
nl_u
=
{
.
ip6_u
=
{
.
daddr
=
&
daddr
->
v6
.
sin6_addr
,
}
}
};
SCTP_DEBUG_PRINTK
(
"%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
,
__FUNCTION__
,
NIP6
(
fl
.
fl6_dst
));
...
...
@@ -181,12 +166,96 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr,
NIP6
(
&
rt
->
rt6i_dst
.
addr
),
NIP6
(
&
rt
->
rt6i_src
.
addr
));
}
else
{
SCTP_DEBUG_PRINTK
(
"NO ROUTE
\n
"
);
return
NULL
;
}
return
dst
;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
* addresses.
*/
static
inline
int
sctp_v6_addr_match_len
(
union
sctp_addr
*
s1
,
union
sctp_addr
*
s2
)
{
struct
in6_addr
*
a1
=
&
s1
->
v6
.
sin6_addr
;
struct
in6_addr
*
a2
=
&
s2
->
v6
.
sin6_addr
;
int
i
,
j
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
__u32
a1xora2
;
a1xora2
=
a1
->
s6_addr32
[
i
]
^
a2
->
s6_addr32
[
i
];
if
((
j
=
fls
(
ntohl
(
a1xora2
))))
return
(
i
*
32
+
32
-
j
);
}
return
(
i
*
32
);
}
/* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list.
*/
void
sctp_v6_get_saddr
(
sctp_association_t
*
asoc
,
struct
dst_entry
*
dst
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
)
{
sctp_bind_addr_t
*
bp
;
rwlock_t
*
addr_lock
;
struct
sockaddr_storage_list
*
laddr
;
struct
list_head
*
pos
;
sctp_scope_t
scope
;
union
sctp_addr
*
baddr
=
NULL
;
__u8
matchlen
=
0
;
__u8
bmatchlen
;
SCTP_DEBUG_PRINTK
(
"%s: asoc:%p dst:%p "
"daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
,
__FUNCTION__
,
asoc
,
dst
,
NIP6
(
&
daddr
->
v6
.
sin6_addr
));
if
(
!
asoc
)
{
ipv6_get_saddr
(
dst
,
&
daddr
->
v6
.
sin6_addr
,
&
saddr
->
v6
.
sin6_addr
);
SCTP_DEBUG_PRINTK
(
"saddr from ipv6_get_saddr: "
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
NIP6
(
&
saddr
->
v6
.
sin6_addr
));
return
;
}
scope
=
sctp_scope
(
daddr
);
bp
=
&
asoc
->
base
.
bind_addr
;
addr_lock
=
&
asoc
->
base
.
addr_lock
;
/* Go through the bind address list and find the best source address
* that matches the scope of the destination address.
*/
sctp_read_lock
(
addr_lock
);
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
((
laddr
->
a
.
sa
.
sa_family
==
AF_INET6
)
&&
(
scope
<=
sctp_scope
(
&
laddr
->
a
)))
{
bmatchlen
=
sctp_v6_addr_match_len
(
daddr
,
&
laddr
->
a
);
if
(
!
baddr
||
(
matchlen
<
bmatchlen
))
{
baddr
=
&
laddr
->
a
;
matchlen
=
bmatchlen
;
}
}
}
if
(
baddr
)
{
memcpy
(
saddr
,
baddr
,
sizeof
(
union
sctp_addr
));
SCTP_DEBUG_PRINTK
(
"saddr: "
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
NIP6
(
&
saddr
->
v6
.
sin6_addr
));
}
else
{
printk
(
KERN_ERR
"%s: asoc:%p Could not find a valid source "
"address for the "
"dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
__FUNCTION__
,
asoc
,
NIP6
(
&
daddr
->
v6
.
sin6_addr
));
}
sctp_read_unlock
(
addr_lock
);
}
/* Make a copy of all potential local addresses. */
static
void
sctp_v6_copy_addrlist
(
struct
list_head
*
addrlist
,
struct
net_device
*
dev
)
...
...
@@ -257,10 +326,12 @@ static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk)
}
/* Initialize a sctp_addr from a dst_entry. */
static
void
sctp_v6_dst_saddr
(
union
sctp_addr
*
addr
,
struct
dst_entry
*
dst
)
static
void
sctp_v6_dst_saddr
(
union
sctp_addr
*
addr
,
struct
dst_entry
*
dst
,
unsigned
short
port
)
{
struct
rt6_info
*
rt
=
(
struct
rt6_info
*
)
dst
;
addr
->
sa
.
sa_family
=
AF_INET6
;
addr
->
v6
.
sin6_port
=
port
;
ipv6_addr_copy
(
&
addr
->
v6
.
sin6_addr
,
&
rt
->
rt6i_src
.
addr
);
}
...
...
@@ -527,10 +598,11 @@ static struct inet6_protocol sctpv6_protocol = {
};
static
struct
sctp_af
sctp_ipv6_specific
=
{
.
queue_xmit
=
sctp_v6_xmit
,
.
sctp_xmit
=
sctp_v6_xmit
,
.
setsockopt
=
ipv6_setsockopt
,
.
getsockopt
=
ipv6_getsockopt
,
.
get_dst
=
sctp_v6_get_dst
,
.
get_saddr
=
sctp_v6_get_saddr
,
.
copy_addrlist
=
sctp_v6_copy_addrlist
,
.
from_skb
=
sctp_v6_from_skb
,
.
from_sk
=
sctp_v6_from_sk
,
...
...
net/sctp/objcnt.c
View file @
a0065b2f
...
...
@@ -54,6 +54,7 @@ SCTP_DBG_OBJCNT(assoc);
SCTP_DBG_OBJCNT
(
bind_addr
);
SCTP_DBG_OBJCNT
(
chunk
);
SCTP_DBG_OBJCNT
(
addr
);
SCTP_DBG_OBJCNT
(
ssnmap
);
/* An array to make it easy to pretty print the debug information
* to the proc fs.
...
...
@@ -66,6 +67,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY
(
chunk
),
SCTP_DBG_OBJCNT_ENTRY
(
bind_addr
),
SCTP_DBG_OBJCNT_ENTRY
(
addr
),
SCTP_DBG_OBJCNT_ENTRY
(
ssnmap
),
};
/* Callback from procfs to read out objcount information.
...
...
net/sctp/output.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2003
International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -62,7 +62,6 @@
#include <net/sctp/sm.h>
/* Forward declarations for private helpers. */
__u32
count_crc
(
__u8
*
ptr
,
__u16
count
);
static
void
sctp_packet_reset
(
sctp_packet_t
*
packet
);
static
sctp_xmit_t
sctp_packet_append_data
(
sctp_packet_t
*
packet
,
sctp_chunk_t
*
chunk
);
...
...
@@ -81,6 +80,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
packet
->
ecn_capable
=
ecn_capable
;
packet
->
get_prepend_chunk
=
prepend_handler
;
packet
->
has_cookie_echo
=
0
;
packet
->
ipfragok
=
0
;
/* We might need to call the prepend_handler right away. */
if
(
packet_empty
)
...
...
@@ -90,7 +90,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
/* Initialize the packet structure. */
sctp_packet_t
*
sctp_packet_init
(
sctp_packet_t
*
packet
,
s
ctp_transport_
t
*
transport
,
s
truct
sctp_transpor
t
*
transport
,
__u16
sport
,
__u16
dport
)
{
...
...
@@ -102,6 +102,7 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
packet
->
ecn_capable
=
0
;
packet
->
get_prepend_chunk
=
NULL
;
packet
->
has_cookie_echo
=
0
;
packet
->
ipfragok
=
0
;
packet
->
malloced
=
0
;
sctp_packet_reset
(
packet
);
return
packet
;
...
...
@@ -193,6 +194,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
* transmit and rely on IP
* fragmentation.
*/
packet
->
ipfragok
=
1
;
goto
append
;
}
}
else
{
/* !packet_empty */
...
...
@@ -228,13 +230,13 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
}
/* All packets are sent to the network through this function from
* sctp_
push_outqueue
().
* sctp_
outq_tail
().
*
* The return value is a normal kernel error return value.
*/
int
sctp_packet_transmit
(
sctp_packet_t
*
packet
)
{
s
ctp_transport_
t
*
transport
=
packet
->
transport
;
s
truct
sctp_transpor
t
*
transport
=
packet
->
transport
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
struct
sctphdr
*
sh
;
__u32
crc32
;
...
...
@@ -358,22 +360,14 @@ int sctp_packet_transmit(sctp_packet_t *packet)
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32
=
count_crc
((
__u8
*
)
sh
,
nskb
->
len
);
crc32
=
sctp_start_cksum
((
__u8
*
)
sh
,
nskb
->
len
);
crc32
=
sctp_end_cksum
(
crc32
);
/* 3) Put the resultant value into the checksum field in the
* common header, and leave the rest of the bits unchanged.
*/
sh
->
checksum
=
htonl
(
crc32
);
/* FIXME: Delete the rest of this switch statement once phase 2
* of address selection (ipv6 support) drops in.
*/
switch
(
transport
->
ipaddr
.
sa
.
sa_family
)
{
case
AF_INET6
:
SCTP_V6
(
inet6_sk
(
sk
)
->
daddr
=
transport
->
ipaddr
.
v6
.
sin6_addr
;)
break
;
};
/* IP layer ECN support
* From RFC 2481
* "The ECN-Capable Transport (ECT) bit would be set by the
...
...
@@ -423,8 +417,10 @@ int sctp_packet_transmit(sctp_packet_t *packet)
}
dst
=
transport
->
dst
;
if
(
!
dst
||
dst
->
obsolete
)
{
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if
(
!
dst
||
(
dst
->
obsolete
>
1
))
{
sctp_transport_route
(
transport
,
NULL
,
sctp_sk
(
sk
));
sctp_assoc_sync_pmtu
(
asoc
);
}
nskb
->
dst
=
dst_clone
(
transport
->
dst
);
...
...
@@ -433,14 +429,22 @@ int sctp_packet_transmit(sctp_packet_t *packet)
SCTP_DEBUG_PRINTK
(
"***sctp_transmit_packet*** skb length %d
\n
"
,
nskb
->
len
);
(
*
transport
->
af_specific
->
queue_xmit
)(
nskb
);
(
*
transport
->
af_specific
->
sctp_xmit
)(
nskb
,
transport
,
packet
->
ipfragok
);
out:
packet
->
size
=
SCTP_IP_OVERHEAD
;
return
err
;
no_route:
kfree_skb
(
nskb
);
IP_INC_STATS_BH
(
IpOutNoRoutes
);
err
=
-
EHOSTUNREACH
;
/* FIXME: Returning the 'err' will effect all the associations
* associated with a socket, although only one of the paths of the
* association is unreachable.
* The real failure of a transport or association can be passed on
* to the user via notifications. So setting this error may not be
* required.
*/
/* err = -EHOSTUNREACH; */
goto
out
;
}
...
...
@@ -473,7 +477,7 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
{
sctp_xmit_t
retval
=
SCTP_XMIT_OK
;
size_t
datasize
,
rwnd
,
inflight
;
s
ctp_transport_
t
*
transport
=
packet
->
transport
;
s
truct
sctp_transpor
t
*
transport
=
packet
->
transport
;
__u32
max_burst_bytes
;
/* RFC 2960 6.1 Transmission of DATA Chunks
...
...
net/sctp/outqueue.c
View file @
a0065b2f
...
...
@@ -2,11 +2,11 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-200
2
International Business Machines Corp.
* Copyright (c) 2001-200
3
International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* These functions implement the
outqueue
class. The outqueue handles
* These functions implement the
sctp_outq
class. The outqueue handles
* bundling and queueing of outgoing SCTP chunks.
*
* The SCTP reference implementation is free software;
...
...
@@ -56,30 +56,30 @@
/* Declare internal functions here. */
static
int
sctp_acked
(
sctp_sackhdr_t
*
sack
,
__u32
tsn
);
static
void
sctp_check_transmitted
(
s
ctp_outqueue_t
*
q
,
static
void
sctp_check_transmitted
(
s
truct
sctp_outq
*
q
,
struct
list_head
*
transmitted_queue
,
s
ctp_transport_
t
*
transport
,
s
truct
sctp_transpor
t
*
transport
,
sctp_sackhdr_t
*
sack
,
__u32
highest_new_tsn
);
/* Generate a new outqueue. */
s
ctp_outqueue_t
*
sctp_outqueue
_new
(
sctp_association_t
*
asoc
)
s
truct
sctp_outq
*
sctp_outq
_new
(
sctp_association_t
*
asoc
)
{
s
ctp_outqueue_t
*
q
;
s
truct
sctp_outq
*
q
;
q
=
t_new
(
s
ctp_outqueue_t
,
GFP_KERNEL
);
q
=
t_new
(
s
truct
sctp_outq
,
GFP_KERNEL
);
if
(
q
)
{
sctp_outq
ueue
_init
(
asoc
,
q
);
sctp_outq_init
(
asoc
,
q
);
q
->
malloced
=
1
;
}
return
q
;
}
/* Initialize an existing
SCTP_outqueue
. This does the boring stuff.
/* Initialize an existing
sctp_outq
. This does the boring stuff.
* You still need to define handlers if you really want to DO
* something with this structure...
*/
void
sctp_outq
ueue_init
(
sctp_association_t
*
asoc
,
sctp_outqueue_t
*
q
)
void
sctp_outq
_init
(
sctp_association_t
*
asoc
,
struct
sctp_outq
*
q
)
{
q
->
asoc
=
asoc
;
skb_queue_head_init
(
&
q
->
out
);
...
...
@@ -102,15 +102,15 @@ void sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q)
/* Free the outqueue structure and any related pending chunks.
* FIXME: Add SEND_FAILED support.
*/
void
sctp_outq
ueue_teardown
(
sctp_outqueue_t
*
q
)
void
sctp_outq
_teardown
(
struct
sctp_outq
*
q
)
{
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
struct
list_head
*
lchunk
,
*
pos
,
*
temp
;
sctp_chunk_t
*
chunk
;
/* Throw away unacknowledged chunks. */
list_for_each
(
pos
,
&
q
->
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
transport
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
while
((
lchunk
=
sctp_list_dequeue
(
&
transport
->
transmitted
)))
{
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
...
...
@@ -125,35 +125,39 @@ void sctp_outqueue_teardown(sctp_outqueue_t *q)
sctp_free_chunk
(
chunk
);
}
/* Throw away any leftover chunks. */
/* Throw away any chunks in the retransmit queue. */
list_for_each_safe
(
lchunk
,
temp
,
&
q
->
retransmit
)
{
list_del
(
lchunk
);
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
sctp_free_chunk
(
chunk
);
}
/* Throw away any leftover data chunks. */
while
((
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
&
q
->
out
)))
sctp_free_chunk
(
chunk
);
/* Throw away any leftover control chunks. */
while
((
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
&
q
->
control
)))
sctp_free_chunk
(
chunk
);
}
/* Free the outqueue structure and any related pending chunks. */
void
sctp_outq
ueue_free
(
sctp_outqueue_t
*
q
)
void
sctp_outq
_free
(
struct
sctp_outq
*
q
)
{
/* Throw away leftover chunks. */
sctp_outq
ueue
_teardown
(
q
);
sctp_outq_teardown
(
q
);
/* If we were kmalloc()'d, free the memory. */
if
(
q
->
malloced
)
kfree
(
q
);
}
/* Transmit any pending partial chunks. */
void
sctp_force_outqueue
(
sctp_outqueue_t
*
q
)
{
/* Do we really need this? */
/* BUG */
}
/* Put a new chunk in an SCTP_outqueue. */
int
sctp_push_outqueue
(
sctp_outqueue_t
*
q
,
sctp_chunk_t
*
chunk
)
/* Put a new chunk in an sctp_outq. */
int
sctp_outq_tail
(
struct
sctp_outq
*
q
,
sctp_chunk_t
*
chunk
)
{
int
error
=
0
;
SCTP_DEBUG_PRINTK
(
"sctp_
push_outqueue
(%p, %p[%s])
\n
"
,
SCTP_DEBUG_PRINTK
(
"sctp_
outq_tail
(%p, %p[%s])
\n
"
,
q
,
chunk
,
chunk
&&
chunk
->
chunk_hdr
?
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
))
:
"Illegal Chunk"
);
...
...
@@ -184,8 +188,7 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
default:
SCTP_DEBUG_PRINTK
(
"outqueueing (%p, %p[%s])
\n
"
,
q
,
chunk
,
chunk
&&
chunk
->
chunk_hdr
?
q
,
chunk
,
chunk
&&
chunk
->
chunk_hdr
?
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
))
:
"Illegal Chunk"
);
...
...
@@ -193,13 +196,13 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
q
->
empty
=
0
;
break
;
};
}
else
{
}
else
skb_queue_tail
(
&
q
->
control
,
(
struct
sk_buff
*
)
chunk
);
}
if
(
error
<
0
)
return
error
;
error
=
sctp_
flush_outqueue
(
q
,
0
);
error
=
sctp_
outq_flush
(
q
,
0
);
return
error
;
}
...
...
@@ -207,7 +210,7 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
/* Insert a chunk into the retransmit queue. Chunks on the retransmit
* queue are kept in order, based on the TSNs.
*/
void
sctp_retransmit_insert
(
struct
list_head
*
tlchunk
,
s
ctp_outqueue_t
*
q
)
void
sctp_retransmit_insert
(
struct
list_head
*
tlchunk
,
s
truct
sctp_outq
*
q
)
{
struct
list_head
*
rlchunk
;
sctp_chunk_t
*
tchunk
,
*
rchunk
;
...
...
@@ -232,13 +235,13 @@ void sctp_retransmit_insert(struct list_head *tlchunk, sctp_outqueue_t *q)
}
/* Mark all the eligible packets on a transport for retransmission. */
void
sctp_retransmit_mark
(
sctp_outqueue_t
*
q
,
sctp_transport_t
*
transport
,
void
sctp_retransmit_mark
(
struct
sctp_outq
*
q
,
struct
sctp_transport
*
transport
,
__u8
fast_retransmit
)
{
struct
list_head
*
lchunk
,
*
ltemp
;
sctp_chunk_t
*
chunk
;
/* Walk through the specified transmitted queue. */
list_for_each_safe
(
lchunk
,
ltemp
,
&
transport
->
transmitted
)
{
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
...
...
@@ -246,8 +249,9 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
/* If we are doing retransmission due to a fast retransmit,
* only the chunk's that are marked for fast retransmit
* should be added to the retransmit queue. If we are doing
* retransmission due to a timeout, only the chunks that are
* not yet acked should be added to the retransmit queue.
* retransmission due to a timeout or pmtu discovery, only the
* chunks that are not yet acked should be added to the
* retransmit queue.
*/
if
((
fast_retransmit
&&
chunk
->
fast_retransmit
)
||
(
!
fast_retransmit
&&
!
chunk
->
tsn_gap_acked
))
{
...
...
@@ -302,20 +306,27 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
/* Mark all the eligible packets on a transport for retransmission and force
* one packet out.
*/
void
sctp_retransmit
(
s
ctp_outqueue_t
*
q
,
sctp_transport_
t
*
transport
,
__u8
fast_retransmit
)
void
sctp_retransmit
(
s
truct
sctp_outq
*
q
,
struct
sctp_transpor
t
*
transport
,
sctp_retransmit_reason_t
reason
)
{
int
error
=
0
;
__u8
fast_retransmit
=
0
;
if
(
fast_retransmit
)
{
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_FAST_RTX
);
}
else
{
switch
(
reason
)
{
case
SCTP_RETRANSMIT_T3_RTX
:
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_T3_RTX
);
break
;
case
SCTP_RETRANSMIT_FAST_RTX
:
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_FAST_RTX
);
fast_retransmit
=
1
;
break
;
default:
break
;
}
sctp_retransmit_mark
(
q
,
transport
,
fast_retransmit
);
error
=
sctp_
flush_outqueue
(
q
,
/* rtx_timeout */
1
);
error
=
sctp_
outq_flush
(
q
,
/* rtx_timeout */
1
);
if
(
error
)
q
->
asoc
->
base
.
sk
->
err
=
-
error
;
...
...
@@ -323,18 +334,18 @@ void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
/*
* Transmit DATA chunks on the retransmit queue. Upon return from
* sctp_
flush_retran_queue
() the packet 'pkt' may contain chunks which
* sctp_
outq_flush_rtx
() the packet 'pkt' may contain chunks which
* need to be transmitted by the caller.
* We assume that pkt->transport has already been set.
*
* The return value is a normal kernel error return value.
*/
static
int
sctp_
flush_retran_queue
(
sctp_outqueue_t
*
q
,
sctp_packet_t
*
pkt
,
static
int
sctp_
outq_flush_rtx
(
struct
sctp_outq
*
q
,
sctp_packet_t
*
pkt
,
int
rtx_timeout
,
int
*
start_timer
)
{
struct
list_head
*
lqueue
;
struct
list_head
*
lchunk
;
s
ctp_transport_
t
*
transport
=
pkt
->
transport
;
s
truct
sctp_transpor
t
*
transport
=
pkt
->
transport
;
sctp_xmit_t
status
;
sctp_chunk_t
*
chunk
;
sctp_association_t
*
asoc
;
...
...
@@ -374,6 +385,18 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
continue;
}
#endif
/* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the
* way and into a 'transmitted' queue and skip to the
* next chunk.
*/
if
(
chunk
->
tsn_gap_acked
)
{
list_add_tail
(
lchunk
,
&
transport
->
transmitted
);
lchunk
=
sctp_list_dequeue
(
lqueue
);
continue
;
}
/* Attempt to append this chunk to the packet. */
status
=
(
*
q
->
append_output
)(
pkt
,
chunk
);
...
...
@@ -427,10 +450,10 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
* queue. 'pos' points to the next chunk in the output queue after the
* chunk that is currently in the process of fragmentation.
*/
void
sctp_xmit_frag
(
s
ctp_outqueue_t
*
q
,
struct
sk_buff
*
pos
,
void
sctp_xmit_frag
(
s
truct
sctp_outq
*
q
,
struct
sk_buff
*
pos
,
sctp_packet_t
*
packet
,
sctp_chunk_t
*
frag
,
__u32
tsn
)
{
s
ctp_transport_
t
*
transport
=
packet
->
transport
;
s
truct
sctp_transpor
t
*
transport
=
packet
->
transport
;
struct
sk_buff_head
*
queue
=
&
q
->
out
;
sctp_xmit_t
status
;
int
error
;
...
...
@@ -503,7 +526,7 @@ void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos,
* The argument 'frag' point to the first fragment and it holds the list
* of all the other fragments in the 'frag_list' field.
*/
void
sctp_xmit_fragmented_chunks
(
s
ctp_outqueue_t
*
q
,
sctp_packet_t
*
packet
,
void
sctp_xmit_fragmented_chunks
(
s
truct
sctp_outq
*
q
,
sctp_packet_t
*
packet
,
sctp_chunk_t
*
frag
)
{
sctp_association_t
*
asoc
=
frag
->
asoc
;
...
...
@@ -548,6 +571,7 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
sctp_chunk_t
*
first_frag
,
*
frag
;
struct
list_head
*
frag_list
;
int
nfrags
;
__u8
old_flags
,
flags
;
/* nfrags = no. of max size fragments + any smaller last fragment. */
nfrags
=
((
chunk_data_len
/
max_frag_data_len
)
+
...
...
@@ -556,13 +580,20 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
/* Start of the data in the chunk. */
data_ptr
+=
sizeof
(
sctp_datahdr_t
);
/* Are we fragmenting an already fragmented large message? */
old_flags
=
chunk
->
chunk_hdr
->
flags
;
if
(
old_flags
&
SCTP_DATA_FIRST_FRAG
)
flags
=
SCTP_DATA_FIRST_FRAG
;
else
flags
=
SCTP_DATA_MIDDLE_FRAG
;
/* Make the first fragment. */
first_frag
=
sctp_make_datafrag
(
asoc
,
sinfo
,
max_frag_data_len
,
data_ptr
,
SCTP_DATA_FIRST_FRAG
,
ssn
);
data_ptr
,
flags
,
ssn
);
if
(
!
first_frag
)
goto
err
;
first_frag
->
has_ssn
=
1
;
/* All the fragments are added to the frag_list of the first chunk. */
frag_list
=
&
first_frag
->
frag_list
;
...
...
@@ -576,7 +607,7 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
ssn
);
if
(
!
frag
)
goto
err
;
frag
->
has_ssn
=
1
;
/* Add the middle fragment to the first fragment's
* frag_list.
*/
...
...
@@ -586,11 +617,17 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
data_ptr
+=
max_frag_data_len
;
}
if
(
old_flags
&
SCTP_DATA_LAST_FRAG
)
flags
=
SCTP_DATA_LAST_FRAG
;
else
flags
=
SCTP_DATA_MIDDLE_FRAG
;
/* Make the last fragment. */
frag
=
sctp_make_datafrag
(
asoc
,
sinfo
,
chunk_data_len
,
data_ptr
,
SCTP_DATA_LAST_FRAG
,
ssn
);
flags
,
ssn
);
if
(
!
frag
)
goto
err
;
frag
->
has_ssn
=
1
;
/* Add the last fragment to the first fragment's frag_list. */
list_add_tail
(
&
frag
->
frag_list
,
frag_list
);
...
...
@@ -620,7 +657,7 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
}
/*
* sctp_
flush_outqueue
- Try to flush an outqueue.
* sctp_
outq_flush
- Try to flush an outqueue.
*
* Description: Send everything in q which we legally can, subject to
* congestion limitations.
...
...
@@ -629,7 +666,7 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
* locking concerns must be made. Today we use the sock lock to protect
* this function.
*/
int
sctp_
flush_outqueue
(
sctp_outqueue_t
*
q
,
int
rtx_timeout
)
int
sctp_
outq_flush
(
struct
sctp_outq
*
q
,
int
rtx_timeout
)
{
sctp_packet_t
*
packet
;
sctp_packet_t
singleton
;
...
...
@@ -642,13 +679,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
sctp_packet_phandler_t
*
s_ecne_handler
=
NULL
;
sctp_packet_phandler_t
*
ecne_handler
=
NULL
;
struct
sk_buff_head
*
queue
;
s
ctp_transport_
t
*
transport
=
NULL
;
s
ctp_transport_
t
*
new_transport
;
s
truct
sctp_transpor
t
*
transport
=
NULL
;
s
truct
sctp_transpor
t
*
new_transport
;
sctp_chunk_t
*
chunk
;
sctp_xmit_t
status
;
int
error
=
0
;
int
start_timer
=
0
;
sctp_ulpevent_t
*
event
;
/* These transports have chunks to send. */
struct
list_head
transport_list
;
...
...
@@ -783,10 +819,8 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
(
*
q
->
config_output
)(
packet
,
vtag
,
ecn_capable
,
ecne_handler
);
retran:
error
=
sctp_flush_retran_queue
(
q
,
packet
,
rtx_timeout
,
&
start_timer
);
error
=
sctp_outq_flush_rtx
(
q
,
packet
,
rtx_timeout
,
&
start_timer
);
if
(
start_timer
)
sctp_transport_reset_timers
(
transport
);
...
...
@@ -813,15 +847,14 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/
if
(
chunk
->
sinfo
.
sinfo_stream
>=
asoc
->
c
.
sinit_num_ostreams
)
{
struct
sctp_ulpevent
*
ev
;
/* Generate a SEND FAILED event. */
ev
ent
=
sctp_ulpevent_make_send_failed
(
asoc
,
ev
=
sctp_ulpevent_make_send_failed
(
asoc
,
chunk
,
SCTP_DATA_UNSENT
,
SCTP_ERROR_INV_STRM
,
GFP_ATOMIC
);
if
(
event
)
{
sctp_ulpqueue_tail_event
(
&
asoc
->
ulpq
,
event
);
}
SCTP_ERROR_INV_STRM
,
GFP_ATOMIC
);
if
(
ev
)
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
ev
);
/* Free the chunk. This chunk is not on any
* list yet, just free it.
...
...
@@ -830,6 +863,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
continue
;
}
/* Now do delayed assignment of SSN. This will
* probably change again when we start supporting
* large (> approximately 2^16) size messages.
*/
sctp_chunk_assign_ssn
(
chunk
);
/* If there is a specified transport, use it.
* Otherwise, we want to use the active path.
*/
...
...
@@ -878,7 +917,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_
outq_flush
: could "
"not transmit TSN: 0x%x, status: %d
\n
"
,
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
),
status
);
...
...
@@ -952,8 +991,9 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
* --xguo
*/
while
((
ltransport
=
sctp_list_dequeue
(
&
transport_list
))
!=
NULL
)
{
sctp_transport_t
*
t
=
list_entry
(
ltransport
,
sctp_transport_t
,
send_ready
);
struct
sctp_transport
*
t
=
list_entry
(
ltransport
,
struct
sctp_transport
,
send_ready
);
if
(
t
!=
transport
)
transport
=
t
;
...
...
@@ -966,12 +1006,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
}
/* Set the various output handling callbacks. */
int
sctp_outq
ueue_set_output_handlers
(
sctp_outqueue_t
*
q
,
sctp_outq
ueue
_ohandler_init_t
init
,
sctp_outq
ueue
_ohandler_config_t
config
,
sctp_outq
ueue
_ohandler_t
append
,
sctp_outq
ueue
_ohandler_t
build
,
sctp_outq
ueue
_ohandler_force_t
force
)
int
sctp_outq
_set_output_handlers
(
struct
sctp_outq
*
q
,
sctp_outq_ohandler_init_t
init
,
sctp_outq_ohandler_config_t
config
,
sctp_outq_ohandler_t
append
,
sctp_outq_ohandler_t
build
,
sctp_outq_ohandler_force_t
force
)
{
q
->
init_output
=
init
;
q
->
config_output
=
config
;
...
...
@@ -1005,7 +1045,7 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
sctp_association_t
*
asoc
)
{
struct
list_head
*
ltransport
,
*
lchunk
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_chunk_t
*
chunk
;
__u32
highest_new_tsn
,
tsn
;
struct
list_head
*
transport_list
=
&
asoc
->
peer
.
transport_addr_list
;
...
...
@@ -1013,7 +1053,7 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
highest_new_tsn
=
ntohl
(
sack
->
cum_tsn_ack
);
list_for_each
(
ltransport
,
transport_list
)
{
transport
=
list_entry
(
ltransport
,
s
ctp_transport_
t
,
transport
=
list_entry
(
ltransport
,
s
truct
sctp_transpor
t
,
transports
);
list_for_each
(
lchunk
,
&
transport
->
transmitted
)
{
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
...
...
@@ -1032,13 +1072,13 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
/* This is where we REALLY process a SACK.
*
* Process the
sack
against the outqueue. Mostly, this just frees
* Process the
SACK
against the outqueue. Mostly, this just frees
* things off the transmitted queue.
*/
int
sctp_
sack_outqueue
(
sctp_outqueue_t
*
q
,
sctp_sackhdr_t
*
sack
)
int
sctp_
outq_sack
(
struct
sctp_outq
*
q
,
sctp_sackhdr_t
*
sack
)
{
sctp_association_t
*
asoc
=
q
->
asoc
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_chunk_t
*
tchunk
;
struct
list_head
*
lchunk
,
*
transport_list
,
*
pos
;
sctp_sack_variable_t
*
frags
=
sack
->
variable
;
...
...
@@ -1074,7 +1114,8 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
* This is a MASSIVE candidate for optimization.
*/
list_for_each
(
pos
,
transport_list
)
{
transport
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
sctp_check_transmitted
(
q
,
&
transport
->
transmitted
,
transport
,
sack
,
highest_new_tsn
);
}
...
...
@@ -1127,7 +1168,8 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
goto
finish
;
list_for_each
(
pos
,
transport_list
)
{
transport
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
q
->
empty
=
q
->
empty
&&
list_empty
(
&
transport
->
transmitted
);
if
(
!
q
->
empty
)
goto
finish
;
...
...
@@ -1139,7 +1181,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
}
/* Is the outqueue empty? */
int
sctp_outq
ueue_is_empty
(
const
sctp_outqueue_t
*
q
)
int
sctp_outq
_is_empty
(
const
struct
sctp_outq
*
q
)
{
return
q
->
empty
;
}
...
...
@@ -1161,9 +1203,9 @@ int sctp_outqueue_is_empty(const sctp_outqueue_t *q)
* transmitted_queue, we print a range: SACKED: TSN1-TSN2, TSN3, TSN4-TSN5.
* KEPT TSN6-TSN7, etc.
*/
static
void
sctp_check_transmitted
(
s
ctp_outqueue_t
*
q
,
static
void
sctp_check_transmitted
(
s
truct
sctp_outq
*
q
,
struct
list_head
*
transmitted_queue
,
s
ctp_transport_
t
*
transport
,
s
truct
sctp_transpor
t
*
transport
,
sctp_sackhdr_t
*
sack
,
__u32
highest_new_tsn_in_sack
)
{
...
...
@@ -1494,7 +1536,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
if
(
transport
)
{
if
(
do_fast_retransmit
)
sctp_retransmit
(
q
,
transport
,
do_fast_retransmit
);
sctp_retransmit
(
q
,
transport
,
SCTP_RETRANSMIT_FAST_RTX
);
SCTP_DEBUG_PRINTK
(
"%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d
\n
"
,
...
...
net/sctp/primitive.c
View file @
a0065b2f
...
...
@@ -203,23 +203,3 @@ DECLARE_PRIMITIVE(SEND);
*/
DECLARE_PRIMITIVE
(
REQUESTHEARTBEAT
);
/* COMMENT BUG. Find out where this is mentioned in the spec. */
int
sctp_other_icmp_unreachfrag
(
sctp_association_t
*
asoc
,
void
*
arg
)
{
int
error
=
0
;
sctp_event_t
event_type
;
sctp_subtype_t
subtype
;
sctp_state_t
state
;
sctp_endpoint_t
*
ep
;
event_type
=
SCTP_EVENT_T_OTHER
;
subtype
=
SCTP_ST_OTHER
(
SCTP_EVENT_ICMP_UNREACHFRAG
);
state
=
asoc
?
asoc
->
state
:
SCTP_STATE_CLOSED
;
ep
=
asoc
?
asoc
->
ep
:
NULL
;
error
=
sctp_do_sm
(
event_type
,
subtype
,
state
,
ep
,
asoc
,
arg
,
GFP_ATOMIC
);
return
error
;
}
net/sctp/protocol.c
View file @
a0065b2f
...
...
@@ -82,7 +82,7 @@ struct sock *sctp_get_ctl_sock(void)
}
/* Set up the proc fs entry for the SCTP protocol. */
void
sctp_proc_init
(
void
)
__init
void
sctp_proc_init
(
void
)
{
if
(
!
proc_net_sctp
)
{
struct
proc_dir_entry
*
ent
;
...
...
@@ -223,37 +223,6 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
return
error
;
}
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
struct
dst_entry
*
sctp_v4_get_dst
(
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
)
{
struct
rtable
*
rt
;
struct
flowi
fl
;
memset
(
&
fl
,
0x0
,
sizeof
(
struct
flowi
));
fl
.
fl4_dst
=
daddr
->
v4
.
sin_addr
.
s_addr
;
fl
.
proto
=
IPPROTO_SCTP
;
if
(
saddr
)
fl
.
fl4_src
=
saddr
->
v4
.
sin_addr
.
s_addr
;
SCTP_DEBUG_PRINTK
(
"%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - "
,
__FUNCTION__
,
NIPQUAD
(
fl
.
fl4_dst
),
NIPQUAD
(
fl
.
fl4_src
));
if
(
ip_route_output_key
(
&
rt
,
&
fl
))
{
SCTP_DEBUG_PRINTK
(
"NO ROUTE
\n
"
);
return
NULL
;
}
SCTP_DEBUG_PRINTK
(
"rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u
\n
"
,
NIPQUAD
(
rt
->
rt_src
),
NIPQUAD
(
rt
->
rt_dst
));
return
&
rt
->
u
.
dst
;
}
/* Initialize a sctp_addr from in incoming skb. */
static
void
sctp_v4_from_skb
(
union
sctp_addr
*
addr
,
struct
sk_buff
*
skb
,
int
is_saddr
)
...
...
@@ -292,10 +261,12 @@ static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk)
/* Initialize a sctp_addr from a dst_entry. */
static
void
sctp_v4_dst_saddr
(
union
sctp_addr
*
saddr
,
struct
dst_entry
*
dst
)
static
void
sctp_v4_dst_saddr
(
union
sctp_addr
*
saddr
,
struct
dst_entry
*
dst
,
unsigned
short
port
)
{
struct
rtable
*
rt
=
(
struct
rtable
*
)
dst
;
saddr
->
v4
.
sin_family
=
AF_INET
;
saddr
->
v4
.
sin_port
=
port
;
saddr
->
v4
.
sin_addr
.
s_addr
=
rt
->
rt_src
;
}
...
...
@@ -394,6 +365,108 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
return
retval
;
}
/* Returns a valid dst cache entry for the given source and destination ip
* addresses. If an association is passed, trys to get a dst entry with a
* source adddress that matches an address in the bind address list.
*/
struct
dst_entry
*
sctp_v4_get_dst
(
sctp_association_t
*
asoc
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
)
{
struct
rtable
*
rt
;
struct
flowi
fl
;
sctp_bind_addr_t
*
bp
;
rwlock_t
*
addr_lock
;
struct
sockaddr_storage_list
*
laddr
;
struct
list_head
*
pos
;
struct
dst_entry
*
dst
=
NULL
;
union
sctp_addr
dst_saddr
;
memset
(
&
fl
,
0x0
,
sizeof
(
struct
flowi
));
fl
.
fl4_dst
=
daddr
->
v4
.
sin_addr
.
s_addr
;
fl
.
proto
=
IPPROTO_SCTP
;
if
(
saddr
)
fl
.
fl4_src
=
saddr
->
v4
.
sin_addr
.
s_addr
;
SCTP_DEBUG_PRINTK
(
"%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - "
,
__FUNCTION__
,
NIPQUAD
(
fl
.
fl4_dst
),
NIPQUAD
(
fl
.
fl4_src
));
if
(
!
ip_route_output_key
(
&
rt
,
&
fl
))
{
dst
=
&
rt
->
u
.
dst
;
}
/* If there is no association or if a source address is passed, no
* more validation is required.
*/
if
(
!
asoc
||
saddr
)
goto
out
;
bp
=
&
asoc
->
base
.
bind_addr
;
addr_lock
=
&
asoc
->
base
.
addr_lock
;
if
(
dst
)
{
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
sctp_read_lock
(
addr_lock
);
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
sctp_v4_dst_saddr
(
&
dst_saddr
,
dst
,
bp
->
port
);
if
(
sctp_v4_cmp_addr
(
&
dst_saddr
,
&
laddr
->
a
))
goto
out_unlock
;
}
sctp_read_unlock
(
addr_lock
);
/* None of the bound addresses match the source address of the
* dst. So release it.
*/
dst_release
(
dst
);
dst
=
NULL
;
}
/* Walk through the bind address list and try to get a dst that
* matches a bind address as the source address.
*/
sctp_read_lock
(
addr_lock
);
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
(
AF_INET
==
laddr
->
a
.
sa
.
sa_family
)
{
fl
.
fl4_src
=
laddr
->
a
.
v4
.
sin_addr
.
s_addr
;
dst
=
sctp_v4_get_dst
(
asoc
,
daddr
,
&
laddr
->
a
);
if
(
!
ip_route_output_key
(
&
rt
,
&
fl
))
{
dst
=
&
rt
->
u
.
dst
;
goto
out_unlock
;
}
}
}
out_unlock:
sctp_read_unlock
(
addr_lock
);
out:
if
(
dst
)
SCTP_DEBUG_PRINTK
(
"rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u
\n
"
,
NIPQUAD
(
rt
->
rt_dst
),
NIPQUAD
(
rt
->
rt_src
));
else
SCTP_DEBUG_PRINTK
(
"NO ROUTE
\n
"
);
return
dst
;
}
/* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine.
*/
void
sctp_v4_get_saddr
(
sctp_association_t
*
asoc
,
struct
dst_entry
*
dst
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
)
{
}
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
*/
...
...
@@ -545,6 +618,19 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return
sctp_v4_available
(
addr
);
}
/* Wrapper routine that calls the ip transmit routine. */
static
inline
int
sctp_v4_xmit
(
struct
sk_buff
*
skb
,
struct
sctp_transport
*
transport
,
int
ipfragok
)
{
SCTP_DEBUG_PRINTK
(
"%s: skb:%p, len:%d, "
"src:%u.%u.%u.%u, dst:%u.%u.%u.%u
\n
"
,
__FUNCTION__
,
skb
,
skb
->
len
,
NIPQUAD
(((
struct
rtable
*
)
skb
->
dst
)
->
rt_src
),
NIPQUAD
(((
struct
rtable
*
)
skb
->
dst
)
->
rt_dst
));
return
ip_queue_xmit
(
skb
,
ipfragok
);
}
struct
sctp_af
sctp_ipv4_specific
;
static
struct
sctp_pf
sctp_pf_inet
=
{
...
...
@@ -601,10 +687,11 @@ static struct inet_protocol sctp_protocol = {
/* IPv4 address related functions. */
struct
sctp_af
sctp_ipv4_specific
=
{
.
queue_xmit
=
ip_queue
_xmit
,
.
sctp_xmit
=
sctp_v4
_xmit
,
.
setsockopt
=
ip_setsockopt
,
.
getsockopt
=
ip_getsockopt
,
.
get_dst
=
sctp_v4_get_dst
,
.
get_saddr
=
sctp_v4_get_saddr
,
.
copy_addrlist
=
sctp_v4_copy_addrlist
,
.
from_skb
=
sctp_v4_from_skb
,
.
from_sk
=
sctp_v4_from_sk
,
...
...
@@ -688,7 +775,7 @@ static void cleanup_sctp_mibs(void)
}
/* Initialize the universe into something sensible. */
int
sctp_init
(
void
)
__init
int
sctp_init
(
void
)
{
int
i
;
int
status
=
0
;
...
...
@@ -750,13 +837,9 @@ int sctp_init(void)
/* Implementation specific variables. */
/* Initialize default stream count setup information.
* Note: today the stream accounting data structures are very
* fixed size, so one really does need to make sure that these have
* upper/lower limits when changing.
*/
sctp_proto
.
max_instreams
=
SCTP_MAX_STREAM
;
sctp_proto
.
max_outstreams
=
SCTP_MAX_STREAM
;
/* Initialize default stream count setup information. */
sctp_proto
.
max_instreams
=
SCTP_DEFAULT_INSTREAMS
;
sctp_proto
.
max_outstreams
=
SCTP_DEFAULT_OUTSTREAMS
;
/* Allocate and initialize the association hash table. */
sctp_proto
.
assoc_hashsize
=
4096
;
...
...
@@ -829,6 +912,7 @@ int sctp_init(void)
sctp_get_local_addr_list
(
&
sctp_proto
);
__unsafe
(
THIS_MODULE
);
return
0
;
err_ctl_sock_init:
...
...
@@ -852,7 +936,7 @@ int sctp_init(void)
}
/* Exit handler for the SCTP protocol. */
void
sctp_exit
(
void
)
__exit
void
sctp_exit
(
void
)
{
/* BUG. This should probably do something useful like clean
* up all the remaining associations and all that memory.
...
...
@@ -889,4 +973,3 @@ module_exit(sctp_exit);
MODULE_AUTHOR
(
"Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>"
);
MODULE_DESCRIPTION
(
"Support for the SCTP protocol (RFC2960)"
);
MODULE_LICENSE
(
"GPL"
);
net/sctp/sm_make_chunk.c
View file @
a0065b2f
...
...
@@ -116,8 +116,8 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
err
.
cause
=
cause_code
;
len
=
sizeof
(
sctp_errhdr_t
)
+
paylen
;
padlen
=
len
%
4
;
len
+=
padlen
;
err
.
length
=
htons
(
len
);
len
+=
padlen
;
sctp_addto_chunk
(
chunk
,
sizeof
(
sctp_errhdr_t
),
&
err
);
chunk
->
subh
.
err_hdr
=
sctp_addto_chunk
(
chunk
,
paylen
,
payload
);
}
...
...
@@ -242,35 +242,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
sctp_cookie_param_t
*
cookie
;
int
cookie_len
;
size_t
chunksize
;
int
error
;
sctp_scope_t
scope
;
sctp_bind_addr_t
*
bp
=
NULL
;
int
flags
;
retval
=
NULL
;
/* Build up the bind address list for the association based on
* info from the local endpoint and the remote peer.
*/
bp
=
sctp_bind_addr_new
(
priority
);
if
(
!
bp
)
goto
nomem_bindaddr
;
/* Look for supported address types parameter and then build
* our address list based on that.
*/
scope
=
sctp_scope
(
&
asoc
->
peer
.
active_path
->
ipaddr
);
flags
=
(
PF_INET6
==
asoc
->
base
.
sk
->
family
)
?
SCTP_ADDR6_ALLOWED
:
0
;
if
(
asoc
->
peer
.
ipv4_address
)
flags
|=
SCTP_ADDR4_PEERSUPP
;
if
(
asoc
->
peer
.
ipv6_address
)
flags
|=
SCTP_ADDR6_PEERSUPP
;
error
=
sctp_bind_addr_copy
(
bp
,
&
asoc
->
ep
->
base
.
bind_addr
,
scope
,
priority
,
flags
);
if
(
error
)
goto
nomem_copyaddr
;
addrs
=
sctp_bind_addrs_to_raw
(
bp
,
&
addrs_len
,
priority
);
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
priority
);
if
(
!
addrs
.
v
)
goto
nomem_rawaddr
;
...
...
@@ -333,9 +308,6 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
nomem_cookie:
kfree
(
addrs
.
v
);
nomem_rawaddr:
nomem_copyaddr:
sctp_bind_addr_free
(
bp
);
nomem_bindaddr:
return
retval
;
}
...
...
@@ -598,23 +570,9 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc,
const
struct
sctp_sndrcvinfo
*
sinfo
,
int
data_len
)
{
__u16
ssn
;
__u8
flags
=
SCTP_DATA_NOT_FRAG
;
/* Sockets API Extensions for SCTP 5.2.2
* MSG_UNORDERED - This flag requests the un-ordered delivery of the
* message. If this flag is clear, the datagram is considered an
* ordered send and a new ssn is generated. The flags field is set
* in the inner routine - sctp_make_datafrag_empty().
*/
if
(
sinfo
->
sinfo_flags
&
MSG_UNORDERED
)
{
ssn
=
0
;
}
else
{
ssn
=
__sctp_association_get_next_ssn
(
asoc
,
sinfo
->
sinfo_stream
);
}
return
sctp_make_datafrag_empty
(
asoc
,
sinfo
,
data_len
,
flags
,
ssn
);
return
sctp_make_datafrag_empty
(
asoc
,
sinfo
,
data_len
,
flags
,
0
);
}
/* Create a selective ackowledgement (SACK) for the given
...
...
@@ -714,6 +672,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
return
retval
;
}
/* FIXME: Comments. */
sctp_chunk_t
*
sctp_make_shutdown
(
const
sctp_association_t
*
asoc
)
{
sctp_chunk_t
*
retval
;
...
...
@@ -897,7 +856,7 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
/* Make a HEARTBEAT chunk. */
sctp_chunk_t
*
sctp_make_heartbeat
(
const
sctp_association_t
*
asoc
,
const
s
ctp_transport_
t
*
transport
,
const
s
truct
sctp_transpor
t
*
transport
,
const
void
*
payload
,
const
size_t
paylen
)
{
sctp_chunk_t
*
retval
=
sctp_make_chunk
(
asoc
,
SCTP_CID_HEARTBEAT
,
...
...
@@ -909,7 +868,7 @@ sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc,
/* Cast away the 'const', as this is just telling the chunk
* what transport it belongs to.
*/
retval
->
transport
=
(
s
ctp_transport_
t
*
)
transport
;
retval
->
transport
=
(
s
truct
sctp_transpor
t
*
)
transport
;
retval
->
subh
.
hbs_hdr
=
sctp_addto_chunk
(
retval
,
paylen
,
payload
);
nodata:
...
...
@@ -1013,6 +972,7 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
retval
->
asoc
=
(
sctp_association_t
*
)
asoc
;
retval
->
num_times_sent
=
0
;
retval
->
has_tsn
=
0
;
retval
->
has_ssn
=
0
;
retval
->
rtt_in_progress
=
0
;
retval
->
sent_at
=
jiffies
;
retval
->
singleton
=
1
;
...
...
@@ -1118,53 +1078,6 @@ void sctp_free_chunk(sctp_chunk_t *chunk)
SCTP_DBG_OBJCNT_DEC
(
chunk
);
}
/* Do a deep copy of a chunk. */
sctp_chunk_t
*
sctp_copy_chunk
(
sctp_chunk_t
*
chunk
,
const
int
priority
)
{
sctp_chunk_t
*
retval
;
long
offset
;
retval
=
t_new
(
sctp_chunk_t
,
priority
);
if
(
!
retval
)
goto
nodata
;
/* Do the shallow copy. */
*
retval
=
*
chunk
;
/* Make sure that the copy does NOT think it is on any lists. */
retval
->
next
=
NULL
;
retval
->
prev
=
NULL
;
retval
->
list
=
NULL
;
INIT_LIST_HEAD
(
&
retval
->
transmitted_list
);
INIT_LIST_HEAD
(
&
retval
->
frag_list
);
/* Now we copy the deep structure. */
retval
->
skb
=
skb_copy
(
chunk
->
skb
,
priority
);
if
(
!
retval
->
skb
)
{
kfree
(
retval
);
goto
nodata
;
}
/* Move the copy headers to point into the new skb. */
offset
=
((
__u8
*
)
retval
->
skb
->
head
)
-
((
__u8
*
)
chunk
->
skb
->
head
);
if
(
retval
->
param_hdr
.
v
)
retval
->
param_hdr
.
v
+=
offset
;
if
(
retval
->
subh
.
v
)
retval
->
subh
.
v
+=
offset
;
if
(
retval
->
chunk_end
)
((
__u8
*
)
retval
->
chunk_end
)
+=
offset
;
if
(
retval
->
chunk_hdr
)
((
__u8
*
)
retval
->
chunk_hdr
)
+=
offset
;
if
(
retval
->
sctp_hdr
)
((
__u8
*
)
retval
->
sctp_hdr
)
+=
offset
;
SCTP_DBG_OBJCNT_INC
(
chunk
);
return
retval
;
nodata:
return
NULL
;
}
/* Append bytes to the end of a chunk. Will panic if chunk is not big
* enough.
...
...
@@ -1193,7 +1106,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data)
* chunk is not big enough.
* Returns a kernel err value.
*/
int
sctp_user_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
struct
iovec
*
data
)
static
int
sctp_user_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
off
,
int
len
,
struct
iovec
*
data
)
{
__u8
*
target
;
int
err
=
0
;
...
...
@@ -1202,7 +1116,7 @@ int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data)
target
=
skb_put
(
chunk
->
skb
,
len
);
/* Copy data (whole iovec) into chunk */
if
((
err
=
memcpy_fromiovec
(
target
,
data
,
len
)))
if
((
err
=
memcpy_fromiovec
end
(
target
,
data
,
off
,
len
)))
goto
out
;
/* Adjust the chunk length field. */
...
...
@@ -1214,6 +1128,152 @@ int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data)
return
err
;
}
/* A data chunk can have a maximum payload of (2^16 - 20). Break
* down any such message into smaller chunks. Opportunistically, fragment
* the chunks down to the current MTU constraints. We may get refragmented
* later if the PMTU changes, but it is _much better_ to fragment immediately
* with a reasonable guess than always doing our fragmentation on the
* soft-interrupt.
*/
int
sctp_datachunks_from_user
(
sctp_association_t
*
asoc
,
const
struct
sctp_sndrcvinfo
*
sinfo
,
struct
msghdr
*
msg
,
int
msg_len
,
struct
sk_buff_head
*
chunks
)
{
int
max
,
whole
,
i
,
offset
,
over
,
err
;
int
len
,
first_len
;
sctp_chunk_t
*
chunk
;
__u8
frag
;
/* What is a reasonable fragmentation point right now? */
max
=
asoc
->
pmtu
;
if
(
max
<
SCTP_MIN_PMTU
)
max
=
SCTP_MIN_PMTU
;
max
-=
SCTP_IP_OVERHEAD
;
/* Make sure not beyond maximum chunk size. */
if
(
max
>
SCTP_MAX_CHUNK_LEN
)
max
=
SCTP_MAX_CHUNK_LEN
;
/* Subtract out the overhead of a data chunk header. */
max
-=
sizeof
(
struct
sctp_data_chunk
);
whole
=
0
;
first_len
=
max
;
/* Encourage Cookie-ECHO bundling. */
if
(
asoc
->
state
<
SCTP_STATE_ESTABLISHED
)
{
whole
=
msg_len
/
(
max
-
SCTP_ARBITRARY_COOKIE_ECHO_LEN
);
/* Account for the DATA to be bundled with the COOKIE-ECHO. */
if
(
whole
)
{
first_len
=
max
-
SCTP_ARBITRARY_COOKIE_ECHO_LEN
;
msg_len
-=
first_len
;
whole
=
1
;
}
}
/* How many full sized? How many bytes leftover? */
whole
+=
msg_len
/
max
;
over
=
msg_len
%
max
;
offset
=
0
;
/* Create chunks for all the full sized DATA chunks. */
for
(
i
=
0
,
len
=
first_len
;
i
<
whole
;
i
++
)
{
frag
=
SCTP_DATA_MIDDLE_FRAG
;
if
(
0
==
i
)
frag
|=
SCTP_DATA_FIRST_FRAG
;
if
((
i
==
(
whole
-
1
))
&&
!
over
)
frag
|=
SCTP_DATA_LAST_FRAG
;
chunk
=
sctp_make_datafrag_empty
(
asoc
,
sinfo
,
len
,
frag
,
0
);
if
(
!
chunk
)
goto
nomem
;
err
=
sctp_user_addto_chunk
(
chunk
,
offset
,
len
,
msg
->
msg_iov
);
if
(
err
<
0
)
goto
errout
;
offset
+=
len
;
/* Put the chunk->skb back into the form expected by send. */
__skb_pull
(
chunk
->
skb
,
(
__u8
*
)
chunk
->
chunk_hdr
-
(
__u8
*
)
chunk
->
skb
->
data
);
__skb_queue_tail
(
chunks
,
(
struct
sk_buff
*
)
chunk
);
/* The first chunk, the first chunk was likely short
* to allow bundling, so reset to full size.
*/
if
(
0
==
i
)
len
=
max
;
}
/* .. now the leftover bytes. */
if
(
over
)
{
if
(
!
whole
)
frag
=
SCTP_DATA_NOT_FRAG
;
else
frag
=
SCTP_DATA_LAST_FRAG
;
chunk
=
sctp_make_datafrag_empty
(
asoc
,
sinfo
,
over
,
frag
,
0
);
if
(
!
chunk
)
goto
nomem
;
err
=
sctp_user_addto_chunk
(
chunk
,
offset
,
over
,
msg
->
msg_iov
);
/* Put the chunk->skb back into the form expected by send. */
__skb_pull
(
chunk
->
skb
,
(
__u8
*
)
chunk
->
chunk_hdr
-
(
__u8
*
)
chunk
->
skb
->
data
);
if
(
err
<
0
)
goto
errout
;
__skb_queue_tail
(
chunks
,
(
struct
sk_buff
*
)
chunk
);
}
err
=
0
;
goto
out
;
nomem:
err
=
-
ENOMEM
;
errout:
while
((
chunk
=
(
sctp_chunk_t
*
)
__skb_dequeue
(
chunks
)))
sctp_free_chunk
(
chunk
);
out:
return
err
;
}
/* Helper function to assign a TSN if needed. This assumes that both
* the data_hdr and association have already been assigned.
*/
void
sctp_chunk_assign_ssn
(
sctp_chunk_t
*
chunk
)
{
__u16
ssn
;
__u16
sid
;
if
(
chunk
->
has_ssn
)
return
;
/* This is the last possible instant to assign a SSN. */
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
{
ssn
=
0
;
}
else
{
sid
=
htons
(
chunk
->
subh
.
data_hdr
->
stream
);
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_LAST_FRAG
)
ssn
=
sctp_ssn_next
(
&
chunk
->
asoc
->
ssnmap
->
out
,
sid
);
else
ssn
=
sctp_ssn_peek
(
&
chunk
->
asoc
->
ssnmap
->
out
,
sid
);
ssn
=
htons
(
ssn
);
}
chunk
->
subh
.
data_hdr
->
ssn
=
ssn
;
chunk
->
has_ssn
=
1
;
}
/* Helper function to assign a TSN if needed. This assumes that both
* the data_hdr and association have already been assigned.
*/
...
...
@@ -1352,11 +1412,10 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
sctp_signed_cookie_t
*
cookie
;
sctp_cookie_t
*
bear_cookie
;
int
headersize
,
bodysize
;
int
fixed_size
,
var_size1
,
var_size2
,
var_size3
;
int
fixed_size
;
__u8
digest_buf
[
SCTP_SIGNATURE_SIZE
];
int
secret
;
sctp_scope_t
scope
;
__u8
*
raw_addr_list
;
headersize
=
sizeof
(
sctp_chunkhdr_t
)
+
SCTP_SECRET_SIZE
;
bodysize
=
ntohs
(
chunk
->
chunk_hdr
->
length
)
-
headersize
;
...
...
@@ -1377,9 +1436,6 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
/* Process the cookie. */
cookie
=
chunk
->
subh
.
cookie_hdr
;
bear_cookie
=
&
cookie
->
c
;
var_size1
=
ntohs
(
chunk
->
chunk_hdr
->
length
)
-
fixed_size
;
var_size2
=
ntohs
(
bear_cookie
->
peer_init
->
chunk_hdr
.
length
);
var_size3
=
bear_cookie
->
raw_addr_list_len
;
/* Check the signature. */
secret
=
ep
->
current_key
;
...
...
@@ -1403,6 +1459,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* for init collision case of lost COOKIE ACK.
*/
if
(
!
asoc
&&
tv_lt
(
bear_cookie
->
expiration
,
chunk
->
skb
->
stamp
))
{
__u16
len
;
/*
* Section 3.3.10.3 Stale Cookie Error (3)
*
...
...
@@ -1411,8 +1468,8 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* Stale Cookie Error: Indicates the receipt of a valid State
* Cookie that has expired.
*/
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
ntohs
(
chunk
->
chunk_hdr
->
length
)
);
len
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
len
);
if
(
*
err_chk_p
)
{
suseconds_t
usecs
=
(
chunk
->
skb
->
stamp
.
tv_sec
-
bear_cookie
->
expiration
.
tv_sec
)
*
1000000L
+
...
...
@@ -1443,12 +1500,8 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
/* Populate the association from the cookie. */
retval
->
c
=
*
bear_cookie
;
/* Build the bind address list based on the cookie. */
raw_addr_list
=
(
__u8
*
)
bear_cookie
+
sizeof
(
sctp_cookie_t
)
+
var_size2
;
if
(
sctp_raw_to_bind_addrs
(
&
retval
->
base
.
bind_addr
,
raw_addr_list
,
var_size3
,
retval
->
base
.
bind_addr
.
port
,
priority
))
{
if
(
sctp_assoc_set_bind_addr_from_cookie
(
retval
,
bear_cookie
,
GFP_ATOMIC
)
<
0
)
{
*
error
=
-
SCTP_IERROR_NOMEM
;
goto
fail
;
}
...
...
@@ -1477,6 +1530,57 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions
********************************************************************/
/*
* Report a missing mandatory parameter.
*/
struct
__sctp_missing
{
__u32
num_missing
;
__u16
type
;
}
__attribute__
((
packed
));;
static
int
sctp_process_missing_param
(
const
sctp_association_t
*
asoc
,
sctp_param_t
paramtype
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
{
struct
__sctp_missing
report
;
__u16
len
;
len
=
WORD_ROUND
(
sizeof
(
report
));
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if
(
!*
err_chk_p
)
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
len
);
if
(
*
err_chk_p
)
{
report
.
num_missing
=
htonl
(
1
);
report
.
type
=
paramtype
;
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_INV_PARAM
,
&
report
,
sizeof
(
report
));
}
/* Stop processing this chunk. */
return
0
;
}
/* Report an Invalid Mandatory Parameter. */
static
int
sctp_process_inv_mandatory
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
{
/* Invalid Mandatory Parameter Error has no payload. */
if
(
!*
err_chk_p
)
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
0
);
if
(
*
err_chk_p
)
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_INV_PARAM
,
NULL
,
0
);
/* Stop processing this chunk. */
return
0
;
}
/* Do not attempt to handle the HOST_NAME parm. However, do
* send back an indicator to the peer.
*/
...
...
@@ -1487,9 +1591,7 @@ static int sctp_process_hn_param(const sctp_association_t *asoc,
{
__u16
len
=
ntohs
(
param
.
p
->
length
);
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
/* Make an ERROR chunk. */
if
(
!*
err_chk_p
)
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
len
);
...
...
@@ -1570,7 +1672,8 @@ static int sctp_process_unk_param(const sctp_association_t *asoc,
}
else
{
/* If there is no memory for generating the ERROR
* report as specified, an ABORT will be triggered
* to the peer and the association won't be established.
* to the peer and the association won't be
* established.
*/
retval
=
0
;
}
...
...
@@ -1633,12 +1736,33 @@ int sctp_verify_init(const sctp_association_t *asoc,
sctp_chunk_t
**
err_chk_p
)
{
union
sctp_params
param
;
int
has_cookie
=
0
;
/* Verify stream values are non-zero. */
if
((
0
==
peer_init
->
init_hdr
.
num_outbound_streams
)
||
(
0
==
peer_init
->
init_hdr
.
num_inbound_streams
))
{
sctp_process_inv_mandatory
(
asoc
,
chunk
,
err_chk_p
);
return
0
;
}
/* Check for missing mandatory parameters. */
sctp_walk_params
(
param
,
peer_init
,
init_hdr
.
params
)
{
if
(
SCTP_PARAM_STATE_COOKIE
==
param
.
p
->
type
)
has_cookie
=
1
;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify
* the mandatory parameters somewhere here and generate either the
* "Missing mandatory parameter" error or the "Invalid mandatory
*
parameter" error
.
}
/* for (loop through all parameters) */
/* The only missing mandatory param possible today is
*
the state cookie for an INIT-ACK chunk
.
*/
if
((
SCTP_CID_INIT_ACK
==
cid
)
&&
!
has_cookie
)
{
sctp_process_missing_param
(
asoc
,
SCTP_PARAM_STATE_COOKIE
,
chunk
,
err_chk_p
);
return
0
;
}
/* Find unrecognized parameters. */
...
...
@@ -1654,6 +1778,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
/* Unpack the parameters in an INIT packet into an association.
* Returns 0 on failure, else success.
* FIXME: This is an association method.
*/
int
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
const
union
sctp_addr
*
peer_addr
,
...
...
@@ -1661,7 +1786,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
int
priority
)
{
union
sctp_params
param
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
struct
list_head
*
pos
,
*
temp
;
char
*
cookie
;
...
...
@@ -1710,6 +1835,12 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
ntohs
(
peer_init
->
init_hdr
.
num_inbound_streams
);
}
if
(
asoc
->
c
.
sinit_max_instreams
>
ntohs
(
peer_init
->
init_hdr
.
num_outbound_streams
))
{
asoc
->
c
.
sinit_max_instreams
=
ntohs
(
peer_init
->
init_hdr
.
num_outbound_streams
);
}
/* Copy Initiation tag from INIT to VT_peer in cookie. */
asoc
->
c
.
peer_vtag
=
asoc
->
peer
.
i
.
init_tag
;
...
...
@@ -1730,7 +1861,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* advertised window).
*/
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
transport
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
transport
->
ssthresh
=
asoc
->
peer
.
i
.
a_rwnd
;
}
...
...
@@ -1738,6 +1869,21 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
sctp_tsnmap_init
(
&
asoc
->
peer
.
tsn_map
,
SCTP_TSN_MAP_SIZE
,
asoc
->
peer
.
i
.
initial_tsn
);
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
*
* The stream sequence number in all the streams shall start
* from 0 when the association is established. Also, when the
* stream sequence number reaches the value 65535 the next
* stream sequence number shall be set to 0.
*/
/* Allocate storage for the negotiated streams. */
asoc
->
ssnmap
=
sctp_ssnmap_new
(
asoc
->
peer
.
i
.
num_outbound_streams
,
asoc
->
c
.
sinit_num_ostreams
,
priority
);
if
(
!
asoc
->
ssnmap
)
goto
nomem_ssnmap
;
/* ADDIP Section 4.1 ASCONF Chunk Procedures
*
* When an endpoint has an ASCONF signaled change to be sent to the
...
...
@@ -1751,10 +1897,11 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
asoc
->
peer
.
addip_serial
=
asoc
->
peer
.
i
.
initial_tsn
-
1
;
return
1
;
nomem_ssnmap:
clean_up:
/* Release the transport structures. */
list_for_each_safe
(
pos
,
temp
,
&
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
transport
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
list_del
(
pos
);
sctp_transport_free
(
transport
);
}
...
...
net/sctp/sm_sideeffect.c
View file @
a0065b2f
...
...
@@ -56,33 +56,29 @@
#include <net/sctp/sm.h>
/* Do forward declarations of static functions. */
static
void
sctp_do_ecn_ce_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
);
static
void
sctp_do_ecn_ce_work
(
sctp_association_t
*
,
__u32
lowest_tsn
);
static
sctp_chunk_t
*
sctp_do_ecn_ecne_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
,
sctp_chunk_t
*
);
static
void
sctp_do_ecn_cwr_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
);
static
void
sctp_do_8_2_transport_strike
(
sctp_association_t
*
asoc
,
sctp_transport_t
*
transport
);
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
);
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
sctp_event_t
event_type
,
sctp_subtype_t
stype
,
static
void
sctp_do_ecn_cwr_work
(
sctp_association_t
*
,
__u32
lowest_tsn
);
static
void
sctp_do_8_2_transport_strike
(
sctp_association_t
*
,
struct
sctp_transport
*
);
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_event_t
,
sctp_subtype_t
,
sctp_chunk_t
*
chunk
);
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_chunk_t
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
int
priority
);
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_hb_timers_update
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_transport_t
*
);
static
void
sctp_cmd_set_bind_addrs
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_bind_addr_t
*
);
static
void
sctp_cmd_hb_timers_stop
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
struct
sctp_transport
*
);
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
s
ctp_transport_
t
*
);
s
truct
sctp_transpor
t
*
);
static
void
sctp_cmd_transport_on
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
s
ctp_transport_
t
*
,
sctp_chunk_t
*
);
s
truct
sctp_transpor
t
*
,
sctp_chunk_t
*
);
static
int
sctp_cmd_process_sack
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_sackhdr_t
*
);
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
...
...
@@ -264,7 +260,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
struct
list_head
*
pos
;
struct
timer_list
*
timer
;
unsigned
long
timeout
;
s
ctp_transport_
t
*
t
;
s
truct
sctp_transpor
t
*
t
;
sctp_sackhdr_t
sackh
;
if
(
SCTP_EVENT_T_TIMEOUT
!=
event_type
)
...
...
@@ -296,7 +292,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break
;
case
SCTP_CMD_PURGE_OUTQUEUE
:
sctp_outq
ueue
_teardown
(
&
asoc
->
outqueue
);
sctp_outq_teardown
(
&
asoc
->
outqueue
);
break
;
case
SCTP_CMD_DELETE_TCB
:
...
...
@@ -395,7 +391,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
command
->
obj
.
ptr
,
"ulpq:"
,
&
asoc
->
ulpq
);
sctp_ulpq
ueue
_tail_data
(
&
asoc
->
ulpq
,
sctp_ulpq_tail_data
(
&
asoc
->
ulpq
,
command
->
obj
.
ptr
,
GFP_ATOMIC
);
break
;
...
...
@@ -407,13 +403,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
command
->
obj
.
ptr
,
"ulpq:"
,
&
asoc
->
ulpq
);
sctp_ulpq
ueue
_tail_event
(
&
asoc
->
ulpq
,
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
command
->
obj
.
ptr
);
break
;
case
SCTP_CMD_REPLY
:
/* Send a chunk to our peer. */
error
=
sctp_
push_outqueue
(
&
asoc
->
outqueue
,
error
=
sctp_
outq_tail
(
&
asoc
->
outqueue
,
command
->
obj
.
ptr
);
break
;
...
...
@@ -427,12 +423,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case
SCTP_CMD_RETRAN
:
/* Mark a transport for retransmission. */
sctp_retransmit
(
&
asoc
->
outqueue
,
command
->
obj
.
transport
,
0
);
command
->
obj
.
transport
,
SCTP_RETRANSMIT_T3_RTX
);
break
;
case
SCTP_CMD_TRANSMIT
:
/* Kick start transmission. */
error
=
sctp_
flush_outqueue
(
&
asoc
->
outqueue
,
0
);
error
=
sctp_
outq_flush
(
&
asoc
->
outqueue
,
0
);
break
;
case
SCTP_CMD_ECN_CE
:
...
...
@@ -502,7 +499,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
* COOKIE-ECHO we need to resend.
*/
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
s
ctp_transport_
t
,
t
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
sctp_retransmit_mark
(
&
asoc
->
outqueue
,
t
,
0
);
}
...
...
@@ -547,11 +544,6 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
SCTP_DEBUG_PRINTK
(
"vtag mismatch!
\n
"
);
break
;
case
SCTP_CMD_SET_BIND_ADDR
:
sctp_cmd_set_bind_addrs
(
commands
,
asoc
,
command
->
obj
.
bp
);
break
;
case
SCTP_CMD_STRIKE
:
/* Mark one strike against a transport. */
sctp_do_8_2_transport_strike
(
asoc
,
...
...
@@ -572,9 +564,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_cmd_hb_timers_start
(
commands
,
asoc
);
break
;
case
SCTP_CMD_HB_TIMER
S
_UPDATE
:
case
SCTP_CMD_HB_TIMER_UPDATE
:
t
=
command
->
obj
.
transport
;
sctp_cmd_hb_timers_update
(
commands
,
asoc
,
t
);
sctp_cmd_hb_timer_update
(
commands
,
asoc
,
t
);
break
;
case
SCTP_CMD_HB_TIMERS_STOP
:
sctp_cmd_hb_timers_stop
(
commands
,
asoc
);
break
;
case
SCTP_CMD_REPORT_ERROR
:
...
...
@@ -656,7 +652,7 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
* recent than the last response.
*/
if
(
TSN_lt
(
asoc
->
last_cwr_tsn
,
lowest_tsn
))
{
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
/* Find which transport's congestion variables
* need to be adjusted.
...
...
@@ -743,7 +739,7 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
error
=
sctp_
push_outqueue
(
&
asoc
->
outqueue
,
sack
);
error
=
sctp_
outq_tail
(
&
asoc
->
outqueue
,
sack
);
/* Stop the SACK timer. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
...
...
@@ -802,7 +798,7 @@ void sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, long gap)
void
sctp_generate_t3_rtx_event
(
unsigned
long
peer
)
{
int
error
;
s
ctp_transport_t
*
transport
=
(
sctp_transport_
t
*
)
peer
;
s
truct
sctp_transport
*
transport
=
(
struct
sctp_transpor
t
*
)
peer
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
/* Check whether a task is in the sock. */
...
...
@@ -917,7 +913,7 @@ void sctp_generate_autoclose_event(unsigned long data)
void
sctp_generate_heartbeat_event
(
unsigned
long
data
)
{
int
error
=
0
;
s
ctp_transport_t
*
transport
=
(
sctp_transport_
t
*
)
data
;
s
truct
sctp_transport
*
transport
=
(
struct
sctp_transpor
t
*
)
data
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
...
...
@@ -957,24 +953,16 @@ void sctp_generate_sack_event(unsigned long data)
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_SACK
);
}
void
sctp_generate_pmtu_raise_event
(
unsigned
long
data
)
{
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_PMTU_RAISE
);
}
sctp_timer_event_t
*
sctp_timer_events
[
SCTP_NUM_TIMEOUT_TYPES
]
=
{
NULL
,
sctp_generate_t1_cookie_event
,
sctp_generate_t1_init_event
,
sctp_generate_t2_shutdown_event
,
NULL
,
NULL
,
sctp_generate_t5_shutdown_guard_event
,
sctp_generate_heartbeat_event
,
sctp_generate_sack_event
,
sctp_generate_autoclose_event
,
sctp_generate_pmtu_raise_event
,
};
/********************************************************************
...
...
@@ -997,7 +985,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
*
*/
static
void
sctp_do_8_2_transport_strike
(
sctp_association_t
*
asoc
,
s
ctp_transport_
t
*
transport
)
s
truct
sctp_transpor
t
*
transport
)
{
/* The check for association's overall error counter exceeding the
* threshold is done in the state function.
...
...
@@ -1125,7 +1113,7 @@ static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
)
{
s
ctp_transport_
t
*
t
;
s
truct
sctp_transpor
t
*
t
;
struct
list_head
*
pos
;
/* Start a heartbeat timer for each transport on the association.
...
...
@@ -1133,45 +1121,43 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
* the needed data structures go away.
*/
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
if
(
!
mod_timer
(
&
t
->
hb_timer
,
t
->
hb_interval
+
t
->
rto
+
jiffies
))
{
t
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)))
sctp_transport_hold
(
t
);
}
}
static
void
sctp_cmd_hb_timers_stop
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
)
{
struct
sctp_transport
*
t
;
struct
list_head
*
pos
;
/* Stop all heartbeat timers. */
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
del_timer
(
&
t
->
hb_timer
))
sctp_transport_put
(
t
);
}
}
/* Helper function to update the heartbeat timer. */
static
void
sctp_cmd_hb_timer
s
_update
(
sctp_cmd_seq_t
*
cmds
,
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_transport_
t
*
t
)
struct
sctp_transpor
t
*
t
)
{
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
t
->
hb_interval
+
t
->
rto
+
jiffies
))
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)
))
sctp_transport_hold
(
t
);
}
/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */
void
sctp_cmd_set_bind_addrs
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_bind_addr_t
*
bp
)
{
struct
list_head
*
pos
,
*
temp
;
list_for_each_safe
(
pos
,
temp
,
&
bp
->
address_list
)
{
list_del_init
(
pos
);
list_add_tail
(
pos
,
&
asoc
->
base
.
bind_addr
.
address_list
);
}
/* Free the temporary bind addr header, otherwise
* there will a memory leak.
*/
sctp_bind_addr_free
(
bp
);
}
/* 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
,
sctp_transport_t
*
t
,
sctp_chunk_t
*
chunk
)
struct
sctp_transport
*
t
,
sctp_chunk_t
*
chunk
)
{
sctp_sender_hb_info_t
*
hbinfo
;
...
...
@@ -1203,7 +1189,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
*/
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
s
ctp_transport_
t
*
t
)
s
truct
sctp_transpor
t
*
t
)
{
sctp_transport_lower_cwnd
(
t
,
SCTP_LOWER_CWND_INACTIVE
);
...
...
@@ -1218,7 +1204,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
{
int
err
;
if
(
sctp_
sack_outqueue
(
&
asoc
->
outqueue
,
sackh
))
{
if
(
sctp_
outq_sack
(
&
asoc
->
outqueue
,
sackh
))
{
/* There are no more TSNs awaiting SACK. */
err
=
sctp_do_sm
(
SCTP_EVENT_T_OTHER
,
SCTP_ST_OTHER
(
SCTP_EVENT_NO_PENDING_TSN
),
...
...
@@ -1228,7 +1214,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
/* Windows may have opened, so we need
* to check if we have DATA to transmit
*/
err
=
sctp_
flush_outqueue
(
&
asoc
->
outqueue
,
0
);
err
=
sctp_
outq_flush
(
&
asoc
->
outqueue
,
0
);
}
return
err
;
...
...
@@ -1240,7 +1226,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
)
{
s
ctp_transport_
t
*
t
;
s
truct
sctp_transpor
t
*
t
;
t
=
sctp_assoc_choose_shutdown_transport
(
asoc
);
asoc
->
shutdown_last_sent_to
=
t
;
...
...
net/sctp/sm_statefuns.c
View file @
a0065b2f
...
...
@@ -191,7 +191,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
int
len
;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond
ing
with an ABORT.
* control endpoint, respond with an ABORT.
*/
if
(
ep
==
sctp_sk
((
sctp_get_ctl_sock
()))
->
ep
)
return
sctp_sf_ootb
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
...
@@ -262,6 +262,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
len
=
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
);
if
(
sctp_assoc_set_bind_addr_from_ep
(
new_asoc
,
GFP_ATOMIC
)
<
0
)
goto
nomem_ack
;
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
,
len
);
if
(
!
repl
)
goto
nomem_ack
;
...
...
@@ -506,7 +509,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_chunk_t
*
err_chk_p
;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond
ing
with an ABORT.
* control endpoint, respond with an ABORT.
*/
if
(
ep
==
sctp_sk
((
sctp_get_ctl_sock
()))
->
ep
)
return
sctp_sf_ootb
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
...
@@ -678,7 +681,7 @@ sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
s
ctp_transport_t
*
transport
=
(
sctp_transport_
t
*
)
arg
;
s
truct
sctp_transport
*
transport
=
(
struct
sctp_transpor
t
*
)
arg
;
sctp_chunk_t
*
reply
;
sctp_sender_hb_info_t
hbinfo
;
size_t
paylen
=
0
;
...
...
@@ -711,7 +714,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
s
ctp_transport_t
*
transport
=
(
sctp_transport_
t
*
)
arg
;
s
truct
sctp_transport
*
transport
=
(
struct
sctp_transpor
t
*
)
arg
;
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
...
...
@@ -737,7 +740,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSPORT_RESET
,
SCTP_TRANSPORT
(
transport
));
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMER
S
_UPDATE
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMER_UPDATE
,
SCTP_TRANSPORT
(
transport
));
return
SCTP_DISPOSITION_CONSUME
;
...
...
@@ -842,7 +845,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
{
sctp_chunk_t
*
chunk
=
arg
;
union
sctp_addr
from_addr
;
s
ctp_transport_
t
*
link
;
s
truct
sctp_transpor
t
*
link
;
sctp_sender_hb_info_t
*
hbinfo
;
unsigned
long
max_interval
;
...
...
@@ -944,7 +947,7 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
sctp_chunk_t
*
init
,
sctp_cmd_seq_t
*
commands
)
{
s
ctp_transport_
t
*
new_addr
,
*
addr
;
s
truct
sctp_transpor
t
*
new_addr
,
*
addr
;
struct
list_head
*
pos
,
*
pos2
;
int
found
;
...
...
@@ -963,10 +966,11 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
found
=
0
;
list_for_each
(
pos
,
&
new_asoc
->
peer
.
transport_addr_list
)
{
new_addr
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
new_addr
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
found
=
0
;
list_for_each
(
pos2
,
&
asoc
->
peer
.
transport_addr_list
)
{
addr
=
list_entry
(
pos2
,
sctp_transport_t
,
transports
);
addr
=
list_entry
(
pos2
,
struct
sctp_transport
,
transports
);
if
(
sctp_cmp_addr_exact
(
&
new_addr
->
ipaddr
,
&
addr
->
ipaddr
))
{
found
=
1
;
...
...
@@ -1048,20 +1052,17 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
(
asoc
->
c
.
peer_vtag
==
new_asoc
->
c
.
peer_ttag
))
return
'A'
;
/* Collision case D.
* Note: Test case D first, otherwise it may be incorrectly
* identified as second case of B if the value of the Tie_tag is
* not filled into the state cookie.
*/
if
((
asoc
->
c
.
my_vtag
==
new_asoc
->
c
.
my_vtag
)
&&
(
asoc
->
c
.
peer_vtag
==
new_asoc
->
c
.
peer_vtag
))
return
'D'
;
/* Collision case B. */
if
((
asoc
->
c
.
my_vtag
==
new_asoc
->
c
.
my_vtag
)
&&
((
asoc
->
c
.
peer_vtag
!=
new_asoc
->
c
.
peer_vtag
)
||
(
!
new_asoc
->
c
.
my_ttag
&&
!
new_asoc
->
c
.
peer_ttag
)))
(
0
==
asoc
->
c
.
peer_vtag
)))
{
return
'B'
;
}
/* Collision case D. */
if
((
asoc
->
c
.
my_vtag
==
new_asoc
->
c
.
my_vtag
)
&&
(
asoc
->
c
.
peer_vtag
==
new_asoc
->
c
.
peer_vtag
))
return
'D'
;
/* Collision case C. */
if
((
asoc
->
c
.
my_vtag
!=
new_asoc
->
c
.
my_vtag
)
&&
...
...
@@ -1070,7 +1071,8 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
(
0
==
new_asoc
->
c
.
peer_ttag
))
return
'C'
;
return
'E'
;
/* No such case available. */
/* No match to any of the special cases; discard this packet. */
return
'E'
;
}
/* Common helper routine for both duplicate and simulataneous INIT
...
...
@@ -1182,6 +1184,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
len
=
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
);
}
if
(
sctp_assoc_set_bind_addr_from_ep
(
new_asoc
,
GFP_ATOMIC
)
<
0
)
goto
nomem
;
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
,
len
);
if
(
!
repl
)
goto
nomem
;
...
...
@@ -1337,7 +1343,7 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep,
/* Unexpected COOKIE-ECHO handlerfor peer restart (Table 2, action 'A')
/* Unexpected COOKIE-ECHO handler
for peer restart (Table 2, action 'A')
*
* Section 5.2.4
* A) In this case, the peer may have restarted.
...
...
@@ -1500,11 +1506,17 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
sctp_ulpevent_t
*
ev
=
NULL
;
sctp_chunk_t
*
repl
;
/* The local endpoint cannot use any value from the received
* state cookie and need to immediately resend a COOKIE-ACK
* and move into ESTABLISHED if it hasn't done so.
/* Clarification from Implementor's Guide:
* D) When both local and remote tags match the endpoint should
* enter the ESTABLISHED state, if it is in the COOKIE-ECHOED state.
* It should stop any cookie timer that may be running and send
* a COOKIE ACK.
*/
if
(
SCTP_STATE_ESTABLISHED
!=
asoc
->
state
)
{
/* Don't accidentally move back into established state. */
if
(
asoc
->
state
<
SCTP_STATE_ESTABLISHED
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_COOKIE
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_ESTABLISHED
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
...
...
@@ -1535,6 +1547,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSMIT
,
SCTP_NULL
());
return
SCTP_DISPOSITION_CONSUME
;
nomem:
...
...
@@ -1605,8 +1618,6 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
sctp_send_stale_cookie_err
(
ep
,
asoc
,
chunk
,
commands
,
err_chk_p
);
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
break
;
case
-
SCTP_IERROR_BAD_SIG
:
default:
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
...
@@ -1629,7 +1640,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
new_asoc
);
break
;
case
'C'
:
/* Collisio
u
n case C. */
case
'C'
:
/* Collision case C. */
retval
=
sctp_sf_do_dupcook_c
(
ep
,
asoc
,
chunk
,
commands
,
new_asoc
);
break
;
...
...
@@ -1639,9 +1650,8 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
new_asoc
);
break
;
default:
/* No such case, discard it. */
printk
(
KERN_WARNING
"%s:unknown case
\n
"
,
__FUNCTION__
);
retval
=
SCTP_DISPOSITION_DISCARD
;
default:
/* Discard packet for all others. */
retval
=
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
break
;
};
...
...
@@ -1799,7 +1809,7 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
sctp_cookie_preserve_param_t
bht
;
sctp_errhdr_t
*
err
;
struct
list_head
*
pos
;
s
ctp_transport_
t
*
t
;
s
truct
sctp_transpor
t
*
t
;
sctp_chunk_t
*
reply
;
sctp_bind_addr_t
*
bp
;
int
attempts
;
...
...
@@ -1848,9 +1858,11 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_COUNTER_INC
,
SCTP_COUNTER
(
SCTP_COUNTER_INIT_ERROR
));
/* If we've sent any data bundled with COOKIE-ECHO we need to resend. */
/* If we've sent any data bundled with COOKIE-ECHO we need to
* resend.
*/
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
s
ctp_transport_
t
,
transports
);
t
=
list_entry
(
pos
,
s
truct
sctp_transpor
t
,
transports
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_RETRAN
,
SCTP_TRANSPORT
(
t
));
}
...
...
@@ -2030,7 +2042,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
SCTP_STATE
(
SCTP_STATE_SHUTDOWN_RECEIVED
));
disposition
=
SCTP_DISPOSITION_CONSUME
;
if
(
sctp_outq
ueue
_is_empty
(
&
asoc
->
outqueue
))
{
if
(
sctp_outq_is_empty
(
&
asoc
->
outqueue
))
{
disposition
=
sctp_sf_do_9_2_shutdown_ack
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
...
...
@@ -3229,10 +3241,6 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
repl
;
sctp_bind_addr_t
*
bp
;
sctp_scope_t
scope
;
int
error
;
int
flags
;
/* The comment below says that we enter COOKIE-WAIT AFTER
* sending the INIT, but that doesn't actually work in our
...
...
@@ -3241,35 +3249,6 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_COOKIE_WAIT
));
/* Build up the bind address list for the association based on
* info from the local endpoint and the remote peer.
*/
bp
=
sctp_bind_addr_new
(
GFP_ATOMIC
);
if
(
!
bp
)
goto
nomem
;
/* Use scoping rules to determine the subset of addresses from
* the endpoint.
*/
scope
=
sctp_scope
(
&
asoc
->
peer
.
active_path
->
ipaddr
);
flags
=
(
PF_INET6
==
asoc
->
base
.
sk
->
family
)
?
SCTP_ADDR6_ALLOWED
:
0
;
if
(
asoc
->
peer
.
ipv4_address
)
flags
|=
SCTP_ADDR4_PEERSUPP
;
if
(
asoc
->
peer
.
ipv6_address
)
flags
|=
SCTP_ADDR6_PEERSUPP
;
error
=
sctp_bind_addr_copy
(
bp
,
&
ep
->
base
.
bind_addr
,
scope
,
GFP_ATOMIC
,
flags
);
if
(
error
)
goto
nomem
;
/* FIXME: Either move address assignment out of this function
* or else move the association allocation/init into this function.
* The association structure is brand new before calling this
* function, so would not be a sideeffect if the allocation
* moved into this function. --jgrimm
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SET_BIND_ADDR
,
(
sctp_arg_t
)
bp
);
/* RFC 2960 5.1 Normal Establishment of an Association
*
* A) "A" first sends an INIT chunk to "Z". In the INIT, "A"
...
...
@@ -3278,7 +3257,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
* 1 to 4294967295 (see 5.3.1 for Tag value selection). ...
*/
repl
=
sctp_make_init
(
asoc
,
bp
,
GFP_ATOMIC
,
0
);
repl
=
sctp_make_init
(
asoc
,
&
asoc
->
base
.
bind_addr
,
GFP_ATOMIC
,
0
);
if
(
!
repl
)
goto
nomem
;
...
...
@@ -3297,9 +3276,6 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_CONSUME
;
nomem:
if
(
bp
)
sctp_bind_addr_free
(
bp
);
return
SCTP_DISPOSITION_NOMEM
;
}
...
...
@@ -3429,7 +3405,7 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD
));
disposition
=
SCTP_DISPOSITION_CONSUME
;
if
(
sctp_outq
ueue
_is_empty
(
&
asoc
->
outqueue
))
{
if
(
sctp_outq_is_empty
(
&
asoc
->
outqueue
))
{
disposition
=
sctp_sf_do_9_2_start_shutdown
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
...
...
@@ -3767,7 +3743,7 @@ sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
return
sctp_sf_heartbeat
(
ep
,
asoc
,
type
,
(
s
ctp_transport_
t
*
)
arg
,
return
sctp_sf_heartbeat
(
ep
,
asoc
,
type
,
(
s
truct
sctp_transpor
t
*
)
arg
,
commands
);
}
...
...
@@ -3837,6 +3813,13 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_SHUTDOWN_SENT
));
/* sctp-implguide 2.10 Issues with Heartbeating and failover
*
* HEARTBEAT ... is discontinued after sending either SHUTDOWN
* or SHUTDOWN-ACK.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_STOP
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
return
SCTP_DISPOSITION_CONSUME
;
...
...
@@ -3889,6 +3872,14 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep,
/* Enter the SHUTDOWN-ACK-SENT state. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_SHUTDOWN_ACK_SENT
));
/* sctp-implguide 2.10 Issues with Heartbeating and failover
*
* HEARTBEAT ... is discontinued after sending either SHUTDOWN
* or SHUTDOWN-ACK.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_STOP
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
return
SCTP_DISPOSITION_CONSUME
;
...
...
@@ -3933,7 +3924,7 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
s
ctp_transport_
t
*
transport
=
arg
;
s
truct
sctp_transpor
t
*
transport
=
arg
;
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
...
...
@@ -4203,7 +4194,7 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_START
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD
));
disposition
=
SCTP_DISPOSITION_CONSUME
;
if
(
sctp_outq
ueue
_is_empty
(
&
asoc
->
outqueue
))
{
if
(
sctp_outq_is_empty
(
&
asoc
->
outqueue
))
{
disposition
=
sctp_sf_do_9_2_start_shutdown
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
...
...
@@ -4333,7 +4324,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
const
sctp_chunk_t
*
chunk
)
{
sctp_packet_t
*
packet
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
__u16
sport
;
__u16
dport
;
__u32
vtag
;
...
...
net/sctp/sm_statetable.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2003
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
*
...
...
@@ -49,7 +49,7 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
sctp_sm_table_entry_t
bug
=
{
s
tatic
s
ctp_sm_table_entry_t
bug
=
{
.
fn
=
sctp_sf_bug
,
.
name
=
"sctp_sf_bug"
};
...
...
@@ -206,7 +206,7 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_violation, .name = "sctp_sf_violation"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
discard_chunk, .name = "sctp_sf_discard_chunk
"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_backbeat_8_3, .name = "sctp_sf_backbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
...
...
@@ -216,7 +216,7 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_backbeat_8_3, .name = "sctp_sf_backbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
discard_chunk, .name = "sctp_sf_discard_chunk
"}, \
}
/* TYPE_SCTP_HEARTBEAT_ACK */
#define TYPE_SCTP_ABORT { \
...
...
@@ -293,19 +293,19 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
discard_chunk, .name = "sctp_sf_discard_chunk
"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_cookie_echoed_err, .name = "sctp_sf_cookie_echoed_err"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_operr_notify, .name = "sctp_sf_operr_notify"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
operr_notify, .name = "sctp_sf_operr_notify
"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
discard_chunk, .name = "sctp_sf_discard_chunk
"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
operr_notify, .name = "sctp_sf_operr_notify
"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
discard_chunk, .name = "sctp_sf_discard_chunk
"}, \
}
/* TYPE_SCTP_ERROR */
#define TYPE_SCTP_COOKIE_ECHO { \
...
...
@@ -504,26 +504,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
{.
fn
=
sctp_sf_unk_chunk
,
.
name
=
"sctp_sf_unk_chunk"
},
};
/* chunk unknown */
#define TYPE_SCTP_PRIMITIVE_INITIALIZE { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_INITIALIZE */
#define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \
/* SCTP_STATE_EMPTY */
\
...
...
@@ -619,90 +599,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
{.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \
}
/* TYPE_SCTP_PRIMITIVE_SEND */
#define TYPE_SCTP_PRIMITIVE_SETPRIMARY { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_SETPRIMARY */
#define TYPE_SCTP_PRIMITIVE_RECEIVE { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_RECEIVE */
#define TYPE_SCTP_PRIMITIVE_STATUS { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_STATUS */
#define TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
...
...
@@ -731,152 +627,16 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
.name = "sctp_sf_do_prm_requestheartbeat"}, \
}
/* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_GETSRTTREPORT */
#define TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD */
#define TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS */
#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT */
#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED */
#define TYPE_SCTP_PRIMITIVE_DESTROY { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
/* TYPE_SCTP_PRIMITIVE_DESTROY */
/* The primary index for this table is the primitive type.
* The secondary index for this table is the state.
*/
sctp_sm_table_entry_t
primitive_event_table
[
SCTP_NUM_PRIMITIVE_TYPES
][
SCTP_STATE_NUM_STATES
]
=
{
TYPE_SCTP_PRIMITIVE_INITIALIZE
,
TYPE_SCTP_PRIMITIVE_ASSOCIATE
,
TYPE_SCTP_PRIMITIVE_SHUTDOWN
,
TYPE_SCTP_PRIMITIVE_ABORT
,
TYPE_SCTP_PRIMITIVE_SEND
,
TYPE_SCTP_PRIMITIVE_SETPRIMARY
,
TYPE_SCTP_PRIMITIVE_RECEIVE
,
TYPE_SCTP_PRIMITIVE_STATUS
,
TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT
,
TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT
,
TYPE_SCTP_PRIMITIVE_GETSRTTREPORT
,
TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD
,
TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS
,
TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT
,
TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED
,
TYPE_SCTP_PRIMITIVE_DESTROY
,
};
#define TYPE_SCTP_OTHER_NO_PENDING_TSN { \
...
...
@@ -902,30 +662,8 @@ sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
}
#define TYPE_SCTP_OTHER_ICMP_UNREACHFRAG { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
sctp_sm_table_entry_t
other_event_table
[
SCTP_NUM_OTHER_TYPES
][
SCTP_STATE_NUM_STATES
]
=
{
TYPE_SCTP_OTHER_NO_PENDING_TSN
,
TYPE_SCTP_OTHER_ICMP_UNREACHFRAG
,
};
#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
...
...
@@ -1033,27 +771,6 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
}
#define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
#define TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
...
...
@@ -1089,11 +806,11 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_sendbeat_8_3, .name = "sctp_sf_sendbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
timer_ignore, .name = "sctp_sf_timer_ignore
"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
sendbeat_8_3, .name = "sctp_sf_sendbeat_8_3
"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
timer_ignore, .name = "sctp_sf_timer_ignore
"}, \
}
#define TYPE_SCTP_EVENT_TIMEOUT_SACK { \
...
...
@@ -1139,39 +856,16 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
}
#define TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE { \
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
sctp_sm_table_entry_t
timeout_event_table
[
SCTP_NUM_TIMEOUT_TYPES
][
SCTP_STATE_NUM_STATES
]
=
{
TYPE_SCTP_EVENT_TIMEOUT_NONE
,
TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE
,
TYPE_SCTP_EVENT_TIMEOUT_T1_INIT
,
TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
,
TYPE_SCTP_EVENT_TIMEOUT_T3_RTX
,
TYPE_SCTP_EVENT_TIMEOUT_T4_RTO
,
TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD
,
TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT
,
TYPE_SCTP_EVENT_TIMEOUT_SACK
,
TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE
,
TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE
,
};
sctp_sm_table_entry_t
*
sctp_chunk_event_lookup
(
sctp_cid_t
cid
,
sctp_state_t
state
)
...
...
net/sctp/socket.c
View file @
a0065b2f
/* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-200
2
International Business Machines, Corp.
* Copyright (c) 2001-200
2
Intel Corp.
* Copyright (c) 2001-200
3
International Business Machines, Corp.
* Copyright (c) 2001-200
3
Intel Corp.
* Copyright (c) 2001-2002 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
...
...
@@ -47,6 +47,7 @@
* Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <samudrala@us.ibm.com>
* Inaky Perez-Gonzalez <inaky.gonzalez@intel.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -716,7 +717,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_opt_t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_chunk_t
*
chunk
=
NULL
;
union
sctp_addr
to
;
struct
sockaddr
*
msg_name
=
NULL
;
...
...
@@ -729,6 +730,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_scope_t
scope
;
long
timeo
;
__u16
sinfo_flags
=
0
;
struct
sk_buff_head
chunks
;
SCTP_DEBUG_PRINTK
(
"sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)
\n
"
,
sk
,
msg
,
msg_len
);
...
...
@@ -868,13 +870,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto
out_unlock
;
}
}
else
{
/* Check against the defaults. */
if
(
sinfo
->
sinfo_stream
>=
sp
->
initmsg
.
sinit_num_ostreams
)
{
err
=
-
EINVAL
;
goto
out_unlock
;
}
/* Check against the requested. */
if
(
sinfo
->
sinfo_stream
>=
sinit
->
sinit_num_ostreams
)
{
...
...
@@ -915,14 +910,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sinit
->
sinit_num_ostreams
;
}
if
(
sinit
->
sinit_max_instreams
)
{
if
(
sinit
->
sinit_max_instreams
<=
SCTP_MAX_STREAM
)
{
asoc
->
c
.
sinit_max_instreams
=
sinit
->
sinit_max_instreams
;
}
else
{
asoc
->
c
.
sinit_max_instreams
=
SCTP_MAX_STREAM
;
}
}
if
(
sinit
->
sinit_max_attempts
)
{
asoc
->
max_init_attempts
...
...
@@ -936,6 +925,15 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* Prime the peer's transport structures. */
transport
=
sctp_assoc_add_peer
(
asoc
,
&
to
,
GFP_KERNEL
);
if
(
!
transport
)
{
err
=
-
ENOMEM
;
goto
out_free
;
}
err
=
sctp_assoc_set_bind_addr_from_ep
(
asoc
,
GFP_KERNEL
);
if
(
err
<
0
)
{
err
=
-
ENOMEM
;
goto
out_free
;
}
}
/* ASSERT: we have a valid association at this point. */
...
...
@@ -949,19 +947,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto
out_free
;
}
/* FIXME: In the current implementation, a single chunk is created
* for the entire message initially, even if it has to be fragmented
* later. As the length field in the chunkhdr is used to set
* the chunk length, the maximum size of the chunk and hence the
* message is limited by its type(__u16).
* The real fix is to fragment the message before creating the chunks.
*/
if
(
msg_len
>
((
__u16
)(
~
(
__u16
)
0
)
-
WORD_ROUND
(
sizeof
(
sctp_data_chunk_t
)
+
1
)))
{
err
=
-
EMSGSIZE
;
goto
out_free
;
}
/* If fragmentation is disabled and the message length exceeds the
* association fragmentation point, return EMSGSIZE. The I-D
* does not specify what this error is, but this looks like
...
...
@@ -994,13 +979,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto
out_free
;
}
/* Get enough memory for the whole message. */
chunk
=
sctp_make_data_empty
(
asoc
,
sinfo
,
msg_len
);
if
(
!
chunk
)
{
err
=
-
ENOMEM
;
goto
out_free
;
}
#if 0
/* FIXME: This looks wrong so I'll comment out.
* We should be able to use this same technique for
...
...
@@ -1016,20 +994,13 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
#endif /* 0 */
/* Copy the message from the user. */
err
=
sctp_user_addto_chunk
(
chunk
,
msg_len
,
msg
->
msg_iov
);
if
(
err
<
0
)
/* Break the message into multiple chunks of maximum size. */
skb_queue_head_init
(
&
chunks
);
err
=
sctp_datachunks_from_user
(
asoc
,
sinfo
,
msg
,
msg_len
,
&
chunks
);
if
(
err
)
goto
out_free
;
SCTP_DEBUG_PRINTK
(
"Copied message to chunk: %p.
\n
"
,
chunk
);
/* Put the chunk->skb back into the form expected by send. */
__skb_pull
(
chunk
->
skb
,
(
__u8
*
)
chunk
->
chunk_hdr
-
(
__u8
*
)
chunk
->
skb
->
data
);
/* Do accounting for the write space. */
sctp_set_owner_w
(
chunk
);
/* Auto-connect, if we aren't connected already. */
if
(
SCTP_STATE_CLOSED
==
asoc
->
state
)
{
err
=
sctp_primitive_ASSOCIATE
(
asoc
,
NULL
);
if
(
err
<
0
)
...
...
@@ -1037,18 +1008,22 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK
(
"We associated primitively.
\n
"
);
}
/*
Send it to the lower layers.
*/
err
=
sctp_primitive_SEND
(
asoc
,
chunk
);
/*
Now send the (possibly) fragmented message.
*/
while
((
chunk
=
(
sctp_chunk_t
*
)
__skb_dequeue
(
&
chunks
)))
{
/* Do accounting for the write space. */
sctp_set_owner_w
(
chunk
);
/* Send it to the lower layers. */
sctp_primitive_SEND
(
asoc
,
chunk
);
SCTP_DEBUG_PRINTK
(
"We sent primitively.
\n
"
);
}
/* BUG: SCTP_CHECK_TIMER(sk); */
if
(
!
err
)
{
err
=
msg_len
;
goto
out_unlock
;
}
/* If we are already past ASSOCIATE, the lower
* layers are responsible for
its
cleanup.
* layers are responsible for
association
cleanup.
*/
goto
out_free_chunk
;
...
...
@@ -1091,18 +1066,25 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
static
int
sctp_skb_pull
(
struct
sk_buff
*
skb
,
int
len
)
{
struct
sk_buff
*
list
;
int
skb_len
=
skb_headlen
(
skb
);
int
rlen
;
if
(
len
<=
skb
->
len
)
{
if
(
len
<=
skb
_
len
)
{
__skb_pull
(
skb
,
len
);
return
0
;
}
len
-=
skb
->
len
;
__skb_pull
(
skb
,
skb
->
len
);
len
-=
skb
_
len
;
__skb_pull
(
skb
,
skb
_
len
);
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
len
=
sctp_skb_pull
(
list
,
len
);
if
(
!
len
)
rlen
=
sctp_skb_pull
(
list
,
len
);
skb
->
len
-=
(
len
-
rlen
);
skb
->
data_len
-=
(
len
-
rlen
);
if
(
!
rlen
)
return
0
;
len
=
rlen
;
}
return
len
;
...
...
@@ -1130,7 +1112,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
{
sctp_ulpevent_t
*
event
=
NULL
;
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
struct
sk_buff
*
skb
,
*
list
;
struct
sk_buff
*
skb
;
int
copied
;
int
err
=
0
;
int
skb_len
;
...
...
@@ -1154,8 +1136,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
* frag_list.
*/
skb_len
=
skb
->
len
;
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
skb_len
+=
list
->
len
;
copied
=
skb_len
;
if
(
copied
>
len
)
...
...
@@ -1198,6 +1178,12 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
goto
out_free
;
sctp_skb_pull
(
skb
,
copied
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
/* When only partial message is copied to the user, increase
* rwnd by that amount. If all the data in the skb is read,
* rwnd is updated when the skb's destructor is called via
* sctp_ulpevent_free().
*/
sctp_assoc_rwnd_increase
(
event
->
asoc
,
copied
);
goto
out
;
}
else
{
msg
->
msg_flags
|=
MSG_EOR
;
...
...
@@ -1260,7 +1246,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
struct
sctp_paddrparams
params
;
sctp_association_t
*
asoc
;
union
sctp_addr
*
addr
;
s
ctp_transport_
t
*
trans
;
s
truct
sctp_transpor
t
*
trans
;
int
error
;
if
(
optlen
!=
sizeof
(
struct
sctp_paddrparams
))
...
...
@@ -1449,7 +1435,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
sctp_opt_t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
union
sctp_addr
to
;
sctp_scope_t
scope
;
long
timeo
;
...
...
@@ -1514,6 +1500,15 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
/* Prime the peer's transport structures. */
transport
=
sctp_assoc_add_peer
(
asoc
,
&
to
,
GFP_KERNEL
);
if
(
!
transport
)
{
sctp_association_free
(
asoc
);
goto
out_unlock
;
}
err
=
sctp_assoc_set_bind_addr_from_ep
(
asoc
,
GFP_KERNEL
);
if
(
err
<
0
)
{
sctp_association_free
(
asoc
);
goto
out_unlock
;
}
err
=
sctp_primitive_ASSOCIATE
(
asoc
,
NULL
);
if
(
err
<
0
)
{
...
...
@@ -1666,7 +1661,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
struct
sctp_status
status
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
assoc
=
NULL
;
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
sctp_assoc_t
associd
;
int
retval
=
0
;
...
...
@@ -1885,7 +1880,7 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
struct
sctp_paddrparams
params
;
sctp_association_t
*
asoc
;
union
sctp_addr
*
addr
;
s
ctp_transport_
t
*
trans
;
s
truct
sctp_transpor
t
*
trans
;
if
(
len
!=
sizeof
(
struct
sctp_paddrparams
))
return
-
EINVAL
;
...
...
@@ -1932,6 +1927,166 @@ static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval
return
0
;
}
static
inline
int
sctp_getsockopt_get_peer_addrs_num
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
sctp_assoc_t
id
;
sctp_association_t
*
asoc
;
struct
list_head
*
pos
;
int
cnt
=
0
;
if
(
len
!=
sizeof
(
sctp_assoc_t
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
id
,
optval
,
sizeof
(
sctp_assoc_t
)))
return
-
EFAULT
;
/*
* For UDP-style sockets, id specifies the association to query.
*/
asoc
=
sctp_id2assoc
(
sk
,
id
);
if
(
!
asoc
)
return
-
EINVAL
;
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
cnt
++
;
}
if
(
copy_to_user
(
optval
,
&
cnt
,
sizeof
(
int
)))
return
-
EFAULT
;
return
0
;
}
static
inline
int
sctp_getsockopt_get_peer_addrs
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
sctp_association_t
*
asoc
;
struct
list_head
*
pos
;
int
cnt
=
0
;
struct
sctp_getaddrs
getaddrs
;
struct
sctp_transport
*
from
;
struct
sockaddr_storage
*
to
;
if
(
len
!=
sizeof
(
struct
sctp_getaddrs
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
getaddrs
,
optval
,
sizeof
(
struct
sctp_getaddrs
)))
return
-
EFAULT
;
if
(
getaddrs
.
addr_num
<=
0
)
return
-
EINVAL
;
/*
* For UDP-style sockets, id specifies the association to query.
*/
asoc
=
sctp_id2assoc
(
sk
,
getaddrs
.
assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
to
=
getaddrs
.
addrs
;
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
from
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
copy_to_user
(
to
,
&
from
->
ipaddr
,
sizeof
(
from
->
ipaddr
)))
return
-
EFAULT
;
to
++
;
cnt
++
;
if
(
cnt
>=
getaddrs
.
addr_num
)
break
;
}
getaddrs
.
addr_num
=
cnt
;
if
(
copy_to_user
(
optval
,
&
getaddrs
,
sizeof
(
struct
sctp_getaddrs
)))
return
-
EFAULT
;
return
0
;
}
static
inline
int
sctp_getsockopt_get_local_addrs_num
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
sctp_assoc_t
id
;
sctp_bind_addr_t
*
bp
;
sctp_association_t
*
asoc
;
struct
list_head
*
pos
;
int
cnt
=
0
;
if
(
len
!=
sizeof
(
sctp_assoc_t
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
id
,
optval
,
sizeof
(
sctp_assoc_t
)))
return
-
EFAULT
;
/*
* For UDP-style sockets, id specifies the association to query.
* If the id field is set to the value '0' then the locally bound
* addresses are returned without regard to any particular
* association.
*/
if
(
0
==
id
)
{
bp
=
&
sctp_sk
(
sk
)
->
ep
->
base
.
bind_addr
;
}
else
{
asoc
=
sctp_id2assoc
(
sk
,
id
);
if
(
!
asoc
)
return
-
EINVAL
;
bp
=
&
asoc
->
base
.
bind_addr
;
}
list_for_each
(
pos
,
&
bp
->
address_list
)
{
cnt
++
;
}
if
(
copy_to_user
(
optval
,
&
cnt
,
sizeof
(
int
)))
return
-
EFAULT
;
return
0
;
}
static
inline
int
sctp_getsockopt_get_local_addrs
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
sctp_bind_addr_t
*
bp
;
sctp_association_t
*
asoc
;
struct
list_head
*
pos
;
int
cnt
=
0
;
struct
sctp_getaddrs
getaddrs
;
struct
sockaddr_storage_list
*
from
;
struct
sockaddr_storage
*
to
;
if
(
len
!=
sizeof
(
struct
sctp_getaddrs
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
getaddrs
,
optval
,
sizeof
(
struct
sctp_getaddrs
)))
return
-
EFAULT
;
if
(
getaddrs
.
addr_num
<=
0
)
return
-
EINVAL
;
/*
* For UDP-style sockets, id specifies the association to query.
* If the id field is set to the value '0' then the locally bound
* addresses are returned without regard to any particular
* association.
*/
if
(
0
==
getaddrs
.
assoc_id
)
{
bp
=
&
sctp_sk
(
sk
)
->
ep
->
base
.
bind_addr
;
}
else
{
asoc
=
sctp_id2assoc
(
sk
,
getaddrs
.
assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
bp
=
&
asoc
->
base
.
bind_addr
;
}
to
=
getaddrs
.
addrs
;
list_for_each
(
pos
,
&
bp
->
address_list
)
{
from
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
(
copy_to_user
(
to
,
&
from
->
a
,
sizeof
(
from
->
a
)))
return
-
EFAULT
;
to
++
;
cnt
++
;
if
(
cnt
>=
getaddrs
.
addr_num
)
break
;
}
getaddrs
.
addr_num
=
cnt
;
if
(
copy_to_user
(
optval
,
&
getaddrs
,
sizeof
(
struct
sctp_getaddrs
)))
return
-
EFAULT
;
return
0
;
}
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
{
...
...
@@ -1989,6 +2144,26 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval
=
sctp_getsockopt_initmsg
(
sk
,
len
,
optval
,
optlen
);
break
;
case
SCTP_GET_PEER_ADDRS_NUM
:
retval
=
sctp_getsockopt_get_peer_addrs_num
(
sk
,
len
,
optval
,
optlen
);
break
;
case
SCTP_GET_LOCAL_ADDRS_NUM
:
retval
=
sctp_getsockopt_get_local_addrs_num
(
sk
,
len
,
optval
,
optlen
);
break
;
case
SCTP_GET_PEER_ADDRS
:
retval
=
sctp_getsockopt_get_peer_addrs
(
sk
,
len
,
optval
,
optlen
);
break
;
case
SCTP_GET_LOCAL_ADDRS
:
retval
=
sctp_getsockopt_get_local_addrs
(
sk
,
len
,
optval
,
optlen
);
break
;
default:
retval
=
-
ENOPROTOOPT
;
break
;
...
...
net/sctp/ssnmap.c
0 → 100644
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* These functions manipulate sctp SSN tracker.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
#include <linux/types.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* Storage size needed for map includes 2 headers and then the
* specific needs of in or out streams.
*/
static
inline
size_t
sctp_ssnmap_size
(
__u16
in
,
__u16
out
)
{
return
sizeof
(
struct
sctp_ssnmap
)
+
(
in
+
out
)
*
sizeof
(
__u16
);
}
/* Create a new sctp_ssnmap.
* Allocate room to store at least 'len' contiguous TSNs.
*/
struct
sctp_ssnmap
*
sctp_ssnmap_new
(
__u16
in
,
__u16
out
,
int
priority
)
{
struct
sctp_ssnmap
*
retval
;
retval
=
kmalloc
(
sctp_ssnmap_size
(
in
,
out
),
priority
);
if
(
!
retval
)
goto
fail
;
if
(
!
sctp_ssnmap_init
(
retval
,
in
,
out
))
goto
fail_map
;
retval
->
malloced
=
1
;
SCTP_DBG_OBJCNT_INC
(
ssnmap
);
return
retval
;
fail_map:
kfree
(
retval
);
fail:
return
NULL
;
}
/* Initialize a block of memory as a ssnmap. */
struct
sctp_ssnmap
*
sctp_ssnmap_init
(
struct
sctp_ssnmap
*
map
,
__u16
in
,
__u16
out
)
{
memset
(
map
,
0x00
,
sctp_ssnmap_size
(
in
,
out
));
/* Start 'in' stream just after the map header. */
map
->
in
.
ssn
=
(
__u16
*
)
&
map
[
1
];
map
->
in
.
len
=
in
;
/* Start 'out' stream just after 'in'. */
map
->
out
.
ssn
=
&
map
->
in
.
ssn
[
in
];
map
->
out
.
len
=
out
;
return
map
;
}
/* Clear out the ssnmap streams. */
void
sctp_ssnmap_clear
(
struct
sctp_ssnmap
*
map
)
{
size_t
size
;
size
=
(
map
->
in
.
len
+
map
->
out
.
len
)
*
sizeof
(
__u16
);
memset
(
map
->
in
.
ssn
,
0x00
,
size
);
}
/* Dispose of a ssnmap. */
void
sctp_ssnmap_free
(
struct
sctp_ssnmap
*
map
)
{
if
(
map
&&
map
->
malloced
)
{
kfree
(
map
);
SCTP_DBG_OBJCNT_DEC
(
ssnmap
);
}
}
net/sctp/transport.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines Corp.
* Copyright (c) 2001
-2003
International Business Machines Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
...
...
@@ -42,6 +42,7 @@
* Xingang Guo <xingang.guo@intel.com>
* Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -53,11 +54,12 @@
/* 1st Level Abstractions. */
/* Allocate and initialize a new transport. */
sctp_transport_t
*
sctp_transport_new
(
const
union
sctp_addr
*
addr
,
int
priority
)
struct
sctp_transport
*
sctp_transport_new
(
const
union
sctp_addr
*
addr
,
int
priority
)
{
s
ctp_transport_
t
*
transport
;
s
truct
sctp_transpor
t
*
transport
;
transport
=
t_new
(
s
ctp_transport_
t
,
priority
);
transport
=
t_new
(
s
truct
sctp_transpor
t
,
priority
);
if
(
!
transport
)
goto
fail
;
...
...
@@ -77,7 +79,7 @@ sctp_transport_t *sctp_transport_new(const union sctp_addr *addr, int priority)
}
/* Intialize a new transport from provided memory. */
s
ctp_transport_t
*
sctp_transport_init
(
sctp_transport_
t
*
peer
,
s
truct
sctp_transport
*
sctp_transport_init
(
struct
sctp_transpor
t
*
peer
,
const
union
sctp_addr
*
addr
,
int
priority
)
{
...
...
@@ -88,6 +90,9 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
peer
->
af_specific
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
peer
->
asoc
=
NULL
;
peer
->
dst
=
NULL
;
memset
(
&
peer
->
saddr
,
0
,
sizeof
(
union
sctp_addr
));
/* From 6.3.1 RTO Calculation:
*
* C1) Until an RTT measurement has been made for a packet sent to the
...
...
@@ -139,7 +144,7 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
/* This transport is no longer needed. Free up if possible, or
* delay until it last reference count.
*/
void
sctp_transport_free
(
s
ctp_transport_
t
*
transport
)
void
sctp_transport_free
(
s
truct
sctp_transpor
t
*
transport
)
{
transport
->
dead
=
1
;
...
...
@@ -153,7 +158,7 @@ void sctp_transport_free(sctp_transport_t *transport)
/* Destroy the transport data structure.
* Assumes there are no more users of this structure.
*/
void
sctp_transport_destroy
(
s
ctp_transport_
t
*
transport
)
void
sctp_transport_destroy
(
s
truct
sctp_transpor
t
*
transport
)
{
SCTP_ASSERT
(
transport
->
dead
,
"Transport is not dead"
,
return
);
...
...
@@ -168,7 +173,7 @@ void sctp_transport_destroy(sctp_transport_t *transport)
/* Start T3_rtx timer if it is not already running and update the heartbeat
* timer. This routine is called everytime a DATA chunk is sent.
*/
void
sctp_transport_reset_timers
(
s
ctp_transport_
t
*
transport
)
void
sctp_transport_reset_timers
(
s
truct
sctp_transpor
t
*
transport
)
{
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
...
...
@@ -177,15 +182,15 @@ void sctp_transport_reset_timers(sctp_transport_t *transport)
* start it running so that it will expire after the RTO of that
* address.
*/
if
(
!
timer_pending
(
&
transport
->
T3_rtx_timer
))
{
if
(
!
timer_pending
(
&
transport
->
T3_rtx_timer
))
if
(
!
mod_timer
(
&
transport
->
T3_rtx_timer
,
jiffies
+
transport
->
rto
))
sctp_transport_hold
(
transport
);
}
/* When a data chunk is sent, reset the heartbeat interval. */
if
(
!
mod_timer
(
&
transport
->
hb_timer
,
transport
->
hb_interval
+
transport
->
rto
+
jiffies
))
sctp_transport_timeout
(
transport
)
))
sctp_transport_hold
(
transport
);
}
...
...
@@ -193,80 +198,45 @@ void sctp_transport_reset_timers(sctp_transport_t *transport)
* Initialize fields from the association or from the sock itself.
* Register the reference count in the association.
*/
void
sctp_transport_set_owner
(
s
ctp_transport_
t
*
transport
,
void
sctp_transport_set_owner
(
s
truct
sctp_transpor
t
*
transport
,
sctp_association_t
*
asoc
)
{
transport
->
asoc
=
asoc
;
sctp_association_hold
(
asoc
);
}
/* Caches the dst entry for a transport's destination address and an optional
* souce address.
*/
void
sctp_transport_route
(
sctp_transport_t
*
transport
,
union
sctp_addr
*
saddr
,
struct
sctp_opt
*
opt
)
/* Initialize the pmtu of a transport. */
void
sctp_transport_pmtu
(
struct
sctp_transport
*
transport
)
{
sctp_association_t
*
asoc
=
transport
->
asoc
;
struct
sctp_af
*
af
=
transport
->
af_specific
;
union
sctp_addr
*
daddr
=
&
transport
->
ipaddr
;
sctp_bind_addr_t
*
bp
;
rwlock_t
*
addr_lock
;
struct
sockaddr_storage_list
*
laddr
;
struct
list_head
*
pos
;
struct
dst_entry
*
dst
;
union
sctp_addr
dst_saddr
;
dst
=
af
->
get_dst
(
daddr
,
saddr
);
/* If there is no association or if a source address is passed,
* no more validation is required.
*/
if
(
!
asoc
||
saddr
)
goto
out
;
if
(
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
{
bp
=
&
asoc
->
base
.
bind_addr
;
addr_lock
=
&
asoc
->
base
.
addr_lock
;
}
else
{
bp
=
&
asoc
->
ep
->
base
.
bind_addr
;
addr_lock
=
&
asoc
->
ep
->
base
.
addr_lock
;
}
dst
=
transport
->
af_specific
->
get_dst
(
NULL
,
&
transport
->
ipaddr
,
NULL
);
if
(
dst
)
{
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
sctp_read_lock
(
addr_lock
);
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
af
->
dst_saddr
(
&
dst_saddr
,
dst
);
if
(
opt
->
pf
->
cmp_addr
(
&
dst_saddr
,
&
laddr
->
a
,
opt
))
goto
out_unlock
;
}
sctp_read_unlock
(
addr_lock
);
/* None of the bound addresses match the source address of the
* dst. So release it.
*/
transport
->
pmtu
=
dst_pmtu
(
dst
);
dst_release
(
dst
);
}
}
else
transport
->
pmtu
=
SCTP_DEFAULT_MAXSEGMENT
;
}
/* Walk through the bind address list and try to get a dst that
* matches a bind address as the source
address.
/* Caches the dst entry and source address for a transport's destination
*
address.
*/
sctp_read_lock
(
addr_lock
);
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
void
sctp_transport_route
(
struct
sctp_transport
*
transport
,
union
sctp_addr
*
saddr
,
struct
sctp_opt
*
opt
)
{
sctp_association_t
*
asoc
=
transport
->
asoc
;
struct
sctp_af
*
af
=
transport
->
af_specific
;
union
sctp_addr
*
daddr
=
&
transport
->
ipaddr
;
struct
dst_entry
*
dst
;
dst
=
af
->
get_dst
(
daddr
,
&
laddr
->
a
);
if
(
dst
)
goto
out_unlock
;
}
dst
=
af
->
get_dst
(
asoc
,
daddr
,
saddr
);
if
(
saddr
)
memcpy
(
&
transport
->
saddr
,
saddr
,
sizeof
(
union
sctp_addr
));
else
af
->
get_saddr
(
asoc
,
dst
,
daddr
,
&
transport
->
saddr
);
out_unlock:
sctp_read_unlock
(
addr_lock
);
out:
transport
->
dst
=
dst
;
if
(
dst
)
transport
->
pmtu
=
dst_pmtu
(
dst
);
...
...
@@ -275,7 +245,7 @@ void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr,
}
/* Hold a reference to a transport. */
void
sctp_transport_hold
(
s
ctp_transport_
t
*
transport
)
void
sctp_transport_hold
(
s
truct
sctp_transpor
t
*
transport
)
{
atomic_inc
(
&
transport
->
refcnt
);
}
...
...
@@ -283,14 +253,14 @@ void sctp_transport_hold(sctp_transport_t *transport)
/* Release a reference to a transport and clean up
* if there are no more references.
*/
void
sctp_transport_put
(
s
ctp_transport_
t
*
transport
)
void
sctp_transport_put
(
s
truct
sctp_transpor
t
*
transport
)
{
if
(
atomic_dec_and_test
(
&
transport
->
refcnt
))
sctp_transport_destroy
(
transport
);
}
/* Update transport's RTO based on the newly calculated RTT. */
void
sctp_transport_update_rto
(
s
ctp_transport_
t
*
tp
,
__u32
rtt
)
void
sctp_transport_update_rto
(
s
truct
sctp_transpor
t
*
tp
,
__u32
rtt
)
{
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
...
...
@@ -360,8 +330,8 @@ void sctp_transport_update_rto(sctp_transport_t *tp, __u32 rtt)
/* This routine updates the transport's cwnd and partial_bytes_acked
* parameters based on the bytes acked in the received SACK.
*/
void
sctp_transport_raise_cwnd
(
s
ctp_transport_t
*
transport
,
__u32
sack_ctsn
,
__u32
bytes_acked
)
void
sctp_transport_raise_cwnd
(
s
truct
sctp_transport
*
transport
,
__u32
sack_ctsn
,
__u32
bytes_acked
)
{
__u32
cwnd
,
ssthresh
,
flight_size
,
pba
,
pmtu
;
...
...
@@ -389,8 +359,8 @@ void sctp_transport_raise_cwnd(sctp_transport_t *transport, __u32 sack_ctsn,
* two conditions are met can the cwnd be increased otherwise
* the cwnd MUST not be increased. If these conditions are met
* then cwnd MUST be increased by at most the lesser of
* 1) the total size of the previously outstanding DATA
chunk(s)
* acknowledged, and 2) the destination's path MTU.
* 1) the total size of the previously outstanding DATA
*
chunk(s)
acknowledged, and 2) the destination's path MTU.
*/
if
(
bytes_acked
>
pmtu
)
cwnd
+=
pmtu
;
...
...
@@ -403,18 +373,18 @@ void sctp_transport_raise_cwnd(sctp_transport_t *transport, __u32 sack_ctsn,
transport
,
bytes_acked
,
cwnd
,
ssthresh
,
flight_size
,
pba
);
}
else
{
/* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh,
upon
*
each SACK arrival that advances the Cumulative TSN Ack Point,
*
increase partial_bytes_acked by the total number of bytes of
*
all new chunks acknowledged in that SACK including chunks
*
acknowledged by the new Cumulative TSN Ack and by Gap Ack
* Blocks.
/* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh,
*
upon each SACK arrival that advances the Cumulative TSN Ack
*
Point, increase partial_bytes_acked by the total number of
*
bytes of all new chunks acknowledged in that SACK including
*
chunks acknowledged by the new Cumulative TSN Ack and by
*
Gap Ack
Blocks.
*
* When partial_bytes_acked is equal to or greater than cwnd
and
*
before the arrival of the SACK the sender had cwnd or more
*
bytes of data outstanding (i.e., before arrival of the SACK,
*
flightsize was greater than or equal to cwnd), increase cwnd
* by MTU, and reset partial_bytes_acked to
* When partial_bytes_acked is equal to or greater than cwnd
*
and before the arrival of the SACK the sender had cwnd or
*
more bytes of data outstanding (i.e., before arrival of the
*
SACK, flightsize was greater than or equal to cwnd),
*
increase cwnd
by MTU, and reset partial_bytes_acked to
* (partial_bytes_acked - cwnd).
*/
pba
+=
bytes_acked
;
...
...
@@ -437,7 +407,7 @@ void sctp_transport_raise_cwnd(sctp_transport_t *transport, __u32 sack_ctsn,
/* This routine is used to lower the transport's cwnd when congestion is
* detected.
*/
void
sctp_transport_lower_cwnd
(
s
ctp_transport_
t
*
transport
,
void
sctp_transport_lower_cwnd
(
s
truct
sctp_transpor
t
*
transport
,
sctp_lower_cwnd_t
reason
)
{
switch
(
reason
)
{
...
...
@@ -514,3 +484,12 @@ void sctp_transport_lower_cwnd(sctp_transport_t *transport,
transport
,
reason
,
transport
->
cwnd
,
transport
->
ssthresh
);
}
/* What is the next timeout value for this transport? */
unsigned
long
sctp_transport_timeout
(
struct
sctp_transport
*
t
)
{
unsigned
long
timeout
;
timeout
=
t
->
hb_interval
+
t
->
rto
+
sctp_jitter
(
t
->
rto
);
timeout
+=
jiffies
;
return
timeout
;
}
net/sctp/ulpevent.c
View file @
a0065b2f
...
...
@@ -606,9 +606,9 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
sctp_ulpevent_t
*
sctp_ulpevent_make_rcvmsg
(
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
int
priority
)
{
sctp_ulpevent_t
*
event
;
sctp_ulpevent_t
*
event
,
*
levent
;
struct
sctp_sndrcvinfo
*
info
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
,
*
list
;
size_t
padding
,
len
;
/* Clone the original skb, sharing the data. */
...
...
@@ -647,6 +647,16 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
event
->
malloced
=
1
;
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
sctp_ulpevent_set_owner_r
(
list
,
asoc
);
/* Initialize event with flags 0. */
levent
=
sctp_ulpevent_init
(
event
,
skb
,
0
);
if
(
!
levent
)
goto
fail_init
;
levent
->
malloced
=
1
;
}
info
=
(
struct
sctp_sndrcvinfo
*
)
&
event
->
sndrcvinfo
;
/* Sockets API Extensions for SCTP
...
...
@@ -762,8 +772,6 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
{
sctp_association_t
*
asoc
;
sctp_ulpevent_t
*
event
;
sctp_chunk_t
*
sack
;
struct
timer_list
*
timer
;
/* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as
...
...
@@ -773,50 +781,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
*/
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
asoc
=
event
->
asoc
;
if
(
asoc
->
rwnd_over
)
{
if
(
asoc
->
rwnd_over
>=
skb
->
len
)
{
asoc
->
rwnd_over
-=
skb
->
len
;
}
else
{
asoc
->
rwnd
+=
(
skb
->
len
-
asoc
->
rwnd_over
);
asoc
->
rwnd_over
=
0
;
}
}
else
{
asoc
->
rwnd
+=
skb
->
len
;
}
SCTP_DEBUG_PRINTK
(
"rwnd increased by %d to (%u, %u) - %u
\n
"
,
skb
->
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
,
asoc
->
a_rwnd
);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in Section 4.2.3.3
* of RFC 1122.
*/
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
(
asoc
->
rwnd
>
asoc
->
a_rwnd
)
&&
((
asoc
->
rwnd
-
asoc
->
a_rwnd
)
>=
min_t
(
__u32
,
(
asoc
->
base
.
sk
->
rcvbuf
>>
1
),
asoc
->
pmtu
)))
{
SCTP_DEBUG_PRINTK
(
"Sending window update SACK- rwnd: %u "
"a_rwnd: %u
\n
"
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
goto
out
;
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
sctp_push_outqueue
(
&
asoc
->
outqueue
,
sack
);
/* Stop the SACK timer. */
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
}
out:
sctp_assoc_rwnd_increase
(
asoc
,
skb_headlen
(
skb
));
sctp_association_put
(
asoc
);
}
...
...
@@ -838,16 +803,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
skb
->
destructor
=
sctp_rcvmsg_rfree
;
SCTP_ASSERT
(
asoc
->
rwnd
,
"rwnd zero"
,
return
);
SCTP_ASSERT
(
!
asoc
->
rwnd_over
,
"rwnd_over not zero"
,
return
);
if
(
asoc
->
rwnd
>=
skb
->
len
)
{
asoc
->
rwnd
-=
skb
->
len
;
}
else
{
asoc
->
rwnd_over
=
skb
->
len
-
asoc
->
rwnd
;
asoc
->
rwnd
=
0
;
}
SCTP_DEBUG_PRINTK
(
"rwnd decreased by %d to (%u, %u)
\n
"
,
skb
->
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
);
sctp_assoc_rwnd_decrease
(
asoc
,
skb_headlen
(
skb
));
}
/* A simple destructor to give up the reference to the association. */
...
...
net/sctp/ulpqueue.c
View file @
a0065b2f
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-200
2
International Business Machines, Corp.
* Copyright (c) 2001-200
3
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
...
...
@@ -49,51 +49,39 @@
#include <net/sctp/sm.h>
/* Forward declarations for internal helpers. */
static
inline
s
ctp_ulpevent_t
*
sctp_ulpqueue_reasm
(
sctp_ulpqueue_t
*
ulpq
,
sctp_ulpevent_t
*
event
);
static
inline
s
ctp_ulpevent_t
*
sctp_ulpqueue_order
(
sctp_ulpqueue_t
*
ulpq
,
sctp_ulpevent_t
*
event
);
static
inline
s
truct
sctp_ulpevent
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
);
static
inline
s
truct
sctp_ulpevent
*
sctp_ulpq_order
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
);
/* 1st Level Abstractions */
/* Create a new ULP queue. */
sctp_ulpqueue_t
*
sctp_ulpqueue_new
(
sctp_association_t
*
asoc
,
__u16
inbound
,
int
priority
)
struct
sctp_ulpq
*
sctp_ulpq_new
(
sctp_association_t
*
asoc
,
int
priority
)
{
sctp_ulpqueue_t
*
ulpq
;
size_t
size
;
struct
sctp_ulpq
*
ulpq
;
/* Today, there is only a fixed size of storage needed for
* stream support, but make the interfaces acceptable for
* the future.
*/
size
=
sizeof
(
sctp_ulpqueue_t
)
+
sctp_ulpqueue_storage_size
(
inbound
);
ulpq
=
kmalloc
(
size
,
priority
);
ulpq
=
kmalloc
(
sizeof
(
struct
sctp_ulpq
),
priority
);
if
(
!
ulpq
)
goto
fail
;
if
(
!
sctp_ulpq
ueue_init
(
ulpq
,
asoc
,
inbound
))
if
(
!
sctp_ulpq
_init
(
ulpq
,
asoc
))
goto
fail_init
;
ulpq
->
malloced
=
1
;
return
ulpq
;
fail_init:
kfree
(
ulpq
);
fail:
return
NULL
;
}
/* Initialize a ULP queue from a block of memory. */
sctp_ulpqueue_t
*
sctp_ulpqueue_init
(
sctp_ulpqueue_t
*
ulpq
,
sctp_association_t
*
asoc
,
__u16
inbound
)
struct
sctp_ulpq
*
sctp_ulpq_init
(
struct
sctp_ulpq
*
ulpq
,
sctp_association_t
*
asoc
)
{
memset
(
ulpq
,
sizeof
(
sctp_ulpqueue_t
)
+
sctp_ulpqueue_storage_size
(
inbound
),
0x00
);
memset
(
ulpq
,
sizeof
(
struct
sctp_ulpq
),
0x00
);
ulpq
->
asoc
=
asoc
;
spin_lock_init
(
&
ulpq
->
lock
);
skb_queue_head_init
(
&
ulpq
->
reasm
);
skb_queue_head_init
(
&
ulpq
->
lobby
);
ulpq
->
malloced
=
0
;
...
...
@@ -101,38 +89,39 @@ sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq,
return
ulpq
;
}
/* Flush the reassembly and ordering queues. */
void
sctp_ulpq
ueue_flush
(
sctp_ulpqueue_t
*
ulpq
)
void
sctp_ulpq
_flush
(
struct
sctp_ulpq
*
ulpq
)
{
struct
sk_buff
*
skb
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
while
((
skb
=
skb_dequeue
(
&
ulpq
->
lobby
)))
{
event
=
(
s
ctp_ulpevent_
t
*
)
skb
->
cb
;
event
=
(
s
truct
sctp_ulpeven
t
*
)
skb
->
cb
;
sctp_ulpevent_free
(
event
);
}
while
((
skb
=
skb_dequeue
(
&
ulpq
->
reasm
)))
{
event
=
(
s
ctp_ulpevent_
t
*
)
skb
->
cb
;
event
=
(
s
truct
sctp_ulpeven
t
*
)
skb
->
cb
;
sctp_ulpevent_free
(
event
);
}
}
/* Dispose of a ulpqueue. */
void
sctp_ulpq
ueue_free
(
sctp_ulpqueue_t
*
ulpq
)
void
sctp_ulpq
_free
(
struct
sctp_ulpq
*
ulpq
)
{
sctp_ulpq
ueue
_flush
(
ulpq
);
sctp_ulpq_flush
(
ulpq
);
if
(
ulpq
->
malloced
)
kfree
(
ulpq
);
}
/* Process an incoming DATA chunk. */
int
sctp_ulpq
ueue_tail_data
(
sctp_ulpqueue_t
*
ulpq
,
sctp_chunk_t
*
chunk
,
int
sctp_ulpq
_tail_data
(
struct
sctp_ulpq
*
ulpq
,
sctp_chunk_t
*
chunk
,
int
priority
)
{
struct
sk_buff_head
temp
;
sctp_data_chunk_t
*
hdr
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
hdr
=
(
sctp_data_chunk_t
*
)
chunk
->
chunk_hdr
;
...
...
@@ -147,7 +136,7 @@ int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk,
return
-
ENOMEM
;
/* Do reassembly if needed. */
event
=
sctp_ulpq
ueue
_reasm
(
ulpq
,
event
);
event
=
sctp_ulpq_reasm
(
ulpq
,
event
);
/* Do ordering if needed. */
if
(
event
)
{
...
...
@@ -155,18 +144,18 @@ int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk,
skb_queue_head_init
(
&
temp
);
skb_queue_tail
(
&
temp
,
event
->
parent
);
event
=
sctp_ulpq
ueue
_order
(
ulpq
,
event
);
event
=
sctp_ulpq_order
(
ulpq
,
event
);
}
/* Send event to the ULP. */
if
(
event
)
sctp_ulpq
ueue
_tail_event
(
ulpq
,
event
);
sctp_ulpq_tail_event
(
ulpq
,
event
);
return
0
;
}
/* Add a new event for propogation to the ULP. */
int
sctp_ulpq
ueue_tail_event
(
sctp_ulpqueue_t
*
ulpq
,
sctp_ulpevent_
t
*
event
)
int
sctp_ulpq
_tail_event
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpeven
t
*
event
)
{
struct
sock
*
sk
=
ulpq
->
asoc
->
base
.
sk
;
...
...
@@ -202,20 +191,18 @@ int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event)
/* 2nd Level Abstractions */
/* Helper function to store chunks that need to be reassembled. */
static
inline
void
sctp_ulpqueue_store_reasm
(
sctp_ulpqueue_t
*
ulpq
,
sctp_ulpevent_t
*
event
)
static
inline
void
sctp_ulpq_store_reasm
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
{
struct
sk_buff
*
pos
,
*
tmp
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
__u32
tsn
,
ctsn
;
unsigned
long
flags
__attribute
((
unused
));
tsn
=
event
->
sndrcvinfo
.
sinfo_tsn
;
sctp_spin_lock_irqsave
(
&
ulpq
->
reasm
.
lock
,
flags
);
/* Find the right place in this list. We store them by TSN. */
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
(
s
ctp_ulpevent_
t
*
)
pos
->
cb
;
cevent
=
(
s
truct
sctp_ulpeven
t
*
)
pos
->
cb
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
if
(
TSN_lt
(
tsn
,
ctsn
))
...
...
@@ -227,22 +214,34 @@ static inline void sctp_ulpqueue_store_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpeven
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
else
__skb_queue_tail
(
&
ulpq
->
reasm
,
event
->
parent
);
sctp_spin_unlock_irqrestore
(
&
ulpq
->
reasm
.
lock
,
flags
);
}
/* Helper function to return an event corresponding to the reassembled
* datagram.
* This routine creates a re-assembled skb given the first and last skb's
* as stored in the reassembly queue. The skb's may be non-linear if the sctp
* payload was fragmented on the way and ip had to reassemble them.
* We add the rest of skb's to the first skb's fraglist.
*/
static
inline
s
ctp_ulpevent_
t
*
sctp_make_reassembled_event
(
struct
sk_buff
*
f_frag
,
struct
sk_buff
*
l_frag
)
static
inline
s
truct
sctp_ulpeven
t
*
sctp_make_reassembled_event
(
struct
sk_buff
*
f_frag
,
struct
sk_buff
*
l_frag
)
{
struct
sk_buff
*
pos
;
sctp_ulpevent_t
*
event
;
struct
sk_buff
*
pnext
;
struct
sctp_ulpevent
*
event
;
struct
sk_buff
*
pnext
,
*
last
;
struct
sk_buff
*
list
=
skb_shinfo
(
f_frag
)
->
frag_list
;
/* Store the pointer to the 2nd skb */
pos
=
f_frag
->
next
;
/* Set the first fragment's frag_list to point to the 2nd fragment. */
/* Get the last skb in the f_frag's frag_list if present. */
for
(
last
=
list
;
list
;
last
=
list
,
list
=
list
->
next
);
/* Add the list of remaining fragments to the first fragments
* frag_list.
*/
if
(
last
)
last
->
next
=
pos
;
else
skb_shinfo
(
f_frag
)
->
frag_list
=
pos
;
/* Remove the first fragment from the reassembly queue. */
...
...
@@ -250,6 +249,10 @@ static inline sctp_ulpevent_t *sctp_make_reassembled_event(struct sk_buff *f_fra
do
{
pnext
=
pos
->
next
;
/* Update the len and data_len fields of the first fragment. */
f_frag
->
len
+=
pos
->
len
;
f_frag
->
data_len
+=
pos
->
len
;
/* Remove the fragment from the reassembly queue. */
__skb_unlink
(
pos
,
pos
->
list
);
...
...
@@ -269,13 +272,12 @@ static inline sctp_ulpevent_t *sctp_make_reassembled_event(struct sk_buff *f_fra
/* Helper function to check if an incoming chunk has filled up the last
* missing fragment in a SCTP datagram and return the corresponding event.
*/
static
inline
sctp_ulpevent_t
*
sctp_ulpq
ueue_retrieve_reassembled
(
sctp_ulpqueue_t
*
ulpq
)
static
inline
sctp_ulpevent_t
*
sctp_ulpq
_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
{
struct
sk_buff
*
pos
,
*
tmp
;
sctp_ulpevent_t
*
cevent
;
struct
sk_buff
*
first_frag
=
NULL
;
__u32
ctsn
,
next_tsn
;
unsigned
long
flags
__attribute
((
unused
));
sctp_ulpevent_t
*
retval
=
NULL
;
/* Initialized to 0 just to avoid compiler warning message. Will
...
...
@@ -284,8 +286,6 @@ static inline sctp_ulpevent_t *sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_
*/
next_tsn
=
0
;
sctp_spin_lock_irqsave
(
&
ulpq
->
reasm
.
lock
,
flags
);
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for a sequence of
* fragmented chunks that complete a datagram.
...
...
@@ -327,7 +327,6 @@ static inline sctp_ulpevent_t *sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_
if
(
retval
)
break
;
}
sctp_spin_unlock_irqrestore
(
&
ulpq
->
reasm
.
lock
,
flags
);
return
retval
;
}
...
...
@@ -335,7 +334,7 @@ static inline sctp_ulpevent_t *sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
* need reassembling.
*/
static
inline
sctp_ulpevent_t
*
sctp_ulpq
ueue_reasm
(
sctp_ulpqueue_t
*
ulpq
,
static
inline
sctp_ulpevent_t
*
sctp_ulpq
_reasm
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_t
*
event
)
{
sctp_ulpevent_t
*
retval
=
NULL
;
...
...
@@ -350,8 +349,8 @@ static inline sctp_ulpevent_t *sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq,
if
(
SCTP_DATA_NOT_FRAG
==
(
event
->
chunk_flags
&
SCTP_DATA_FRAG_MASK
))
return
event
;
sctp_ulpq
ueue
_store_reasm
(
ulpq
,
event
);
retval
=
sctp_ulpq
ueue
_retrieve_reassembled
(
ulpq
);
sctp_ulpq_store_reasm
(
ulpq
,
event
);
retval
=
sctp_ulpq_retrieve_reassembled
(
ulpq
);
return
retval
;
}
...
...
@@ -359,20 +358,20 @@ static inline sctp_ulpevent_t *sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq,
/* Helper function to gather skbs that have possibly become
* ordered by an an incoming chunk.
*/
static
inline
void
sctp_ulpq
ueue_retrieve_ordered
(
sctp_ulpqueue_t
*
ulpq
,
static
inline
void
sctp_ulpq
_retrieve_ordered
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_t
*
event
)
{
struct
sk_buff
*
pos
,
*
tmp
;
sctp_ulpevent_t
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_stream
*
in
;
__u16
sid
,
csid
;
__u16
ssn
,
cssn
;
unsigned
long
flags
__attribute
((
unused
));
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
in
=
&
ulpq
->
asoc
->
ssnmap
->
in
;
/* We are holding the chunks by stream, by SSN. */
sctp_spin_lock_irqsave
(
&
ulpq
->
lobby
.
lock
,
flags
);
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
cevent
=
(
sctp_ulpevent_t
*
)
pos
->
cb
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
...
...
@@ -386,32 +385,31 @@ static inline void sctp_ulpqueue_retrieve_ordered(sctp_ulpqueue_t *ulpq,
if
(
csid
<
sid
)
continue
;
if
(
cssn
!=
ulpq
->
ssn
[
sid
]
)
if
(
cssn
!=
sctp_ssn_peek
(
in
,
sid
)
)
break
;
ulpq
->
ssn
[
sid
]
++
;
/* Found it, so mark in the ssnmap. */
sctp_ssn_next
(
in
,
sid
);
__skb_unlink
(
pos
,
pos
->
list
);
/* Attach all gathered skbs to the event. */
__skb_queue_tail
(
event
->
parent
->
list
,
pos
);
}
sctp_spin_unlock_irqrestore
(
&
ulpq
->
lobby
.
lock
,
flags
);
}
/* Helper function to store chunks needing ordering. */
static
inline
void
sctp_ulpq
ueue_store_ordered
(
sctp_ulpqueue_t
*
ulpq
,
static
inline
void
sctp_ulpq
_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_t
*
event
)
{
struct
sk_buff
*
pos
,
*
tmp
;
sctp_ulpevent_t
*
cevent
;
__u16
sid
,
csid
;
__u16
ssn
,
cssn
;
unsigned
long
flags
__attribute
((
unused
));
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
sctp_spin_lock_irqsave
(
&
ulpq
->
lobby
.
lock
,
flags
);
/* Find the right place in this list. We store them by
* stream ID and then by SSN.
...
...
@@ -432,14 +430,13 @@ static inline void sctp_ulpqueue_store_ordered(sctp_ulpqueue_t *ulpq,
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
else
__skb_queue_tail
(
&
ulpq
->
lobby
,
event
->
parent
);
sctp_spin_unlock_irqrestore
(
&
ulpq
->
lobby
.
lock
,
flags
);
}
static
inline
sctp_ulpevent_t
*
sctp_ulpq
ueue_order
(
sctp_ulpqueue_t
*
ulpq
,
static
inline
sctp_ulpevent_t
*
sctp_ulpq
_order
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_t
*
event
)
{
__u16
sid
,
ssn
;
struct
sctp_stream
*
in
;
/* FIXME: We should be using some new chunk structure here
* instead of carrying chunk fields in the event structure.
...
...
@@ -454,23 +451,24 @@ static inline sctp_ulpevent_t *sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq,
/* Note: The stream ID must be verified before this routine. */
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
in
=
&
ulpq
->
asoc
->
ssnmap
->
in
;
/* Is this the expected SSN for this stream ID? */
if
(
ssn
!=
ulpq
->
ssn
[
sid
]
)
{
if
(
ssn
!=
sctp_ssn_peek
(
in
,
sid
)
)
{
/* We've received something out of order, so find where it
* needs to be placed. We order by stream and then by SSN.
*/
sctp_ulpq
ueue
_store_ordered
(
ulpq
,
event
);
sctp_ulpq_store_ordered
(
ulpq
,
event
);
return
NULL
;
}
/* Mark that the next chunk has been found. */
ulpq
->
ssn
[
sid
]
++
;
sctp_ssn_next
(
in
,
sid
)
;
/* Go find any other chunks that were waiting for
* ordering.
*/
sctp_ulpq
ueue
_retrieve_ordered
(
ulpq
,
event
);
sctp_ulpq_retrieve_ordered
(
ulpq
,
event
);
return
event
;
}
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