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
9967b51f
Commit
9967b51f
authored
Feb 17, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Plain Diff
Merge us.ibm.com:/home/sridhar/BK/linux-2.5.62
into us.ibm.com:/home/sridhar/BK/lksctp-2.5.62
parents
611f4c04
13970d8e
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
1254 additions
and
572 deletions
+1254
-572
include/net/sctp/command.h
include/net/sctp/command.h
+3
-2
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+1
-0
include/net/sctp/structs.h
include/net/sctp/structs.h
+42
-43
include/net/sctp/tsnmap.h
include/net/sctp/tsnmap.h
+59
-37
include/net/sctp/ulpevent.h
include/net/sctp/ulpevent.h
+87
-75
include/net/sctp/ulpqueue.h
include/net/sctp/ulpqueue.h
+11
-4
include/net/sctp/user.h
include/net/sctp/user.h
+3
-1
net/sctp/Makefile
net/sctp/Makefile
+1
-1
net/sctp/associola.c
net/sctp/associola.c
+41
-32
net/sctp/endpointola.c
net/sctp/endpointola.c
+8
-6
net/sctp/input.c
net/sctp/input.c
+8
-3
net/sctp/inqueue.c
net/sctp/inqueue.c
+13
-13
net/sctp/ipv6.c
net/sctp/ipv6.c
+3
-1
net/sctp/output.c
net/sctp/output.c
+1
-0
net/sctp/outqueue.c
net/sctp/outqueue.c
+12
-1
net/sctp/proc.c
net/sctp/proc.c
+128
-0
net/sctp/protocol.c
net/sctp/protocol.c
+18
-5
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+17
-19
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+16
-13
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+106
-20
net/sctp/socket.c
net/sctp/socket.c
+140
-44
net/sctp/tsnmap.c
net/sctp/tsnmap.c
+60
-56
net/sctp/ulpevent.c
net/sctp/ulpevent.c
+176
-129
net/sctp/ulpqueue.c
net/sctp/ulpqueue.c
+300
-67
No files found.
include/net/sctp/command.h
View file @
9967b51f
...
@@ -86,6 +86,7 @@ typedef enum {
...
@@ -86,6 +86,7 @@ typedef enum {
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING
,
/* Set transport's rto_pending. */
SCTP_CMD_RTO_PENDING
,
/* Set transport's rto_pending. */
SCTP_CMD_CHUNK_PD
,
/* Partial data delivery considerations. */
SCTP_CMD_LAST
SCTP_CMD_LAST
}
sctp_verb_t
;
}
sctp_verb_t
;
...
@@ -115,7 +116,7 @@ typedef union {
...
@@ -115,7 +116,7 @@ typedef union {
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_bind_addr_t
*
bp
;
sctp_bind_addr_t
*
bp
;
sctp_init_chunk_t
*
init
;
sctp_init_chunk_t
*
init
;
s
ctp_ulpevent_
t
*
ulpevent
;
s
truct
sctp_ulpeven
t
*
ulpevent
;
sctp_packet_t
*
packet
;
sctp_packet_t
*
packet
;
sctp_sackhdr_t
*
sackh
;
sctp_sackhdr_t
*
sackh
;
}
sctp_arg_t
;
}
sctp_arg_t
;
...
@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
...
@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
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
,
s
ctp_ulpevent_
t
*
,
ulpevent
)
SCTP_ARG_CONSTRUCTOR
(
ULPEVENT
,
s
truct
sctp_ulpeven
t
*
,
ulpevent
)
SCTP_ARG_CONSTRUCTOR
(
PACKET
,
sctp_packet_t
*
,
packet
)
SCTP_ARG_CONSTRUCTOR
(
PACKET
,
sctp_packet_t
*
,
packet
)
SCTP_ARG_CONSTRUCTOR
(
SACKH
,
sctp_sackhdr_t
*
,
sackh
)
SCTP_ARG_CONSTRUCTOR
(
SACKH
,
sctp_sackhdr_t
*
,
sackh
)
...
...
include/net/sctp/sctp.h
View file @
9967b51f
...
@@ -214,6 +214,7 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
...
@@ -214,6 +214,7 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
#define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field)
#define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field)
#define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field)
#define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field)
#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
#define SCTP_DEC_STATS(field) SNMP_DEC_STATS(sctp_statistics, field)
/* Determine if this is a valid kernel address. */
/* Determine if this is a valid kernel address. */
static
inline
int
sctp_is_valid_kaddr
(
unsigned
long
addr
)
static
inline
int
sctp_is_valid_kaddr
(
unsigned
long
addr
)
...
...
include/net/sctp/structs.h
View file @
9967b51f
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* 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
*
*
...
@@ -105,27 +105,25 @@ union sctp_addr {
...
@@ -105,27 +105,25 @@ 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_inq
;
struct
sctp_outq
;
struct
sctp_outq
;
struct
SCTP
_bind_addr
;
struct
sctp
_bind_addr
;
struct
sctp_ulpq
;
struct
sctp_ulpq
;
struct
sctp_opt
;
struct
sctp_opt
;
struct
sctp_endpoint_common
;
struct
sctp_endpoint_common
;
struct
sctp_ssnmap
;
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_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_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_endpoint_common
sctp_endpoint_common_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
#include <net/sctp/tsnmap.h>
#include <net/sctp/tsnmap.h>
...
@@ -250,10 +248,10 @@ struct sctp_af {
...
@@ -250,10 +248,10 @@ struct sctp_af {
int
optname
,
int
optname
,
char
*
optval
,
char
*
optval
,
int
*
optlen
);
int
*
optlen
);
struct
dst_entry
*
(
*
get_dst
)
(
s
ctp_association_t
*
asoc
,
struct
dst_entry
*
(
*
get_dst
)
(
s
truct
sctp_association
*
asoc
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
union
sctp_addr
*
saddr
);
void
(
*
get_saddr
)
(
s
ctp_association_t
*
asoc
,
void
(
*
get_saddr
)
(
s
truct
sctp_association
*
asoc
,
struct
dst_entry
*
dst
,
struct
dst_entry
*
dst
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
union
sctp_addr
*
saddr
);
...
@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
...
@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */
/* Protocol family functions. */
struct
sctp_pf
{
struct
sctp_pf
{
void
(
*
event_msgname
)(
s
ctp_ulpevent_
t
*
,
char
*
,
int
*
);
void
(
*
event_msgname
)(
s
truct
sctp_ulpeven
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
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
...
@@ -311,6 +309,9 @@ struct sctp_opt {
...
@@ -311,6 +309,9 @@ struct sctp_opt {
/* What kind of a socket is this? */
/* What kind of a socket is this? */
sctp_socket_type_t
type
;
sctp_socket_type_t
type
;
/* PF_ family specific functions. */
struct
sctp_pf
*
pf
;
/* What is our base endpointer? */
/* What is our base endpointer? */
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
...
@@ -324,7 +325,10 @@ struct sctp_opt {
...
@@ -324,7 +325,10 @@ struct sctp_opt {
__u32
autoclose
;
__u32
autoclose
;
__u8
nodelay
;
__u8
nodelay
;
__u8
disable_fragments
;
__u8
disable_fragments
;
struct
sctp_pf
*
pf
;
__u8
pd_mode
;
/* Receive to here while partial delivery is in effect. */
struct
sk_buff_head
pd_lobby
;
};
};
...
@@ -484,7 +488,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
...
@@ -484,7 +488,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
* As a matter of convenience, we remember the SCTP common header for
* As a matter of convenience, we remember the SCTP common header for
* each chunk as well as a few other header pointers...
* each chunk as well as a few other header pointers...
*/
*/
struct
SCTP
_chunk
{
struct
sctp
_chunk
{
/* These first three elements MUST PRECISELY match the first
/* These first three elements MUST PRECISELY match the first
* three elements of struct sk_buff. This allows us to reuse
* three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions.
* all the skb_* queue management functions.
...
@@ -594,7 +598,7 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
...
@@ -594,7 +598,7 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
/* This structure holds lists of chunks as we are assembling for
/* This structure holds lists of chunks as we are assembling for
* transmission.
* transmission.
*/
*/
struct
SCTP
_packet
{
struct
sctp
_packet
{
/* These are the SCTP header values (host order) for the packet. */
/* These are the SCTP header values (host order) for the packet. */
__u16
source_port
;
__u16
source_port
;
__u16
destination_port
;
__u16
destination_port
;
...
@@ -846,8 +850,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *);
...
@@ -846,8 +850,8 @@ 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.
* SCTP. We write packets to it and read chunks from it.
*/
*/
struct
SCTP_inqueue
{
struct
sctp_inq
{
/* This is actually a queue of sctp_chunk
_t
each
/* This is actually a queue of sctp_chunk each
* containing a partially decoded packet.
* containing a partially decoded packet.
*/
*/
struct
sk_buff_head
in
;
struct
sk_buff_head
in
;
...
@@ -864,13 +868,12 @@ struct SCTP_inqueue {
...
@@ -864,13 +868,12 @@ struct SCTP_inqueue {
int
malloced
;
/* Is this structure kfree()able? */
int
malloced
;
/* Is this structure kfree()able? */
};
};
sctp_inqueue_t
*
sctp_inqueue_new
(
void
);
struct
sctp_inq
*
sctp_inq_new
(
void
);
void
sctp_inqueue_init
(
sctp_inqueue_t
*
);
void
sctp_inq_init
(
struct
sctp_inq
*
);
void
sctp_inqueue_free
(
sctp_inqueue_t
*
);
void
sctp_inq_free
(
struct
sctp_inq
*
);
void
sctp_push_inqueue
(
sctp_inqueue_t
*
,
sctp_chunk_t
*
packet
);
void
sctp_inq_push
(
struct
sctp_inq
*
,
sctp_chunk_t
*
packet
);
sctp_chunk_t
*
sctp_pop_inqueue
(
sctp_inqueue_t
*
);
struct
sctp_chunk
*
sctp_inq_pop
(
struct
sctp_inq
*
);
void
sctp_inqueue_set_th_handler
(
sctp_inqueue_t
*
,
void
sctp_inq_set_th_handler
(
struct
sctp_inq
*
,
void
(
*
)(
void
*
),
void
*
);
void
(
*
)(
void
*
),
void
*
);
/* This is the structure we use to hold outbound chunks. You push
/* This is the structure we use to hold outbound chunks. You push
* chunks in and they automatically pop out the other end as bundled
* chunks in and they automatically pop out the other end as bundled
...
@@ -954,7 +957,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
...
@@ -954,7 +957,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
/* These bind address data fields common between endpoints and associations */
/* These bind address data fields common between endpoints and associations */
struct
SCTP
_bind_addr
{
struct
sctp
_bind_addr
{
/* RFC 2960 12.1 Parameters necessary for the SCTP instance
/* RFC 2960 12.1 Parameters necessary for the SCTP instance
*
*
...
@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
...
@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
struct
sock
*
sk
;
struct
sock
*
sk
;
/* This is where we receive inbound chunks. */
/* This is where we receive inbound chunks. */
s
ctp_inqueue_t
inqueue
;
s
truct
sctp_inq
inqueue
;
/* This substructure includes the defining parameters of the
/* This substructure includes the defining parameters of the
* endpoint:
* endpoint:
...
@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
...
@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
* off one of these.
* off one of these.
*/
*/
struct
SCTP
_endpoint
{
struct
sctp
_endpoint
{
/* Common substructure for endpoint and association. */
/* Common substructure for endpoint and association. */
sctp_endpoint_common_t
base
;
sctp_endpoint_common_t
base
;
...
@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
...
@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
/* Here we have information about each individual association. */
/* Here we have information about each individual association. */
struct
SCTP
_association
{
struct
sctp
_association
{
/* A base structure common to endpoint and association.
/* A base structure common to endpoint and association.
* In this context, it represents the associations's view
* In this context, it represents the associations's view
...
@@ -1288,19 +1291,11 @@ struct SCTP_association {
...
@@ -1288,19 +1291,11 @@ struct SCTP_association {
* used in the bulk of the text. This value is hidden
* used in the bulk of the text. This value is hidden
* in tsn_map--we get it by calling sctp_tsnmap_get_ctsn().
* in tsn_map--we get it by calling sctp_tsnmap_get_ctsn().
*/
*/
s
ctp_tsnmap_t
tsn_map
;
s
truct
sctp_tsnmap
tsn_map
;
__u8
_map
[
sctp_tsnmap_storage_size
(
SCTP_TSN_MAP_SIZE
)];
__u8
_map
[
sctp_tsnmap_storage_size
(
SCTP_TSN_MAP_SIZE
)];
/* We record duplicate TSNs here. We clear this after
* every SACK.
* FIXME: We should move this into the tsnmap? --jgrimm
*/
sctp_dup_tsn_t
dup_tsns
[
SCTP_MAX_DUP_TSNS
];
int
next_dup_tsn
;
/* Do we need to sack the peer? */
/* Do we need to sack the peer? */
uint8_t
sack_needed
;
__u8
sack_needed
;
/* These are capabilities which our peer advertised. */
/* These are capabilities which our peer advertised. */
__u8
ecn_capable
;
/* Can peer do ECN? */
__u8
ecn_capable
;
/* Can peer do ECN? */
__u8
ipv4_address
;
/* Peer understands IPv4 addresses? */
__u8
ipv4_address
;
/* Peer understands IPv4 addresses? */
...
@@ -1457,7 +1452,10 @@ struct SCTP_association {
...
@@ -1457,7 +1452,10 @@ struct SCTP_association {
struct
{
struct
{
__u16
stream
;
__u16
stream
;
__u16
flags
;
__u32
ppid
;
__u32
ppid
;
__u32
context
;
__u32
timetolive
;
}
defaults
;
}
defaults
;
/* This tracks outbound ssn for a given stream. */
/* This tracks outbound ssn for a given stream. */
...
@@ -1615,6 +1613,7 @@ void sctp_association_put(sctp_association_t *);
...
@@ -1615,6 +1613,7 @@ void sctp_association_put(sctp_association_t *);
void
sctp_association_hold
(
sctp_association_t
*
);
void
sctp_association_hold
(
sctp_association_t
*
);
struct
sctp_transport
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
struct
sctp_transport
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
void
sctp_assoc_update_retran_path
(
sctp_association_t
*
);
struct
sctp_transport
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
struct
sctp_transport
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
const
union
sctp_addr
*
);
const
union
sctp_addr
*
);
struct
sctp_transport
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
struct
sctp_transport
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
...
...
include/net/sctp/tsnmap.h
View file @
9967b51f
/* SCTP kernel reference Implementation Copyright (C) 1999-2001
/* SCTP kernel reference Implementation Copyright (C) 1999-2001
* Cisco, Motorola, Intel, and International Business Machines Corp.
* Cisco, Motorola, Intel, and 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 are the definitions needed for the tsnmap type. The tsnmap is used
* These are the definitions needed for the tsnmap type. The tsnmap is used
* to track out of order TSNs received.
* to track out of order TSNs received.
*
*
* 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:
*
*
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* 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>
*
*
* 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.
*/
*/
...
@@ -38,8 +38,6 @@
...
@@ -38,8 +38,6 @@
#ifndef __sctp_tsnmap_h__
#ifndef __sctp_tsnmap_h__
#define __sctp_tsnmap_h__
#define __sctp_tsnmap_h__
/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB)
/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB)
* Mapping An array of bits or bytes indicating which out of
* Mapping An array of bits or bytes indicating which out of
* Array order TSN's have been received (relative to the
* Array order TSN's have been received (relative to the
...
@@ -48,9 +46,7 @@
...
@@ -48,9 +46,7 @@
* will be set to all zero. This structure may be
* will be set to all zero. This structure may be
* in the form of a circular buffer or bit array.
* in the form of a circular buffer or bit array.
*/
*/
typedef
struct
sctp_tsnmap
{
struct
sctp_tsnmap
{
/* This array counts the number of chunks with each TSN.
/* This array counts the number of chunks with each TSN.
* It points at one of the two buffers with which we will
* It points at one of the two buffers with which we will
* ping-pong between.
* ping-pong between.
...
@@ -93,25 +89,30 @@ typedef struct sctp_tsnmap {
...
@@ -93,25 +89,30 @@ typedef struct sctp_tsnmap {
/* This is the highest TSN we've marked. */
/* This is the highest TSN we've marked. */
__u32
max_tsn_seen
;
__u32
max_tsn_seen
;
/*
No. of d
ata chunks pending receipt. used by SCTP_STATUS sockopt */
/*
D
ata chunks pending receipt. used by SCTP_STATUS sockopt */
__u16
pending_data
;
__u16
pending_data
;
/* We record duplicate TSNs here. We clear this after
* every SACK. Store up to SCTP_MAX_DUP_TSNS worth of
* information.
*/
__u32
dup_tsns
[
SCTP_MAX_DUP_TSNS
];
__u16
num_dup_tsns
;
int
malloced
;
int
malloced
;
__u8
raw_map
[
0
];
__u8
raw_map
[
0
];
}
sctp_tsnmap_t
;
};
typedef
struct
sctp_tsnmap_iter
{
struct
sctp_tsnmap_iter
{
__u32
start
;
__u32
start
;
}
sctp_tsnmap_iter_t
;
};
/* Create a new tsnmap. */
/* Create a new tsnmap. */
sctp_tsnmap_t
*
sctp_tsnmap_new
(
__u16
len
,
__u32
initial_tsn
,
struct
sctp_tsnmap
*
sctp_tsnmap_new
(
__u16
len
,
__u32
init_tsn
,
int
priority
);
int
priority
);
/* Dispose of a tsnmap. */
/* Dispose of a tsnmap. */
void
sctp_tsnmap_free
(
s
ctp_tsnmap_t
*
map
);
void
sctp_tsnmap_free
(
s
truct
sctp_tsnmap
*
);
/* This macro assists in creation of external storage for variable length
/* This macro assists in creation of external storage for variable length
* internal buffers. We double allocate so the overflow map works.
* internal buffers. We double allocate so the overflow map works.
...
@@ -119,9 +120,8 @@ void sctp_tsnmap_free(sctp_tsnmap_t *map);
...
@@ -119,9 +120,8 @@ void sctp_tsnmap_free(sctp_tsnmap_t *map);
#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
/* Initialize a block of memory as a tsnmap. */
/* Initialize a block of memory as a tsnmap. */
sctp_tsnmap_t
*
sctp_tsnmap_init
(
sctp_tsnmap_t
*
map
,
__u16
len
,
__u32
initial_tsn
);
struct
sctp_tsnmap
*
sctp_tsnmap_init
(
struct
sctp_tsnmap
*
,
__u16
len
,
__u32
initial_tsn
);
/* Test the tracking state of this TSN.
/* Test the tracking state of this TSN.
* Returns:
* Returns:
...
@@ -129,29 +129,51 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
...
@@ -129,29 +129,51 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
* >0 if the TSN has been seen (duplicate)
* >0 if the TSN has been seen (duplicate)
* <0 if the TSN is invalid (too large to track)
* <0 if the TSN is invalid (too large to track)
*/
*/
int
sctp_tsnmap_check
(
const
s
ctp_tsnmap_t
*
map
,
__u32
tsn
);
int
sctp_tsnmap_check
(
const
s
truct
sctp_tsnmap
*
,
__u32
tsn
);
/* Mark this TSN as seen. */
/* Mark this TSN as seen. */
void
sctp_tsnmap_mark
(
s
ctp_tsnmap_t
*
map
,
__u32
tsn
);
void
sctp_tsnmap_mark
(
s
truct
sctp_tsnmap
*
,
__u32
tsn
);
/* Retrieve the Cumulative TSN ACK Point. */
/* Retrieve the Cumulative TSN ACK Point. */
__u32
sctp_tsnmap_get_ctsn
(
const
s
ctp_tsnmap_t
*
map
);
__u32
sctp_tsnmap_get_ctsn
(
const
s
truct
sctp_tsnmap
*
);
/* Retrieve the highest TSN we've seen. */
/* Retrieve the highest TSN we've seen. */
__u32
sctp_tsnmap_get_max_tsn_seen
(
const
sctp_tsnmap_t
*
map
);
__u32
sctp_tsnmap_get_max_tsn_seen
(
const
struct
sctp_tsnmap
*
);
/* How many Duplicate TSNs are stored? */
static
inline
__u16
sctp_tsnmap_num_dups
(
struct
sctp_tsnmap
*
map
)
{
return
map
->
num_dup_tsns
;
}
/* Return pointer to duplicate tsn array as needed by SACK. */
static
inline
__u32
*
sctp_tsnmap_get_dups
(
struct
sctp_tsnmap
*
map
)
{
map
->
num_dup_tsns
=
0
;
return
map
->
dup_tsns
;
}
/* Mark a duplicate TSN. Note: we limit how many we are willing to
* store and consequently report.
*/
static
inline
void
sctp_tsnmap_mark_dup
(
struct
sctp_tsnmap
*
map
,
__u32
tsn
)
{
if
(
map
->
num_dup_tsns
<
SCTP_MAX_DUP_TSNS
)
map
->
dup_tsns
[
map
->
num_dup_tsns
++
]
=
tsn
;
}
/* Is there a gap in the TSN map? */
/* Is there a gap in the TSN map? */
int
sctp_tsnmap_has_gap
(
const
s
ctp_tsnmap_t
*
map
);
int
sctp_tsnmap_has_gap
(
const
s
truct
sctp_tsnmap
*
);
/* Initialize a gap ack block interator from user-provided memory. */
/* Initialize a gap ack block interator from user-provided memory. */
void
sctp_tsnmap_iter_init
(
const
sctp_tsnmap_t
*
map
,
sctp_tsnmap_iter_t
*
iter
);
void
sctp_tsnmap_iter_init
(
const
struct
sctp_tsnmap
*
,
struct
sctp_tsnmap_iter
*
);
/* Get the next gap ack blocks. We return 0 if there are no more
/* Get the next gap ack blocks. We return 0 if there are no more
* gap ack blocks.
* gap ack blocks.
*/
*/
int
sctp_tsnmap_next_gap_ack
(
const
sctp_tsnmap_t
*
map
,
sctp_tsnmap_iter_t
*
iter
,
int
sctp_tsnmap_next_gap_ack
(
const
struct
sctp_tsnmap
*
,
__u16
*
start
,
__u16
*
end
);
struct
sctp_tsnmap_iter
*
,
__u16
*
start
,
__u16
*
end
);
#endif
/* __sctp_tsnmap_h__ */
#endif
/* __sctp_tsnmap_h__ */
...
...
include/net/sctp/ulpevent.h
View file @
9967b51f
...
@@ -6,34 +6,34 @@
...
@@ -6,34 +6,34 @@
* 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_ulpevent type. The
* These are the definitions needed for the sctp_ulpevent type. The
* sctp_ulpevent type is used to carry information from the state machine
* sctp_ulpevent type is used to carry information from the state machine
* upwards to the ULP.
* upwards to the ULP.
*
*
* 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:
*
*
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* 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>
*
*
* 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.
*/
*/
...
@@ -46,85 +46,97 @@
...
@@ -46,85 +46,97 @@
/* Warning: This sits inside an skb.cb[] area. Be very careful of
/* Warning: This sits inside an skb.cb[] area. Be very careful of
* growing this structure as it is at the maximum limit now.
* growing this structure as it is at the maximum limit now.
*/
*/
typedef
struct
sctp_ulpevent
{
struct
sctp_ulpevent
{
int
malloced
;
struct
sctp_association
*
asoc
;
sctp_association_t
*
asoc
;
struct
sk_buff
*
parent
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
int
chunk_flags
;
/* Temp. until we get a new chunk_t */
int
msg_flags
;
int
msg_flags
;
}
sctp_ulpevent_t
;
};
sctp_ulpevent_t
*
sctp_ulpevent_new
(
int
size
,
int
msg_flags
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_init
(
sctp_ulpevent_t
*
event
,
struct
sk_buff
*
skb
,
int
msg_flags
);
void
sctp_ulpevent_free
(
sctp_ulpevent_t
*
event
);
int
sctp_ulpevent_is_notification
(
const
sctp_ulpevent_t
*
event
);
sctp_ulpevent_t
*
sctp_ulpevent_make_assoc_change
(
const
struct
SCTP_association
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
inbound
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_peer_addr_change
(
const
struct
SCTP_association
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_remote_error
(
const
struct
SCTP_association
*
asoc
,
struct
SCTP_chunk
*
chunk
,
__u16
flags
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_send_failed
(
const
struct
SCTP_association
*
asoc
,
struct
SCTP_chunk
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_shutdown_event
(
const
struct
SCTP_association
*
asoc
,
__u16
flags
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_rcvmsg
(
struct
SCTP_association
*
asoc
,
struct
SCTP_chunk
*
chunk
,
int
priority
);
void
sctp_ulpevent_read_sndrcvinfo
(
const
sctp_ulpevent_t
*
event
,
struct
msghdr
*
msghdr
);
__u16
sctp_ulpevent_get_notification_type
(
const
sctp_ulpevent_t
*
event
);
/* Retrieve the skb this event sits inside of. */
static
inline
struct
sk_buff
*
sctp_event2skb
(
struct
sctp_ulpevent
*
ev
)
{
return
container_of
((
void
*
)
ev
,
struct
sk_buff
,
cb
);
}
/* Retrieve & cast the event sitting inside the skb. */
static
inline
struct
sctp_ulpevent
*
sctp_skb2event
(
struct
sk_buff
*
skb
)
{
return
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
}
struct
sctp_ulpevent
*
sctp_ulpevent_new
(
int
size
,
int
flags
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_init
(
struct
sctp_ulpevent
*
,
int
flags
);
void
sctp_ulpevent_free
(
struct
sctp_ulpevent
*
);
int
sctp_ulpevent_is_notification
(
const
struct
sctp_ulpevent
*
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_assoc_change
(
const
struct
sctp_association
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
inbound
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_peer_addr_change
(
const
struct
sctp_association
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_remote_error
(
const
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
__u16
flags
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_send_failed
(
const
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_shutdown_event
(
const
struct
sctp_association
*
asoc
,
__u16
flags
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_pdapi
(
const
struct
sctp_association
*
asoc
,
__u32
indication
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_rcvmsg
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
int
priority
);
void
sctp_ulpevent_read_sndrcvinfo
(
const
struct
sctp_ulpevent
*
event
,
struct
msghdr
*
);
__u16
sctp_ulpevent_get_notification_type
(
const
struct
sctp_ulpevent
*
event
);
/* Is this event type enabled? */
static
inline
int
sctp_ulpevent_type_enabled
(
__u16
sn_type
,
struct
sctp_event_subscribe
*
mask
)
{
char
*
amask
=
(
char
*
)
mask
;
return
amask
[
sn_type
-
SCTP_SN_TYPE_BASE
];
}
/* Given an event subscription, is this event enabled? */
/* Given an event subscription, is this event enabled? */
static
inline
int
sctp_ulpevent_is_enabled
(
const
s
ctp_ulpevent_
t
*
event
,
static
inline
int
sctp_ulpevent_is_enabled
(
const
s
truct
sctp_ulpeven
t
*
event
,
const
struct
sctp_event_subscribe
*
mask
)
struct
sctp_event_subscribe
*
mask
)
{
{
const
char
*
amask
=
(
const
char
*
)
mask
;
__u16
sn_type
;
__u16
sn_type
;
int
enabled
=
1
;
int
enabled
=
1
;
if
(
sctp_ulpevent_is_notification
(
event
))
{
if
(
sctp_ulpevent_is_notification
(
event
))
{
sn_type
=
sctp_ulpevent_get_notification_type
(
event
);
sn_type
=
sctp_ulpevent_get_notification_type
(
event
);
enabled
=
amask
[
sn_type
-
SCTP_SN_TYPE_BASE
]
;
enabled
=
sctp_ulpevent_type_enabled
(
sn_type
,
mask
)
;
}
}
return
enabled
;
return
enabled
;
}
}
#endif
/* __sctp_ulpevent_h__ */
#endif
/* __sctp_ulpevent_h__ */
...
...
include/net/sctp/ulpqueue.h
View file @
9967b51f
...
@@ -48,7 +48,8 @@
...
@@ -48,7 +48,8 @@
/* A structure to carry information to the ULP (e.g. Sockets API) */
/* A structure to carry information to the ULP (e.g. Sockets API) */
struct
sctp_ulpq
{
struct
sctp_ulpq
{
int
malloced
;
char
malloced
;
char
pd_mode
;
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
;
...
@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
...
@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void
sctp_ulpq_free
(
struct
sctp_ulpq
*
);
void
sctp_ulpq_free
(
struct
sctp_ulpq
*
);
/* Add a new DATA chunk for processing. */
/* Add a new DATA chunk for processing. */
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
,
s
ctp_chunk_t
*
chunk
,
int
priority
);
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
,
s
truct
sctp_chunk
*
,
int
);
/* Add a new event for propogation to the ULP. */
/* Add a new event for propogation to the ULP. */
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
ev
);
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
ev
);
/* Is the ulpqueue empty. */
/* Perform partial delivery. */
int
sctp_ulpqueue_is_empty
(
struct
sctp_ulpq
*
);
void
sctp_ulpq_partial_delivery
(
struct
sctp_ulpq
*
,
struct
sctp_chunk
*
,
int
);
/* Abort the partial delivery. */
void
sctp_ulpq_abort_pd
(
struct
sctp_ulpq
*
,
int
);
/* Clear the partial data delivery condition on this socket. */
int
sctp_clear_pd
(
struct
sock
*
sk
);
#endif
/* __sctp_ulpqueue_h__ */
#endif
/* __sctp_ulpqueue_h__ */
...
...
include/net/sctp/user.h
View file @
9967b51f
...
@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
...
@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
__u32
sinfo_context
;
__u32
sinfo_context
;
__u32
sinfo_timetolive
;
__u32
sinfo_timetolive
;
__u32
sinfo_tsn
;
__u32
sinfo_tsn
;
__u32
sinfo_cumtsn
;
sctp_assoc_t
sinfo_assoc_id
;
sctp_assoc_t
sinfo_assoc_id
;
};
};
...
@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
...
@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
sctp_assoc_t
pdapi_assoc_id
;
sctp_assoc_t
pdapi_assoc_id
;
};
};
enum
{
SCTP_PARTIAL_DELIVERY_ABORTED
=
0
,
};
/*
/*
* Described in Section 7.3
* Described in Section 7.3
...
@@ -414,8 +416,8 @@ enum sctp_sn_type {
...
@@ -414,8 +416,8 @@ enum sctp_sn_type {
SCTP_SN_TYPE_BASE
=
(
1
<<
15
),
SCTP_SN_TYPE_BASE
=
(
1
<<
15
),
SCTP_ASSOC_CHANGE
,
SCTP_ASSOC_CHANGE
,
SCTP_PEER_ADDR_CHANGE
,
SCTP_PEER_ADDR_CHANGE
,
SCTP_REMOTE_ERROR
,
SCTP_SEND_FAILED
,
SCTP_SEND_FAILED
,
SCTP_REMOTE_ERROR
,
SCTP_SHUTDOWN_EVENT
,
SCTP_SHUTDOWN_EVENT
,
SCTP_PARTIAL_DELIVERY_EVENT
,
SCTP_PARTIAL_DELIVERY_EVENT
,
SCTP_ADAPTION_INDICATION
,
SCTP_ADAPTION_INDICATION
,
...
...
net/sctp/Makefile
View file @
9967b51f
...
@@ -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 ssnmap.o
debug.o ssnmap.o
proc.o
ifeq
($(CONFIG_SCTP_ADLER32), y)
ifeq
($(CONFIG_SCTP_ADLER32), y)
sctp-y
+=
adler32.o
sctp-y
+=
adler32.o
...
...
net/sctp/associola.c
View file @
9967b51f
...
@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
sctp_scope_t
scope
,
sctp_scope_t
scope
,
int
priority
)
int
priority
)
{
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
int
i
;
int
i
;
/* Retrieve the SCTP per socket area. */
/* Retrieve the SCTP per socket area. */
...
@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
->
peer
.
sack_needed
=
1
;
asoc
->
peer
.
sack_needed
=
1
;
/* Create an input queue. */
/* Create an input queue. */
sctp_inq
ueue
_init
(
&
asoc
->
base
.
inqueue
);
sctp_inq_init
(
&
asoc
->
base
.
inqueue
);
sctp_inq
ueue
_set_th_handler
(
&
asoc
->
base
.
inqueue
,
sctp_inq_set_th_handler
(
&
asoc
->
base
.
inqueue
,
(
void
(
*
)(
void
*
))
sctp_assoc_bh_rcv
,
(
void
(
*
)(
void
*
))
sctp_assoc_bh_rcv
,
asoc
);
asoc
);
...
@@ -260,7 +260,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -260,7 +260,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
/* Set up the tsn tracking. */
/* Set up the tsn tracking. */
sctp_tsnmap_init
(
&
asoc
->
peer
.
tsn_map
,
SCTP_TSN_MAP_SIZE
,
0
);
sctp_tsnmap_init
(
&
asoc
->
peer
.
tsn_map
,
SCTP_TSN_MAP_SIZE
,
0
);
asoc
->
peer
.
next_dup_tsn
=
0
;
skb_queue_head_init
(
&
asoc
->
addip_chunks
);
skb_queue_head_init
(
&
asoc
->
addip_chunks
);
...
@@ -311,7 +310,7 @@ void sctp_association_free(sctp_association_t *asoc)
...
@@ -311,7 +310,7 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_ulpq_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_inq
ueue
_free
(
&
asoc
->
base
.
inqueue
);
sctp_inq_free
(
&
asoc
->
base
.
inqueue
);
/* Free ssnmap storage. */
/* Free ssnmap storage. */
sctp_ssnmap_free
(
asoc
->
ssnmap
);
sctp_ssnmap_free
(
asoc
->
ssnmap
);
...
@@ -368,7 +367,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -368,7 +367,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
int
priority
)
int
priority
)
{
{
struct
sctp_transport
*
peer
;
struct
sctp_transport
*
peer
;
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
unsigned
short
port
;
unsigned
short
port
;
/* AF_INET and AF_INET6 share common port field. */
/* AF_INET and AF_INET6 share common port field. */
...
@@ -505,7 +504,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
...
@@ -505,7 +504,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
struct
sctp_transport
*
t
=
NULL
;
struct
sctp_transport
*
t
=
NULL
;
struct
sctp_transport
*
first
;
struct
sctp_transport
*
first
;
struct
sctp_transport
*
second
;
struct
sctp_transport
*
second
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
int
spc_state
=
0
;
int
spc_state
=
0
;
...
@@ -776,7 +775,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -776,7 +775,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
struct
sock
*
sk
;
struct
sock
*
sk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
int
state
,
subtype
;
int
state
,
subtype
;
sctp_assoc_t
associd
=
sctp_assoc2id
(
asoc
);
sctp_assoc_t
associd
=
sctp_assoc2id
(
asoc
);
int
error
=
0
;
int
error
=
0
;
...
@@ -786,7 +785,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -786,7 +785,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sk
=
asoc
->
base
.
sk
;
sk
=
asoc
->
base
.
sk
;
inqueue
=
&
asoc
->
base
.
inqueue
;
inqueue
=
&
asoc
->
base
.
inqueue
;
while
(
NULL
!=
(
chunk
=
sctp_
pop_inqueue
(
inqueue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_
inq_pop
(
inqueue
)))
{
state
=
asoc
->
state
;
state
=
asoc
->
state
;
subtype
=
chunk
->
chunk_hdr
->
type
;
subtype
=
chunk
->
chunk_hdr
->
type
;
...
@@ -795,6 +794,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -795,6 +794,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
*/
*/
if
(
sctp_chunk_is_data
(
chunk
))
if
(
sctp_chunk_is_data
(
chunk
))
asoc
->
peer
.
last_data_from
=
chunk
->
transport
;
asoc
->
peer
.
last_data_from
=
chunk
->
transport
;
else
SCTP_INC_STATS
(
SctpInCtrlChunks
);
if
(
chunk
->
transport
)
if
(
chunk
->
transport
)
chunk
->
transport
->
last_time_heard
=
jiffies
;
chunk
->
transport
->
last_time_heard
=
jiffies
;
...
@@ -819,7 +820,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -819,7 +820,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
/* This routine moves an association from its old sk to a new sk. */
/* This routine moves an association from its old sk to a new sk. */
void
sctp_assoc_migrate
(
sctp_association_t
*
assoc
,
struct
sock
*
newsk
)
void
sctp_assoc_migrate
(
sctp_association_t
*
assoc
,
struct
sock
*
newsk
)
{
{
s
ctp_opt_
t
*
newsp
=
sctp_sk
(
newsk
);
s
truct
sctp_op
t
*
newsp
=
sctp_sk
(
newsk
);
/* Delete the association from the old endpoint's list of
/* Delete the association from the old endpoint's list of
* associations.
* associations.
...
@@ -848,7 +849,6 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
...
@@ -848,7 +849,6 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
/* 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
;
asoc
->
peer
.
next_dup_tsn
=
new
->
peer
.
next_dup_tsn
;
asoc
->
peer
.
sack_needed
=
new
->
peer
.
sack_needed
;
asoc
->
peer
.
sack_needed
=
new
->
peer
.
sack_needed
;
asoc
->
peer
.
i
=
new
->
peer
.
i
;
asoc
->
peer
.
i
=
new
->
peer
.
i
;
sctp_tsnmap_init
(
&
asoc
->
peer
.
tsn_map
,
SCTP_TSN_MAP_SIZE
,
sctp_tsnmap_init
(
&
asoc
->
peer
.
tsn_map
,
SCTP_TSN_MAP_SIZE
,
...
@@ -887,26 +887,19 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
...
@@ -887,26 +887,19 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
}
}
/*
Choose the transport for sending a shutdown
packet.
/*
Update the retran path for sending a retransmitted
packet.
* Round-robin through the active transports, else round-robin
* Round-robin through the active transports, else round-robin
* 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.
*/
*/
struct
sctp_transport
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
asoc
)
void
sctp_assoc_update_retran_path
(
sctp_association_t
*
asoc
)
{
{
struct
sctp_transport
*
t
,
*
next
;
struct
sctp_transport
*
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
;
/* If this is the first time SHUTDOWN is sent, use the active
/* Find the next transport in a round-robin fashion. */
* path.
t
=
asoc
->
peer
.
retran_path
;
*/
if
(
!
asoc
->
shutdown_last_sent_to
)
return
asoc
->
peer
.
active_path
;
/* Otherwise, find the next transport in a round-robin fashion. */
t
=
asoc
->
shutdown_last_sent_to
;
pos
=
&
t
->
transports
;
pos
=
&
t
->
transports
;
next
=
NULL
;
next
=
NULL
;
...
@@ -935,13 +928,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *
...
@@ -935,13 +928,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *
* other active transports. If so, use the next
* other active transports. If so, use the next
* transport.
* transport.
*/
*/
if
(
t
==
asoc
->
shutdown_last_sent_to
)
{
if
(
t
==
asoc
->
peer
.
retran_path
)
{
t
=
next
;
t
=
next
;
break
;
break
;
}
}
}
}
return
t
;
asoc
->
peer
.
retran_path
=
t
;
}
/* Choose the transport for sending a SHUTDOWN packet. */
struct
sctp_transport
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
asoc
)
{
/* If this is the first time SHUTDOWN is sent, use the active path,
* else use the retran path. If the last SHUTDOWN was sent over the
* retran path, update the retran path and use it.
*/
if
(
!
asoc
->
shutdown_last_sent_to
)
return
asoc
->
peer
.
active_path
;
else
{
if
(
asoc
->
shutdown_last_sent_to
==
asoc
->
peer
.
retran_path
)
sctp_assoc_update_retran_path
(
asoc
);
return
asoc
->
peer
.
retran_path
;
}
}
}
/* Update the association's pmtu and frag_point by going through all the
/* Update the association's pmtu and frag_point by going through all the
...
@@ -990,13 +1000,13 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -990,13 +1000,13 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
asoc
->
rwnd
+=
len
;
asoc
->
rwnd
+=
len
;
}
}
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd increased by %d to (%u, %u)
- %u
\n
"
,
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd increased by %d to (%u, %u)
"
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
,
"- %u
\n
"
,
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
asoc
->
rwnd_over
,
asoc
->
a_rwnd
);
/* Send a window update SACK if the rwnd has increased by at least the
/* 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.
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in
* The algorithm used is similar to the one described in
* Section 4.2.3.3 of RFC 1122.
* Section 4.2.3.3 of RFC 1122.
*/
*/
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
...
@@ -1006,15 +1016,14 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -1006,15 +1016,14 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
"rwnd: %u a_rwnd: %u
\n
"
,
"rwnd: %u a_rwnd: %u
\n
"
,
__FUNCTION__
,
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
__FUNCTION__
,
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
sack
=
sctp_make_sack
(
asoc
);
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
if
(
!
sack
)
return
;
return
;
/* Update the last advertised rwnd value. */
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
...
@@ -1022,7 +1031,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -1022,7 +1031,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
sctp_association_put
(
asoc
);
}
}
}
}
/* Decrease asoc's rwnd by len. */
/* Decrease asoc's rwnd by len. */
...
...
net/sctp/endpointola.c
View file @
9967b51f
...
@@ -92,7 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
...
@@ -92,7 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
ep
,
sctp_protocol_t
*
proto
,
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
ep
,
sctp_protocol_t
*
proto
,
struct
sock
*
sk
,
int
priority
)
struct
sock
*
sk
,
int
priority
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
memset
(
ep
,
0
,
sizeof
(
sctp_endpoint_t
));
memset
(
ep
,
0
,
sizeof
(
sctp_endpoint_t
));
/* Initialize the base structure. */
/* Initialize the base structure. */
...
@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
...
@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep
->
base
.
malloced
=
1
;
ep
->
base
.
malloced
=
1
;
/* Create an input queue. */
/* Create an input queue. */
sctp_inq
ueue
_init
(
&
ep
->
base
.
inqueue
);
sctp_inq_init
(
&
ep
->
base
.
inqueue
);
/* Set its top-half handler */
/* Set its top-half handler */
sctp_inq
ueue
_set_th_handler
(
&
ep
->
base
.
inqueue
,
sctp_inq_set_th_handler
(
&
ep
->
base
.
inqueue
,
(
void
(
*
)(
void
*
))
sctp_endpoint_bh_rcv
,
(
void
(
*
)(
void
*
))
sctp_endpoint_bh_rcv
,
ep
);
ep
);
...
@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
...
@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
sctp_unhash_endpoint
(
ep
);
sctp_unhash_endpoint
(
ep
);
/* Cleanup the inqueue. */
/* Cleanup the inqueue. */
sctp_inq
ueue
_free
(
&
ep
->
base
.
inqueue
);
sctp_inq_free
(
&
ep
->
base
.
inqueue
);
sctp_bind_addr_free
(
&
ep
->
base
.
bind_addr
);
sctp_bind_addr_free
(
&
ep
->
base
.
bind_addr
);
...
@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
struct
sock
*
sk
;
struct
sock
*
sk
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
sctp_subtype_t
subtype
;
sctp_subtype_t
subtype
;
sctp_state_t
state
;
sctp_state_t
state
;
int
error
=
0
;
int
error
=
0
;
...
@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
inqueue
=
&
ep
->
base
.
inqueue
;
inqueue
=
&
ep
->
base
.
inqueue
;
sk
=
ep
->
base
.
sk
;
sk
=
ep
->
base
.
sk
;
while
(
NULL
!=
(
chunk
=
sctp_
pop_inqueue
(
inqueue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_
inq_pop
(
inqueue
)))
{
subtype
.
chunk
=
chunk
->
chunk_hdr
->
type
;
subtype
.
chunk
=
chunk
->
chunk_hdr
->
type
;
/* We might have grown an association since last we
/* We might have grown an association since last we
...
@@ -369,6 +369,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -369,6 +369,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
*/
*/
if
(
asoc
&&
sctp_chunk_is_data
(
chunk
))
if
(
asoc
&&
sctp_chunk_is_data
(
chunk
))
asoc
->
peer
.
last_data_from
=
chunk
->
transport
;
asoc
->
peer
.
last_data_from
=
chunk
->
transport
;
else
SCTP_INC_STATS
(
SctpInCtrlChunks
);
if
(
chunk
->
transport
)
if
(
chunk
->
transport
)
chunk
->
transport
->
last_time_heard
=
jiffies
;
chunk
->
transport
->
last_time_heard
=
jiffies
;
...
...
net/sctp/input.c
View file @
9967b51f
...
@@ -90,6 +90,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
...
@@ -90,6 +90,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
if
(
val
!=
cmp
)
{
if
(
val
!=
cmp
)
{
/* CRC failure, dump it. */
/* CRC failure, dump it. */
SCTP_INC_STATS_BH
(
SctpChecksumErrors
);
return
-
1
;
return
-
1
;
}
}
return
0
;
return
0
;
...
@@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb)
if
(
skb
->
pkt_type
!=
PACKET_HOST
)
if
(
skb
->
pkt_type
!=
PACKET_HOST
)
goto
discard_it
;
goto
discard_it
;
SCTP_INC_STATS_BH
(
SctpInSCTPPacks
);
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
/* Pull up the IP and SCTP headers. */
/* Pull up the IP and SCTP headers. */
...
@@ -160,8 +163,10 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -160,8 +163,10 @@ int sctp_rcv(struct sk_buff *skb)
*/
*/
if
(
!
asoc
)
{
if
(
!
asoc
)
{
ep
=
__sctp_rcv_lookup_endpoint
(
&
dest
);
ep
=
__sctp_rcv_lookup_endpoint
(
&
dest
);
if
(
sctp_rcv_ootb
(
skb
))
if
(
sctp_rcv_ootb
(
skb
))
{
SCTP_INC_STATS_BH
(
SctpOutOfBlues
);
goto
discard_release
;
goto
discard_release
;
}
}
}
/* Retrieve the common input handling substructure. */
/* Retrieve the common input handling substructure. */
...
@@ -248,7 +253,7 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -248,7 +253,7 @@ int sctp_rcv(struct sk_buff *skb)
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
{
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
/* One day chunk will live inside the skb, but for
/* One day chunk will live inside the skb, but for
* now this works.
* now this works.
...
@@ -256,7 +261,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
...
@@ -256,7 +261,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
chunk
=
(
sctp_chunk_t
*
)
skb
;
chunk
=
(
sctp_chunk_t
*
)
skb
;
inqueue
=
&
chunk
->
rcvr
->
inqueue
;
inqueue
=
&
chunk
->
rcvr
->
inqueue
;
sctp_
push_inqueue
(
inqueue
,
chunk
);
sctp_
inq_push
(
inqueue
,
chunk
);
return
0
;
return
0
;
}
}
...
...
net/sctp/inqueue.c
View file @
9967b51f
...
@@ -47,8 +47,8 @@
...
@@ -47,8 +47,8 @@
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
/* Initialize an SCTP
_
inqueue. */
/* Initialize an SCTP
inqueue. */
void
sctp_inq
ueue_init
(
sctp_inqueue_t
*
queue
)
void
sctp_inq
_init
(
struct
sctp_inq
*
queue
)
{
{
skb_queue_head_init
(
&
queue
->
in
);
skb_queue_head_init
(
&
queue
->
in
);
queue
->
in_progress
=
NULL
;
queue
->
in_progress
=
NULL
;
...
@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
...
@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
queue
->
malloced
=
0
;
queue
->
malloced
=
0
;
}
}
/* Create an initialized
SCTP_inqueue
. */
/* Create an initialized
sctp_inq
. */
s
ctp_inqueue_t
*
sctp_inqueue
_new
(
void
)
s
truct
sctp_inq
*
sctp_inq
_new
(
void
)
{
{
s
ctp_inqueue_t
*
retval
;
s
truct
sctp_inq
*
retval
;
retval
=
t_new
(
s
ctp_inqueue_t
,
GFP_ATOMIC
);
retval
=
t_new
(
s
truct
sctp_inq
,
GFP_ATOMIC
);
if
(
retval
)
{
if
(
retval
)
{
sctp_inq
ueue
_init
(
retval
);
sctp_inq_init
(
retval
);
retval
->
malloced
=
1
;
retval
->
malloced
=
1
;
}
}
return
retval
;
return
retval
;
}
}
/* Release the memory associated with an SCTP inqueue. */
/* Release the memory associated with an SCTP inqueue. */
void
sctp_inq
ueue_free
(
sctp_inqueue_t
*
queue
)
void
sctp_inq
_free
(
struct
sctp_inq
*
queue
)
{
{
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
...
@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
...
@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
/* Put a new packet in an SCTP inqueue.
/* Put a new packet in an SCTP inqueue.
* We assume that packet->sctp_hdr is set and in host byte order.
* We assume that packet->sctp_hdr is set and in host byte order.
*/
*/
void
sctp_
push_inqueue
(
sctp_inqueue_t
*
q
,
sctp_chunk_t
*
packet
)
void
sctp_
inq_push
(
struct
sctp_inq
*
q
,
sctp_chunk_t
*
packet
)
{
{
/* Directly call the packet handling routine. */
/* Directly call the packet handling routine. */
...
@@ -114,7 +114,7 @@ void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
...
@@ -114,7 +114,7 @@ void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
* WARNING: If you need to put the chunk on another queue, you need to
* WARNING: If you need to put the chunk on another queue, you need to
* make a shallow copy (clone) of it.
* make a shallow copy (clone) of it.
*/
*/
sctp_chunk_t
*
sctp_
pop_inqueue
(
sctp_inqueue_t
*
queue
)
sctp_chunk_t
*
sctp_
inq_pop
(
struct
sctp_inq
*
queue
)
{
{
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
sctp_chunkhdr_t
*
ch
=
NULL
;
sctp_chunkhdr_t
*
ch
=
NULL
;
...
@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
...
@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
chunk
->
end_of_packet
=
1
;
chunk
->
end_of_packet
=
1
;
}
}
SCTP_DEBUG_PRINTK
(
"+++sctp_
pop_inqueue
+++ chunk %p[%s],"
SCTP_DEBUG_PRINTK
(
"+++sctp_
inq_pop
+++ chunk %p[%s],"
" length %d, skb->len %d
\n
"
,
chunk
,
" length %d, skb->len %d
\n
"
,
chunk
,
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
)),
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
)),
ntohs
(
chunk
->
chunk_hdr
->
length
),
chunk
->
skb
->
len
);
ntohs
(
chunk
->
chunk_hdr
->
length
),
chunk
->
skb
->
len
);
...
@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
...
@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
/* Set a top-half handler.
/* Set a top-half handler.
*
*
* Originally, we the top-half handler was scheduled as a BH. We now
* Originally, we the top-half handler was scheduled as a BH. We now
* call the handler directly in sctp_
push_inqueue
() at a time that
* call the handler directly in sctp_
inq_push
() at a time that
* we know we are lock safe.
* we know we are lock safe.
* The intent is that this routine will pull stuff out of the
* The intent is that this routine will pull stuff out of the
* inqueue and process it.
* inqueue and process it.
*/
*/
void
sctp_inq
ueue_set_th_handler
(
sctp_inqueue_t
*
q
,
void
sctp_inq
_set_th_handler
(
struct
sctp_inq
*
q
,
void
(
*
callback
)(
void
*
),
void
*
arg
)
void
(
*
callback
)(
void
*
),
void
*
arg
)
{
{
INIT_WORK
(
&
q
->
immediate
,
callback
,
arg
);
INIT_WORK
(
&
q
->
immediate
,
callback
,
arg
);
...
...
net/sctp/ipv6.c
View file @
9967b51f
...
@@ -132,6 +132,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb,
...
@@ -132,6 +132,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb,
__FUNCTION__
,
skb
,
skb
->
len
,
NIP6
(
fl
.
fl6_src
),
__FUNCTION__
,
skb
,
skb
->
len
,
NIP6
(
fl
.
fl6_src
),
NIP6
(
fl
.
fl6_dst
));
NIP6
(
fl
.
fl6_dst
));
SCTP_INC_STATS
(
SctpOutSCTPPacks
);
return
ip6_xmit
(
sk
,
skb
,
&
fl
,
np
->
opt
);
return
ip6_xmit
(
sk
,
skb
,
&
fl
,
np
->
opt
);
}
}
...
@@ -444,7 +446,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
...
@@ -444,7 +446,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
}
}
/* Initialize a PF_INET msgname from a ulpevent. */
/* Initialize a PF_INET msgname from a ulpevent. */
static
void
sctp_inet6_event_msgname
(
s
ctp_ulpevent_
t
*
event
,
char
*
msgname
,
static
void
sctp_inet6_event_msgname
(
s
truct
sctp_ulpeven
t
*
event
,
char
*
msgname
,
int
*
addrlen
)
int
*
addrlen
)
{
{
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
...
...
net/sctp/output.c
View file @
9967b51f
...
@@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst
=
transport
->
dst
;
dst
=
transport
->
dst
;
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if
(
!
dst
||
(
dst
->
obsolete
>
1
))
{
if
(
!
dst
||
(
dst
->
obsolete
>
1
))
{
dst_release
(
dst
);
sctp_transport_route
(
transport
,
NULL
,
sctp_sk
(
sk
));
sctp_transport_route
(
transport
,
NULL
,
sctp_sk
(
sk
));
sctp_assoc_sync_pmtu
(
asoc
);
sctp_assoc_sync_pmtu
(
asoc
);
}
}
...
...
net/sctp/outqueue.c
View file @
9967b51f
...
@@ -193,11 +193,17 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
...
@@ -193,11 +193,17 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
:
"Illegal Chunk"
);
:
"Illegal Chunk"
);
skb_queue_tail
(
&
q
->
out
,
(
struct
sk_buff
*
)
chunk
);
skb_queue_tail
(
&
q
->
out
,
(
struct
sk_buff
*
)
chunk
);
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
SCTP_INC_STATS
(
SctpOutUnorderChunks
);
else
SCTP_INC_STATS
(
SctpOutOrderChunks
);
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
);
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
}
if
(
error
<
0
)
if
(
error
<
0
)
return
error
;
return
error
;
...
@@ -315,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
...
@@ -315,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
switch
(
reason
)
{
switch
(
reason
)
{
case
SCTP_RETRANSMIT_T3_RTX
:
case
SCTP_RETRANSMIT_T3_RTX
:
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_T3_RTX
);
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_T3_RTX
);
/* Update the retran path if the T3-rtx timer has expired for
* the current retran path.
*/
if
(
transport
==
transport
->
asoc
->
peer
.
retran_path
)
sctp_assoc_update_retran_path
(
transport
->
asoc
);
break
;
break
;
case
SCTP_RETRANSMIT_FAST_RTX
:
case
SCTP_RETRANSMIT_FAST_RTX
:
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_FAST_RTX
);
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_FAST_RTX
);
...
...
net/sctp/proc.c
0 → 100644
View file @
9967b51f
/* SCTP kernel reference Implementation
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the 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:
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
#include <linux/types.h>
#include <linux/seq_file.h>
#include <net/sctp/sctp.h>
static
char
*
sctp_snmp_list
[]
=
{
#define SCTP_SNMP_ENTRY(x) #x
SCTP_SNMP_ENTRY
(
SctpCurrEstab
),
SCTP_SNMP_ENTRY
(
SctpActiveEstabs
),
SCTP_SNMP_ENTRY
(
SctpPassiveEstabs
),
SCTP_SNMP_ENTRY
(
SctpAborteds
),
SCTP_SNMP_ENTRY
(
SctpShutdowns
),
SCTP_SNMP_ENTRY
(
SctpOutOfBlues
),
SCTP_SNMP_ENTRY
(
SctpChecksumErrors
),
SCTP_SNMP_ENTRY
(
SctpOutCtrlChunks
),
SCTP_SNMP_ENTRY
(
SctpOutOrderChunks
),
SCTP_SNMP_ENTRY
(
SctpOutUnorderChunks
),
SCTP_SNMP_ENTRY
(
SctpInCtrlChunks
),
SCTP_SNMP_ENTRY
(
SctpInOrderChunks
),
SCTP_SNMP_ENTRY
(
SctpInUnorderChunks
),
SCTP_SNMP_ENTRY
(
SctpFragUsrMsgs
),
SCTP_SNMP_ENTRY
(
SctpReasmUsrMsgs
),
SCTP_SNMP_ENTRY
(
SctpOutSCTPPacks
),
SCTP_SNMP_ENTRY
(
SctpInSCTPPacks
),
#undef SCTP_SNMP_ENTRY
};
/* Return the current value of a particular entry in the mib by adding its
* per cpu counters.
*/
static
unsigned
long
fold_field
(
void
*
mib
[],
int
nr
)
{
unsigned
long
res
=
0
;
int
i
;
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
!
cpu_possible
(
i
))
continue
;
res
+=
*
((
unsigned
long
*
)
(((
void
*
)
per_cpu_ptr
(
mib
[
0
],
i
))
+
sizeof
(
unsigned
long
)
*
nr
));
res
+=
*
((
unsigned
long
*
)
(((
void
*
)
per_cpu_ptr
(
mib
[
1
],
i
))
+
sizeof
(
unsigned
long
)
*
nr
));
}
return
res
;
}
/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
static
int
sctp_snmp_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
int
i
;
for
(
i
=
0
;
i
<
sizeof
(
sctp_snmp_list
)
/
sizeof
(
char
*
);
i
++
)
seq_printf
(
seq
,
"%-32s
\t
%ld
\n
"
,
sctp_snmp_list
[
i
],
fold_field
((
void
**
)
sctp_statistics
,
i
));
return
0
;
}
/* Initialize the seq file operations for 'snmp' object. */
static
int
sctp_snmp_seq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
sctp_snmp_seq_show
,
NULL
);
}
static
struct
file_operations
sctp_snmp_seq_fops
=
{
.
open
=
sctp_snmp_seq_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
/* Set up the proc fs entry for 'snmp' object. */
int
__init
sctp_snmp_proc_init
(
void
)
{
struct
proc_dir_entry
*
p
;
p
=
create_proc_entry
(
"snmp"
,
S_IRUGO
,
proc_net_sctp
);
if
(
!
p
)
return
-
ENOMEM
;
p
->
proc_fops
=
&
sctp_snmp_seq_fops
;
return
0
;
}
/* Cleanup the proc fs entry for 'snmp' object. */
void
sctp_snmp_proc_exit
(
void
)
{
remove_proc_entry
(
"snmp"
,
proc_net_sctp
);
}
net/sctp/protocol.c
View file @
9967b51f
...
@@ -75,6 +75,9 @@ static struct sctp_af *sctp_af_v6_specific;
...
@@ -75,6 +75,9 @@ static struct sctp_af *sctp_af_v6_specific;
extern
struct
net_proto_family
inet_family_ops
;
extern
struct
net_proto_family
inet_family_ops
;
extern
int
sctp_snmp_proc_init
(
void
);
extern
int
sctp_snmp_proc_exit
(
void
);
/* Return the address of the control sock. */
/* Return the address of the control sock. */
struct
sock
*
sctp_get_ctl_sock
(
void
)
struct
sock
*
sctp_get_ctl_sock
(
void
)
{
{
...
@@ -82,21 +85,32 @@ struct sock *sctp_get_ctl_sock(void)
...
@@ -82,21 +85,32 @@ 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. */
__init
void
sctp_proc_init
(
void
)
__init
int
sctp_proc_init
(
void
)
{
{
int
rc
=
0
;
if
(
!
proc_net_sctp
)
{
if
(
!
proc_net_sctp
)
{
struct
proc_dir_entry
*
ent
;
struct
proc_dir_entry
*
ent
;
ent
=
proc_mkdir
(
"net/sctp"
,
0
);
ent
=
proc_mkdir
(
"net/sctp"
,
0
);
if
(
ent
)
{
if
(
ent
)
{
ent
->
owner
=
THIS_MODULE
;
ent
->
owner
=
THIS_MODULE
;
proc_net_sctp
=
ent
;
proc_net_sctp
=
ent
;
}
}
else
rc
=
-
ENOMEM
;
}
}
if
(
sctp_snmp_proc_init
())
rc
=
-
ENOMEM
;
return
rc
;
}
}
/* Clean up the proc fs entry for the SCTP protocol. */
/* Clean up the proc fs entry for the SCTP protocol. */
void
sctp_proc_exit
(
void
)
void
sctp_proc_exit
(
void
)
{
{
sctp_snmp_proc_exit
();
if
(
proc_net_sctp
)
{
if
(
proc_net_sctp
)
{
proc_net_sctp
=
NULL
;
proc_net_sctp
=
NULL
;
remove_proc_entry
(
"net/sctp"
,
0
);
remove_proc_entry
(
"net/sctp"
,
0
);
...
@@ -124,7 +138,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
...
@@ -124,7 +138,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Add the address to the local list. */
/* Add the address to the local list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
if
(
addr
)
{
if
(
addr
)
{
INIT_LIST_HEAD
(
&
addr
->
list
);
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_port
=
0
;
addr
->
a
.
v4
.
sin_port
=
0
;
addr
->
a
.
v4
.
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
addr
->
a
.
v4
.
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
...
@@ -436,7 +449,6 @@ struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
...
@@ -436,7 +449,6 @@ struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
if
(
AF_INET
==
laddr
->
a
.
sa
.
sa_family
)
{
if
(
AF_INET
==
laddr
->
a
.
sa
.
sa_family
)
{
fl
.
fl4_src
=
laddr
->
a
.
v4
.
sin_addr
.
s_addr
;
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
))
{
if
(
!
ip_route_output_key
(
&
rt
,
&
fl
))
{
dst
=
&
rt
->
u
.
dst
;
dst
=
&
rt
->
u
.
dst
;
goto
out_unlock
;
goto
out_unlock
;
...
@@ -557,7 +569,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
...
@@ -557,7 +569,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
}
}
/* Copy the primary address of the peer primary address as the msg_name. */
/* Copy the primary address of the peer primary address as the msg_name. */
static
void
sctp_inet_event_msgname
(
s
ctp_ulpevent_
t
*
event
,
char
*
msgname
,
static
void
sctp_inet_event_msgname
(
s
truct
sctp_ulpeven
t
*
event
,
char
*
msgname
,
int
*
addr_len
)
int
*
addr_len
)
{
{
struct
sockaddr_in
*
sin
,
*
sinfrom
;
struct
sockaddr_in
*
sin
,
*
sinfrom
;
...
@@ -628,6 +640,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
...
@@ -628,6 +640,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
NIPQUAD
(((
struct
rtable
*
)
skb
->
dst
)
->
rt_src
),
NIPQUAD
(((
struct
rtable
*
)
skb
->
dst
)
->
rt_src
),
NIPQUAD
(((
struct
rtable
*
)
skb
->
dst
)
->
rt_dst
));
NIPQUAD
(((
struct
rtable
*
)
skb
->
dst
)
->
rt_dst
));
SCTP_INC_STATS
(
SctpOutSCTPPacks
);
return
ip_queue_xmit
(
skb
,
ipfragok
);
return
ip_queue_xmit
(
skb
,
ipfragok
);
}
}
...
...
net/sctp/sm_make_chunk.c
View file @
9967b51f
...
@@ -222,9 +222,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -222,9 +222,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_paramhdr_t
),
&
sat_param
);
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_paramhdr_t
),
&
sat_param
);
sctp_addto_chunk
(
retval
,
sizeof
(
sat_addr_types
),
sat_addr_types
);
sctp_addto_chunk
(
retval
,
sizeof
(
sat_addr_types
),
sat_addr_types
);
sctp_addto_chunk
(
retval
,
sizeof
(
ecap_param
),
&
ecap_param
);
sctp_addto_chunk
(
retval
,
sizeof
(
ecap_param
),
&
ecap_param
);
nodata:
nodata:
if
(
addrs
.
v
)
if
(
addrs
.
v
)
kfree
(
addrs
.
v
);
kfree
(
addrs
.
v
);
...
@@ -245,7 +243,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
...
@@ -245,7 +243,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
retval
=
NULL
;
retval
=
NULL
;
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
priority
);
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
priority
);
if
(
!
addrs
.
v
)
if
(
!
addrs
.
v
)
goto
nomem_rawaddr
;
goto
nomem_rawaddr
;
...
@@ -586,14 +585,12 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
...
@@ -586,14 +585,12 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
sctp_gap_ack_block_t
gab
;
sctp_gap_ack_block_t
gab
;
int
length
;
int
length
;
__u32
ctsn
;
__u32
ctsn
;
sctp_tsnmap_iter_t
iter
;
struct
sctp_tsnmap_iter
iter
;
__u16
num_gabs
;
__u16
num_gabs
,
num_dup_tsns
;
__u16
num_dup_tsns
=
asoc
->
peer
.
next_dup_tsn
;
struct
sctp_tsnmap
*
map
=
(
struct
sctp_tsnmap
*
)
&
asoc
->
peer
.
tsn_map
;
const
sctp_tsnmap_t
*
map
=
&
asoc
->
peer
.
tsn_map
;
ctsn
=
sctp_tsnmap_get_ctsn
(
map
);
ctsn
=
sctp_tsnmap_get_ctsn
(
map
);
SCTP_DEBUG_PRINTK
(
"make_sack: sackCTSNAck sent is 0x%x.
\n
"
,
SCTP_DEBUG_PRINTK
(
"sackCTSNAck sent is 0x%x.
\n
"
,
ctsn
);
ctsn
);
/* Count the number of Gap Ack Blocks. */
/* Count the number of Gap Ack Blocks. */
sctp_tsnmap_iter_init
(
map
,
&
iter
);
sctp_tsnmap_iter_init
(
map
,
&
iter
);
...
@@ -603,15 +600,17 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
...
@@ -603,15 +600,17 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Do nothing. */
/* Do nothing. */
}
}
num_dup_tsns
=
sctp_tsnmap_num_dups
(
map
);
/* Initialize the SACK header. */
/* Initialize the SACK header. */
sack
.
cum_tsn_ack
=
htonl
(
ctsn
);
sack
.
cum_tsn_ack
=
htonl
(
ctsn
);
sack
.
a_rwnd
=
htonl
(
asoc
->
rwnd
);
sack
.
a_rwnd
=
htonl
(
asoc
->
rwnd
);
sack
.
num_gap_ack_blocks
=
htons
(
num_gabs
);
sack
.
num_gap_ack_blocks
=
htons
(
num_gabs
);
sack
.
num_dup_tsns
=
htons
(
num_dup_tsns
);
sack
.
num_dup_tsns
=
htons
(
num_dup_tsns
);
length
=
sizeof
(
sack
)
length
=
sizeof
(
sack
)
+
sizeof
(
sctp_gap_ack_block_t
)
*
num_gabs
+
sizeof
(
sctp_gap_ack_block_t
)
*
num_gabs
+
sizeof
(
sctp_dup_tsn_t
)
*
num_dup_tsns
;
+
sizeof
(
__u32
)
*
num_dup_tsns
;
/* Create the chunk. */
/* Create the chunk. */
retval
=
sctp_make_chunk
(
asoc
,
SCTP_CID_SACK
,
0
,
length
);
retval
=
sctp_make_chunk
(
asoc
,
SCTP_CID_SACK
,
0
,
length
);
...
@@ -658,21 +657,18 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
...
@@ -658,21 +657,18 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
while
(
sctp_tsnmap_next_gap_ack
(
map
,
&
iter
,
&
gab
.
start
,
&
gab
.
end
))
{
while
(
sctp_tsnmap_next_gap_ack
(
map
,
&
iter
,
&
gab
.
start
,
&
gab
.
end
))
{
gab
.
start
=
htons
(
gab
.
start
);
gab
.
start
=
htons
(
gab
.
start
);
gab
.
end
=
htons
(
gab
.
end
);
gab
.
end
=
htons
(
gab
.
end
);
sctp_addto_chunk
(
retval
,
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_gap_ack_block_t
),
&
gab
);
sizeof
(
sctp_gap_ack_block_t
),
&
gab
);
}
}
/* Register the duplicates. */
/* Register the duplicates. */
sctp_addto_chunk
(
retval
,
sctp_addto_chunk
(
retval
,
sizeof
(
__u32
)
*
num_dup_tsns
,
sizeof
(
sctp_dup_tsn_t
)
*
num_dup_tsns
,
sctp_tsnmap_get_dups
(
map
));
&
asoc
->
peer
.
dup_tsns
);
nodata:
nodata:
return
retval
;
return
retval
;
}
}
/*
FIXME: Comments
. */
/*
Make a SHUTDOWN chunk
. */
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
;
...
@@ -689,7 +685,6 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
...
@@ -689,7 +685,6 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
retval
->
subh
.
shutdown_hdr
=
retval
->
subh
.
shutdown_hdr
=
sctp_addto_chunk
(
retval
,
sizeof
(
shut
),
&
shut
);
sctp_addto_chunk
(
retval
,
sizeof
(
shut
),
&
shut
);
nodata:
nodata:
return
retval
;
return
retval
;
}
}
...
@@ -1180,6 +1175,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
...
@@ -1180,6 +1175,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
over
=
msg_len
%
max
;
over
=
msg_len
%
max
;
offset
=
0
;
offset
=
0
;
if
(
whole
&&
over
)
SCTP_INC_STATS_USER
(
SctpFragUsrMsgs
);
/* Create chunks for all the full sized DATA chunks. */
/* Create chunks for all the full sized DATA chunks. */
for
(
i
=
0
,
len
=
first_len
;
i
<
whole
;
i
++
)
{
for
(
i
=
0
,
len
=
first_len
;
i
<
whole
;
i
++
)
{
frag
=
SCTP_DATA_MIDDLE_FRAG
;
frag
=
SCTP_DATA_MIDDLE_FRAG
;
...
...
net/sctp/sm_sideeffect.c
View file @
9967b51f
...
@@ -527,10 +527,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -527,10 +527,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break
;
break
;
case
SCTP_CMD_REPORT_DUP
:
case
SCTP_CMD_REPORT_DUP
:
if
(
asoc
->
peer
.
next_dup_tsn
<
SCTP_MAX_DUP_TSNS
)
{
sctp_tsnmap_mark_dup
(
&
asoc
->
peer
.
tsn_map
,
asoc
->
peer
.
dup_tsns
[
asoc
->
peer
.
next_dup_tsn
++
]
=
ntohl
(
command
->
obj
.
u32
));
ntohl
(
command
->
obj
.
u32
);
}
break
;
break
;
case
SCTP_CMD_REPORT_BIGGAP
:
case
SCTP_CMD_REPORT_BIGGAP
:
...
@@ -598,6 +596,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -598,6 +596,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
t
->
rto_pending
=
1
;
t
->
rto_pending
=
1
;
break
;
break
;
case
SCTP_CMD_CHUNK_PD
:
/* Send a chunk to the sockets layer. */
sctp_ulpq_partial_delivery
(
&
asoc
->
ulpq
,
command
->
obj
.
ptr
,
GFP_ATOMIC
);
break
;
default:
default:
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
command
->
verb
,
command
->
obj
.
ptr
);
command
->
verb
,
command
->
obj
.
ptr
);
...
@@ -737,7 +742,6 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
...
@@ -737,7 +742,6 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
...
@@ -1014,7 +1018,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
...
@@ -1014,7 +1018,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
commands
,
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
asoc
)
sctp_association_t
*
asoc
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
0
,
...
@@ -1041,7 +1045,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
...
@@ -1041,7 +1045,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_subtype_t
subtype
,
sctp_subtype_t
subtype
,
sctp_chunk_t
*
chunk
)
sctp_chunk_t
*
chunk
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
__u16
error
=
0
;
__u16
error
=
0
;
switch
(
event_type
)
{
switch
(
event_type
)
{
...
@@ -1061,12 +1065,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
...
@@ -1061,12 +1065,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
break
;
break
;
}
}
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
/* Cancel any partial delivery in progress. */
0
,
sctp_ulpq_abort_pd
(
&
asoc
->
ulpq
,
GFP_ATOMIC
);
SCTP_COMM_LOST
,
error
,
0
,
0
,
GFP_ATOMIC
);
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_COMM_LOST
,
error
,
0
,
0
,
GFP_ATOMIC
);
if
(
event
)
if
(
event
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
SCTP_ULPEVENT
(
event
));
SCTP_ULPEVENT
(
event
));
...
@@ -1141,7 +1144,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
...
@@ -1141,7 +1144,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
if
(
del_timer
(
&
t
->
hb_timer
))
if
(
del_timer
(
&
t
->
hb_timer
))
sctp_transport_put
(
t
);
sctp_transport_put
(
t
);
}
}
}
}
/* Helper function to update the heartbeat timer. */
/* Helper function to update the heartbeat timer. */
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
...
...
net/sctp/sm_statefuns.c
View file @
9967b51f
...
@@ -102,7 +102,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
...
@@ -102,7 +102,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* RFC 2960 6.10 Bundling
/* RFC 2960 6.10 Bundling
*
*
...
@@ -145,6 +145,9 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
...
@@ -145,6 +145,9 @@ sctp_disposition_t sctp_sf_do_4_C(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_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpShutdowns
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
...
@@ -223,6 +226,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -223,6 +226,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if
(
packet
)
{
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
else
{
}
else
{
return
SCTP_DISPOSITION_NOMEM
;
return
SCTP_DISPOSITION_NOMEM
;
...
@@ -264,7 +268,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -264,7 +268,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if
(
sctp_assoc_set_bind_addr_from_ep
(
new_asoc
,
GFP_ATOMIC
)
<
0
)
if
(
sctp_assoc_set_bind_addr_from_ep
(
new_asoc
,
GFP_ATOMIC
)
<
0
)
goto
nomem_ack
;
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
;
...
@@ -379,6 +383,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
...
@@ -379,6 +383,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpAborteds
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
...
@@ -388,6 +393,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
...
@@ -388,6 +393,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
chunk
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
chunk
,
&
err_chunk
))
{
&
err_chunk
))
{
SCTP_INC_STATS
(
SctpAborteds
);
/* This chunk contains fatal error. It is to be discarded.
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
* Send an ABORT, with causes if there is any.
*/
*/
...
@@ -403,6 +411,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
...
@@ -403,6 +411,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
if
(
packet
)
{
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
...
@@ -504,7 +513,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
...
@@ -504,7 +513,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
;
sctp_association_t
*
new_asoc
;
sctp_init_chunk_t
*
peer_init
;
sctp_init_chunk_t
*
peer_init
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
int
error
=
0
;
int
error
=
0
;
sctp_chunk_t
*
err_chk_p
;
sctp_chunk_t
*
err_chk_p
;
...
@@ -557,6 +566,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
...
@@ -557,6 +566,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
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_INC_STATS
(
SctpCurrEstab
);
SCTP_INC_STATS
(
SctpPassiveEstabs
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
if
(
new_asoc
->
autoclose
)
if
(
new_asoc
->
autoclose
)
...
@@ -636,7 +647,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
...
@@ -636,7 +647,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
const
sctp_subtype_t
type
,
void
*
arg
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* RFC 2960 5.1 Normal Establishment of an Association
/* RFC 2960 5.1 Normal Establishment of an Association
*
*
...
@@ -648,6 +659,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
...
@@ -648,6 +659,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_COOKIE
));
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_INC_STATS
(
SctpCurrEstab
);
SCTP_INC_STATS
(
SctpActiveEstabs
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
if
(
asoc
->
autoclose
)
if
(
asoc
->
autoclose
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_START
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_START
,
...
@@ -719,6 +732,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
...
@@ -719,6 +732,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
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. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
...
@@ -929,6 +944,8 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
...
@@ -929,6 +944,8 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
goto
out
;
goto
out
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
pkt
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
pkt
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
/* Discard the rest of the inbound packet. */
/* Discard the rest of the inbound packet. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
...
@@ -1125,6 +1142,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
...
@@ -1125,6 +1142,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
if
(
packet
)
{
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
retval
=
SCTP_DISPOSITION_CONSUME
;
retval
=
SCTP_DISPOSITION_CONSUME
;
}
else
{
}
else
{
retval
=
SCTP_DISPOSITION_NOMEM
;
retval
=
SCTP_DISPOSITION_NOMEM
;
...
@@ -1355,7 +1373,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
...
@@ -1355,7 +1373,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
)
sctp_association_t
*
new_asoc
)
{
{
sctp_init_chunk_t
*
peer_init
;
sctp_init_chunk_t
*
peer_init
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
/* new_asoc is a brand-new association, so these are not yet
/* new_asoc is a brand-new association, so these are not yet
...
@@ -1421,7 +1439,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
...
@@ -1421,7 +1439,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
)
sctp_association_t
*
new_asoc
)
{
{
sctp_init_chunk_t
*
peer_init
;
sctp_init_chunk_t
*
peer_init
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
/* new_asoc is a brand-new association, so these are not yet
/* new_asoc is a brand-new association, so these are not yet
...
@@ -1436,6 +1454,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
...
@@ -1436,6 +1454,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_UPDATE_ASSOC
,
SCTP_ASOC
(
new_asoc
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_UPDATE_ASSOC
,
SCTP_ASOC
(
new_asoc
));
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_INC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
...
@@ -1503,7 +1522,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
...
@@ -1503,7 +1522,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
,
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
new_asoc
)
sctp_association_t
*
new_asoc
)
{
{
s
ctp_ulpevent_
t
*
ev
=
NULL
;
s
truct
sctp_ulpeven
t
*
ev
=
NULL
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
/* Clarification from Implementor's Guide:
/* Clarification from Implementor's Guide:
...
@@ -1519,6 +1538,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
...
@@ -1519,6 +1538,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_COOKIE
));
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_INC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
SCTP_NULL
());
...
@@ -1540,11 +1560,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
...
@@ -1540,11 +1560,11 @@ 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
());
...
@@ -1925,6 +1945,8 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
...
@@ -1925,6 +1945,8 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
/* ASSOC_FAILED will DELETE_TCB. */
/* ASSOC_FAILED will DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
/* BUG? This does not look complete... */
/* BUG? This does not look complete... */
return
SCTP_DISPOSITION_ABORT
;
return
SCTP_DISPOSITION_ABORT
;
...
@@ -1948,6 +1970,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
...
@@ -1948,6 +1970,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(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_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpAborteds
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_INIT
));
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_INIT
));
...
@@ -2241,6 +2264,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2241,6 +2264,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
sctp_datahdr_t
*
data_hdr
;
sctp_datahdr_t
*
data_hdr
;
sctp_chunk_t
*
err
;
sctp_chunk_t
*
err
;
size_t
datalen
;
size_t
datalen
;
sctp_verb_t
deliver
;
int
tmp
;
int
tmp
;
__u32
tsn
;
__u32
tsn
;
...
@@ -2307,10 +2331,32 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2307,10 +2331,32 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
datalen
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
datalen
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
datalen
-=
sizeof
(
sctp_data_chunk_t
);
datalen
-=
sizeof
(
sctp_data_chunk_t
);
deliver
=
SCTP_CMD_CHUNK_ULP
;
/* Think about partial delivery. */
if
((
datalen
>=
asoc
->
rwnd
)
&&
(
!
asoc
->
ulpq
.
pd_mode
))
{
/* Even if we don't accept this chunk there is
* memory pressure.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_CHUNK_PD
,
SCTP_NULL
());
}
if
(
asoc
->
rwnd_over
||
(
datalen
>
asoc
->
rwnd
+
asoc
->
frag_point
))
{
if
(
asoc
->
rwnd_over
||
(
datalen
>
asoc
->
rwnd
+
asoc
->
frag_point
))
{
SCTP_DEBUG_PRINTK
(
"Discarding tsn: %u datalen: %Zd, "
"rwnd: %d
\n
"
,
tsn
,
datalen
,
asoc
->
rwnd
);
goto
discard_force
;
/* There is absolutely no room, but this is the most
* important tsn that we are waiting on, try to
* to partial deliver or renege to make room.
*/
if
((
sctp_tsnmap_get_ctsn
(
&
asoc
->
peer
.
tsn_map
)
+
1
)
==
tsn
)
{
deliver
=
SCTP_CMD_CHUNK_PD
;
}
else
{
SCTP_DEBUG_PRINTK
(
"Discard tsn: %u len: %Zd, "
"rwnd: %d
\n
"
,
tsn
,
datalen
,
asoc
->
rwnd
);
goto
discard_force
;
}
}
}
/*
/*
...
@@ -2332,13 +2378,22 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2332,13 +2378,22 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
}
/* We are accepting this DATA chunk. */
/* If definately accepting the DATA chunk, record its TSN, otherwise
* wait for renege processing.
*/
if
(
deliver
!=
SCTP_CMD_CHUNK_PD
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPORT_TSN
,
SCTP_U32
(
tsn
));
/* Record the fact that we have received this TSN. */
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPORT_TSN
,
SCTP_U32
(
tsn
));
SCTP_INC_STATS
(
SctpInUnorderChunks
);
else
SCTP_INC_STATS
(
SctpInOrderChunks
);
}
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
*
*
...
@@ -2352,10 +2407,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2352,10 +2407,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
err
=
sctp_make_op_error
(
asoc
,
chunk
,
SCTP_ERROR_INV_STRM
,
err
=
sctp_make_op_error
(
asoc
,
chunk
,
SCTP_ERROR_INV_STRM
,
&
data_hdr
->
stream
,
&
data_hdr
->
stream
,
sizeof
(
data_hdr
->
stream
));
sizeof
(
data_hdr
->
stream
));
if
(
err
)
{
if
(
err
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
err
));
SCTP_CHUNK
(
err
));
}
goto
discard_noforce
;
goto
discard_noforce
;
}
}
...
@@ -2363,7 +2417,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2363,7 +2417,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
* SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
* chunk needs the updated rwnd.
* chunk needs the updated rwnd.
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_CHUNK_ULP
,
SCTP_CHUNK
(
chunk
));
sctp_add_cmd_sf
(
commands
,
deliver
,
SCTP_CHUNK
(
chunk
));
if
(
asoc
->
autoclose
)
{
if
(
asoc
->
autoclose
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_RESTART
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_RESTART
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_AUTOCLOSE
));
SCTP_TO
(
SCTP_EVENT_TIMEOUT_AUTOCLOSE
));
...
@@ -2536,6 +2591,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
...
@@ -2536,6 +2591,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
}
...
@@ -2544,6 +2601,11 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
...
@@ -2544,6 +2601,11 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
/* Record the fact that we have received this TSN. */
/* Record the fact that we have received this TSN. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPORT_TSN
,
SCTP_U32
(
tsn
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPORT_TSN
,
SCTP_U32
(
tsn
));
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
SCTP_INC_STATS
(
SctpInUnorderChunks
);
else
SCTP_INC_STATS
(
SctpInOrderChunks
);
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
*
*
* If an endpoint receive a DATA chunk with an invalid stream
* If an endpoint receive a DATA chunk with an invalid stream
...
@@ -2705,6 +2767,8 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
...
@@ -2705,6 +2767,8 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
}
...
@@ -2726,7 +2790,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
...
@@ -2726,7 +2790,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
while
(
chunk
->
chunk_end
>
chunk
->
skb
->
data
)
{
while
(
chunk
->
chunk_end
>
chunk
->
skb
->
data
)
{
ev
=
sctp_ulpevent_make_remote_error
(
asoc
,
chunk
,
0
,
ev
=
sctp_ulpevent_make_remote_error
(
asoc
,
chunk
,
0
,
...
@@ -2764,7 +2828,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
...
@@ -2764,7 +2828,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
reply
;
sctp_chunk_t
*
reply
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* 10.2 H) SHUTDOWN COMPLETE notification
/* 10.2 H) SHUTDOWN COMPLETE notification
*
*
...
@@ -2794,6 +2858,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
...
@@ -2794,6 +2858,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(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_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpShutdowns
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
/* ...and remove all record of the association. */
/* ...and remove all record of the association. */
...
@@ -2834,6 +2900,8 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
...
@@ -2834,6 +2900,8 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
__u8
*
ch_end
;
__u8
*
ch_end
;
int
ootb_shut_ack
=
0
;
int
ootb_shut_ack
=
0
;
SCTP_INC_STATS
(
SctpOutOfBlues
);
ch
=
(
sctp_chunkhdr_t
*
)
chunk
->
chunk_hdr
;
ch
=
(
sctp_chunkhdr_t
*
)
chunk
->
chunk_hdr
;
do
{
do
{
ch_end
=
((
__u8
*
)
ch
)
+
WORD_ROUND
(
ntohs
(
ch
->
length
));
ch_end
=
((
__u8
*
)
ch
)
+
WORD_ROUND
(
ntohs
(
ch
->
length
));
...
@@ -2901,6 +2969,8 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
...
@@ -2901,6 +2969,8 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
}
...
@@ -3472,6 +3542,10 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
...
@@ -3472,6 +3542,10 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
/* Delete the established association. */
/* Delete the established association. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
retval
;
return
retval
;
}
}
...
@@ -3527,6 +3601,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
...
@@ -3527,6 +3601,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpShutdowns
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
...
@@ -3597,6 +3673,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
...
@@ -3597,6 +3673,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(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_CLOSED
));
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpAborteds
);
/* Even if we can't send the ABORT due to low memory delete the
/* Even if we can't send the ABORT due to low memory delete the
* TCB. This is a departure from our typical NOMEM handling.
* TCB. This is a departure from our typical NOMEM handling.
*/
*/
...
@@ -3929,6 +4007,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
...
@@ -3929,6 +4007,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
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. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
...
@@ -4096,6 +4176,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
...
@@ -4096,6 +4176,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
...
@@ -4271,6 +4353,9 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
...
@@ -4271,6 +4353,9 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
__u16
num_blocks
;
__u16
num_blocks
;
__u16
num_dup_tsns
;
__u16
num_dup_tsns
;
/* FIXME: Protect ourselves from reading too far into
* the skb from a bogus sender.
*/
sack
=
(
sctp_sackhdr_t
*
)
chunk
->
skb
->
data
;
sack
=
(
sctp_sackhdr_t
*
)
chunk
->
skb
->
data
;
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_sackhdr_t
));
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_sackhdr_t
));
...
@@ -4401,6 +4486,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
...
@@ -4401,6 +4486,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
sctp_packet_append_chunk
(
packet
,
err_chunk
);
sctp_packet_append_chunk
(
packet
,
err_chunk
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
}
else
}
else
sctp_free_chunk
(
err_chunk
);
sctp_free_chunk
(
err_chunk
);
}
}
...
...
net/sctp/socket.c
View file @
9967b51f
...
@@ -81,13 +81,13 @@
...
@@ -81,13 +81,13 @@
/* Forward declarations for internal helper functions. */
/* Forward declarations for internal helper functions. */
static
int
sctp_writeable
(
struct
sock
*
sk
);
static
int
sctp_writeable
(
struct
sock
*
sk
);
static
inline
int
sctp_wspace
(
s
ctp_association_t
*
asoc
);
static
inline
int
sctp_wspace
(
s
truct
sctp_association
*
asoc
);
static
inline
void
sctp_set_owner_w
(
sctp_chunk_t
*
chunk
);
static
inline
void
sctp_set_owner_w
(
sctp_chunk_t
*
chunk
);
static
void
sctp_wfree
(
struct
sk_buff
*
skb
);
static
void
sctp_wfree
(
struct
sk_buff
*
skb
);
static
int
sctp_wait_for_sndbuf
(
s
ctp_association_t
*
asoc
,
long
*
timeo_p
,
static
int
sctp_wait_for_sndbuf
(
s
truct
sctp_association
*
,
long
*
timeo_p
,
int
msg_len
);
int
msg_len
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
s
ctp_association_t
*
asoc
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
s
truct
sctp_association
*
,
long
*
timeo_p
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
...
@@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
...
@@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
/* Bind a local address either to an endpoint or to an association. */
/* Bind a local address either to an endpoint or to an association. */
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
...
@@ -454,7 +454,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
...
@@ -454,7 +454,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
*/
*/
int
sctp_bindx_rem
(
struct
sock
*
sk
,
struct
sockaddr_storage
*
addrs
,
int
addrcnt
)
int
sctp_bindx_rem
(
struct
sock
*
sk
,
struct
sockaddr_storage
*
addrs
,
int
addrcnt
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
int
cnt
;
int
cnt
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
...
@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
...
@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Clean up any skbs sitting on the receive queue. */
/* Clean up any skbs sitting on the receive queue. */
skb_queue_purge
(
&
sk
->
receive_queue
);
skb_queue_purge
(
&
sk
->
receive_queue
);
skb_queue_purge
(
&
sctp_sk
(
sk
)
->
pd_lobby
);
/* This will run the backlog queue. */
/* This will run the backlog queue. */
sctp_release_sock
(
sk
);
sctp_release_sock
(
sk
);
...
@@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
...
@@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
SCTP_STATIC
int
sctp_sendmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
SCTP_STATIC
int
sctp_sendmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
int
msg_len
)
struct
msghdr
*
msg
,
int
msg_len
)
{
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
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
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
...
@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* ASSERT: we have a valid association at this point. */
/* ASSERT: we have a valid association at this point. */
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
if
(
!
sinfo
)
{
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo
.
sinfo_stream
=
asoc
->
defaults
.
stream
;
default_sinfo
.
sinfo_flags
=
asoc
->
defaults
.
flags
;
default_sinfo
.
sinfo_ppid
=
asoc
->
defaults
.
ppid
;
default_sinfo
.
sinfo_context
=
asoc
->
defaults
.
context
;
default_sinfo
.
sinfo_timetolive
=
asoc
->
defaults
.
timetolive
;
default_sinfo
.
sinfo_assoc_id
=
sctp_assoc2id
(
asoc
);
sinfo
=
&
default_sinfo
;
}
/* API 7.1.7, the sndbuf size per association bounds the
/* API 7.1.7, the sndbuf size per association bounds the
* maximum size of data that can be sent in a single send call.
* maximum size of data that can be sent in a single send call.
*/
*/
...
@@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
out_free
;
goto
out_free
;
}
}
}
else
{
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo
.
sinfo_stream
=
asoc
->
defaults
.
stream
;
default_sinfo
.
sinfo_ppid
=
asoc
->
defaults
.
ppid
;
sinfo
=
&
default_sinfo
;
}
}
timeo
=
sock_sndtimeo
(
sk
,
msg
->
msg_flags
&
MSG_DONTWAIT
);
timeo
=
sock_sndtimeo
(
sk
,
msg
->
msg_flags
&
MSG_DONTWAIT
);
...
@@ -979,21 +986,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -979,21 +986,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto
out_free
;
goto
out_free
;
}
}
#if 0
/* FIXME: This looks wrong so I'll comment out.
* We should be able to use this same technique for
* primary address override! --jgrimm
*/
/* If the user gave us an address, copy it in. */
if (msg->msg_name) {
chunk->transport = sctp_assoc_lookup_paddr(asoc, &to);
if (!chunk->transport) {
err = -EINVAL;
goto out_free;
}
}
#endif /* 0 */
/* Break the message into multiple chunks of maximum size. */
/* Break the message into multiple chunks of maximum size. */
skb_queue_head_init
(
&
chunks
);
skb_queue_head_init
(
&
chunks
);
err
=
sctp_datachunks_from_user
(
asoc
,
sinfo
,
msg
,
msg_len
,
&
chunks
);
err
=
sctp_datachunks_from_user
(
asoc
,
sinfo
,
msg
,
msg_len
,
&
chunks
);
...
@@ -1013,6 +1005,23 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -1013,6 +1005,23 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* Do accounting for the write space. */
/* Do accounting for the write space. */
sctp_set_owner_w
(
chunk
);
sctp_set_owner_w
(
chunk
);
/* This flag, in the UDP model, requests the SCTP stack to
* override the primary destination address with the
* address found with the sendto/sendmsg call.
*/
if
(
sinfo_flags
&
MSG_ADDR_OVER
)
{
if
(
!
msg
->
msg_name
)
{
err
=
-
EINVAL
;
goto
out_free
;
}
chunk
->
transport
=
sctp_assoc_lookup_paddr
(
asoc
,
&
to
);
if
(
!
chunk
->
transport
)
{
err
=
-
EINVAL
;
goto
out_free
;
}
}
/* Send it to the lower layers. */
/* Send it to the lower layers. */
sctp_primitive_SEND
(
asoc
,
chunk
);
sctp_primitive_SEND
(
asoc
,
chunk
);
SCTP_DEBUG_PRINTK
(
"We sent primitively.
\n
"
);
SCTP_DEBUG_PRINTK
(
"We sent primitively.
\n
"
);
...
@@ -1110,8 +1119,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
...
@@ -1110,8 +1119,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
SCTP_STATIC
int
sctp_recvmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
SCTP_STATIC
int
sctp_recvmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
int
len
,
int
noblock
,
int
flags
,
int
*
addr_len
)
int
len
,
int
noblock
,
int
flags
,
int
*
addr_len
)
{
{
s
ctp_ulpevent_
t
*
event
=
NULL
;
s
truct
sctp_ulpeven
t
*
event
=
NULL
;
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
int
copied
;
int
copied
;
int
err
=
0
;
int
err
=
0
;
...
@@ -1143,7 +1152,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1143,7 +1152,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
if
(
err
)
if
(
err
)
goto
out_free
;
goto
out_free
;
...
@@ -1170,7 +1179,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1170,7 +1179,6 @@ 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.
*/
*/
if
(
skb_len
>
copied
)
{
if
(
skb_len
>
copied
)
{
msg
->
msg_flags
&=
~
MSG_EOR
;
msg
->
msg_flags
&=
~
MSG_EOR
;
...
@@ -1178,6 +1186,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1178,6 +1186,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
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
/* When only partial message is copied to the user, increase
* rwnd by that amount. If all the data in the skb is read,
* rwnd by that amount. If all the data in the skb is read,
* rwnd is updated when the skb's destructor is called via
* rwnd is updated when the skb's destructor is called via
...
@@ -1185,9 +1194,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1185,9 +1194,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
*/
*/
sctp_assoc_rwnd_increase
(
event
->
asoc
,
copied
);
sctp_assoc_rwnd_increase
(
event
->
asoc
,
copied
);
goto
out
;
goto
out
;
}
else
{
}
else
if
((
event
->
msg_flags
&
MSG_NOTIFICATION
)
||
msg
->
msg_flags
|=
MSG_EOR
;
(
event
->
msg_flags
&
MSG_EOR
))
}
msg
->
msg_flags
|=
MSG_EOR
;
else
msg
->
msg_flags
&=
~
MSG_EOR
;
out_free:
out_free:
sctp_ulpevent_free
(
event
);
/* Free the skb. */
sctp_ulpevent_free
(
event
);
/* Free the skb. */
...
@@ -1225,7 +1236,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
...
@@ -1225,7 +1236,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
static
inline
int
sctp_setsockopt_autoclose
(
struct
sock
*
sk
,
char
*
optval
,
static
inline
int
sctp_setsockopt_autoclose
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
int
optlen
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
/* Applicable to UDP-style socket only */
/* Applicable to UDP-style socket only */
if
(
SCTP_SOCKET_TCP
==
sp
->
type
)
if
(
SCTP_SOCKET_TCP
==
sp
->
type
)
...
@@ -1310,6 +1321,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
...
@@ -1310,6 +1321,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
return
0
;
return
0
;
}
}
/*
*
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied
* through the inclusion of ancillary data. This socket option allows
* such an application to set the default sctp_sndrcvinfo structure.
* The application that wishes to use this socket option simply passes
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
* sinfo_timetolive. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*/
static
inline
int
sctp_setsockopt_set_default_send_param
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
struct
sctp_sndrcvinfo
info
;
sctp_association_t
*
asoc
;
if
(
optlen
!=
sizeof
(
struct
sctp_sndrcvinfo
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
info
,
optval
,
optlen
))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
info
.
sinfo_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
asoc
->
defaults
.
stream
=
info
.
sinfo_stream
;
asoc
->
defaults
.
flags
=
info
.
sinfo_flags
;
asoc
->
defaults
.
ppid
=
info
.
sinfo_ppid
;
asoc
->
defaults
.
context
=
info
.
sinfo_context
;
asoc
->
defaults
.
timetolive
=
info
.
sinfo_timetolive
;
return
0
;
}
/* API 6.2 setsockopt(), getsockopt()
/* API 6.2 setsockopt(), getsockopt()
*
*
* Applications use setsockopt() and getsockopt() to set or retrieve
* Applications use setsockopt() and getsockopt() to set or retrieve
...
@@ -1401,6 +1450,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1401,6 +1450,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval
=
sctp_setsockopt_initmsg
(
sk
,
optval
,
optlen
);
retval
=
sctp_setsockopt_initmsg
(
sk
,
optval
,
optlen
);
break
;
break
;
case
SCTP_SET_DEFAULT_SEND_PARAM
:
retval
=
sctp_setsockopt_set_default_send_param
(
sk
,
optval
,
optlen
);
break
;
default:
default:
retval
=
-
ENOPROTOOPT
;
retval
=
-
ENOPROTOOPT
;
break
;
break
;
...
@@ -1432,7 +1486,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1432,7 +1486,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
SCTP_STATIC
int
sctp_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
uaddr
,
SCTP_STATIC
int
sctp_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
int
addr_len
)
{
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
...
@@ -1554,7 +1608,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1554,7 +1608,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
{
{
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_protocol_t
*
proto
;
sctp_protocol_t
*
proto
;
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
...
@@ -1583,7 +1637,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1583,7 +1637,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Initialize default RTO related parameters. These parameters can
/* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option.
* be modified for with the SCTP_RTOINFO socket option.
* FIXME: Th
is
are not used yet.
* FIXME: Th
ese
are not used yet.
*/
*/
sp
->
rtoinfo
.
srto_initial
=
proto
->
rto_initial
;
sp
->
rtoinfo
.
srto_initial
=
proto
->
rto_initial
;
sp
->
rtoinfo
.
srto_max
=
proto
->
rto_max
;
sp
->
rtoinfo
.
srto_max
=
proto
->
rto_max
;
...
@@ -1620,6 +1674,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1620,6 +1674,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/
*/
sp
->
autoclose
=
0
;
sp
->
autoclose
=
0
;
sp
->
pf
=
sctp_get_pf_specific
(
sk
->
family
);
sp
->
pf
=
sctp_get_pf_specific
(
sk
->
family
);
/* Control variables for partial data delivery. */
sp
->
pd_mode
=
0
;
skb_queue_head_init
(
&
sp
->
pd_lobby
);
/* Create a per socket endpoint structure. Even if we
/* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still
* change the data structure relationships, this may still
* be useful for storing pre-connect address information.
* be useful for storing pre-connect address information.
...
@@ -1774,10 +1833,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1774,10 +1833,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
struct
sock
*
newsk
;
struct
sock
*
newsk
;
struct
socket
*
tmpsock
;
struct
socket
*
tmpsock
;
sctp_endpoint_t
*
newep
;
sctp_endpoint_t
*
newep
;
s
ctp_opt_
t
*
oldsp
=
sctp_sk
(
oldsk
);
s
truct
sctp_op
t
*
oldsp
=
sctp_sk
(
oldsk
);
s
ctp_opt_
t
*
newsp
;
s
truct
sctp_op
t
*
newsp
;
struct
sk_buff
*
skb
,
*
tmp
;
struct
sk_buff
*
skb
,
*
tmp
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
int
err
=
0
;
int
err
=
0
;
/* An association cannot be branched off from an already peeled-off
/* An association cannot be branched off from an already peeled-off
...
@@ -1811,13 +1870,50 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1811,13 +1870,50 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
* peeled off association to the new socket's receive queue.
* peeled off association to the new socket's receive queue.
*/
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
if
(
event
->
asoc
==
assoc
)
{
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
}
}
/* Clean up an messages pending delivery due to partial
* delivery. Three cases:
* 1) No partial deliver; no work.
* 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
* 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
*/
skb_queue_head_init
(
&
newsp
->
pd_lobby
);
sctp_sk
(
newsk
)
->
pd_mode
=
assoc
->
ulpq
.
pd_mode
;;
if
(
sctp_sk
(
oldsk
)
->
pd_mode
)
{
struct
sk_buff_head
*
queue
;
/* Decide which queue to move pd_lobby skbs to. */
if
(
assoc
->
ulpq
.
pd_mode
)
{
queue
=
&
newsp
->
pd_lobby
;
}
else
queue
=
&
newsk
->
receive_queue
;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each
(
skb
,
&
oldsp
->
pd_lobby
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
queue
,
skb
);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if
(
assoc
->
ulpq
.
pd_mode
)
sctp_clear_pd
(
oldsk
);
}
/* Set the type of socket to indicate that it is peeled off from the
/* Set the type of socket to indicate that it is peeled off from the
* original socket.
* original socket.
*/
*/
...
@@ -2389,7 +2485,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
...
@@ -2389,7 +2485,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
*/
*/
SCTP_STATIC
int
sctp_seqpacket_listen
(
struct
sock
*
sk
,
int
backlog
)
SCTP_STATIC
int
sctp_seqpacket_listen
(
struct
sock
*
sk
,
int
backlog
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
/* Only UDP style sockets that are not peeled off are allowed to
/* Only UDP style sockets that are not peeled off are allowed to
...
...
net/sctp/tsnmap.c
View file @
9967b51f
...
@@ -3,40 +3,40 @@
...
@@ -3,40 +3,40 @@
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
* This file is part of the SCTP kernel reference Implementation
*
*
* These functions manipulate sctp tsn mapping array.
* These functions manipulate sctp tsn mapping array.
*
*
* 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 the
* Please send any bug reports or fixes you make to the
* email address(es):
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
*
* Or submit a bug report through the following website:
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
* http://www.sf.net/projects/lksctp
*
*
* Written or modified by:
* Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org>
* La Monte H.P. Yarroll <piggy@acm.org>
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Karl Knutson <karl@athena.chicago.il.us>
* Karl Knutson <karl@athena.chicago.il.us>
*
*
* 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.
*/
*/
...
@@ -45,21 +45,21 @@
...
@@ -45,21 +45,21 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
static
void
_sctp_tsnmap_update
(
sctp_tsnmap_t
*
map
);
static
void
sctp_tsnmap_update
(
struct
sctp_tsnmap
*
map
);
static
void
_sctp_tsnmap_update_pending_data
(
sctp_tsnmap_t
*
map
);
static
void
sctp_tsnmap_update_pending_data
(
struct
sctp_tsnmap
*
map
);
static
void
_
sctp_tsnmap_find_gap_ack
(
__u8
*
map
,
__u16
off
,
static
void
sctp_tsnmap_find_gap_ack
(
__u8
*
map
,
__u16
off
,
__u16
len
,
__u16
base
,
__u16
len
,
__u16
base
,
int
*
started
,
__u16
*
start
,
int
*
started
,
__u16
*
start
,
int
*
ended
,
__u16
*
end
);
int
*
ended
,
__u16
*
end
);
/* Create a new sctp_tsnmap.
/* Create a new sctp_tsnmap.
* Allocate room to store at least 'len' contiguous TSNs.
* Allocate room to store at least 'len' contiguous TSNs.
*/
*/
s
ctp_tsnmap_t
*
sctp_tsnmap_new
(
__u16
len
,
__u32
initial_tsn
,
int
priority
)
s
truct
sctp_tsnmap
*
sctp_tsnmap_new
(
__u16
len
,
__u32
initial_tsn
,
int
priority
)
{
{
s
ctp_tsnmap_t
*
retval
;
s
truct
sctp_tsnmap
*
retval
;
retval
=
kmalloc
(
sizeof
(
s
ctp_tsnmap_t
)
+
retval
=
kmalloc
(
sizeof
(
s
truct
sctp_tsnmap
)
+
sctp_tsnmap_storage_size
(
len
),
sctp_tsnmap_storage_size
(
len
),
priority
);
priority
);
if
(
!
retval
)
if
(
!
retval
)
...
@@ -72,13 +72,13 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
...
@@ -72,13 +72,13 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
fail_map:
fail_map:
kfree
(
retval
);
kfree
(
retval
);
fail:
fail:
return
NULL
;
return
NULL
;
}
}
/* Initialize a block of memory as a tsnmap. */
/* Initialize a block of memory as a tsnmap. */
sctp_tsnmap_t
*
sctp_tsnmap_init
(
sctp_tsnmap_t
*
map
,
__u16
len
,
__u32
initial_tsn
)
struct
sctp_tsnmap
*
sctp_tsnmap_init
(
struct
sctp_tsnmap
*
map
,
__u16
len
,
__u32
initial_tsn
)
{
{
map
->
tsn_map
=
map
->
raw_map
;
map
->
tsn_map
=
map
->
raw_map
;
map
->
overflow_map
=
map
->
tsn_map
+
len
;
map
->
overflow_map
=
map
->
tsn_map
+
len
;
...
@@ -94,6 +94,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
...
@@ -94,6 +94,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
map
->
max_tsn_seen
=
map
->
cumulative_tsn_ack_point
;
map
->
max_tsn_seen
=
map
->
cumulative_tsn_ack_point
;
map
->
malloced
=
0
;
map
->
malloced
=
0
;
map
->
pending_data
=
0
;
map
->
pending_data
=
0
;
map
->
num_dup_tsns
=
0
;
return
map
;
return
map
;
}
}
...
@@ -104,7 +105,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
...
@@ -104,7 +105,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
* >0 if the TSN has been seen (duplicate)
* >0 if the TSN has been seen (duplicate)
* <0 if the TSN is invalid (too large to track)
* <0 if the TSN is invalid (too large to track)
*/
*/
int
sctp_tsnmap_check
(
const
s
ctp_tsnmap_t
*
map
,
__u32
tsn
)
int
sctp_tsnmap_check
(
const
s
truct
sctp_tsnmap
*
map
,
__u32
tsn
)
{
{
__s32
gap
;
__s32
gap
;
int
dup
;
int
dup
;
...
@@ -136,7 +137,7 @@ int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
...
@@ -136,7 +137,7 @@ int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
}
}
/* Is there a gap in the TSN map? */
/* Is there a gap in the TSN map? */
int
sctp_tsnmap_has_gap
(
const
s
ctp_tsnmap_t
*
map
)
int
sctp_tsnmap_has_gap
(
const
s
truct
sctp_tsnmap
*
map
)
{
{
int
has_gap
;
int
has_gap
;
...
@@ -145,7 +146,7 @@ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
...
@@ -145,7 +146,7 @@ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
}
}
/* Mark this TSN as seen. */
/* Mark this TSN as seen. */
void
sctp_tsnmap_mark
(
s
ctp_tsnmap_t
*
map
,
__u32
tsn
)
void
sctp_tsnmap_mark
(
s
truct
sctp_tsnmap
*
map
,
__u32
tsn
)
{
{
__s32
gap
;
__s32
gap
;
...
@@ -173,40 +174,45 @@ void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
...
@@ -173,40 +174,45 @@ void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
/* Go fixup any internal TSN mapping variables including
/* Go fixup any internal TSN mapping variables including
* cumulative_tsn_ack_point.
* cumulative_tsn_ack_point.
*/
*/
_sctp_tsnmap_update
(
map
);
sctp_tsnmap_update
(
map
);
}
void
sctp_tsnmap_report_dup
(
struct
sctp_tsnmap
*
map
,
__u32
tsn
)
{
}
}
/* Retrieve the Cumulative TSN Ack Point. */
/* Retrieve the Cumulative TSN Ack Point. */
__u32
sctp_tsnmap_get_ctsn
(
const
s
ctp_tsnmap_t
*
map
)
__u32
sctp_tsnmap_get_ctsn
(
const
s
truct
sctp_tsnmap
*
map
)
{
{
return
map
->
cumulative_tsn_ack_point
;
return
map
->
cumulative_tsn_ack_point
;
}
}
/* Retrieve the highest TSN we've seen. */
/* Retrieve the highest TSN we've seen. */
__u32
sctp_tsnmap_get_max_tsn_seen
(
const
s
ctp_tsnmap_t
*
map
)
__u32
sctp_tsnmap_get_max_tsn_seen
(
const
s
truct
sctp_tsnmap
*
map
)
{
{
return
map
->
max_tsn_seen
;
return
map
->
max_tsn_seen
;
}
}
/* Dispose of a tsnmap. */
/* Dispose of a tsnmap. */
void
sctp_tsnmap_free
(
s
ctp_tsnmap_t
*
map
)
void
sctp_tsnmap_free
(
s
truct
sctp_tsnmap
*
map
)
{
{
if
(
map
->
malloced
)
if
(
map
->
malloced
)
kfree
(
map
);
kfree
(
map
);
}
}
/* Initialize a Gap Ack Block iterator from memory being provided. */
/* Initialize a Gap Ack Block iterator from memory being provided. */
void
sctp_tsnmap_iter_init
(
const
sctp_tsnmap_t
*
map
,
sctp_tsnmap_iter_t
*
iter
)
void
sctp_tsnmap_iter_init
(
const
struct
sctp_tsnmap
*
map
,
struct
sctp_tsnmap_iter
*
iter
)
{
{
/* Only start looking one past the Cumulative TSN Ack Point. */
/* Only start looking one past the Cumulative TSN Ack Point. */
iter
->
start
=
map
->
cumulative_tsn_ack_point
+
1
;
iter
->
start
=
map
->
cumulative_tsn_ack_point
+
1
;
}
}
/* Get the next Gap Ack Blocks. Returns 0 if there was not
/* Get the next Gap Ack Blocks. Returns 0 if there was not
another block
*
another block
to get.
* to get.
*/
*/
int
sctp_tsnmap_next_gap_ack
(
const
s
ctp_tsnmap_t
*
map
,
sctp_tsnmap_iter_t
*
iter
,
int
sctp_tsnmap_next_gap_ack
(
const
s
truct
sctp_tsnmap
*
map
,
__u16
*
start
,
__u16
*
end
)
struct
sctp_tsnmap_iter
*
iter
,
__u16
*
start
,
__u16
*
end
)
{
{
int
started
,
ended
;
int
started
,
ended
;
__u16
_start
,
_end
,
offset
;
__u16
_start
,
_end
,
offset
;
...
@@ -216,12 +222,10 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
...
@@ -216,12 +222,10 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
/* Search the first mapping array. */
/* Search the first mapping array. */
if
(
iter
->
start
-
map
->
base_tsn
<
map
->
len
)
{
if
(
iter
->
start
-
map
->
base_tsn
<
map
->
len
)
{
offset
=
iter
->
start
-
map
->
base_tsn
;
offset
=
iter
->
start
-
map
->
base_tsn
;
_sctp_tsnmap_find_gap_ack
(
map
->
tsn_map
,
sctp_tsnmap_find_gap_ack
(
map
->
tsn_map
,
offset
,
map
->
len
,
0
,
offset
,
&
started
,
&
_start
,
&
ended
,
&
_end
);
map
->
len
,
0
,
&
started
,
&
_start
,
&
ended
,
&
_end
);
}
}
/* Do we need to check the overflow map? */
/* Do we need to check the overflow map? */
...
@@ -235,12 +239,12 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
...
@@ -235,12 +239,12 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
offset
=
iter
->
start
-
map
->
base_tsn
-
map
->
len
;
offset
=
iter
->
start
-
map
->
base_tsn
-
map
->
len
;
/* Search the overflow map. */
/* Search the overflow map. */
_
sctp_tsnmap_find_gap_ack
(
map
->
overflow_map
,
sctp_tsnmap_find_gap_ack
(
map
->
overflow_map
,
offset
,
offset
,
map
->
len
,
map
->
len
,
map
->
len
,
map
->
len
,
&
started
,
&
_start
,
&
started
,
&
_start
,
&
ended
,
&
_end
);
&
ended
,
&
_end
);
}
}
/* The Gap Ack Block happens to end at the end of the
/* The Gap Ack Block happens to end at the end of the
...
@@ -278,7 +282,7 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
...
@@ -278,7 +282,7 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
/* This private helper function updates the tsnmap buffers and
/* This private helper function updates the tsnmap buffers and
* the Cumulative TSN Ack Point.
* the Cumulative TSN Ack Point.
*/
*/
static
void
_sctp_tsnmap_update
(
sctp_tsnmap_t
*
map
)
static
void
sctp_tsnmap_update
(
struct
sctp_tsnmap
*
map
)
{
{
__u32
ctsn
;
__u32
ctsn
;
...
@@ -301,10 +305,10 @@ static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
...
@@ -301,10 +305,10 @@ static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
}
while
(
map
->
tsn_map
[
ctsn
-
map
->
base_tsn
]);
}
while
(
map
->
tsn_map
[
ctsn
-
map
->
base_tsn
]);
map
->
cumulative_tsn_ack_point
=
ctsn
-
1
;
/* Back up one. */
map
->
cumulative_tsn_ack_point
=
ctsn
-
1
;
/* Back up one. */
_
sctp_tsnmap_update_pending_data
(
map
);
sctp_tsnmap_update_pending_data
(
map
);
}
}
static
void
_sctp_tsnmap_update_pending_data
(
sctp_tsnmap_t
*
map
)
static
void
sctp_tsnmap_update_pending_data
(
struct
sctp_tsnmap
*
map
)
{
{
__u32
cum_tsn
=
map
->
cumulative_tsn_ack_point
;
__u32
cum_tsn
=
map
->
cumulative_tsn_ack_point
;
__u32
max_tsn
=
map
->
max_tsn_seen
;
__u32
max_tsn
=
map
->
max_tsn_seen
;
...
@@ -324,7 +328,7 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
...
@@ -324,7 +328,7 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
for
(
i
=
start
;
i
<
end
;
i
++
)
{
for
(
i
=
start
;
i
<
end
;
i
++
)
{
if
(
map
->
tsn_map
[
i
])
if
(
map
->
tsn_map
[
i
])
pending_data
--
;
pending_data
--
;
}
}
if
(
gap
>=
map
->
len
)
{
if
(
gap
>=
map
->
len
)
{
start
=
0
;
start
=
0
;
...
@@ -345,14 +349,14 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
...
@@ -345,14 +349,14 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
* The flags "started" and "ended" tell is if we found the beginning
* The flags "started" and "ended" tell is if we found the beginning
* or (respectively) the end of a Gap Ack Block.
* or (respectively) the end of a Gap Ack Block.
*/
*/
static
void
_
sctp_tsnmap_find_gap_ack
(
__u8
*
map
,
__u16
off
,
static
void
sctp_tsnmap_find_gap_ack
(
__u8
*
map
,
__u16
off
,
__u16
len
,
__u16
base
,
__u16
len
,
__u16
base
,
int
*
started
,
__u16
*
start
,
int
*
started
,
__u16
*
start
,
int
*
ended
,
__u16
*
end
)
int
*
ended
,
__u16
*
end
)
{
{
int
i
=
off
;
int
i
=
off
;
/* L
et's l
ook through the entire array, but break out
/* Look through the entire array, but break out
* early if we have found the end of the Gap Ack Block.
* early if we have found the end of the Gap Ack Block.
*/
*/
...
...
net/sctp/ulpevent.c
View file @
9967b51f
...
@@ -5,37 +5,37 @@
...
@@ -5,37 +5,37 @@
* 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 functions manipulate an sctp event. The s
ctp_ulpevent_
t is used
* These functions manipulate an sctp event. The s
truct ulpeven
t is used
* to carry notifications and data to the ULP (sockets).
* to carry notifications and data to the ULP (sockets).
* 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 the
* Please send any bug reports or fixes you make to the
* email address(es):
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
*
* Or submit a bug report through the following website:
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
* http://www.sf.net/projects/lksctp
*
*
* Written or modified by:
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
* 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.
*/
*/
...
@@ -47,58 +47,51 @@
...
@@ -47,58 +47,51 @@
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
s
ctp_association_t
*
asoc
);
s
truct
sctp_association
*
asoc
);
static
void
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
const
sctp_association_t
*
asoc
);
const
struct
sctp_association
*
asoc
);
/* Create a new sctp_ulpevent. */
/* Create a new sctp_ulpevent. */
s
ctp_ulpevent_
t
*
sctp_ulpevent_new
(
int
size
,
int
msg_flags
,
int
priority
)
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_new
(
int
size
,
int
msg_flags
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
skb
=
alloc_skb
(
size
,
priority
);
skb
=
alloc_skb
(
size
,
priority
);
if
(
!
skb
)
if
(
!
skb
)
goto
fail
;
goto
fail
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
msg_flags
);
event
=
sctp_ulpevent_init
(
event
,
msg_flags
);
if
(
!
event
)
if
(
!
event
)
goto
fail_init
;
goto
fail_init
;
event
->
malloced
=
1
;
return
event
;
return
event
;
fail_init:
fail_init:
kfree_skb
(
event
->
parent
);
kfree_skb
(
skb
);
fail:
fail:
return
NULL
;
return
NULL
;
}
}
/* Initialize an ULP event from an given skb. */
/* Initialize an ULP event from an given skb. */
sctp_ulpevent_t
*
sctp_ulpevent_init
(
sctp_ulpevent_t
*
event
,
struct
sctp_ulpevent
*
sctp_ulpevent_init
(
struct
sctp_ulpevent
*
event
,
struct
sk_buff
*
parent
,
int
msg_flags
)
int
msg_flags
)
{
{
memset
(
event
,
sizeof
(
s
ctp_ulpevent_
t
),
0x00
);
memset
(
event
,
sizeof
(
s
truct
sctp_ulpeven
t
),
0x00
);
event
->
msg_flags
=
msg_flags
;
event
->
msg_flags
=
msg_flags
;
event
->
parent
=
parent
;
event
->
malloced
=
0
;
return
event
;
return
event
;
}
}
/* Dispose of an event. */
/* Dispose of an event. */
void
sctp_ulpevent_free
(
s
ctp_ulpevent_
t
*
event
)
void
sctp_ulpevent_free
(
s
truct
sctp_ulpeven
t
*
event
)
{
{
if
(
event
->
malloced
)
kfree_skb
(
sctp_event2skb
(
event
));
kfree_skb
(
event
->
parent
);
}
}
/* Is this a MSG_NOTIFICATION? */
/* Is this a MSG_NOTIFICATION? */
int
sctp_ulpevent_is_notification
(
const
s
ctp_ulpevent_
t
*
event
)
int
sctp_ulpevent_is_notification
(
const
s
truct
sctp_ulpeven
t
*
event
)
{
{
return
event
->
msg_flags
&
MSG_NOTIFICATION
;
return
MSG_NOTIFICATION
==
(
event
->
msg_flags
&
MSG_NOTIFICATION
)
;
}
}
/* Create and initialize an SCTP_ASSOC_CHANGE event.
/* Create and initialize an SCTP_ASSOC_CHANGE event.
...
@@ -112,24 +105,22 @@ int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event)
...
@@ -112,24 +105,22 @@ int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event)
* Note: There is no field checking here. If a field is unused it will be
* Note: There is no field checking here. If a field is unused it will be
* zero'd out.
* zero'd out.
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_assoc_change
(
const
sctp_association_t
*
asoc
,
struct
sctp_ulpevent
*
sctp_ulpevent_make_assoc_change
(
__u16
flags
,
const
sctp_association_t
*
asoc
,
__u16
state
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
error
,
__u16
inbound
,
int
priority
)
__u16
outbound
,
__u16
inbound
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_assoc_change
*
sac
;
struct
sctp_assoc_change
*
sac
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
skb
=
sctp_event2skb
(
event
);
sac
=
(
struct
sctp_assoc_change
*
)
sac
=
(
struct
sctp_assoc_change
*
)
skb_put
(
event
->
parent
,
sizeof
(
struct
sctp_assoc_change
));
skb_put
(
skb
,
sizeof
(
struct
sctp_assoc_change
));
/* Socket Extensions for SCTP
/* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE
* 5.3.1.1 SCTP_ASSOC_CHANGE
...
@@ -198,13 +189,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
...
@@ -198,13 +189,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
sac
->
sac_assoc_id
=
sctp_assoc2id
(
asoc
);
sac
->
sac_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
fail:
fail:
return
NULL
;
return
NULL
;
}
}
/* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
/* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
...
@@ -215,24 +206,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
...
@@ -215,24 +206,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* When a destination address on a multi-homed peer encounters a change
* When a destination address on a multi-homed peer encounters a change
* an interface details event is sent.
* an interface details event is sent.
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_peer_addr_change
(
struct
sctp_ulpevent
*
sctp_ulpevent_make_peer_addr_change
(
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
)
int
flags
,
int
state
,
int
error
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_paddr_change
*
spc
;
struct
sctp_paddr_change
*
spc
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_paddr_change
),
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_paddr_change
),
MSG_NOTIFICATION
,
priority
);
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
skb
=
sctp_event2skb
(
event
);
spc
=
(
struct
sctp_paddr_change
*
)
spc
=
(
struct
sctp_paddr_change
*
)
skb_put
(
event
->
parent
,
sizeof
(
struct
sctp_paddr_change
));
skb_put
(
skb
,
sizeof
(
struct
sctp_paddr_change
));
/* Sockets API Extensions for SCTP
/* Sockets API Extensions for SCTP
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
...
@@ -265,7 +254,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
...
@@ -265,7 +254,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
*
*
* spc_state: 32 bits (signed integer)
* spc_state: 32 bits (signed integer)
*
*
* This field holds one of a number of values that communicate the
* This field holds one of a number of values that communicate the
* event that happened to the address.
* event that happened to the address.
*/
*/
...
@@ -291,7 +280,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
...
@@ -291,7 +280,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
spc
->
spc_assoc_id
=
sctp_assoc2id
(
asoc
);
spc
->
spc_assoc_id
=
sctp_assoc2id
(
asoc
);
/* Sockets API Extensions for SCTP
/* Sockets API Extensions for SCTP
...
@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
...
@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* specification [SCTP] and any extensions for a list of possible
* specification [SCTP] and any extensions for a list of possible
* error formats.
* error formats.
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_remote_error
(
const
sctp_association_t
*
asoc
,
struct
sctp_ulpevent
*
sctp_ulpevent_make_remote_error
(
sctp_chunk_t
*
chunk
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
__u16
flags
,
int
priority
)
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_remote_error
*
sre
;
struct
sctp_remote_error
*
sre
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
sctp_errhdr_t
*
ch
;
sctp_errhdr_t
*
ch
;
...
@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
...
@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
goto
fail
;
goto
fail
;
/* Embed the event fields inside the cloned skb. */
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
MSG_NOTIFICATION
);
event
=
sctp_ulpevent_init
(
event
,
MSG_NOTIFICATION
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
event
->
malloced
=
1
;
sre
=
(
struct
sctp_remote_error
*
)
sre
=
(
struct
sctp_remote_error
*
)
skb_push
(
skb
,
sizeof
(
struct
sctp_remote_error
));
skb_push
(
skb
,
sizeof
(
struct
sctp_remote_error
));
...
@@ -416,7 +403,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
...
@@ -416,7 +403,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
skb
=
sctp_event2skb
(
event
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
sre
->
sre_assoc_id
=
sctp_assoc2id
(
asoc
);
sre
->
sre_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
...
@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
...
@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01
* Socket Extensions for SCTP - draft-01
* 5.3.1.4 SCTP_SEND_FAILED
* 5.3.1.4 SCTP_SEND_FAILED
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_send_failed
(
const
sctp_association_t
*
asoc
,
struct
sctp_ulpevent
*
sctp_ulpevent_make_send_failed
(
sctp_chunk_t
*
chunk
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
__u16
flags
,
__u32
error
,
int
priority
)
__u32
error
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_send_failed
*
ssf
;
struct
sctp_send_failed
*
ssf
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
...
@@ -452,16 +438,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
...
@@ -452,16 +438,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
skb_pull
(
skb
,
sizeof
(
sctp_data_chunk_t
));
skb_pull
(
skb
,
sizeof
(
sctp_data_chunk_t
));
/* Embed the event fields inside the cloned skb. */
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
MSG_NOTIFICATION
);
event
=
sctp_ulpevent_init
(
event
,
MSG_NOTIFICATION
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
/* Mark as malloced, even though the constructor was not
* called.
*/
event
->
malloced
=
1
;
ssf
=
(
struct
sctp_send_failed
*
)
ssf
=
(
struct
sctp_send_failed
*
)
skb_push
(
skb
,
sizeof
(
struct
sctp_send_failed
));
skb_push
(
skb
,
sizeof
(
struct
sctp_send_failed
));
...
@@ -525,7 +506,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
...
@@ -525,7 +506,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* same association identifier. For TCP style socket, this field is
* same association identifier. For TCP style socket, this field is
* ignored.
* ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
skb
=
sctp_event2skb
(
event
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
ssf
->
ssf_assoc_id
=
sctp_assoc2id
(
asoc
);
ssf
->
ssf_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
...
@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
...
@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01
* Socket Extensions for SCTP - draft-01
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
*/
*/
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_shutdown_event
(
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_shutdown_event
(
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
__u16
flags
,
__u16
flags
,
int
priority
)
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_shutdown_event
*
sse
;
struct
sctp_shutdown_event
*
sse
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
skb
=
sctp_event2skb
(
event
);
sse
=
(
struct
sctp_shutdown_event
*
)
sse
=
(
struct
sctp_shutdown_event
*
)
skb_put
(
event
->
parent
,
sizeof
(
struct
sctp_shutdown_event
));
skb_put
(
skb
,
sizeof
(
struct
sctp_shutdown_event
));
/* Socket Extensions for SCTP
/* Socket Extensions for SCTP
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
...
@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
...
@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
sse
->
sse_assoc_id
=
sctp_assoc2id
(
asoc
);
sse
->
sse_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
...
@@ -600,13 +583,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
...
@@ -600,13 +583,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* to pass it to the upper layers. Go ahead and calculate the sndrcvinfo
* to pass it to the upper layers. Go ahead and calculate the sndrcvinfo
* even if filtered out later.
* even if filtered out later.
*
*
* Socket Extensions for SCTP
- draft-01
* Socket Extensions for SCTP
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
*/
*/
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_rcvmsg
(
sctp_association_t
*
asoc
,
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_rcvmsg
(
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
int
priority
)
sctp_chunk_t
*
chunk
,
int
priority
)
{
{
s
ctp_ulpevent_t
*
event
,
*
l
event
;
s
truct
sctp_ulpevent
*
event
;
struct
sctp_sndrcvinfo
*
info
;
struct
sctp_sndrcvinfo
*
info
;
struct
sk_buff
*
skb
,
*
list
;
struct
sk_buff
*
skb
,
*
list
;
size_t
padding
,
len
;
size_t
padding
,
len
;
...
@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_ulpevent_set_owner_r
(
skb
,
asoc
);
sctp_ulpevent_set_owner_r
(
skb
,
asoc
);
/* Embed the event fields inside the cloned skb. */
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
/* Initialize event with flags 0. */
/* Initialize event with flags 0. */
event
=
sctp_ulpevent_init
(
event
,
skb
,
0
);
event
=
sctp_ulpevent_init
(
event
,
0
);
if
(
!
event
)
if
(
!
event
)
goto
fail_init
;
goto
fail_init
;
event
->
malloced
=
1
;
/* Note: Not clearing the entire event struct as
* this is just a fragment of the real event. However,
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
* we still need to do rwnd accounting.
*/
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
sctp_ulpevent_set_owner_r
(
list
,
asoc
);
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
;
...
@@ -707,18 +685,26 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -707,18 +685,26 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
* MSG_UNORDERED - This flag is present when the message was sent
* MSG_UNORDERED - This flag is present when the message was sent
* non-ordered.
* non-ordered.
*/
*/
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
{
info
->
sinfo_flags
|=
MSG_UNORDERED
;
info
->
sinfo_flags
|=
MSG_UNORDERED
;
/* FIXME: For reassembly, we need to have the fragmentation bits.
/* sinfo_cumtsn: 32 bit (unsigned integer)
* This really does not belong in the event structure, but
*
* its difficult to fix everything at the same time. Eventually,
* This field will hold the current cumulative TSN as
* we should create and skb based chunk structure. This structure
* known by the underlying SCTP layer. Note this field is
* storage can be converted to an event. --jgrimm
* ignored when sending and only valid for a receive
* operation when sinfo_flags are set to MSG_UNORDERED.
*/
info
->
sinfo_cumtsn
=
sctp_tsnmap_get_ctsn
(
&
asoc
->
peer
.
tsn_map
);
}
/* Note: For reassembly, we need to have the fragmentation bits.
* For now, merge these into the msg_flags, since those bit
* possitions are not used.
*/
*/
event
->
chunk_flags
=
chunk
->
chunk_hdr
->
flags
;
event
->
msg_flags
|
=
chunk
->
chunk_hdr
->
flags
;
/* With
-
04 draft, tsn moves into sndrcvinfo. */
/* With 04 draft, tsn moves into sndrcvinfo. */
info
->
sinfo_tsn
=
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
);
info
->
sinfo_tsn
=
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
);
/* Context is not used on receive. */
/* Context is not used on receive. */
...
@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
return
NULL
;
return
NULL
;
}
}
/* Create a partial delivery related event.
*
* 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
*
* When a reciever is engaged in a partial delivery of a
* message this notification will be used to inidicate
* various events.
*/
struct
sctp_ulpevent
*
sctp_ulpevent_make_pdapi
(
const
sctp_association_t
*
asoc
,
__u32
indication
,
int
priority
)
{
struct
sctp_ulpevent
*
event
;
struct
sctp_rcv_pdapi_event
*
pd
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
goto
fail
;
skb
=
sctp_event2skb
(
event
);
pd
=
(
struct
sctp_rcv_pdapi_event
*
)
skb_put
(
skb
,
sizeof
(
struct
sctp_rcv_pdapi_event
));
/* pdapi_type
* It should be SCTP_PARTIAL_DELIVERY_EVENT
*
* pdapi_flags: 16 bits (unsigned integer)
* Currently unused.
*/
pd
->
pdapi_type
=
SCTP_PARTIAL_DELIVERY_EVENT
;
pd
->
pdapi_flags
=
0
;
/* pdapi_length: 32 bits (unsigned integer)
*
* This field is the total length of the notification data, including
* the notification header. It will generally be sizeof (struct
* sctp_rcv_pdapi_event).
*/
pd
->
pdapi_length
=
sizeof
(
struct
sctp_rcv_pdapi_event
);
/* pdapi_indication: 32 bits (unsigned integer)
*
* This field holds the indication being sent to the application.
*/
pd
->
pdapi_indication
=
indication
;
/* pdapi_assoc_id: sizeof (sctp_assoc_t)
*
* The association id field, holds the identifier for the association.
*/
pd
->
pdapi_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
fail:
return
NULL
;
}
/* Return the notification type, assuming this is a notification
/* Return the notification type, assuming this is a notification
* event.
* event.
*/
*/
__u16
sctp_ulpevent_get_notification_type
(
const
s
ctp_ulpevent_
t
*
event
)
__u16
sctp_ulpevent_get_notification_type
(
const
s
truct
sctp_ulpeven
t
*
event
)
{
{
union
sctp_notification
*
notification
;
union
sctp_notification
*
notification
;
struct
sk_buff
*
skb
;
notification
=
(
union
sctp_notification
*
)
event
->
parent
->
data
;
skb
=
sctp_event2skb
((
struct
sctp_ulpevent
*
)
event
);
notification
=
(
union
sctp_notification
*
)
skb
->
data
;
return
notification
->
h
.
sn_type
;
return
notification
->
h
.
sn_type
;
}
}
/* Copy out the sndrcvinfo into a msghdr. */
/* Copy out the sndrcvinfo into a msghdr. */
void
sctp_ulpevent_read_sndrcvinfo
(
const
s
ctp_ulpevent_
t
*
event
,
void
sctp_ulpevent_read_sndrcvinfo
(
const
s
truct
sctp_ulpeven
t
*
event
,
struct
msghdr
*
msghdr
)
struct
msghdr
*
msghdr
)
{
{
if
(
!
sctp_ulpevent_is_notification
(
event
))
{
if
(
!
sctp_ulpevent_is_notification
(
event
))
{
...
@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
...
@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
static
void
sctp_rcvmsg_rfree
(
struct
sk_buff
*
skb
)
static
void
sctp_rcvmsg_rfree
(
struct
sk_buff
*
skb
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* 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
...
@@ -779,16 +825,17 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
...
@@ -779,16 +825,17 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
* Use the local private area of the skb to track the owning
* Use the local private area of the skb to track the owning
* association.
* association.
*/
*/
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
asoc
=
event
->
asoc
;
asoc
=
event
->
asoc
;
sctp_assoc_rwnd_increase
(
asoc
,
skb_headlen
(
skb
));
sctp_assoc_rwnd_increase
(
asoc
,
skb_headlen
(
skb
));
sctp_association_put
(
asoc
);
sctp_association_put
(
asoc
);
}
}
/* Charge receive window for bytes recieved. */
/* Charge receive window for bytes recieved. */
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
sctp_association_t
*
asoc
)
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
sctp_association_t
*
asoc
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* The current stack structures assume that the rcv buffer is
/* The 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
...
@@ -798,7 +845,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
...
@@ -798,7 +845,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
*/
*/
sctp_association_hold
(
asoc
);
sctp_association_hold
(
asoc
);
skb
->
sk
=
asoc
->
base
.
sk
;
skb
->
sk
=
asoc
->
base
.
sk
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
->
asoc
=
asoc
;
event
->
asoc
=
asoc
;
skb
->
destructor
=
sctp_rcvmsg_rfree
;
skb
->
destructor
=
sctp_rcvmsg_rfree
;
...
@@ -809,26 +856,26 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
...
@@ -809,26 +856,26 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
/* A simple destructor to give up the reference to the association. */
/* A simple destructor to give up the reference to the association. */
static
void
sctp_ulpevent_rfree
(
struct
sk_buff
*
skb
)
static
void
sctp_ulpevent_rfree
(
struct
sk_buff
*
skb
)
{
{
s
ctp_ulpevent_t
*
event
;
s
truct
sctp_ulpevent
*
event
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
sctp_association_put
(
event
->
asoc
);
sctp_association_put
(
event
->
asoc
);
}
}
/* Hold the association in case the msg_name needs read out of
/* Hold the association in case the msg_name needs read out of
* the association.
* the association.
*/
*/
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
const
s
ctp_association_t
*
asoc
)
const
s
truct
sctp_association
*
asoc
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* Cast away the const, as we are just wanting to
/* Cast away the const, as we are just wanting to
* bump the reference count.
* bump the reference count.
*/
*/
sctp_association_hold
((
s
ctp_association_t
*
)
asoc
);
sctp_association_hold
((
s
truct
sctp_association
*
)
asoc
);
skb
->
sk
=
asoc
->
base
.
sk
;
skb
->
sk
=
asoc
->
base
.
sk
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
->
asoc
=
(
s
ctp_association_t
*
)
asoc
;
event
->
asoc
=
(
s
truct
sctp_association
*
)
asoc
;
skb
->
destructor
=
sctp_ulpevent_rfree
;
skb
->
destructor
=
sctp_ulpevent_rfree
;
}
}
net/sctp/ulpqueue.c
View file @
9967b51f
...
@@ -84,6 +84,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
...
@@ -84,6 +84,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
ulpq
->
asoc
=
asoc
;
ulpq
->
asoc
=
asoc
;
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
->
pd_mode
=
0
;
ulpq
->
malloced
=
0
;
ulpq
->
malloced
=
0
;
return
ulpq
;
return
ulpq
;
...
@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
...
@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
sctp_ulpevent
*
event
;
struct
sctp_ulpevent
*
event
;
while
((
skb
=
skb_dequeue
(
&
ulpq
->
lobby
)))
{
while
((
skb
=
__
skb_dequeue
(
&
ulpq
->
lobby
)))
{
event
=
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
sctp_ulpevent_free
(
event
);
sctp_ulpevent_free
(
event
);
}
}
while
((
skb
=
skb_dequeue
(
&
ulpq
->
reasm
)))
{
while
((
skb
=
__
skb_dequeue
(
&
ulpq
->
reasm
)))
{
event
=
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
sctp_ulpevent_free
(
event
);
sctp_ulpevent_free
(
event
);
}
}
}
}
/* Dispose of a ulpqueue. */
/* Dispose of a ulpqueue. */
...
@@ -117,7 +119,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
...
@@ -117,7 +119,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
/* Process an incoming DATA chunk. */
/* Process an incoming DATA chunk. */
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
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
;
...
@@ -125,12 +127,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
...
@@ -125,12 +127,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
hdr
=
(
sctp_data_chunk_t
*
)
chunk
->
chunk_hdr
;
hdr
=
(
sctp_data_chunk_t
*
)
chunk
->
chunk_hdr
;
/* FIXME: Instead of event being the skb clone, we really should
/* Create an event from the incoming chunk. */
* have a new skb based chunk structure that we can convert to
* an event. Temporarily, I'm carrying a few chunk fields in
* the event to allow reassembly. Its too painful to change
* everything at once. --jgrimm
*/
event
=
sctp_ulpevent_make_rcvmsg
(
chunk
->
asoc
,
chunk
,
priority
);
event
=
sctp_ulpevent_make_rcvmsg
(
chunk
->
asoc
,
chunk
,
priority
);
if
(
!
event
)
if
(
!
event
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
...
@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
event
=
sctp_ulpq_reasm
(
ulpq
,
event
);
event
=
sctp_ulpq_reasm
(
ulpq
,
event
);
/* Do ordering if needed. */
/* Do ordering if needed. */
if
(
event
)
{
if
(
(
event
)
&&
(
event
->
msg_flags
&
MSG_EOR
))
{
/* Create a temporary list to collect chunks on. */
/* Create a temporary list to collect chunks on. */
skb_queue_head_init
(
&
temp
);
skb_queue_head_init
(
&
temp
);
skb_queue_tail
(
&
temp
,
event
->
parent
);
__skb_queue_tail
(
&
temp
,
sctp_event2skb
(
event
)
);
event
=
sctp_ulpq_order
(
ulpq
,
event
);
event
=
sctp_ulpq_order
(
ulpq
,
event
);
}
}
...
@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
...
@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
return
0
;
return
0
;
}
}
/* Clear the partial delivery mode for this socket. Note: This
* assumes that no association is currently in partial delivery mode.
*/
int
sctp_clear_pd
(
struct
sock
*
sk
)
{
struct
sctp_opt
*
sp
;
sp
=
sctp_sk
(
sk
);
sp
->
pd_mode
=
0
;
if
(
!
skb_queue_empty
(
&
sp
->
pd_lobby
))
{
struct
list_head
*
list
;
sctp_skb_list_tail
(
&
sp
->
pd_lobby
,
&
sk
->
receive_queue
);
list
=
(
struct
list_head
*
)
&
sctp_sk
(
sk
)
->
pd_lobby
;
INIT_LIST_HEAD
(
list
);
return
1
;
}
return
0
;
}
/* Clear the pd_mode and restart any pending messages waiting for delivery. */
static
int
sctp_ulpq_clear_pd
(
struct
sctp_ulpq
*
ulpq
)
{
ulpq
->
pd_mode
=
0
;
return
sctp_clear_pd
(
ulpq
->
asoc
->
base
.
sk
);
}
/* Add a new event for propogation to the ULP. */
/* Add a new event for propogation to the ULP. */
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
{
{
struct
sock
*
sk
=
ulpq
->
asoc
->
base
.
sk
;
struct
sock
*
sk
=
ulpq
->
asoc
->
base
.
sk
;
struct
sk_buff_head
*
queue
;
int
clear_pd
=
0
;
/* If the socket is just going to throw this away, do not
/* If the socket is just going to throw this away, do not
* even try to deliver it.
* even try to deliver it.
...
@@ -169,29 +196,55 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
...
@@ -169,29 +196,55 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
if
(
!
sctp_ulpevent_is_enabled
(
event
,
&
sctp_sk
(
sk
)
->
subscribe
))
if
(
!
sctp_ulpevent_is_enabled
(
event
,
&
sctp_sk
(
sk
)
->
subscribe
))
goto
out_free
;
goto
out_free
;
/* If we are in partial delivery mode, post to the lobby until
* partial delivery is cleared, unless, of course _this_ is
* the association the cause of the partial delivery.
*/
if
(
!
sctp_sk
(
sk
)
->
pd_mode
)
{
queue
=
&
sk
->
receive_queue
;
}
else
if
(
ulpq
->
pd_mode
)
{
if
(
event
->
msg_flags
&
MSG_NOTIFICATION
)
queue
=
&
sctp_sk
(
sk
)
->
pd_lobby
;
else
{
clear_pd
=
event
->
msg_flags
&
MSG_EOR
;
queue
=
&
sk
->
receive_queue
;
}
}
else
queue
=
&
sctp_sk
(
sk
)
->
pd_lobby
;
/* If we are harvesting multiple skbs they will be
/* If we are harvesting multiple skbs they will be
* collected on a list.
* collected on a list.
*/
*/
if
(
event
->
parent
->
list
)
if
(
sctp_event2skb
(
event
)
->
list
)
sctp_skb_list_tail
(
event
->
parent
->
list
,
&
sk
->
receive_
queue
);
sctp_skb_list_tail
(
sctp_event2skb
(
event
)
->
list
,
queue
);
else
else
skb_queue_tail
(
&
sk
->
receive_queue
,
event
->
parent
);
skb_queue_tail
(
queue
,
sctp_event2skb
(
event
)
);
wake_up_interruptible
(
sk
->
sleep
);
/* Did we just complete partial delivery and need to get
* rolling again? Move pending data to the receive
* queue.
*/
if
(
clear_pd
)
sctp_ulpq_clear_pd
(
ulpq
);
if
(
queue
==
&
sk
->
receive_queue
)
wake_up_interruptible
(
sk
->
sleep
);
return
1
;
return
1
;
out_free:
out_free:
if
(
event
->
parent
->
list
)
if
(
sctp_event2skb
(
event
)
->
list
)
skb_queue_purge
(
event
->
parent
->
list
);
skb_queue_purge
(
sctp_event2skb
(
event
)
->
list
);
else
else
kfree_skb
(
event
->
parent
);
kfree_skb
(
sctp_event2skb
(
event
)
);
return
0
;
return
0
;
}
}
/* 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_ulpq_store_reasm
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_store_reasm
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
struct
sctp_ulpevent
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
...
@@ -202,7 +255,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
...
@@ -202,7 +255,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
/* 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
=
(
struct
sctp_ulpevent
*
)
pos
->
cb
;
cevent
=
sctp_skb2event
(
pos
)
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
if
(
TSN_lt
(
tsn
,
ctsn
))
if
(
TSN_lt
(
tsn
,
ctsn
))
...
@@ -211,9 +264,10 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
...
@@ -211,9 +264,10 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
/* If the queue is empty, we have a different function to call. */
/* If the queue is empty, we have a different function to call. */
if
(
skb_peek
(
&
ulpq
->
reasm
))
if
(
skb_peek
(
&
ulpq
->
reasm
))
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
__skb_insert
(
sctp_event2skb
(
event
),
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
else
else
__skb_queue_tail
(
&
ulpq
->
reasm
,
event
->
parent
);
__skb_queue_tail
(
&
ulpq
->
reasm
,
sctp_event2skb
(
event
)
);
}
}
/* Helper function to return an event corresponding to the reassembled
/* Helper function to return an event corresponding to the reassembled
...
@@ -231,7 +285,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -231,7 +285,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
struct
sk_buff
*
list
=
skb_shinfo
(
f_frag
)
->
frag_list
;
struct
sk_buff
*
list
=
skb_shinfo
(
f_frag
)
->
frag_list
;
/* Store the pointer to the 2nd skb */
/* Store the pointer to the 2nd skb */
pos
=
f_frag
->
next
;
if
(
f_frag
==
l_frag
)
pos
=
NULL
;
else
pos
=
f_frag
->
next
;
/* Get the last skb in the f_frag's frag_list if present. */
/* Get the last skb in the f_frag's frag_list if present. */
for
(
last
=
list
;
list
;
last
=
list
,
list
=
list
->
next
);
for
(
last
=
list
;
list
;
last
=
list
,
list
=
list
->
next
);
...
@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
/* 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
{
while
(
pos
)
{
pnext
=
pos
->
next
;
pnext
=
pos
->
next
;
/* Update the len and data_len fields of the first fragment. */
/* Update the len and data_len fields of the first fragment. */
...
@@ -262,25 +320,27 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -262,25 +320,27 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
pos
->
next
=
pnext
;
pos
->
next
=
pnext
;
pos
=
pnext
;
pos
=
pnext
;
}
while
(
1
)
;
};
event
=
(
sctp_ulpevent_t
*
)
f_frag
->
cb
;
event
=
sctp_skb2event
(
f_frag
);
SCTP_INC_STATS
(
SctpReasmUsrMsgs
);
return
event
;
return
event
;
}
}
/* 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
s
ctp_ulpevent_
t
*
sctp_ulpq_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
static
inline
s
truct
sctp_ulpeven
t
*
sctp_ulpq_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
struct
sk_buff
*
first_frag
=
NULL
;
struct
sk_buff
*
first_frag
=
NULL
;
__u32
ctsn
,
next_tsn
;
__u32
ctsn
,
next_tsn
;
s
ctp_ulpevent_
t
*
retval
=
NULL
;
s
truct
sctp_ulpeven
t
*
retval
=
NULL
;
/* Initialized to 0 just to avoid compiler warning message. Will
/* Initialized to 0 just to avoid compiler warning message.
Will
* never be used with this value. It is referenced only after it
* never be used with this value. It is referenced only after it
* is set when we find the first fragment of a message.
* is set when we find the first fragment of a message.
*/
*/
...
@@ -296,10 +356,10 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
...
@@ -296,10 +356,10 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
* start the next pass when we find another first fragment.
* start the next pass when we find another first fragment.
*/
*/
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
(
sctp_ulpevent_t
*
)
pos
->
cb
;
cevent
=
sctp_skb2event
(
pos
)
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
switch
(
cevent
->
chunk
_flags
&
SCTP_DATA_FRAG_MASK
)
{
switch
(
cevent
->
msg
_flags
&
SCTP_DATA_FRAG_MASK
)
{
case
SCTP_DATA_FIRST_FRAG
:
case
SCTP_DATA_FIRST_FRAG
:
first_frag
=
pos
;
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
next_tsn
=
ctsn
+
1
;
...
@@ -313,7 +373,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
...
@@ -313,7 +373,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
break
;
break
;
case
SCTP_DATA_LAST_FRAG
:
case
SCTP_DATA_LAST_FRAG
:
if
(
(
first_frag
)
&&
(
ctsn
==
next_tsn
))
if
(
first_frag
&&
(
ctsn
==
next_tsn
))
retval
=
sctp_make_reassembled_event
(
retval
=
sctp_make_reassembled_event
(
first_frag
,
pos
);
first_frag
,
pos
);
else
else
...
@@ -324,42 +384,170 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
...
@@ -324,42 +384,170 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
/* We have the reassembled event. There is no need to look
/* We have the reassembled event. There is no need to look
* further.
* further.
*/
*/
if
(
retval
)
if
(
retval
)
{
retval
->
msg_flags
|=
MSG_EOR
;
break
;
break
;
}
}
}
return
retval
;
return
retval
;
}
}
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
/* Retrieve the next set of fragments of a partial message. */
* need reassembling.
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_partial
(
struct
sctp_ulpq
*
ulpq
)
*/
static
inline
sctp_ulpevent_t
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_t
*
event
)
{
{
sctp_ulpevent_t
*
retval
=
NULL
;
struct
sk_buff
*
pos
,
*
tmp
,
*
last_frag
,
*
first_frag
;
struct
sctp_ulpevent
*
cevent
;
__u32
ctsn
,
next_tsn
;
int
is_last
;
struct
sctp_ulpevent
*
retval
;
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for the first
* sequence of fragmented chunks.
*/
if
(
skb_queue_empty
(
&
ulpq
->
reasm
))
return
NULL
;
last_frag
=
first_frag
=
NULL
;
retval
=
NULL
;
next_tsn
=
0
;
is_last
=
0
;
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
switch
(
cevent
->
msg_flags
&
SCTP_DATA_FRAG_MASK
)
{
case
SCTP_DATA_MIDDLE_FRAG
:
if
(
!
first_frag
)
{
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
last_frag
=
pos
;
}
else
if
(
next_tsn
==
ctsn
)
next_tsn
++
;
else
goto
done
;
break
;
case
SCTP_DATA_LAST_FRAG
:
if
(
!
first_frag
)
first_frag
=
pos
;
else
if
(
ctsn
!=
next_tsn
)
goto
done
;
last_frag
=
pos
;
is_last
=
1
;
goto
done
;
default:
return
NULL
;
};
}
/* FIXME: We should be using some new chunk structure here
/* We have the reassembled event. There is no need to look
* instead of carrying chunk fields in the event structure.
* further.
* This is temporary as it is too painful to change everything
* at once.
*/
*/
done:
retval
=
sctp_make_reassembled_event
(
first_frag
,
last_frag
);
if
(
is_last
)
retval
->
msg_flags
|=
MSG_EOR
;
return
retval
;
}
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
* need reassembling.
*/
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
{
struct
sctp_ulpevent
*
retval
=
NULL
;
/* Check if this is part of a fragmented message. */
/* Check if this is part of a fragmented message. */
if
(
SCTP_DATA_NOT_FRAG
==
(
event
->
chunk_flags
&
SCTP_DATA_FRAG_MASK
))
if
(
SCTP_DATA_NOT_FRAG
==
(
event
->
msg_flags
&
SCTP_DATA_FRAG_MASK
))
{
event
->
msg_flags
|=
MSG_EOR
;
return
event
;
return
event
;
}
sctp_ulpq_store_reasm
(
ulpq
,
event
);
sctp_ulpq_store_reasm
(
ulpq
,
event
);
retval
=
sctp_ulpq_retrieve_reassembled
(
ulpq
);
if
(
!
ulpq
->
pd_mode
)
retval
=
sctp_ulpq_retrieve_reassembled
(
ulpq
);
else
{
__u32
ctsn
,
ctsnap
;
/* Do not even bother unless this is the next tsn to
* be delivered.
*/
ctsn
=
event
->
sndrcvinfo
.
sinfo_tsn
;
ctsnap
=
sctp_tsnmap_get_ctsn
(
&
ulpq
->
asoc
->
peer
.
tsn_map
);
if
(
TSN_lte
(
ctsn
,
ctsnap
))
retval
=
sctp_ulpq_retrieve_partial
(
ulpq
);
}
return
retval
;
return
retval
;
}
}
/* Retrieve the first part (sequential fragments) for partial delivery. */
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_first
(
struct
sctp_ulpq
*
ulpq
)
{
struct
sk_buff
*
pos
,
*
tmp
,
*
last_frag
,
*
first_frag
;
struct
sctp_ulpevent
*
cevent
;
__u32
ctsn
,
next_tsn
;
struct
sctp_ulpevent
*
retval
;
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for a sequence of
* fragmented chunks that start a datagram.
*/
if
(
skb_queue_empty
(
&
ulpq
->
reasm
))
return
NULL
;
last_frag
=
first_frag
=
NULL
;
retval
=
NULL
;
next_tsn
=
0
;
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
switch
(
cevent
->
msg_flags
&
SCTP_DATA_FRAG_MASK
)
{
case
SCTP_DATA_FIRST_FRAG
:
if
(
!
first_frag
)
{
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
last_frag
=
pos
;
}
else
goto
done
;
break
;
case
SCTP_DATA_MIDDLE_FRAG
:
if
(
!
first_frag
)
return
NULL
;
if
(
ctsn
==
next_tsn
)
{
next_tsn
++
;
last_frag
=
pos
;
}
else
goto
done
;
break
;
default:
return
NULL
;
};
}
/* We have the reassembled event. There is no need to look
* further.
*/
done:
retval
=
sctp_make_reassembled_event
(
first_frag
,
last_frag
);
return
retval
;
}
/* 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_retrieve_ordered
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_retrieve_ordered
(
struct
sctp_ulpq
*
ulpq
,
s
ctp_ulpevent_
t
*
event
)
s
truct
sctp_ulpeven
t
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
...
@@ -373,7 +561,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
...
@@ -373,7 +561,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* We are holding the chunks by stream, by SSN. */
/* We are holding the chunks by stream, by SSN. */
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
cevent
=
(
s
ctp_ulpevent_
t
*
)
pos
->
cb
;
cevent
=
(
s
truct
sctp_ulpeven
t
*
)
pos
->
cb
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
@@ -390,32 +578,31 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
...
@@ -390,32 +578,31 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* Found it, so mark in the ssnmap. */
/* Found it, so mark in the ssnmap. */
sctp_ssn_next
(
in
,
sid
);
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
(
sctp_event2skb
(
event
)
->
list
,
pos
);
}
}
}
}
/* Helper function to store chunks needing ordering. */
/* Helper function to store chunks needing ordering. */
static
inline
void
sctp_ulpq_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
s
ctp_ulpevent_
t
*
event
)
s
truct
sctp_ulpeven
t
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
__u16
sid
,
csid
;
__u16
sid
,
csid
;
__u16
ssn
,
cssn
;
__u16
ssn
,
cssn
;
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
/* 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.
*/
*/
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
cevent
=
(
s
ctp_ulpevent_
t
*
)
pos
->
cb
;
cevent
=
(
s
truct
sctp_ulpeven
t
*
)
pos
->
cb
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
@@ -427,25 +614,20 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
...
@@ -427,25 +614,20 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
/* If the queue is empty, we have a different function to call. */
/* If the queue is empty, we have a different function to call. */
if
(
skb_peek
(
&
ulpq
->
lobby
))
if
(
skb_peek
(
&
ulpq
->
lobby
))
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
__skb_insert
(
sctp_event2skb
(
event
),
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
else
else
__skb_queue_tail
(
&
ulpq
->
lobby
,
event
->
parent
);
__skb_queue_tail
(
&
ulpq
->
lobby
,
sctp_event2skb
(
event
)
);
}
}
static
inline
s
ctp_ulpevent_
t
*
sctp_ulpq_order
(
struct
sctp_ulpq
*
ulpq
,
static
inline
s
truct
sctp_ulpeven
t
*
sctp_ulpq_order
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_
t
*
event
)
struct
sctp_ulpeven
t
*
event
)
{
{
__u16
sid
,
ssn
;
__u16
sid
,
ssn
;
struct
sctp_stream
*
in
;
struct
sctp_stream
*
in
;
/* FIXME: We should be using some new chunk structure here
* instead of carrying chunk fields in the event structure.
* This is temporary as it is too painful to change everything
* at once.
*/
/* Check if this message needs ordering. */
/* Check if this message needs ordering. */
if
(
SCTP_DATA_UNORDERED
&
event
->
chunk
_flags
)
if
(
SCTP_DATA_UNORDERED
&
event
->
msg
_flags
)
return
event
;
return
event
;
/* Note: The stream ID must be verified before this routine. */
/* Note: The stream ID must be verified before this routine. */
...
@@ -472,3 +654,54 @@ static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq,
...
@@ -472,3 +654,54 @@ static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq,
return
event
;
return
event
;
}
}
/* Partial deliver the first message as there is pressure on rwnd. */
void
sctp_ulpq_partial_delivery
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_chunk
*
chunk
,
int
priority
)
{
struct
sctp_ulpevent
*
event
;
/* Are we already in partial delivery mode? */
if
(
!
sctp_sk
(
ulpq
->
asoc
->
base
.
sk
)
->
pd_mode
)
{
/* Is partial delivery possible? */
event
=
sctp_ulpq_retrieve_first
(
ulpq
);
/* Send event to the ULP. */
if
(
event
)
{
sctp_ulpq_tail_event
(
ulpq
,
event
);
sctp_sk
(
ulpq
->
asoc
->
base
.
sk
)
->
pd_mode
=
1
;
ulpq
->
pd_mode
=
1
;
return
;
}
}
/* Assert: Either already in partial delivery mode or partial
* delivery wasn't possible, so now the only recourse is
* to renege. FIXME: Add renege support starts here.
*/
}
/* Notify the application if an association is aborted and in
* partial delivery mode. Send up any pending received messages.
*/
void
sctp_ulpq_abort_pd
(
struct
sctp_ulpq
*
ulpq
,
int
priority
)
{
struct
sctp_ulpevent
*
ev
=
NULL
;
struct
sock
*
sk
;
if
(
!
ulpq
->
pd_mode
)
return
;
sk
=
ulpq
->
asoc
->
base
.
sk
;
if
(
sctp_ulpevent_type_enabled
(
SCTP_PARTIAL_DELIVERY_EVENT
,
&
sctp_sk
(
sk
)
->
subscribe
))
ev
=
sctp_ulpevent_make_pdapi
(
ulpq
->
asoc
,
SCTP_PARTIAL_DELIVERY_ABORTED
,
priority
);
if
(
ev
)
skb_queue_tail
(
&
sk
->
receive_queue
,
sctp_event2skb
(
ev
));
/* If there is data waiting, send it up the socket now. */
if
(
sctp_ulpq_clear_pd
(
ulpq
)
||
ev
)
wake_up_interruptible
(
sk
->
sleep
);
}
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