Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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
Hide 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
/* SCTP kernel reference Implementation Copyright (C) 1999-2001
* Cisco, Motorola, and IBM
*
*
* This file is part of the SCTP kernel reference Implementation
*
*
* These are the definitions needed for the command object.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
*
* 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
*
* 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.
*
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to one of the
* following email addresses:
*
*
* La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* 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.
*/
...
...
@@ -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_TIMERS_START
,
/* Start 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
...
...
@@ -3,33 +3,33 @@
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
*
*
* This file is part of the implementation of the add-IP extension,
* based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
* for the SCTP kernel reference Implementation.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
*
* 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
*
* 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.
*
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to one of the following email
* addresses:
*
*
* La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Randall Stewart <randall@stewart.chicago.il.us>
...
...
@@ -38,14 +38,14 @@
* Xingang Guo <xingang.guo@intel.com>
* Sridhar Samudrala <samudrala@us.ibm.com>
* Daisy Chang <daisyc@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.
*
*
* There are still LOTS of bugs in this code... I always run on the motto
* "it is a wonder any code ever works :)"
*
*
*
*
*/
#ifndef __sctp_constants_h__
...
...
@@ -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
*
...
...
@@ -36,7 +36,9 @@
* La Monte H.P. Yarroll <piggy@acm.org>
* Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@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
...
...
@@ -42,7 +42,7 @@
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Ardelle Fan <ardelle.fan@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.
...
...
@@ -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:
...
...
@@ -183,8 +181,8 @@ struct SCTP_protocol {
/* Valid.Cookie.Life - 60 seconds */
int
valid_cookie_life
;
/* Whether Cookie Preservative is enabled(1) or not(0) */
/* Whether Cookie Preservative is enabled(1) or not(0) */
int
cookie_preserve_enable
;
/* Association.Max.Retrans - 10 attempts
...
...
@@ -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
*
,
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
*
,
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
);
struct
sctp_transport
*
sctp_transport_new
(
const
union
sctp_addr
*
,
int
);
struct
sctp_transport
*
sctp_transport_init
(
struct
sctp_transport
*
,
const
union
sctp_addr
*
,
int
);
void
sctp_transport_set_owner
(
struct
sctp_transport
*
,
sctp_association_t
*
);
void
sctp_transport_route
(
struct
sctp_transport
*
,
union
sctp_addr
*
,
struct
sctp_opt
*
);
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,18 +1614,19 @@ 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
*
,
const
union
sctp_addr
*
,
const
union
sctp_addr
*
);
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
*
);
void
sctp_assoc_update
(
sctp_association_t
*
dst
,
sctp_association_t
*
src
);
...
...
@@ -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.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* reassembly and ordering.
*
* 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
*
* 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 one of the
* following email addresses:
*
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
*
* Boston, MA 02111-1307, USA.
*
* 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>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
...
...
@@ -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__ */
...
...
@@ -90,4 +75,4 @@ int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *);
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_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
))
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
_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
,
const
union
sctp_addr
*
addr
,
int
priority
)
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
,
const
union
sctp_addr
*
laddr
,
const
union
sctp_addr
*
paddr
)
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,8 +47,8 @@ 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 */
sctp_init_cmd_seq
(
retval
);
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
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
transport
)
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
const
union
sctp_addr
*
paddr
,
struct
sctp_transport
**
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
,
.
setsockopt
=
ipv6_setsockopt
,
.
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
,
...
...
@@ -572,7 +644,7 @@ int sctp_v6_init(void)
/* Register the SCTP specfic AF_INET6 functions. */
sctp_register_af
(
&
sctp_ipv6_specific
);
/* Register notifier for inet6 address additions/deletions. */
/* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
return
0
;
...
...
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;
...
...
@@ -47,39 +47,39 @@
*/
#include <linux/types.h>
#include <linux/list.h>
/* For struct list_head */
#include <linux/list.h>
/* For struct list_head */
#include <linux/socket.h>
#include <linux/ip.h>
#include <net/sock.h>
/* For skb_set_owner_w */
#include <net/sock.h>
/* For skb_set_owner_w */
#include <net/sctp/sctp.h>
/* 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
;
...
...
@@ -230,15 +233,15 @@ void sctp_retransmit_insert(struct list_head *tlchunk, sctp_outqueue_t *q)
list_add_tail
(
tlchunk
,
&
q
->
retransmit
);
}
}
/* 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
,
int
rtx_timeout
,
int
*
start_timer
)
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. */
event
=
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
);
}
ev
=
sctp_ulpevent_make_send_failed
(
asoc
,
chunk
,
SCTP_DATA_UNSENT
,
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
,
...
...
@@ -1028,17 +1068,17 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
}
return
highest_new_tsn
;
}
}
/* 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
;
...
...
@@ -1053,7 +1093,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
sack_ctsn
=
ntohl
(
sack
->
cum_tsn_ack
);
/* Get the highest TSN in the sack. */
highest_tsn
=
sack_ctsn
+
highest_tsn
=
sack_ctsn
+
ntohs
(
frags
[
ntohs
(
sack
->
num_gap_ack_blocks
)
-
1
].
gab
.
end
);
if
(
TSN_lt
(
asoc
->
highest_sacked
,
highest_tsn
))
{
...
...
@@ -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
...
...
@@ -82,12 +82,12 @@ static const sctp_supported_addrs_param_t sat_param = {
/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above
* structure is split and the address types array is initialized using a
* fixed length array.
* fixed length array.
*/
static
const
__u16
sat_addr_types
[
2
]
=
{
SCTP_PARAM_IPV4_ADDRESS
,
SCTP_V6
(
SCTP_PARAM_IPV6_ADDRESS
,)
};
};
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
...
...
@@ -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
)
{
/* 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.
if
(
SCTP_PARAM_STATE_COOKIE
==
param
.
p
->
type
)
has_cookie
=
1
;
}
/* 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,9 +391,9 @@ 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
,
command
->
obj
.
ptr
,
GFP_ATOMIC
);
sctp_ulpq_tail_data
(
&
asoc
->
ulpq
,
command
->
obj
.
ptr
,
GFP_ATOMIC
);
break
;
case
SCTP_CMD_EVENT_ULP
:
...
...
@@ -407,14 +403,14 @@ 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
,
command
->
obj
.
ptr
);
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
,
command
->
obj
.
ptr
);
error
=
sctp_
outq_tail
(
&
asoc
->
outqueue
,
command
->
obj
.
ptr
);
break
;
case
SCTP_CMD_SEND_PKT
:
...
...
@@ -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
:
...
...
@@ -599,7 +595,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case
SCTP_CMD_RTO_PENDING
:
t
=
command
->
obj
.
transport
;
t
->
rto_pending
=
1
;
t
->
rto_pending
=
1
;
break
;
default:
...
...
@@ -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.
...
...
@@ -1095,7 +1083,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
* inside the cookie. In reality, this is only used for INIT-ACK processing
* since all other cases use "temporary" associations and can do all
* their work in statefuns directly.
* their work in statefuns directly.
*/
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
asoc
,
...
...
@@ -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
);
}
}
}
/* Helper function to update the heartbeat timer. */
static
void
sctp_cmd_hb_timers_update
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_transport_t
*
t
)
static
void
sctp_cmd_hb_timers_stop
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
)
{
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
t
->
hb_interval
+
t
->
rto
+
jiffies
))
sctp_transport_hold
(
t
);
}
struct
sctp_transport
*
t
;
struct
list_head
*
pos
;
/* 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
;
/* Stop all heartbeat timers. */
list_for_each_safe
(
pos
,
temp
,
&
bp
->
address_list
)
{
list_del_init
(
pos
);
list_add_tail
(
pos
,
&
asoc
->
base
.
bind_addr
.
address_list
);
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
);
}
}
/* Free the temporary bind addr header, otherwise
* there will a memory leak.
*/
sctp_bind_addr_free
(
bp
);
/* Helper function to update the heartbeat timer. */
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
struct
sctp_transport
*
t
)
{
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)))
sctp_transport_hold
(
t
);
}
/* 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
,
...
...
@@ -1528,13 +1540,14 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
SCTP_ULPEVENT
(
ev
));
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSMIT
,
SCTP_NULL
());
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
if
(
!
repl
)
goto
nomem
;
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.
...
...
@@ -131,7 +132,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
static
long
sctp_get_port_local
(
struct
sock
*
,
union
sctp_addr
*
);
/* Verify this is a valid sockaddr. */
static
struct
sctp_af
*
sctp_sockaddr_af
(
struct
sctp_opt
*
opt
,
static
struct
sctp_af
*
sctp_sockaddr_af
(
struct
sctp_opt
*
opt
,
union
sctp_addr
*
addr
,
int
len
)
{
struct
sctp_af
*
af
;
...
...
@@ -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
);
...
...
@@ -754,8 +756,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
*/
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sp
->
type
)
&&
msg
->
msg_name
)
{
int
msg_namelen
=
msg
->
msg_namelen
;
err
=
sctp_verify_addr
(
sk
,
(
union
sctp_addr
*
)
msg
->
msg_name
,
err
=
sctp_verify_addr
(
sk
,
(
union
sctp_addr
*
)
msg
->
msg_name
,
msg_namelen
);
if
(
err
)
return
err
;
...
...
@@ -806,7 +808,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
asoc
=
sctp_endpoint_lookup_assoc
(
ep
,
&
to
,
&
transport
);
if
(
!
asoc
)
{
/* If we could not find a matching association on the
* endpoint, make sure that there is no peeled-off
* endpoint, make sure that there is no peeled-off
* association on another socket.
*/
if
(
sctp_endpoint_is_peeled_off
(
ep
,
&
to
))
{
...
...
@@ -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
;
}
asoc
->
c
.
sinit_max_instreams
=
sinit
->
sinit_max_instreams
;
}
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
)))
{
SCTP_DEBUG_PRINTK
(
"We sent primitively.
\n
"
);
/* 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
;
...
...
@@ -1086,23 +1061,30 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
* frag_list. len specifies the total amount of data that needs to be removed.
* when 'len' bytes could be removed from the skb, it returns 0.
* If 'len' exceeds the total skb length, it returns the no. of bytes that
* could not be removed.
*/
* could not be removed.
*/
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
;
...
...
@@ -1152,10 +1134,8 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
/* Get the total length of the skb including any skb's in the
* 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
)
...
...
@@ -1190,14 +1170,20 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
/* If skb's length exceeds the user's buffer, update the skb and
* push it back to the receive_queue so that the next call to
* recvmsg() will return the remaining data. Don't set MSG_EOR.
* Otherwise, set MSG_EOR indicating the end of a message.
* Otherwise, set MSG_EOR indicating the end of a message.
*/
if
(
skb_len
>
copied
)
{
msg
->
msg_flags
&=
~
MSG_EOR
;
if
(
flags
&
MSG_PEEK
)
goto
out_free
;
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
;
...
...
@@ -1463,7 +1449,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
/* connect() cannot be done on a peeled-off socket. */
/* connect() cannot be done on a peeled-off socket. */
if
(
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
==
sp
->
type
)
{
err
=
-
EISCONN
;
goto
out_unlock
;
...
...
@@ -1471,7 +1457,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
err
=
sctp_verify_addr
(
sk
,
(
union
sctp_addr
*
)
uaddr
,
addr_len
);
if
(
err
)
goto
out_unlock
;
goto
out_unlock
;
memcpy
(
&
to
,
uaddr
,
addr_len
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
...
...
@@ -1479,7 +1465,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
asoc
=
sctp_endpoint_lookup_assoc
(
ep
,
&
to
,
&
transport
);
if
(
asoc
)
{
if
(
asoc
->
state
>=
SCTP_STATE_ESTABLISHED
)
err
=
-
EISCONN
;
err
=
-
EISCONN
;
else
err
=
-
EALREADY
;
goto
out_unlock
;
...
...
@@ -1514,10 +1500,19 @@ 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
)
{
sctp_association_free
(
asoc
);
sctp_association_free
(
asoc
);
goto
out_unlock
;
}
...
...
@@ -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
;
...
...
@@ -1915,7 +1910,7 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
* before this address shall be considered unreachable.
*/
params
.
spp_pathmaxrxt
=
trans
->
error_threshold
;
if
(
copy_to_user
(
optval
,
&
params
,
len
))
return
-
EFAULT
;
*
optlen
=
len
;
...
...
@@ -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
;
...
...
@@ -2029,7 +2204,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
sctp_protocol_t
*
sctp
=
sctp_get_protocol
();
unsigned
short
snum
;
int
ret
;
/* NOTE: Remember to put this back to net order. */
addr
->
v4
.
sin_port
=
ntohs
(
addr
->
v4
.
sin_port
);
snum
=
addr
->
v4
.
sin_port
;
...
...
@@ -2098,7 +2273,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
}
}
if
(
pp
!=
NULL
&&
pp
->
sk
!=
NULL
)
{
/* We had a port hash table hit - there is an
* available port (pp != NULL) and it is being
...
...
@@ -2129,7 +2304,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
if
(
sk_reuse
&&
sk2
->
reuse
)
continue
;
if
(
sctp_bind_addr_match
(
&
ep2
->
base
.
bind_addr
,
addr
,
sctp_sk
(
sk
)))
goto
found
;
...
...
@@ -2187,7 +2362,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
}
/* Assign a 'snum' port to the socket. If snum == 0, an ephemeral
* port is requested.
* port is requested.
*/
static
int
sctp_get_port
(
struct
sock
*
sk
,
unsigned
short
snum
)
{
...
...
@@ -2657,10 +2832,10 @@ static int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len)
return
-
EINVAL
;
/* Is this a valid SCTP address? */
if
(
!
af
->
addr_valid
((
union
sctp_addr
*
)
addr
))
if
(
!
af
->
addr_valid
((
union
sctp_addr
*
)
addr
))
return
-
EINVAL
;
return
0
;
return
0
;
}
/* Get the sndbuf space available at the time on the association. */
...
...
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,9 +79,9 @@ 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
,
const
union
sctp_addr
*
addr
,
int
priority
)
s
truct
sctp_transport
*
sctp_transport_init
(
struct
sctp_transpor
t
*
peer
,
const
union
sctp_addr
*
addr
,
int
priority
)
{
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
...
...
@@ -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,96 +182,61 @@ 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_hold
(
transport
);
sctp_transport_timeout
(
transport
)
))
sctp_transport_hold
(
transport
);
}
/* This transport has been assigned to an association.
* 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.
*/
sctp_read_lock
(
addr_lock
);
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
/* Caches the dst entry and source address for a transport's destination
* address.
*/
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
();
...
...
@@ -330,7 +300,7 @@ void sctp_transport_update_rto(sctp_transport_t *tp, __u32 rtt)
if
(
tp
->
rttvar
==
0
)
tp
->
rttvar
=
SCTP_CLOCK_GRANULARITY
;
/* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR.
*/
/* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */
tp
->
rto
=
tp
->
srtt
+
(
tp
->
rttvar
<<
2
);
/* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min
...
...
@@ -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,29 +214,45 @@ 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. */
skb_shinfo
(
f_frag
)
->
frag_list
=
pos
;
/* 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. */
__skb_unlink
(
f_frag
,
f_frag
->
list
);
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
,
sctp_ulpevent_t
*
event
)
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
,
sctp_ulpevent_t
*
event
)
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
,
sctp_ulpevent_t
*
event
)
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