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