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
551c773f
Commit
551c773f
authored
Feb 11, 2003
by
Jon Grimm
Browse files
Options
Browse Files
Download
Plain Diff
Merge touki.austin.ibm.com:/home/jgrimm/bk/lksctp-2.5
into touki.austin.ibm.com:/home/jgrimm/bk/lksctp-2.5.work
parents
a0065b2f
62603506
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
838 additions
and
407 deletions
+838
-407
include/net/sctp/command.h
include/net/sctp/command.h
+3
-2
include/net/sctp/structs.h
include/net/sctp/structs.h
+39
-33
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/associola.c
net/sctp/associola.c
+13
-13
net/sctp/endpointola.c
net/sctp/endpointola.c
+6
-6
net/sctp/input.c
net/sctp/input.c
+2
-2
net/sctp/inqueue.c
net/sctp/inqueue.c
+13
-13
net/sctp/ipv6.c
net/sctp/ipv6.c
+1
-1
net/sctp/protocol.c
net/sctp/protocol.c
+1
-2
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+2
-1
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+14
-8
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+45
-21
net/sctp/socket.c
net/sctp/socket.c
+123
-29
net/sctp/ulpevent.c
net/sctp/ulpevent.c
+176
-129
net/sctp/ulpqueue.c
net/sctp/ulpqueue.c
+299
-67
No files found.
include/net/sctp/command.h
View file @
551c773f
...
...
@@ -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/structs.h
View file @
551c773f
...
...
@@ -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
...
...
@@ -1457,7 +1460,10 @@ struct SCTP_association {
struct
{
__u16
stream
;
__u16
flags
;
__u32
ppid
;
__u32
context
;
__u32
timetolive
;
}
defaults
;
/* This tracks outbound ssn for a given stream. */
...
...
include/net/sctp/ulpevent.h
View file @
551c773f
...
...
@@ -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 @
551c773f
...
...
@@ -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 @
551c773f
...
...
@@ -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/associola.c
View file @
551c773f
...
...
@@ -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
);
...
...
@@ -311,7 +311,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 +368,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 +505,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 +776,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 +786,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
;
...
...
@@ -819,7 +819,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.
...
...
net/sctp/endpointola.c
View file @
551c773f
...
...
@@ -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
...
...
net/sctp/input.c
View file @
551c773f
...
...
@@ -248,7 +248,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 +256,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 @
551c773f
...
...
@@ -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 @
551c773f
...
...
@@ -444,7 +444,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/protocol.c
View file @
551c773f
...
...
@@ -124,7 +124,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
;
...
...
@@ -557,7 +556,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
;
...
...
net/sctp/sm_make_chunk.c
View file @
551c773f
...
...
@@ -245,7 +245,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
;
...
...
net/sctp/sm_sideeffect.c
View file @
551c773f
...
...
@@ -598,6 +598,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
);
...
...
@@ -1014,7 +1021,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 +1048,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 +1068,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 @
551c773f
...
...
@@ -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
*
...
...
@@ -504,7 +504,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
;
...
...
@@ -636,7 +636,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
*
...
...
@@ -1355,7 +1355,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 +1421,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
...
...
@@ -1503,7 +1503,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:
...
...
@@ -2241,6 +2241,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 +2308,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)
...
...
@@ -2335,9 +2358,10 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
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
));
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
...
...
@@ -2352,10 +2376,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 +2386,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
));
...
...
@@ -2726,7 +2750,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 +2788,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
*
...
...
net/sctp/socket.c
View file @
551c773f
...
...
@@ -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
);
...
...
@@ -1110,8 +1117,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 +1150,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 +1177,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 +1184,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 +1192,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 +1234,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 +1319,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 +1448,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 +1484,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 +1606,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 +1635,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 +1672,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 +1831,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 +1868,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 +2483,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/ulpevent.c
View file @
551c773f
...
...
@@ -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 @
551c773f
...
...
@@ -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,24 @@ 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
)
;
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 +355,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 +372,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 +383,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 +546,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 +560,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 +581,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 +613,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 +653,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