Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
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
Show 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 {
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING
,
/* Set transport's rto_pending. */
SCTP_CMD_CHUNK_PD
,
/* Partial data delivery considerations. */
SCTP_CMD_LAST
}
sctp_verb_t
;
...
...
@@ -115,7 +116,7 @@ typedef union {
struct
sctp_transport
*
transport
;
sctp_bind_addr_t
*
bp
;
sctp_init_chunk_t
*
init
;
s
ctp_ulpevent_
t
*
ulpevent
;
s
truct
sctp_ulpeven
t
*
ulpevent
;
sctp_packet_t
*
packet
;
sctp_sackhdr_t
*
sackh
;
}
sctp_arg_t
;
...
...
@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
BA
,
sctp_bind_addr_t
*
,
bp
)
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
(
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);
#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_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. */
static
inline
int
sctp_is_valid_kaddr
(
unsigned
long
addr
)
...
...
include/net/sctp/structs.h
View file @
9967b51f
...
...
@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-200
2
International Business Machines Corp.
* Copyright (c) 2001-200
3
International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -105,27 +105,25 @@ union sctp_addr {
/* Forward declarations for data structures. */
struct
sctp_protocol
;
struct
SCTP
_endpoint
;
struct
SCTP
_association
;
struct
sctp
_endpoint
;
struct
sctp
_association
;
struct
sctp_transport
;
struct
SCTP
_packet
;
struct
SCTP
_chunk
;
struct
SCTP_inqueue
;
struct
sctp
_packet
;
struct
sctp
_chunk
;
struct
sctp_inq
;
struct
sctp_outq
;
struct
SCTP
_bind_addr
;
struct
sctp
_bind_addr
;
struct
sctp_ulpq
;
struct
sctp_opt
;
struct
sctp_endpoint_common
;
struct
sctp_ssnmap
;
typedef
struct
sctp_protocol
sctp_protocol_t
;
typedef
struct
SCTP_endpoint
sctp_endpoint_t
;
typedef
struct
SCTP_association
sctp_association_t
;
typedef
struct
SCTP_packet
sctp_packet_t
;
typedef
struct
SCTP_chunk
sctp_chunk_t
;
typedef
struct
SCTP_inqueue
sctp_inqueue_t
;
typedef
struct
SCTP_bind_addr
sctp_bind_addr_t
;
typedef
struct
sctp_opt
sctp_opt_t
;
typedef
struct
sctp_endpoint
sctp_endpoint_t
;
typedef
struct
sctp_association
sctp_association_t
;
typedef
struct
sctp_packet
sctp_packet_t
;
typedef
struct
sctp_chunk
sctp_chunk_t
;
typedef
struct
sctp_bind_addr
sctp_bind_addr_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
#include <net/sctp/tsnmap.h>
...
...
@@ -250,10 +248,10 @@ struct sctp_af {
int
optname
,
char
*
optval
,
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
*
saddr
);
void
(
*
get_saddr
)
(
s
ctp_association_t
*
asoc
,
void
(
*
get_saddr
)
(
s
truct
sctp_association
*
asoc
,
struct
dst_entry
*
dst
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
...
...
@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */
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
*
);
int
(
*
af_supported
)
(
sa_family_t
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
...
...
@@ -311,6 +309,9 @@ struct sctp_opt {
/* What kind of a socket is this? */
sctp_socket_type_t
type
;
/* PF_ family specific functions. */
struct
sctp_pf
*
pf
;
/* What is our base endpointer? */
sctp_endpoint_t
*
ep
;
...
...
@@ -324,7 +325,10 @@ struct sctp_opt {
__u32
autoclose
;
__u8
nodelay
;
__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)
* As a matter of convenience, we remember the SCTP common header for
* 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
* three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions.
...
...
@@ -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
* transmission.
*/
struct
SCTP
_packet
{
struct
sctp
_packet
{
/* These are the SCTP header values (host order) for the packet. */
__u16
source_port
;
__u16
destination_port
;
...
...
@@ -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
* SCTP. We write packets to it and read chunks from it.
*/
struct
SCTP_inqueue
{
/* This is actually a queue of sctp_chunk
_t
each
struct
sctp_inq
{
/* This is actually a queue of sctp_chunk each
* containing a partially decoded packet.
*/
struct
sk_buff_head
in
;
...
...
@@ -864,13 +868,12 @@ struct SCTP_inqueue {
int
malloced
;
/* Is this structure kfree()able? */
};
sctp_inqueue_t
*
sctp_inqueue_new
(
void
);
void
sctp_inqueue_init
(
sctp_inqueue_t
*
);
void
sctp_inqueue_free
(
sctp_inqueue_t
*
);
void
sctp_push_inqueue
(
sctp_inqueue_t
*
,
sctp_chunk_t
*
packet
);
sctp_chunk_t
*
sctp_pop_inqueue
(
sctp_inqueue_t
*
);
void
sctp_inqueue_set_th_handler
(
sctp_inqueue_t
*
,
void
(
*
)(
void
*
),
void
*
);
struct
sctp_inq
*
sctp_inq_new
(
void
);
void
sctp_inq_init
(
struct
sctp_inq
*
);
void
sctp_inq_free
(
struct
sctp_inq
*
);
void
sctp_inq_push
(
struct
sctp_inq
*
,
sctp_chunk_t
*
packet
);
struct
sctp_chunk
*
sctp_inq_pop
(
struct
sctp_inq
*
);
void
sctp_inq_set_th_handler
(
struct
sctp_inq
*
,
void
(
*
)(
void
*
),
void
*
);
/* This is the structure we use to hold outbound chunks. You push
* 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);
/* 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
*
...
...
@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
struct
sock
*
sk
;
/* 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
* endpoint:
...
...
@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
* off one of these.
*/
struct
SCTP
_endpoint
{
struct
sctp
_endpoint
{
/* Common substructure for endpoint and association. */
sctp_endpoint_common_t
base
;
...
...
@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
/* Here we have information about each individual association. */
struct
SCTP
_association
{
struct
sctp
_association
{
/* A base structure common to endpoint and association.
* In this context, it represents the associations's view
...
...
@@ -1288,19 +1291,11 @@ struct SCTP_association {
* used in the bulk of the text. This value is hidden
* 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
)];
/* 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? */
uint8_t
sack_needed
;
__u8
sack_needed
;
/* These are capabilities which our peer advertised. */
__u8
ecn_capable
;
/* Can peer do ECN? */
__u8
ipv4_address
;
/* Peer understands IPv4 addresses? */
...
...
@@ -1457,7 +1452,10 @@ struct SCTP_association {
struct
{
__u16
stream
;
__u16
flags
;
__u32
ppid
;
__u32
context
;
__u32
timetolive
;
}
defaults
;
/* This tracks outbound ssn for a given stream. */
...
...
@@ -1615,6 +1613,7 @@ void sctp_association_put(sctp_association_t *);
void
sctp_association_hold
(
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
*
,
const
union
sctp_addr
*
);
struct
sctp_transport
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
...
...
include/net/sctp/tsnmap.h
View file @
9967b51f
...
...
@@ -38,8 +38,6 @@
#ifndef __sctp_tsnmap_h__
#define __sctp_tsnmap_h__
/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB)
* Mapping An array of bits or bytes indicating which out of
* Array order TSN's have been received (relative to the
...
...
@@ -48,9 +46,7 @@
* will be set to all zero. This structure may be
* 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.
* It points at one of the two buffers with which we will
* ping-pong between.
...
...
@@ -93,25 +89,30 @@ typedef struct sctp_tsnmap {
/* This is the highest TSN we've marked. */
__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
;
/* 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
;
__u8
raw_map
[
0
];
}
sctp_tsnmap_t
;
};
typedef
struct
sctp_tsnmap_iter
{
struct
sctp_tsnmap_iter
{
__u32
start
;
}
sctp_tsnmap_iter_t
;
};
/* Create a new tsnmap. */
sctp_tsnmap_t
*
sctp_tsnmap_new
(
__u16
len
,
__u32
initial_tsn
,
int
priority
);
struct
sctp_tsnmap
*
sctp_tsnmap_new
(
__u16
len
,
__u32
init_tsn
,
int
priority
);
/* 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
* internal buffers. We double allocate so the overflow map works.
...
...
@@ -119,9 +120,8 @@ void sctp_tsnmap_free(sctp_tsnmap_t *map);
#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
/* 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.
* Returns:
...
...
@@ -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 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. */
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. */
__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. */
__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? */
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. */
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
* gap ack blocks.
*/
int
sctp_tsnmap_next_gap_ack
(
const
sctp_tsnmap_t
*
map
,
sctp_tsnmap_iter_t
*
iter
,
__u16
*
start
,
__u16
*
end
);
int
sctp_tsnmap_next_gap_ack
(
const
struct
sctp_tsnmap
*
,
struct
sctp_tsnmap_iter
*
,
__u16
*
start
,
__u16
*
end
);
#endif
/* __sctp_tsnmap_h__ */
...
...
include/net/sctp/ulpevent.h
View file @
9967b51f
...
...
@@ -46,26 +46,31 @@
/* Warning: This sits inside an skb.cb[] area. Be very careful of
* growing this structure as it is at the maximum limit now.
*/
typedef
struct
sctp_ulpevent
{
int
malloced
;
sctp_association_t
*
asoc
;
struct
sk_buff
*
parent
;
struct
sctp_ulpevent
{
struct
sctp_association
*
asoc
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
int
chunk_flags
;
/* Temp. until we get a new chunk_t */
int
msg_flags
;
}
sctp_ulpevent_t
;
};
/* 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
);
}
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
);
/* 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
;
}
int
sctp_ulpevent_is_notification
(
const
sctp_ulpevent_t
*
event
);
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
*
);
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_assoc_change
(
const
struct
SCTP
_association
*
asoc
,
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_assoc_change
(
const
struct
sctp
_association
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
...
...
@@ -73,58 +78,65 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(
__u16
inbound
,
int
priority
);
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_peer_addr_change
(
const
struct
SCTP
_association
*
asoc
,
s
truct
sctp_ulpeven
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
);
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_remote_error
(
const
struct
SCTP
_association
*
asoc
,
struct
SCTP
_chunk
*
chunk
,
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_remote_error
(
const
struct
sctp
_association
*
asoc
,
struct
sctp
_chunk
*
chunk
,
__u16
flags
,
int
priority
);
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_send_failed
(
const
struct
SCTP
_association
*
asoc
,
struct
SCTP
_chunk
*
chunk
,
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_send_failed
(
const
struct
sctp
_association
*
asoc
,
struct
sctp
_chunk
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
);
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_shutdown_event
(
const
struct
SCTP
_association
*
asoc
,
s
truct
sctp_ulpeven
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
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_pdapi
(
const
struct
sctp_association
*
asoc
,
__u32
indication
,
int
priority
);
__u16
sctp_ulpevent_get_notification_type
(
const
sctp_ulpevent_t
*
event
);
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? */
static
inline
int
sctp_ulpevent_is_enabled
(
const
s
ctp_ulpevent_
t
*
event
,
const
struct
sctp_event_subscribe
*
mask
)
static
inline
int
sctp_ulpevent_is_enabled
(
const
s
truct
sctp_ulpeven
t
*
event
,
struct
sctp_event_subscribe
*
mask
)
{
const
char
*
amask
=
(
const
char
*
)
mask
;
__u16
sn_type
;
int
enabled
=
1
;
if
(
sctp_ulpevent_is_notification
(
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
;
}
#endif
/* __sctp_ulpevent_h__ */
...
...
include/net/sctp/ulpqueue.h
View file @
9967b51f
...
...
@@ -48,7 +48,8 @@
/* A structure to carry information to the ULP (e.g. Sockets API) */
struct
sctp_ulpq
{
int
malloced
;
char
malloced
;
char
pd_mode
;
sctp_association_t
*
asoc
;
struct
sk_buff_head
reasm
;
struct
sk_buff_head
lobby
;
...
...
@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void
sctp_ulpq_free
(
struct
sctp_ulpq
*
);
/* Add a new DATA chunk for processing. */
int
sctp_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. */
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
ev
);
/* Is the ulpqueue empty. */
int
sctp_ulpqueue_is_empty
(
struct
sctp_ulpq
*
);
/* Perform partial delivery. */
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__ */
...
...
include/net/sctp/user.h
View file @
9967b51f
...
...
@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
__u32
sinfo_context
;
__u32
sinfo_timetolive
;
__u32
sinfo_tsn
;
__u32
sinfo_cumtsn
;
sctp_assoc_t
sinfo_assoc_id
;
};
...
...
@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
sctp_assoc_t
pdapi_assoc_id
;
};
enum
{
SCTP_PARTIAL_DELIVERY_ABORTED
=
0
,
};
/*
* Described in Section 7.3
...
...
@@ -414,8 +416,8 @@ enum sctp_sn_type {
SCTP_SN_TYPE_BASE
=
(
1
<<
15
),
SCTP_ASSOC_CHANGE
,
SCTP_PEER_ADDR_CHANGE
,
SCTP_REMOTE_ERROR
,
SCTP_SEND_FAILED
,
SCTP_REMOTE_ERROR
,
SCTP_SHUTDOWN_EVENT
,
SCTP_PARTIAL_DELIVERY_EVENT
,
SCTP_ADAPTION_INDICATION
,
...
...
net/sctp/Makefile
View file @
9967b51f
...
...
@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
inqueue.o outqueue.o ulpqueue.o command.o
\
tsnmap.o bind_addr.o socket.o primitive.o
\
output.o input.o hashdriver.o sla1.o
\
debug.o ssnmap.o
debug.o ssnmap.o
proc.o
ifeq
($(CONFIG_SCTP_ADLER32), y)
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,
sctp_scope_t
scope
,
int
priority
)
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
int
i
;
/* Retrieve the SCTP per socket area. */
...
...
@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
->
peer
.
sack_needed
=
1
;
/* Create an input queue. */
sctp_inq
ueue
_init
(
&
asoc
->
base
.
inqueue
);
sctp_inq
ueue
_set_th_handler
(
&
asoc
->
base
.
inqueue
,
sctp_inq_init
(
&
asoc
->
base
.
inqueue
);
sctp_inq_set_th_handler
(
&
asoc
->
base
.
inqueue
,
(
void
(
*
)(
void
*
))
sctp_assoc_bh_rcv
,
asoc
);
...
...
@@ -260,7 +260,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
/* Set up the tsn tracking. */
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
);
...
...
@@ -311,7 +310,7 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_ulpq_free
(
&
asoc
->
ulpq
);
/* Dispose of any pending chunks on the inqueue. */
sctp_inq
ueue
_free
(
&
asoc
->
base
.
inqueue
);
sctp_inq_free
(
&
asoc
->
base
.
inqueue
);
/* Free ssnmap storage. */
sctp_ssnmap_free
(
asoc
->
ssnmap
);
...
...
@@ -368,7 +367,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
int
priority
)
{
struct
sctp_transport
*
peer
;
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
unsigned
short
port
;
/* AF_INET and AF_INET6 share common port field. */
...
...
@@ -505,7 +504,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
struct
sctp_transport
*
t
=
NULL
;
struct
sctp_transport
*
first
;
struct
sctp_transport
*
second
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
list_head
*
pos
;
int
spc_state
=
0
;
...
...
@@ -776,7 +775,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sctp_endpoint_t
*
ep
;
sctp_chunk_t
*
chunk
;
struct
sock
*
sk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
int
state
,
subtype
;
sctp_assoc_t
associd
=
sctp_assoc2id
(
asoc
);
int
error
=
0
;
...
...
@@ -786,7 +785,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sk
=
asoc
->
base
.
sk
;
inqueue
=
&
asoc
->
base
.
inqueue
;
while
(
NULL
!=
(
chunk
=
sctp_
pop_inqueue
(
inqueue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_
inq_pop
(
inqueue
)))
{
state
=
asoc
->
state
;
subtype
=
chunk
->
chunk_hdr
->
type
;
...
...
@@ -795,6 +794,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
*/
if
(
sctp_chunk_is_data
(
chunk
))
asoc
->
peer
.
last_data_from
=
chunk
->
transport
;
else
SCTP_INC_STATS
(
SctpInCtrlChunks
);
if
(
chunk
->
transport
)
chunk
->
transport
->
last_time_heard
=
jiffies
;
...
...
@@ -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. */
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
* associations.
...
...
@@ -848,7 +849,6 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
/* Copy in new parameters of peer. */
asoc
->
c
=
new
->
c
;
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
.
i
=
new
->
peer
.
i
;
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)
}
/*
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
* through the inactive transports as this is the next best thing
* 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
list_head
*
head
=
&
asoc
->
peer
.
transport_addr_list
;
struct
list_head
*
pos
;
/* If this is the first time SHUTDOWN is sent, use the active
* 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
;
/* Find the next transport in a round-robin fashion. */
t
=
asoc
->
peer
.
retran_path
;
pos
=
&
t
->
transports
;
next
=
NULL
;
...
...
@@ -935,13 +928,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *
* other active transports. If so, use the next
* transport.
*/
if
(
t
==
asoc
->
shutdown_last_sent_to
)
{
if
(
t
==
asoc
->
peer
.
retran_path
)
{
t
=
next
;
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
...
...
@@ -990,9 +1000,9 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
asoc
->
rwnd
+=
len
;
}
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd increased by %d to (%u, %u)
- %u
\n
"
,
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
,
asoc
->
a_rwnd
);
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd increased by %d to (%u, %u)
"
"- %u
\n
"
,
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
,
asoc
->
a_rwnd
);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
...
...
@@ -1014,7 +1024,6 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
...
...
net/sctp/endpointola.c
View file @
9967b51f
...
...
@@ -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
,
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
));
/* Initialize the base structure. */
...
...
@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep
->
base
.
malloced
=
1
;
/* Create an input queue. */
sctp_inq
ueue
_init
(
&
ep
->
base
.
inqueue
);
sctp_inq_init
(
&
ep
->
base
.
inqueue
);
/* 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
,
ep
);
...
...
@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
sctp_unhash_endpoint
(
ep
);
/* Cleanup the inqueue. */
sctp_inq
ueue
_free
(
&
ep
->
base
.
inqueue
);
sctp_inq_free
(
&
ep
->
base
.
inqueue
);
sctp_bind_addr_free
(
&
ep
->
base
.
bind_addr
);
...
...
@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
struct
sock
*
sk
;
struct
sctp_transport
*
transport
;
sctp_chunk_t
*
chunk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
sctp_subtype_t
subtype
;
sctp_state_t
state
;
int
error
=
0
;
...
...
@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
inqueue
=
&
ep
->
base
.
inqueue
;
sk
=
ep
->
base
.
sk
;
while
(
NULL
!=
(
chunk
=
sctp_
pop_inqueue
(
inqueue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_
inq_pop
(
inqueue
)))
{
subtype
.
chunk
=
chunk
->
chunk_hdr
->
type
;
/* We might have grown an association since last we
...
...
@@ -369,6 +369,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
*/
if
(
asoc
&&
sctp_chunk_is_data
(
chunk
))
asoc
->
peer
.
last_data_from
=
chunk
->
transport
;
else
SCTP_INC_STATS
(
SctpInCtrlChunks
);
if
(
chunk
->
transport
)
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)
if
(
val
!=
cmp
)
{
/* CRC failure, dump it. */
SCTP_INC_STATS_BH
(
SctpChecksumErrors
);
return
-
1
;
}
return
0
;
...
...
@@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb)
if
(
skb
->
pkt_type
!=
PACKET_HOST
)
goto
discard_it
;
SCTP_INC_STATS_BH
(
SctpInSCTPPacks
);
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
/* Pull up the IP and SCTP headers. */
...
...
@@ -160,9 +163,11 @@ int sctp_rcv(struct sk_buff *skb)
*/
if
(
!
asoc
)
{
ep
=
__sctp_rcv_lookup_endpoint
(
&
dest
);
if
(
sctp_rcv_ootb
(
skb
))
if
(
sctp_rcv_ootb
(
skb
))
{
SCTP_INC_STATS_BH
(
SctpOutOfBlues
);
goto
discard_release
;
}
}
/* Retrieve the common input handling substructure. */
rcvr
=
asoc
?
&
asoc
->
base
:
&
ep
->
base
;
...
...
@@ -248,7 +253,7 @@ int sctp_rcv(struct sk_buff *skb)
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
sctp_chunk_t
*
chunk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
/* One day chunk will live inside the skb, but for
* now this works.
...
...
@@ -256,7 +261,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
chunk
=
(
sctp_chunk_t
*
)
skb
;
inqueue
=
&
chunk
->
rcvr
->
inqueue
;
sctp_
push_inqueue
(
inqueue
,
chunk
);
sctp_
inq_push
(
inqueue
,
chunk
);
return
0
;
}
...
...
net/sctp/inqueue.c
View file @
9967b51f
...
...
@@ -47,8 +47,8 @@
#include <net/sctp/sm.h>
#include <linux/interrupt.h>
/* Initialize an SCTP
_
inqueue. */
void
sctp_inq
ueue_init
(
sctp_inqueue_t
*
queue
)
/* Initialize an SCTP
inqueue. */
void
sctp_inq
_init
(
struct
sctp_inq
*
queue
)
{
skb_queue_head_init
(
&
queue
->
in
);
queue
->
in_progress
=
NULL
;
...
...
@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
queue
->
malloced
=
0
;
}
/* Create an initialized
SCTP_inqueue
. */
s
ctp_inqueue_t
*
sctp_inqueue
_new
(
void
)
/* Create an initialized
sctp_inq
. */
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
)
{
sctp_inq
ueue
_init
(
retval
);
sctp_inq_init
(
retval
);
retval
->
malloced
=
1
;
}
return
retval
;
}
/* 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
;
...
...
@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
/* Put a new packet in an SCTP inqueue.
* 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. */
...
...
@@ -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
* 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_chunkhdr_t
*
ch
=
NULL
;
...
...
@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
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
,
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
)),
ntohs
(
chunk
->
chunk_hdr
->
length
),
chunk
->
skb
->
len
);
...
...
@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
/* Set a top-half handler.
*
* 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.
* The intent is that this routine will pull stuff out of the
* 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
)
{
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,
__FUNCTION__
,
skb
,
skb
->
len
,
NIP6
(
fl
.
fl6_src
),
NIP6
(
fl
.
fl6_dst
));
SCTP_INC_STATS
(
SctpOutSCTPPacks
);
return
ip6_xmit
(
sk
,
skb
,
&
fl
,
np
->
opt
);
}
...
...
@@ -444,7 +446,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
}
/* 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
)
{
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
...
...
net/sctp/output.c
View file @
9967b51f
...
...
@@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst
=
transport
->
dst
;
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if
(
!
dst
||
(
dst
->
obsolete
>
1
))
{
dst_release
(
dst
);
sctp_transport_route
(
transport
,
NULL
,
sctp_sk
(
sk
));
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)
:
"Illegal 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
;
break
;
};
}
else
}
else
{
skb_queue_tail
(
&
q
->
control
,
(
struct
sk_buff
*
)
chunk
);
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
}
if
(
error
<
0
)
return
error
;
...
...
@@ -315,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
switch
(
reason
)
{
case
SCTP_RETRANSMIT_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
;
case
SCTP_RETRANSMIT_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;
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. */
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. */
__init
void
sctp_proc_init
(
void
)
__init
int
sctp_proc_init
(
void
)
{
int
rc
=
0
;
if
(
!
proc_net_sctp
)
{
struct
proc_dir_entry
*
ent
;
ent
=
proc_mkdir
(
"net/sctp"
,
0
);
if
(
ent
)
{
ent
->
owner
=
THIS_MODULE
;
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. */
void
sctp_proc_exit
(
void
)
{
sctp_snmp_proc_exit
();
if
(
proc_net_sctp
)
{
proc_net_sctp
=
NULL
;
remove_proc_entry
(
"net/sctp"
,
0
);
...
...
@@ -124,7 +138,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Add the address to the local list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
if
(
addr
)
{
INIT_LIST_HEAD
(
&
addr
->
list
);
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_port
=
0
;
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,
if
(
AF_INET
==
laddr
->
a
.
sa
.
sa_family
)
{
fl
.
fl4_src
=
laddr
->
a
.
v4
.
sin_addr
.
s_addr
;
dst
=
sctp_v4_get_dst
(
asoc
,
daddr
,
&
laddr
->
a
);
if
(
!
ip_route_output_key
(
&
rt
,
&
fl
))
{
dst
=
&
rt
->
u
.
dst
;
goto
out_unlock
;
...
...
@@ -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. */
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
)
{
struct
sockaddr_in
*
sin
,
*
sinfrom
;
...
...
@@ -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_dst
));
SCTP_INC_STATS
(
SctpOutSCTPPacks
);
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,
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
(
ecap_param
),
&
ecap_param
);
nodata:
if
(
addrs
.
v
)
kfree
(
addrs
.
v
);
...
...
@@ -245,7 +243,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
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
)
goto
nomem_rawaddr
;
...
...
@@ -586,14 +585,12 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
sctp_gap_ack_block_t
gab
;
int
length
;
__u32
ctsn
;
sctp_tsnmap_iter_t
iter
;
__u16
num_gabs
;
__u16
num_dup_tsns
=
asoc
->
peer
.
next_dup_tsn
;
const
sctp_tsnmap_t
*
map
=
&
asoc
->
peer
.
tsn_map
;
struct
sctp_tsnmap_iter
iter
;
__u16
num_gabs
,
num_dup_tsns
;
struct
sctp_tsnmap
*
map
=
(
struct
sctp_tsnmap
*
)
&
asoc
->
peer
.
tsn_map
;
ctsn
=
sctp_tsnmap_get_ctsn
(
map
);
SCTP_DEBUG_PRINTK
(
"make_sack: sackCTSNAck sent is 0x%x.
\n
"
,
ctsn
);
SCTP_DEBUG_PRINTK
(
"sackCTSNAck sent is 0x%x.
\n
"
,
ctsn
);
/* Count the number of Gap Ack Blocks. */
sctp_tsnmap_iter_init
(
map
,
&
iter
);
...
...
@@ -603,6 +600,8 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Do nothing. */
}
num_dup_tsns
=
sctp_tsnmap_num_dups
(
map
);
/* Initialize the SACK header. */
sack
.
cum_tsn_ack
=
htonl
(
ctsn
);
sack
.
a_rwnd
=
htonl
(
asoc
->
rwnd
);
...
...
@@ -611,7 +610,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
length
=
sizeof
(
sack
)
+
sizeof
(
sctp_gap_ack_block_t
)
*
num_gabs
+
sizeof
(
sctp_dup_tsn_t
)
*
num_dup_tsns
;
+
sizeof
(
__u32
)
*
num_dup_tsns
;
/* Create the chunk. */
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)
while
(
sctp_tsnmap_next_gap_ack
(
map
,
&
iter
,
&
gab
.
start
,
&
gab
.
end
))
{
gab
.
start
=
htons
(
gab
.
start
);
gab
.
end
=
htons
(
gab
.
end
);
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_gap_ack_block_t
),
&
gab
);
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_gap_ack_block_t
),
&
gab
);
}
/* Register the duplicates. */
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_dup_tsn_t
)
*
num_dup_tsns
,
&
asoc
->
peer
.
dup_tsns
);
sctp_addto_chunk
(
retval
,
sizeof
(
__u32
)
*
num_dup_tsns
,
sctp_tsnmap_get_dups
(
map
));
nodata:
return
retval
;
}
/*
FIXME: Comments
. */
/*
Make a SHUTDOWN chunk
. */
sctp_chunk_t
*
sctp_make_shutdown
(
const
sctp_association_t
*
asoc
)
{
sctp_chunk_t
*
retval
;
...
...
@@ -689,7 +685,6 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
retval
->
subh
.
shutdown_hdr
=
sctp_addto_chunk
(
retval
,
sizeof
(
shut
),
&
shut
);
nodata:
return
retval
;
}
...
...
@@ -1180,6 +1175,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
over
=
msg_len
%
max
;
offset
=
0
;
if
(
whole
&&
over
)
SCTP_INC_STATS_USER
(
SctpFragUsrMsgs
);
/* Create chunks for all the full sized DATA chunks. */
for
(
i
=
0
,
len
=
first_len
;
i
<
whole
;
i
++
)
{
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,
break
;
case
SCTP_CMD_REPORT_DUP
:
if
(
asoc
->
peer
.
next_dup_tsn
<
SCTP_MAX_DUP_TSNS
)
{
asoc
->
peer
.
dup_tsns
[
asoc
->
peer
.
next_dup_tsn
++
]
=
ntohl
(
command
->
obj
.
u32
);
}
sctp_tsnmap_mark_dup
(
&
asoc
->
peer
.
tsn_map
,
ntohl
(
command
->
obj
.
u32
));
break
;
case
SCTP_CMD_REPORT_BIGGAP
:
...
...
@@ -598,6 +596,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
t
->
rto_pending
=
1
;
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:
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
command
->
verb
,
command
->
obj
.
ptr
);
...
...
@@ -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
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
...
...
@@ -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
,
sctp_association_t
*
asoc
)
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
...
...
@@ -1041,7 +1045,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_subtype_t
subtype
,
sctp_chunk_t
*
chunk
)
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
__u16
error
=
0
;
switch
(
event_type
)
{
...
...
@@ -1061,12 +1065,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
break
;
}
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_COMM_LOST
,
error
,
0
,
0
,
GFP_ATOMIC
);
/* Cancel any partial delivery in progress. */
sctp_ulpq_abort_pd
(
&
asoc
->
ulpq
,
GFP_ATOMIC
);
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_COMM_LOST
,
error
,
0
,
0
,
GFP_ATOMIC
);
if
(
event
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
SCTP_ULPEVENT
(
event
));
...
...
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,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* RFC 2960 6.10 Bundling
*
...
...
@@ -146,6 +146,9 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpShutdowns
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
...
...
@@ -223,6 +226,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
return
SCTP_DISPOSITION_CONSUME
;
}
else
{
return
SCTP_DISPOSITION_NOMEM
;
...
...
@@ -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_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpAborteds
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
}
...
...
@@ -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
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
chunk
,
&
err_chunk
))
{
SCTP_INC_STATS
(
SctpAborteds
);
/* This chunk contains fatal error. It is to be discarded.
* 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,
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
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,
sctp_association_t
*
new_asoc
;
sctp_init_chunk_t
*
peer_init
;
sctp_chunk_t
*
repl
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
int
error
=
0
;
sctp_chunk_t
*
err_chk_p
;
...
...
@@ -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_STATE
,
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
());
if
(
new_asoc
->
autoclose
)
...
...
@@ -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
,
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
*
...
...
@@ -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_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
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
());
if
(
asoc
->
autoclose
)
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,
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
}
...
...
@@ -929,6 +944,8 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
goto
out
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
pkt
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
/* Discard the rest of the inbound packet. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
...
...
@@ -1125,6 +1142,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
retval
=
SCTP_DISPOSITION_CONSUME
;
}
else
{
retval
=
SCTP_DISPOSITION_NOMEM
;
...
...
@@ -1355,7 +1373,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
)
{
sctp_init_chunk_t
*
peer_init
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
sctp_chunk_t
*
repl
;
/* 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,
sctp_association_t
*
new_asoc
)
{
sctp_init_chunk_t
*
peer_init
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
sctp_chunk_t
*
repl
;
/* 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,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_UPDATE_ASSOC
,
SCTP_ASOC
(
new_asoc
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_ESTABLISHED
));
SCTP_INC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
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,
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
new_asoc
)
{
s
ctp_ulpevent_
t
*
ev
=
NULL
;
s
truct
sctp_ulpeven
t
*
ev
=
NULL
;
sctp_chunk_t
*
repl
;
/* Clarification from Implementor's Guide:
...
...
@@ -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_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_ESTABLISHED
));
SCTP_INC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_START
,
SCTP_NULL
());
...
...
@@ -1925,6 +1945,8 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
/* ASSOC_FAILED will DELETE_TCB. */
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... */
return
SCTP_DISPOSITION_ABORT
;
...
...
@@ -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_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpAborteds
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
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,
sctp_datahdr_t
*
data_hdr
;
sctp_chunk_t
*
err
;
size_t
datalen
;
sctp_verb_t
deliver
;
int
tmp
;
__u32
tsn
;
...
...
@@ -2307,11 +2331,33 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
datalen
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
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
))
{
SCTP_DEBUG_PRINTK
(
"Discarding tsn: %u datalen: %Zd, "
"rwnd: %d
\n
"
,
tsn
,
datalen
,
asoc
->
rwnd
);
/* 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
;
}
}
/*
* Section 3.3.10.9 No User Data (9)
...
...
@@ -2332,14 +2378,23 @@ 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_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_CONSUME
;
}
/* We are accepting this DATA chunk. */
/* Record the fact that we have received this TSN. */
/* 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
));
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
*
* If an endpoint receive a DATA chunk with an invalid stream
...
...
@@ -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
,
&
data_hdr
->
stream
,
sizeof
(
data_hdr
->
stream
));
if
(
err
)
{
if
(
err
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
err
));
}
goto
discard_noforce
;
}
...
...
@@ -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
* 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
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_RESTART
,
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,
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
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
;
}
...
...
@@ -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. */
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
*
* 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,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
return
SCTP_DISPOSITION_CONSUME
;
}
...
...
@@ -2726,7 +2790,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
while
(
chunk
->
chunk_end
>
chunk
->
skb
->
data
)
{
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,
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
reply
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* 10.2 H) SHUTDOWN COMPLETE notification
*
...
...
@@ -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_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpShutdowns
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
/* ...and remove all record of the association. */
...
...
@@ -2834,6 +2900,8 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
__u8
*
ch_end
;
int
ootb_shut_ack
=
0
;
SCTP_INC_STATS
(
SctpOutOfBlues
);
ch
=
(
sctp_chunkhdr_t
*
)
chunk
->
chunk_hdr
;
do
{
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,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
return
SCTP_DISPOSITION_CONSUME
;
}
...
...
@@ -3472,6 +3542,10 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
/* Delete the established association. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
retval
;
}
...
...
@@ -3527,6 +3601,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpShutdowns
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
...
...
@@ -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_STATE
(
SCTP_STATE_CLOSED
));
SCTP_INC_STATS
(
SctpAborteds
);
/* Even if we can't send the ABORT due to low memory delete the
* 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,
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
}
...
...
@@ -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
)
{
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
}
...
...
@@ -4271,6 +4353,9 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
__u16
num_blocks
;
__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
;
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_sackhdr_t
));
...
...
@@ -4401,6 +4486,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
sctp_packet_append_chunk
(
packet
,
err_chunk
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
}
else
sctp_free_chunk
(
err_chunk
);
}
...
...
net/sctp/socket.c
View file @
9967b51f
...
...
@@ -81,13 +81,13 @@
/* Forward declarations for internal helper functions. */
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
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
);
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
int
sctp_bindx_add
(
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,
/* 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
)
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
struct
sctp_af
*
af
;
...
...
@@ -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
)
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
int
cnt
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
...
...
@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Clean up any skbs sitting on the receive queue. */
skb_queue_purge
(
&
sk
->
receive_queue
);
skb_queue_purge
(
&
sctp_sk
(
sk
)
->
pd_lobby
);
/* This will run the backlog queue. */
sctp_release_sock
(
sk
);
...
...
@@ -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
,
struct
msghdr
*
msg
,
int
msg_len
)
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
struct
sctp_transport
*
transport
;
...
...
@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* ASSERT: we have a valid association at this point. */
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
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
* 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,
err
=
-
EINVAL
;
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
);
...
...
@@ -979,21 +986,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
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. */
skb_queue_head_init
(
&
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,
/* Do accounting for the write space. */
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. */
sctp_primitive_SEND
(
asoc
,
chunk
);
SCTP_DEBUG_PRINTK
(
"We sent primitively.
\n
"
);
...
...
@@ -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
,
int
len
,
int
noblock
,
int
flags
,
int
*
addr_len
)
{
s
ctp_ulpevent_
t
*
event
=
NULL
;
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_ulpeven
t
*
event
=
NULL
;
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
struct
sk_buff
*
skb
;
int
copied
;
int
err
=
0
;
...
...
@@ -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
);
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
if
(
err
)
goto
out_free
;
...
...
@@ -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
* push it back to the receive_queue so that the next call to
* recvmsg() will return the remaining data. Don't set MSG_EOR.
* Otherwise, set MSG_EOR indicating the end of a message.
*/
if
(
skb_len
>
copied
)
{
msg
->
msg_flags
&=
~
MSG_EOR
;
...
...
@@ -1178,6 +1186,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
goto
out_free
;
sctp_skb_pull
(
skb
,
copied
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
/* When only partial message is copied to the user, increase
* rwnd by that amount. If all the data in the skb is read,
* rwnd is updated when the skb's destructor is called via
...
...
@@ -1185,9 +1194,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
*/
sctp_assoc_rwnd_increase
(
event
->
asoc
,
copied
);
goto
out
;
}
else
{
}
else
if
((
event
->
msg_flags
&
MSG_NOTIFICATION
)
||
(
event
->
msg_flags
&
MSG_EOR
))
msg
->
msg_flags
|=
MSG_EOR
;
}
else
msg
->
msg_flags
&=
~
MSG_EOR
;
out_free:
sctp_ulpevent_free
(
event
);
/* Free the skb. */
...
...
@@ -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
,
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 */
if
(
SCTP_SOCKET_TCP
==
sp
->
type
)
...
...
@@ -1310,6 +1321,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
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()
*
* 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,
retval
=
sctp_setsockopt_initmsg
(
sk
,
optval
,
optlen
);
break
;
case
SCTP_SET_DEFAULT_SEND_PARAM
:
retval
=
sctp_setsockopt_set_default_send_param
(
sk
,
optval
,
optlen
);
break
;
default:
retval
=
-
ENOPROTOOPT
;
break
;
...
...
@@ -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
,
int
addr_len
)
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
struct
sctp_transport
*
transport
;
...
...
@@ -1554,7 +1608,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
{
sctp_endpoint_t
*
ep
;
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
);
...
...
@@ -1583,7 +1637,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Initialize default RTO related parameters. These parameters can
* 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_max
=
proto
->
rto_max
;
...
...
@@ -1620,6 +1674,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/
sp
->
autoclose
=
0
;
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
* change the data structure relationships, this may still
* 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
struct
sock
*
newsk
;
struct
socket
*
tmpsock
;
sctp_endpoint_t
*
newep
;
s
ctp_opt_
t
*
oldsp
=
sctp_sk
(
oldsk
);
s
ctp_opt_
t
*
newsp
;
s
truct
sctp_op
t
*
oldsp
=
sctp_sk
(
oldsk
);
s
truct
sctp_op
t
*
newsp
;
struct
sk_buff
*
skb
,
*
tmp
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
int
err
=
0
;
/* 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
* peeled off association to the new socket's receive queue.
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__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
* original socket.
*/
...
...
@@ -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
)
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
/* Only UDP style sockets that are not peeled off are allowed to
...
...
net/sctp/tsnmap.c
View file @
9967b51f
...
...
@@ -45,9 +45,9 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
static
void
_sctp_tsnmap_update
(
sctp_tsnmap_t
*
map
);
static
void
_sctp_tsnmap_update_pending_data
(
sctp_tsnmap_t
*
map
);
static
void
_
sctp_tsnmap_find_gap_ack
(
__u8
*
map
,
__u16
off
,
static
void
sctp_tsnmap_update
(
struct
sctp_tsnmap
*
map
);
static
void
sctp_tsnmap_update_pending_data
(
struct
sctp_tsnmap
*
map
);
static
void
sctp_tsnmap_find_gap_ack
(
__u8
*
map
,
__u16
off
,
__u16
len
,
__u16
base
,
int
*
started
,
__u16
*
start
,
int
*
ended
,
__u16
*
end
);
...
...
@@ -55,11 +55,11 @@ static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
/* Create a new sctp_tsnmap.
* 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
),
priority
);
if
(
!
retval
)
...
...
@@ -72,13 +72,13 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
fail_map:
kfree
(
retval
);
fail:
return
NULL
;
}
/* 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
->
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
map
->
max_tsn_seen
=
map
->
cumulative_tsn_ack_point
;
map
->
malloced
=
0
;
map
->
pending_data
=
0
;
map
->
num_dup_tsns
=
0
;
return
map
;
}
...
...
@@ -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 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
;
int
dup
;
...
...
@@ -136,7 +137,7 @@ int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
}
/* 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
;
...
...
@@ -145,7 +146,7 @@ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
}
/* 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
;
...
...
@@ -173,40 +174,45 @@ void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
/* Go fixup any internal TSN mapping variables including
* 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. */
__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
;
}
/* 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
;
}
/* 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
)
kfree
(
map
);
}
/* 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. */
iter
->
start
=
map
->
cumulative_tsn_ack_point
+
1
;
}
/* Get the next Gap Ack Blocks. Returns 0 if there was not
*
another block
to get.
/* Get the next Gap Ack Blocks. Returns 0 if there was not
another block
* to get.
*/
int
sctp_tsnmap_next_gap_ack
(
const
s
ctp_tsnmap_t
*
map
,
sctp_tsnmap_iter_t
*
iter
,
__u16
*
start
,
__u16
*
end
)
int
sctp_tsnmap_next_gap_ack
(
const
s
truct
sctp_tsnmap
*
map
,
struct
sctp_tsnmap_iter
*
iter
,
__u16
*
start
,
__u16
*
end
)
{
int
started
,
ended
;
__u16
_start
,
_end
,
offset
;
...
...
@@ -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. */
if
(
iter
->
start
-
map
->
base_tsn
<
map
->
len
)
{
offset
=
iter
->
start
-
map
->
base_tsn
;
_sctp_tsnmap_find_gap_ack
(
map
->
tsn_map
,
offset
,
map
->
len
,
0
,
&
started
,
&
_start
,
&
ended
,
&
_end
);
sctp_tsnmap_find_gap_ack
(
map
->
tsn_map
,
offset
,
map
->
len
,
0
,
&
started
,
&
_start
,
&
ended
,
&
_end
);
}
/* Do we need to check the overflow map? */
...
...
@@ -235,7 +239,7 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
offset
=
iter
->
start
-
map
->
base_tsn
-
map
->
len
;
/* Search the overflow map. */
_
sctp_tsnmap_find_gap_ack
(
map
->
overflow_map
,
sctp_tsnmap_find_gap_ack
(
map
->
overflow_map
,
offset
,
map
->
len
,
map
->
len
,
...
...
@@ -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
* 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
;
...
...
@@ -301,10 +305,10 @@ static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
}
while
(
map
->
tsn_map
[
ctsn
-
map
->
base_tsn
]);
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
max_tsn
=
map
->
max_tsn_seen
;
...
...
@@ -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
* 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
,
int
*
started
,
__u16
*
start
,
int
*
ended
,
__u16
*
end
)
{
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.
*/
...
...
net/sctp/ulpevent.c
View file @
9967b51f
...
...
@@ -6,7 +6,7 @@
* Copyright (c) 2001 Nokia, Inc.
* 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).
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
...
...
@@ -47,58 +47,51 @@
#include <net/sctp/sm.h>
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
s
ctp_association_t
*
asoc
);
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
const
sctp_association_t
*
asoc
);
s
truct
sctp_association
*
asoc
);
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
const
struct
sctp_association
*
asoc
);
/* 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
;
skb
=
alloc_skb
(
size
,
priority
);
if
(
!
skb
)
goto
fail
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
msg_flags
);
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
msg_flags
);
if
(
!
event
)
goto
fail_init
;
event
->
malloced
=
1
;
return
event
;
fail_init:
kfree_skb
(
event
->
parent
);
kfree_skb
(
skb
);
fail:
return
NULL
;
}
/* Initialize an ULP event from an given skb. */
sctp_ulpevent_t
*
sctp_ulpevent_init
(
sctp_ulpevent_t
*
event
,
struct
sk_buff
*
parent
,
struct
sctp_ulpevent
*
sctp_ulpevent_init
(
struct
sctp_ulpevent
*
event
,
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
->
parent
=
parent
;
event
->
malloced
=
0
;
return
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
(
event
->
parent
);
kfree_skb
(
sctp_event2skb
(
event
));
}
/* 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.
...
...
@@ -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
* zero'd out.
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_assoc_change
(
const
sctp_association_t
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
inbound
,
int
priority
)
struct
sctp_ulpevent
*
sctp_ulpevent_make_assoc_change
(
const
sctp_association_t
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
inbound
,
int
priority
)
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_assoc_change
*
sac
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
goto
fail
;
skb
=
sctp_event2skb
(
event
);
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
* 5.3.1.1 SCTP_ASSOC_CHANGE
...
...
@@ -198,7 +189,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* All notifications for a given association have the same association
* 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
);
return
event
;
...
...
@@ -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
* an interface details event is sent.
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_peer_addr_change
(
const
sctp_association_t
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
)
struct
sctp_ulpevent
*
sctp_ulpevent_make_peer_addr_change
(
const
sctp_association_t
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
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
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_paddr_change
),
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
goto
fail
;
skb
=
sctp_event2skb
(
event
);
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
* Section 5.3.1.2 SCTP_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
* 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
);
/* Sockets API Extensions for SCTP
...
...
@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* specification [SCTP] and any extensions for a list of possible
* error formats.
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_remote_error
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
int
priority
)
struct
sctp_ulpevent
*
sctp_ulpevent_make_remote_error
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
int
priority
)
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_remote_error
*
sre
;
struct
sk_buff
*
skb
;
sctp_errhdr_t
*
ch
;
...
...
@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
goto
fail
;
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
MSG_NOTIFICATION
);
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
MSG_NOTIFICATION
);
if
(
!
event
)
goto
fail
;
event
->
malloced
=
1
;
sre
=
(
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,
* All notifications for a given association have the same association
* 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
);
return
event
;
...
...
@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01
* 5.3.1.4 SCTP_SEND_FAILED
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_send_failed
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
)
struct
sctp_ulpevent
*
sctp_ulpevent_make_send_failed
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
)
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_send_failed
*
ssf
;
struct
sk_buff
*
skb
;
...
...
@@ -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
));
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
MSG_NOTIFICATION
);
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
MSG_NOTIFICATION
);
if
(
!
event
)
goto
fail
;
/* Mark as malloced, even though the constructor was not
* called.
*/
event
->
malloced
=
1
;
ssf
=
(
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,
* same association 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
);
ssf
->
ssf_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
...
...
@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01
* 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
,
__u16
flags
,
int
priority
)
__u16
flags
,
int
priority
)
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_shutdown_event
*
sse
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
goto
fail
;
skb
=
sctp_event2skb
(
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
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
...
...
@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* All notifications for a given association have the same association
* 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
);
return
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
* even if filtered out later.
*
* Socket Extensions for SCTP
- draft-01
* Socket Extensions for SCTP
* 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
)
{
s
ctp_ulpevent_t
*
event
,
*
l
event
;
s
truct
sctp_ulpevent
*
event
;
struct
sctp_sndrcvinfo
*
info
;
struct
sk_buff
*
skb
,
*
list
;
size_t
padding
,
len
;
...
...
@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_ulpevent_set_owner_r
(
skb
,
asoc
);
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
/* Initialize event with flags 0. */
event
=
sctp_ulpevent_init
(
event
,
skb
,
0
);
event
=
sctp_ulpevent_init
(
event
,
0
);
if
(
!
event
)
goto
fail_init
;
event
->
malloced
=
1
;
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
/* Note: Not clearing the entire event struct as
* this is just a fragment of the real event. However,
* 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
);
/* 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
;
...
...
@@ -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
* non-ordered.
*/
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
{
info
->
sinfo_flags
|=
MSG_UNORDERED
;
/* FIXME: For reassembly, we need to have the fragmentation bits.
* This really does not belong in the event structure, but
* its difficult to fix everything at the same time. Eventually,
* we should create and skb based chunk structure. This structure
* storage can be converted to an event. --jgrimm
/* sinfo_cumtsn: 32 bit (unsigned integer)
*
* This field will hold the current cumulative TSN as
* known by the underlying SCTP layer. Note this field is
* 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
);
/* Context is not used on receive. */
...
...
@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
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
* 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
;
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
;
}
/* 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
)
{
if
(
!
sctp_ulpevent_is_notification
(
event
))
{
...
...
@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
static
void
sctp_rcvmsg_rfree
(
struct
sk_buff
*
skb
)
{
sctp_association_t
*
asoc
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as
...
...
@@ -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
* association.
*/
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
asoc
=
event
->
asoc
;
sctp_assoc_rwnd_increase
(
asoc
,
skb_headlen
(
skb
));
sctp_association_put
(
asoc
);
}
/* 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
* 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
*/
sctp_association_hold
(
asoc
);
skb
->
sk
=
asoc
->
base
.
sk
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
->
asoc
=
asoc
;
skb
->
destructor
=
sctp_rcvmsg_rfree
;
...
...
@@ -809,9 +856,9 @@ 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. */
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
);
}
...
...
@@ -819,16 +866,16 @@ static void sctp_ulpevent_rfree(struct sk_buff *skb)
* the association.
*/
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
* 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
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
->
asoc
=
(
s
ctp_association_t
*
)
asoc
;
event
=
sctp_skb2event
(
skb
)
;
event
->
asoc
=
(
s
truct
sctp_association
*
)
asoc
;
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,
ulpq
->
asoc
=
asoc
;
skb_queue_head_init
(
&
ulpq
->
reasm
);
skb_queue_head_init
(
&
ulpq
->
lobby
);
ulpq
->
pd_mode
=
0
;
ulpq
->
malloced
=
0
;
return
ulpq
;
...
...
@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
struct
sk_buff
*
skb
;
struct
sctp_ulpevent
*
event
;
while
((
skb
=
skb_dequeue
(
&
ulpq
->
lobby
)))
{
event
=
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
while
((
skb
=
__
skb_dequeue
(
&
ulpq
->
lobby
)))
{
event
=
sctp_skb2event
(
skb
)
;
sctp_ulpevent_free
(
event
);
}
while
((
skb
=
skb_dequeue
(
&
ulpq
->
reasm
)))
{
event
=
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
while
((
skb
=
__
skb_dequeue
(
&
ulpq
->
reasm
)))
{
event
=
sctp_skb2event
(
skb
)
;
sctp_ulpevent_free
(
event
);
}
}
/* Dispose of a ulpqueue. */
...
...
@@ -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
;
/* FIXME: Instead of event being the skb clone, we really should
* 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
*/
/* Create an event from the incoming chunk. */
event
=
sctp_ulpevent_make_rcvmsg
(
chunk
->
asoc
,
chunk
,
priority
);
if
(
!
event
)
return
-
ENOMEM
;
...
...
@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
event
=
sctp_ulpq_reasm
(
ulpq
,
event
);
/* Do ordering if needed. */
if
(
event
)
{
if
(
(
event
)
&&
(
event
->
msg_flags
&
MSG_EOR
))
{
/* Create a temporary list to collect chunks on. */
skb_queue_head_init
(
&
temp
);
skb_queue_tail
(
&
temp
,
event
->
parent
);
__skb_queue_tail
(
&
temp
,
sctp_event2skb
(
event
)
);
event
=
sctp_ulpq_order
(
ulpq
,
event
);
}
...
...
@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
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. */
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
{
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
* even try to deliver it.
...
...
@@ -169,22 +196,48 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
if
(
!
sctp_ulpevent_is_enabled
(
event
,
&
sctp_sk
(
sk
)
->
subscribe
))
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
* collected on a list.
*/
if
(
event
->
parent
->
list
)
sctp_skb_list_tail
(
event
->
parent
->
list
,
&
sk
->
receive_
queue
);
if
(
sctp_event2skb
(
event
)
->
list
)
sctp_skb_list_tail
(
sctp_event2skb
(
event
)
->
list
,
queue
);
else
skb_queue_tail
(
&
sk
->
receive_queue
,
event
->
parent
);
skb_queue_tail
(
queue
,
sctp_event2skb
(
event
));
/* 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
;
out_free:
if
(
event
->
parent
->
list
)
skb_queue_purge
(
event
->
parent
->
list
);
if
(
sctp_event2skb
(
event
)
->
list
)
skb_queue_purge
(
sctp_event2skb
(
event
)
->
list
);
else
kfree_skb
(
event
->
parent
);
kfree_skb
(
sctp_event2skb
(
event
)
);
return
0
;
}
...
...
@@ -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. */
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
(
struct
sctp_ulpevent
*
)
pos
->
cb
;
cevent
=
sctp_skb2event
(
pos
)
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
if
(
TSN_lt
(
tsn
,
ctsn
))
...
...
@@ -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
(
skb_peek
(
&
ulpq
->
reasm
))
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
__skb_insert
(
sctp_event2skb
(
event
),
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
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
...
...
@@ -231,6 +285,9 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
struct
sk_buff
*
list
=
skb_shinfo
(
f_frag
)
->
frag_list
;
/* Store the pointer to the 2nd skb */
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. */
...
...
@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
/* Remove the first fragment from the reassembly queue. */
__skb_unlink
(
f_frag
,
f_frag
->
list
);
do
{
while
(
pos
)
{
pnext
=
pos
->
next
;
/* Update the len and data_len fields of the first fragment. */
...
...
@@ -262,23 +320,25 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
pos
->
next
=
pnext
;
pos
=
pnext
;
}
while
(
1
)
;
};
event
=
(
sctp_ulpevent_t
*
)
f_frag
->
cb
;
event
=
sctp_skb2event
(
f_frag
);
SCTP_INC_STATS
(
SctpReasmUsrMsgs
);
return
event
;
}
/* Helper function to check if an incoming chunk has filled up the last
* missing fragment in a SCTP datagram and return the corresponding event.
*/
static
inline
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
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
struct
sk_buff
*
first_frag
=
NULL
;
__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
* never be used with this value. It is referenced only after it
...
...
@@ -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.
*/
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
(
sctp_ulpevent_t
*
)
pos
->
cb
;
cevent
=
sctp_skb2event
(
pos
)
;
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
:
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
...
...
@@ -313,7 +373,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
break
;
case
SCTP_DATA_LAST_FRAG
:
if
(
(
first_frag
)
&&
(
ctsn
==
next_tsn
))
if
(
first_frag
&&
(
ctsn
==
next_tsn
))
retval
=
sctp_make_reassembled_event
(
first_frag
,
pos
);
else
...
...
@@ -324,34 +384,162 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
/* We have the reassembled event. There is no need to look
* further.
*/
if
(
retval
)
if
(
retval
)
{
retval
->
msg_flags
|=
MSG_EOR
;
break
;
}
}
return
retval
;
}
/* Retrieve the next set of fragments of a partial message. */
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_partial
(
struct
sctp_ulpq
*
ulpq
)
{
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
;
};
}
/* We have the reassembled event. There is no need to look
* further.
*/
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
s
ctp_ulpevent_
t
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
s
ctp_ulpevent_
t
*
event
)
static
inline
s
truct
sctp_ulpeven
t
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
s
truct
sctp_ulpeven
t
*
event
)
{
sctp_ulpevent_t
*
retval
=
NULL
;
/* 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.
*/
struct
sctp_ulpevent
*
retval
=
NULL
;
/* 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
;
}
sctp_ulpq_store_reasm
(
ulpq
,
event
);
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
;
}
/* 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
;
}
...
...
@@ -359,7 +547,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
* ordered by an an incoming chunk.
*/
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
sctp_ulpevent
*
cevent
;
...
...
@@ -373,7 +561,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* We are holding the chunks by stream, by SSN. */
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
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
...
@@ -394,28 +582,27 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
__skb_unlink
(
pos
,
pos
->
list
);
/* 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. */
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
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
__u16
sid
,
csid
;
__u16
ssn
,
cssn
;
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
/* Find the right place in this list. We store them by
* stream ID and then by SSN.
*/
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
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
...
@@ -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
(
skb_peek
(
&
ulpq
->
lobby
))
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
__skb_insert
(
sctp_event2skb
(
event
),
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
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
,
sctp_ulpevent_
t
*
event
)
static
inline
s
truct
sctp_ulpeven
t
*
sctp_ulpq_order
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpeven
t
*
event
)
{
__u16
sid
,
ssn
;
struct
sctp_stream
*
in
;
/* FIXME: We should be using some new chunk structure here
* instead of carrying chunk fields in the event structure.
* This is temporary as it is too painful to change everything
* at once.
*/
/* Check if this message needs ordering. */
if
(
SCTP_DATA_UNORDERED
&
event
->
chunk
_flags
)
if
(
SCTP_DATA_UNORDERED
&
event
->
msg
_flags
)
return
event
;
/* 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,
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