Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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
Hide 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 {
...
@@ -86,6 +86,7 @@ typedef enum {
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING
,
/* Set transport's rto_pending. */
SCTP_CMD_RTO_PENDING
,
/* Set transport's rto_pending. */
SCTP_CMD_CHUNK_PD
,
/* Partial data delivery considerations. */
SCTP_CMD_LAST
SCTP_CMD_LAST
}
sctp_verb_t
;
}
sctp_verb_t
;
...
@@ -115,7 +116,7 @@ typedef union {
...
@@ -115,7 +116,7 @@ typedef union {
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_bind_addr_t
*
bp
;
sctp_bind_addr_t
*
bp
;
sctp_init_chunk_t
*
init
;
sctp_init_chunk_t
*
init
;
s
ctp_ulpevent_
t
*
ulpevent
;
s
truct
sctp_ulpeven
t
*
ulpevent
;
sctp_packet_t
*
packet
;
sctp_packet_t
*
packet
;
sctp_sackhdr_t
*
sackh
;
sctp_sackhdr_t
*
sackh
;
}
sctp_arg_t
;
}
sctp_arg_t
;
...
@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
...
@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
BA
,
sctp_bind_addr_t
*
,
bp
)
SCTP_ARG_CONSTRUCTOR
(
BA
,
sctp_bind_addr_t
*
,
bp
)
SCTP_ARG_CONSTRUCTOR
(
PEER_INIT
,
sctp_init_chunk_t
*
,
init
)
SCTP_ARG_CONSTRUCTOR
(
PEER_INIT
,
sctp_init_chunk_t
*
,
init
)
SCTP_ARG_CONSTRUCTOR
(
ULPEVENT
,
s
ctp_ulpevent_
t
*
,
ulpevent
)
SCTP_ARG_CONSTRUCTOR
(
ULPEVENT
,
s
truct
sctp_ulpeven
t
*
,
ulpevent
)
SCTP_ARG_CONSTRUCTOR
(
PACKET
,
sctp_packet_t
*
,
packet
)
SCTP_ARG_CONSTRUCTOR
(
PACKET
,
sctp_packet_t
*
,
packet
)
SCTP_ARG_CONSTRUCTOR
(
SACKH
,
sctp_sackhdr_t
*
,
sackh
)
SCTP_ARG_CONSTRUCTOR
(
SACKH
,
sctp_sackhdr_t
*
,
sackh
)
...
...
include/net/sctp/structs.h
View file @
551c773f
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-200
2
International Business Machines Corp.
* Copyright (c) 2001-200
3
International Business Machines Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
* This file is part of the SCTP kernel reference Implementation
*
*
...
@@ -105,27 +105,25 @@ union sctp_addr {
...
@@ -105,27 +105,25 @@ union sctp_addr {
/* Forward declarations for data structures. */
/* Forward declarations for data structures. */
struct
sctp_protocol
;
struct
sctp_protocol
;
struct
SCTP
_endpoint
;
struct
sctp
_endpoint
;
struct
SCTP
_association
;
struct
sctp
_association
;
struct
sctp_transport
;
struct
sctp_transport
;
struct
SCTP
_packet
;
struct
sctp
_packet
;
struct
SCTP
_chunk
;
struct
sctp
_chunk
;
struct
SCTP_inqueue
;
struct
sctp_inq
;
struct
sctp_outq
;
struct
sctp_outq
;
struct
SCTP
_bind_addr
;
struct
sctp
_bind_addr
;
struct
sctp_ulpq
;
struct
sctp_ulpq
;
struct
sctp_opt
;
struct
sctp_opt
;
struct
sctp_endpoint_common
;
struct
sctp_endpoint_common
;
struct
sctp_ssnmap
;
struct
sctp_ssnmap
;
typedef
struct
sctp_protocol
sctp_protocol_t
;
typedef
struct
sctp_protocol
sctp_protocol_t
;
typedef
struct
SCTP_endpoint
sctp_endpoint_t
;
typedef
struct
sctp_endpoint
sctp_endpoint_t
;
typedef
struct
SCTP_association
sctp_association_t
;
typedef
struct
sctp_association
sctp_association_t
;
typedef
struct
SCTP_packet
sctp_packet_t
;
typedef
struct
sctp_packet
sctp_packet_t
;
typedef
struct
SCTP_chunk
sctp_chunk_t
;
typedef
struct
sctp_chunk
sctp_chunk_t
;
typedef
struct
SCTP_inqueue
sctp_inqueue_t
;
typedef
struct
sctp_bind_addr
sctp_bind_addr_t
;
typedef
struct
SCTP_bind_addr
sctp_bind_addr_t
;
typedef
struct
sctp_opt
sctp_opt_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
#include <net/sctp/tsnmap.h>
#include <net/sctp/tsnmap.h>
...
@@ -250,10 +248,10 @@ struct sctp_af {
...
@@ -250,10 +248,10 @@ struct sctp_af {
int
optname
,
int
optname
,
char
*
optval
,
char
*
optval
,
int
*
optlen
);
int
*
optlen
);
struct
dst_entry
*
(
*
get_dst
)
(
s
ctp_association_t
*
asoc
,
struct
dst_entry
*
(
*
get_dst
)
(
s
truct
sctp_association
*
asoc
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
union
sctp_addr
*
saddr
);
void
(
*
get_saddr
)
(
s
ctp_association_t
*
asoc
,
void
(
*
get_saddr
)
(
s
truct
sctp_association
*
asoc
,
struct
dst_entry
*
dst
,
struct
dst_entry
*
dst
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
);
union
sctp_addr
*
saddr
);
...
@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
...
@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */
/* Protocol family functions. */
struct
sctp_pf
{
struct
sctp_pf
{
void
(
*
event_msgname
)(
s
ctp_ulpevent_
t
*
,
char
*
,
int
*
);
void
(
*
event_msgname
)(
s
truct
sctp_ulpeven
t
*
,
char
*
,
int
*
);
void
(
*
skb_msgname
)
(
struct
sk_buff
*
,
char
*
,
int
*
);
void
(
*
skb_msgname
)
(
struct
sk_buff
*
,
char
*
,
int
*
);
int
(
*
af_supported
)
(
sa_family_t
);
int
(
*
af_supported
)
(
sa_family_t
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
...
@@ -311,6 +309,9 @@ struct sctp_opt {
...
@@ -311,6 +309,9 @@ struct sctp_opt {
/* What kind of a socket is this? */
/* What kind of a socket is this? */
sctp_socket_type_t
type
;
sctp_socket_type_t
type
;
/* PF_ family specific functions. */
struct
sctp_pf
*
pf
;
/* What is our base endpointer? */
/* What is our base endpointer? */
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
...
@@ -324,7 +325,10 @@ struct sctp_opt {
...
@@ -324,7 +325,10 @@ struct sctp_opt {
__u32
autoclose
;
__u32
autoclose
;
__u8
nodelay
;
__u8
nodelay
;
__u8
disable_fragments
;
__u8
disable_fragments
;
struct
sctp_pf
*
pf
;
__u8
pd_mode
;
/* Receive to here while partial delivery is in effect. */
struct
sk_buff_head
pd_lobby
;
};
};
...
@@ -484,7 +488,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
...
@@ -484,7 +488,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
* As a matter of convenience, we remember the SCTP common header for
* As a matter of convenience, we remember the SCTP common header for
* each chunk as well as a few other header pointers...
* each chunk as well as a few other header pointers...
*/
*/
struct
SCTP
_chunk
{
struct
sctp
_chunk
{
/* These first three elements MUST PRECISELY match the first
/* These first three elements MUST PRECISELY match the first
* three elements of struct sk_buff. This allows us to reuse
* three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions.
* all the skb_* queue management functions.
...
@@ -594,7 +598,7 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
...
@@ -594,7 +598,7 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
/* This structure holds lists of chunks as we are assembling for
/* This structure holds lists of chunks as we are assembling for
* transmission.
* transmission.
*/
*/
struct
SCTP
_packet
{
struct
sctp
_packet
{
/* These are the SCTP header values (host order) for the packet. */
/* These are the SCTP header values (host order) for the packet. */
__u16
source_port
;
__u16
source_port
;
__u16
destination_port
;
__u16
destination_port
;
...
@@ -846,8 +850,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *);
...
@@ -846,8 +850,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *);
/* This is the structure we use to queue packets as they come into
/* This is the structure we use to queue packets as they come into
* SCTP. We write packets to it and read chunks from it.
* SCTP. We write packets to it and read chunks from it.
*/
*/
struct
SCTP_inqueue
{
struct
sctp_inq
{
/* This is actually a queue of sctp_chunk
_t
each
/* This is actually a queue of sctp_chunk each
* containing a partially decoded packet.
* containing a partially decoded packet.
*/
*/
struct
sk_buff_head
in
;
struct
sk_buff_head
in
;
...
@@ -864,13 +868,12 @@ struct SCTP_inqueue {
...
@@ -864,13 +868,12 @@ struct SCTP_inqueue {
int
malloced
;
/* Is this structure kfree()able? */
int
malloced
;
/* Is this structure kfree()able? */
};
};
sctp_inqueue_t
*
sctp_inqueue_new
(
void
);
struct
sctp_inq
*
sctp_inq_new
(
void
);
void
sctp_inqueue_init
(
sctp_inqueue_t
*
);
void
sctp_inq_init
(
struct
sctp_inq
*
);
void
sctp_inqueue_free
(
sctp_inqueue_t
*
);
void
sctp_inq_free
(
struct
sctp_inq
*
);
void
sctp_push_inqueue
(
sctp_inqueue_t
*
,
sctp_chunk_t
*
packet
);
void
sctp_inq_push
(
struct
sctp_inq
*
,
sctp_chunk_t
*
packet
);
sctp_chunk_t
*
sctp_pop_inqueue
(
sctp_inqueue_t
*
);
struct
sctp_chunk
*
sctp_inq_pop
(
struct
sctp_inq
*
);
void
sctp_inqueue_set_th_handler
(
sctp_inqueue_t
*
,
void
sctp_inq_set_th_handler
(
struct
sctp_inq
*
,
void
(
*
)(
void
*
),
void
*
);
void
(
*
)(
void
*
),
void
*
);
/* This is the structure we use to hold outbound chunks. You push
/* This is the structure we use to hold outbound chunks. You push
* chunks in and they automatically pop out the other end as bundled
* chunks in and they automatically pop out the other end as bundled
...
@@ -954,7 +957,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
...
@@ -954,7 +957,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
/* These bind address data fields common between endpoints and associations */
/* These bind address data fields common between endpoints and associations */
struct
SCTP
_bind_addr
{
struct
sctp
_bind_addr
{
/* RFC 2960 12.1 Parameters necessary for the SCTP instance
/* RFC 2960 12.1 Parameters necessary for the SCTP instance
*
*
...
@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
...
@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
struct
sock
*
sk
;
struct
sock
*
sk
;
/* This is where we receive inbound chunks. */
/* This is where we receive inbound chunks. */
s
ctp_inqueue_t
inqueue
;
s
truct
sctp_inq
inqueue
;
/* This substructure includes the defining parameters of the
/* This substructure includes the defining parameters of the
* endpoint:
* endpoint:
...
@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
...
@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
* off one of these.
* off one of these.
*/
*/
struct
SCTP
_endpoint
{
struct
sctp
_endpoint
{
/* Common substructure for endpoint and association. */
/* Common substructure for endpoint and association. */
sctp_endpoint_common_t
base
;
sctp_endpoint_common_t
base
;
...
@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
...
@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
/* Here we have information about each individual association. */
/* Here we have information about each individual association. */
struct
SCTP
_association
{
struct
sctp
_association
{
/* A base structure common to endpoint and association.
/* A base structure common to endpoint and association.
* In this context, it represents the associations's view
* In this context, it represents the associations's view
...
@@ -1457,7 +1460,10 @@ struct SCTP_association {
...
@@ -1457,7 +1460,10 @@ struct SCTP_association {
struct
{
struct
{
__u16
stream
;
__u16
stream
;
__u16
flags
;
__u32
ppid
;
__u32
ppid
;
__u32
context
;
__u32
timetolive
;
}
defaults
;
}
defaults
;
/* This tracks outbound ssn for a given stream. */
/* This tracks outbound ssn for a given stream. */
...
...
include/net/sctp/ulpevent.h
View file @
551c773f
...
@@ -6,34 +6,34 @@
...
@@ -6,34 +6,34 @@
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2001 La Monte H.P. Yarroll
*
*
* These are the definitions needed for the sctp_ulpevent type. The
* These are the definitions needed for the sctp_ulpevent type. The
* sctp_ulpevent type is used to carry information from the state machine
* sctp_ulpevent type is used to carry information from the state machine
* upwards to the ULP.
* upwards to the ULP.
*
*
* The SCTP reference implementation is free software;
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
* any later version.
*
*
* the SCTP reference implementation is distributed in the hope that it
* the SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* See the GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Boston, MA 02111-1307, USA.
*
*
* Please send any bug reports or fixes you make to one of the
* Please send any bug reports or fixes you make to one of the
* following email addresses:
* following email addresses:
*
*
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
* La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Karl Knutson <karl@athena.chicago.il.us>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
*/
*/
...
@@ -46,85 +46,97 @@
...
@@ -46,85 +46,97 @@
/* Warning: This sits inside an skb.cb[] area. Be very careful of
/* Warning: This sits inside an skb.cb[] area. Be very careful of
* growing this structure as it is at the maximum limit now.
* growing this structure as it is at the maximum limit now.
*/
*/
typedef
struct
sctp_ulpevent
{
struct
sctp_ulpevent
{
int
malloced
;
struct
sctp_association
*
asoc
;
sctp_association_t
*
asoc
;
struct
sk_buff
*
parent
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
int
chunk_flags
;
/* Temp. until we get a new chunk_t */
int
msg_flags
;
int
msg_flags
;
}
sctp_ulpevent_t
;
};
sctp_ulpevent_t
*
sctp_ulpevent_new
(
int
size
,
int
msg_flags
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_init
(
sctp_ulpevent_t
*
event
,
struct
sk_buff
*
skb
,
int
msg_flags
);
void
sctp_ulpevent_free
(
sctp_ulpevent_t
*
event
);
int
sctp_ulpevent_is_notification
(
const
sctp_ulpevent_t
*
event
);
sctp_ulpevent_t
*
sctp_ulpevent_make_assoc_change
(
const
struct
SCTP_association
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
inbound
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_peer_addr_change
(
const
struct
SCTP_association
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_remote_error
(
const
struct
SCTP_association
*
asoc
,
struct
SCTP_chunk
*
chunk
,
__u16
flags
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_send_failed
(
const
struct
SCTP_association
*
asoc
,
struct
SCTP_chunk
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_shutdown_event
(
const
struct
SCTP_association
*
asoc
,
__u16
flags
,
int
priority
);
sctp_ulpevent_t
*
sctp_ulpevent_make_rcvmsg
(
struct
SCTP_association
*
asoc
,
struct
SCTP_chunk
*
chunk
,
int
priority
);
void
sctp_ulpevent_read_sndrcvinfo
(
const
sctp_ulpevent_t
*
event
,
struct
msghdr
*
msghdr
);
__u16
sctp_ulpevent_get_notification_type
(
const
sctp_ulpevent_t
*
event
);
/* Retrieve the skb this event sits inside of. */
static
inline
struct
sk_buff
*
sctp_event2skb
(
struct
sctp_ulpevent
*
ev
)
{
return
container_of
((
void
*
)
ev
,
struct
sk_buff
,
cb
);
}
/* Retrieve & cast the event sitting inside the skb. */
static
inline
struct
sctp_ulpevent
*
sctp_skb2event
(
struct
sk_buff
*
skb
)
{
return
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
}
struct
sctp_ulpevent
*
sctp_ulpevent_new
(
int
size
,
int
flags
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_init
(
struct
sctp_ulpevent
*
,
int
flags
);
void
sctp_ulpevent_free
(
struct
sctp_ulpevent
*
);
int
sctp_ulpevent_is_notification
(
const
struct
sctp_ulpevent
*
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_assoc_change
(
const
struct
sctp_association
*
asoc
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
inbound
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_peer_addr_change
(
const
struct
sctp_association
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_remote_error
(
const
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
__u16
flags
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_send_failed
(
const
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
__u16
flags
,
__u32
error
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_shutdown_event
(
const
struct
sctp_association
*
asoc
,
__u16
flags
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_pdapi
(
const
struct
sctp_association
*
asoc
,
__u32
indication
,
int
priority
);
struct
sctp_ulpevent
*
sctp_ulpevent_make_rcvmsg
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
int
priority
);
void
sctp_ulpevent_read_sndrcvinfo
(
const
struct
sctp_ulpevent
*
event
,
struct
msghdr
*
);
__u16
sctp_ulpevent_get_notification_type
(
const
struct
sctp_ulpevent
*
event
);
/* Is this event type enabled? */
static
inline
int
sctp_ulpevent_type_enabled
(
__u16
sn_type
,
struct
sctp_event_subscribe
*
mask
)
{
char
*
amask
=
(
char
*
)
mask
;
return
amask
[
sn_type
-
SCTP_SN_TYPE_BASE
];
}
/* Given an event subscription, is this event enabled? */
/* Given an event subscription, is this event enabled? */
static
inline
int
sctp_ulpevent_is_enabled
(
const
s
ctp_ulpevent_
t
*
event
,
static
inline
int
sctp_ulpevent_is_enabled
(
const
s
truct
sctp_ulpeven
t
*
event
,
const
struct
sctp_event_subscribe
*
mask
)
struct
sctp_event_subscribe
*
mask
)
{
{
const
char
*
amask
=
(
const
char
*
)
mask
;
__u16
sn_type
;
__u16
sn_type
;
int
enabled
=
1
;
int
enabled
=
1
;
if
(
sctp_ulpevent_is_notification
(
event
))
{
if
(
sctp_ulpevent_is_notification
(
event
))
{
sn_type
=
sctp_ulpevent_get_notification_type
(
event
);
sn_type
=
sctp_ulpevent_get_notification_type
(
event
);
enabled
=
amask
[
sn_type
-
SCTP_SN_TYPE_BASE
]
;
enabled
=
sctp_ulpevent_type_enabled
(
sn_type
,
mask
)
;
}
}
return
enabled
;
return
enabled
;
}
}
#endif
/* __sctp_ulpevent_h__ */
#endif
/* __sctp_ulpevent_h__ */
...
...
include/net/sctp/ulpqueue.h
View file @
551c773f
...
@@ -48,7 +48,8 @@
...
@@ -48,7 +48,8 @@
/* A structure to carry information to the ULP (e.g. Sockets API) */
/* A structure to carry information to the ULP (e.g. Sockets API) */
struct
sctp_ulpq
{
struct
sctp_ulpq
{
int
malloced
;
char
malloced
;
char
pd_mode
;
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
struct
sk_buff_head
reasm
;
struct
sk_buff_head
reasm
;
struct
sk_buff_head
lobby
;
struct
sk_buff_head
lobby
;
...
@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
...
@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void
sctp_ulpq_free
(
struct
sctp_ulpq
*
);
void
sctp_ulpq_free
(
struct
sctp_ulpq
*
);
/* Add a new DATA chunk for processing. */
/* Add a new DATA chunk for processing. */
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
,
s
ctp_chunk_t
*
chunk
,
int
priority
);
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
,
s
truct
sctp_chunk
*
,
int
);
/* Add a new event for propogation to the ULP. */
/* Add a new event for propogation to the ULP. */
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
ev
);
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
,
struct
sctp_ulpevent
*
ev
);
/* Is the ulpqueue empty. */
/* Perform partial delivery. */
int
sctp_ulpqueue_is_empty
(
struct
sctp_ulpq
*
);
void
sctp_ulpq_partial_delivery
(
struct
sctp_ulpq
*
,
struct
sctp_chunk
*
,
int
);
/* Abort the partial delivery. */
void
sctp_ulpq_abort_pd
(
struct
sctp_ulpq
*
,
int
);
/* Clear the partial data delivery condition on this socket. */
int
sctp_clear_pd
(
struct
sock
*
sk
);
#endif
/* __sctp_ulpqueue_h__ */
#endif
/* __sctp_ulpqueue_h__ */
...
...
include/net/sctp/user.h
View file @
551c773f
...
@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
...
@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
__u32
sinfo_context
;
__u32
sinfo_context
;
__u32
sinfo_timetolive
;
__u32
sinfo_timetolive
;
__u32
sinfo_tsn
;
__u32
sinfo_tsn
;
__u32
sinfo_cumtsn
;
sctp_assoc_t
sinfo_assoc_id
;
sctp_assoc_t
sinfo_assoc_id
;
};
};
...
@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
...
@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
sctp_assoc_t
pdapi_assoc_id
;
sctp_assoc_t
pdapi_assoc_id
;
};
};
enum
{
SCTP_PARTIAL_DELIVERY_ABORTED
=
0
,
};
/*
/*
* Described in Section 7.3
* Described in Section 7.3
...
@@ -414,8 +416,8 @@ enum sctp_sn_type {
...
@@ -414,8 +416,8 @@ enum sctp_sn_type {
SCTP_SN_TYPE_BASE
=
(
1
<<
15
),
SCTP_SN_TYPE_BASE
=
(
1
<<
15
),
SCTP_ASSOC_CHANGE
,
SCTP_ASSOC_CHANGE
,
SCTP_PEER_ADDR_CHANGE
,
SCTP_PEER_ADDR_CHANGE
,
SCTP_REMOTE_ERROR
,
SCTP_SEND_FAILED
,
SCTP_SEND_FAILED
,
SCTP_REMOTE_ERROR
,
SCTP_SHUTDOWN_EVENT
,
SCTP_SHUTDOWN_EVENT
,
SCTP_PARTIAL_DELIVERY_EVENT
,
SCTP_PARTIAL_DELIVERY_EVENT
,
SCTP_ADAPTION_INDICATION
,
SCTP_ADAPTION_INDICATION
,
...
...
net/sctp/associola.c
View file @
551c773f
...
@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
sctp_scope_t
scope
,
sctp_scope_t
scope
,
int
priority
)
int
priority
)
{
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
int
i
;
int
i
;
/* Retrieve the SCTP per socket area. */
/* Retrieve the SCTP per socket area. */
...
@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
->
peer
.
sack_needed
=
1
;
asoc
->
peer
.
sack_needed
=
1
;
/* Create an input queue. */
/* Create an input queue. */
sctp_inq
ueue
_init
(
&
asoc
->
base
.
inqueue
);
sctp_inq_init
(
&
asoc
->
base
.
inqueue
);
sctp_inq
ueue
_set_th_handler
(
&
asoc
->
base
.
inqueue
,
sctp_inq_set_th_handler
(
&
asoc
->
base
.
inqueue
,
(
void
(
*
)(
void
*
))
sctp_assoc_bh_rcv
,
(
void
(
*
)(
void
*
))
sctp_assoc_bh_rcv
,
asoc
);
asoc
);
...
@@ -311,7 +311,7 @@ void sctp_association_free(sctp_association_t *asoc)
...
@@ -311,7 +311,7 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_ulpq_free
(
&
asoc
->
ulpq
);
sctp_ulpq_free
(
&
asoc
->
ulpq
);
/* Dispose of any pending chunks on the inqueue. */
/* Dispose of any pending chunks on the inqueue. */
sctp_inq
ueue
_free
(
&
asoc
->
base
.
inqueue
);
sctp_inq_free
(
&
asoc
->
base
.
inqueue
);
/* Free ssnmap storage. */
/* Free ssnmap storage. */
sctp_ssnmap_free
(
asoc
->
ssnmap
);
sctp_ssnmap_free
(
asoc
->
ssnmap
);
...
@@ -368,7 +368,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -368,7 +368,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
int
priority
)
int
priority
)
{
{
struct
sctp_transport
*
peer
;
struct
sctp_transport
*
peer
;
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
unsigned
short
port
;
unsigned
short
port
;
/* AF_INET and AF_INET6 share common port field. */
/* AF_INET and AF_INET6 share common port field. */
...
@@ -505,7 +505,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
...
@@ -505,7 +505,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
struct
sctp_transport
*
t
=
NULL
;
struct
sctp_transport
*
t
=
NULL
;
struct
sctp_transport
*
first
;
struct
sctp_transport
*
first
;
struct
sctp_transport
*
second
;
struct
sctp_transport
*
second
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
int
spc_state
=
0
;
int
spc_state
=
0
;
...
@@ -776,7 +776,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -776,7 +776,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
struct
sock
*
sk
;
struct
sock
*
sk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
int
state
,
subtype
;
int
state
,
subtype
;
sctp_assoc_t
associd
=
sctp_assoc2id
(
asoc
);
sctp_assoc_t
associd
=
sctp_assoc2id
(
asoc
);
int
error
=
0
;
int
error
=
0
;
...
@@ -786,7 +786,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -786,7 +786,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sk
=
asoc
->
base
.
sk
;
sk
=
asoc
->
base
.
sk
;
inqueue
=
&
asoc
->
base
.
inqueue
;
inqueue
=
&
asoc
->
base
.
inqueue
;
while
(
NULL
!=
(
chunk
=
sctp_
pop_inqueue
(
inqueue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_
inq_pop
(
inqueue
)))
{
state
=
asoc
->
state
;
state
=
asoc
->
state
;
subtype
=
chunk
->
chunk_hdr
->
type
;
subtype
=
chunk
->
chunk_hdr
->
type
;
...
@@ -819,7 +819,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -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. */
/* This routine moves an association from its old sk to a new sk. */
void
sctp_assoc_migrate
(
sctp_association_t
*
assoc
,
struct
sock
*
newsk
)
void
sctp_assoc_migrate
(
sctp_association_t
*
assoc
,
struct
sock
*
newsk
)
{
{
s
ctp_opt_
t
*
newsp
=
sctp_sk
(
newsk
);
s
truct
sctp_op
t
*
newsp
=
sctp_sk
(
newsk
);
/* Delete the association from the old endpoint's list of
/* Delete the association from the old endpoint's list of
* associations.
* associations.
...
@@ -996,7 +996,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -996,7 +996,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
/* Send a window update SACK if the rwnd has increased by at least the
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in
* The algorithm used is similar to the one described in
* Section 4.2.3.3 of RFC 1122.
* Section 4.2.3.3 of RFC 1122.
*/
*/
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
...
@@ -1006,9 +1006,9 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -1006,9 +1006,9 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
"rwnd: %u a_rwnd: %u
\n
"
,
"rwnd: %u a_rwnd: %u
\n
"
,
__FUNCTION__
,
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
__FUNCTION__
,
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
sack
=
sctp_make_sack
(
asoc
);
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
if
(
!
sack
)
return
;
return
;
/* Update the last advertised rwnd value. */
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
a_rwnd
=
asoc
->
rwnd
;
...
@@ -1022,7 +1022,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -1022,7 +1022,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
sctp_association_put
(
asoc
);
}
}
}
}
/* Decrease asoc's rwnd by len. */
/* Decrease asoc's rwnd by len. */
...
...
net/sctp/endpointola.c
View file @
551c773f
...
@@ -92,7 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
...
@@ -92,7 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
ep
,
sctp_protocol_t
*
proto
,
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
ep
,
sctp_protocol_t
*
proto
,
struct
sock
*
sk
,
int
priority
)
struct
sock
*
sk
,
int
priority
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
memset
(
ep
,
0
,
sizeof
(
sctp_endpoint_t
));
memset
(
ep
,
0
,
sizeof
(
sctp_endpoint_t
));
/* Initialize the base structure. */
/* Initialize the base structure. */
...
@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
...
@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep
->
base
.
malloced
=
1
;
ep
->
base
.
malloced
=
1
;
/* Create an input queue. */
/* Create an input queue. */
sctp_inq
ueue
_init
(
&
ep
->
base
.
inqueue
);
sctp_inq_init
(
&
ep
->
base
.
inqueue
);
/* Set its top-half handler */
/* Set its top-half handler */
sctp_inq
ueue
_set_th_handler
(
&
ep
->
base
.
inqueue
,
sctp_inq_set_th_handler
(
&
ep
->
base
.
inqueue
,
(
void
(
*
)(
void
*
))
sctp_endpoint_bh_rcv
,
(
void
(
*
)(
void
*
))
sctp_endpoint_bh_rcv
,
ep
);
ep
);
...
@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
...
@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
sctp_unhash_endpoint
(
ep
);
sctp_unhash_endpoint
(
ep
);
/* Cleanup the inqueue. */
/* Cleanup the inqueue. */
sctp_inq
ueue
_free
(
&
ep
->
base
.
inqueue
);
sctp_inq_free
(
&
ep
->
base
.
inqueue
);
sctp_bind_addr_free
(
&
ep
->
base
.
bind_addr
);
sctp_bind_addr_free
(
&
ep
->
base
.
bind_addr
);
...
@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
struct
sock
*
sk
;
struct
sock
*
sk
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
sctp_subtype_t
subtype
;
sctp_subtype_t
subtype
;
sctp_state_t
state
;
sctp_state_t
state
;
int
error
=
0
;
int
error
=
0
;
...
@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
inqueue
=
&
ep
->
base
.
inqueue
;
inqueue
=
&
ep
->
base
.
inqueue
;
sk
=
ep
->
base
.
sk
;
sk
=
ep
->
base
.
sk
;
while
(
NULL
!=
(
chunk
=
sctp_
pop_inqueue
(
inqueue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_
inq_pop
(
inqueue
)))
{
subtype
.
chunk
=
chunk
->
chunk_hdr
->
type
;
subtype
.
chunk
=
chunk
->
chunk_hdr
->
type
;
/* We might have grown an association since last we
/* We might have grown an association since last we
...
...
net/sctp/input.c
View file @
551c773f
...
@@ -248,7 +248,7 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -248,7 +248,7 @@ int sctp_rcv(struct sk_buff *skb)
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
{
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
s
ctp_inqueue_t
*
inqueue
;
s
truct
sctp_inq
*
inqueue
;
/* One day chunk will live inside the skb, but for
/* One day chunk will live inside the skb, but for
* now this works.
* now this works.
...
@@ -256,7 +256,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
...
@@ -256,7 +256,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
chunk
=
(
sctp_chunk_t
*
)
skb
;
chunk
=
(
sctp_chunk_t
*
)
skb
;
inqueue
=
&
chunk
->
rcvr
->
inqueue
;
inqueue
=
&
chunk
->
rcvr
->
inqueue
;
sctp_
push_inqueue
(
inqueue
,
chunk
);
sctp_
inq_push
(
inqueue
,
chunk
);
return
0
;
return
0
;
}
}
...
...
net/sctp/inqueue.c
View file @
551c773f
...
@@ -47,8 +47,8 @@
...
@@ -47,8 +47,8 @@
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
/* Initialize an SCTP
_
inqueue. */
/* Initialize an SCTP
inqueue. */
void
sctp_inq
ueue_init
(
sctp_inqueue_t
*
queue
)
void
sctp_inq
_init
(
struct
sctp_inq
*
queue
)
{
{
skb_queue_head_init
(
&
queue
->
in
);
skb_queue_head_init
(
&
queue
->
in
);
queue
->
in_progress
=
NULL
;
queue
->
in_progress
=
NULL
;
...
@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
...
@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
queue
->
malloced
=
0
;
queue
->
malloced
=
0
;
}
}
/* Create an initialized
SCTP_inqueue
. */
/* Create an initialized
sctp_inq
. */
s
ctp_inqueue_t
*
sctp_inqueue
_new
(
void
)
s
truct
sctp_inq
*
sctp_inq
_new
(
void
)
{
{
s
ctp_inqueue_t
*
retval
;
s
truct
sctp_inq
*
retval
;
retval
=
t_new
(
s
ctp_inqueue_t
,
GFP_ATOMIC
);
retval
=
t_new
(
s
truct
sctp_inq
,
GFP_ATOMIC
);
if
(
retval
)
{
if
(
retval
)
{
sctp_inq
ueue
_init
(
retval
);
sctp_inq_init
(
retval
);
retval
->
malloced
=
1
;
retval
->
malloced
=
1
;
}
}
return
retval
;
return
retval
;
}
}
/* Release the memory associated with an SCTP inqueue. */
/* Release the memory associated with an SCTP inqueue. */
void
sctp_inq
ueue_free
(
sctp_inqueue_t
*
queue
)
void
sctp_inq
_free
(
struct
sctp_inq
*
queue
)
{
{
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
...
@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
...
@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
/* Put a new packet in an SCTP inqueue.
/* Put a new packet in an SCTP inqueue.
* We assume that packet->sctp_hdr is set and in host byte order.
* We assume that packet->sctp_hdr is set and in host byte order.
*/
*/
void
sctp_
push_inqueue
(
sctp_inqueue_t
*
q
,
sctp_chunk_t
*
packet
)
void
sctp_
inq_push
(
struct
sctp_inq
*
q
,
sctp_chunk_t
*
packet
)
{
{
/* Directly call the packet handling routine. */
/* Directly call the packet handling routine. */
...
@@ -114,7 +114,7 @@ void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
...
@@ -114,7 +114,7 @@ void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
* WARNING: If you need to put the chunk on another queue, you need to
* WARNING: If you need to put the chunk on another queue, you need to
* make a shallow copy (clone) of it.
* make a shallow copy (clone) of it.
*/
*/
sctp_chunk_t
*
sctp_
pop_inqueue
(
sctp_inqueue_t
*
queue
)
sctp_chunk_t
*
sctp_
inq_pop
(
struct
sctp_inq
*
queue
)
{
{
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
sctp_chunkhdr_t
*
ch
=
NULL
;
sctp_chunkhdr_t
*
ch
=
NULL
;
...
@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
...
@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
chunk
->
end_of_packet
=
1
;
chunk
->
end_of_packet
=
1
;
}
}
SCTP_DEBUG_PRINTK
(
"+++sctp_
pop_inqueue
+++ chunk %p[%s],"
SCTP_DEBUG_PRINTK
(
"+++sctp_
inq_pop
+++ chunk %p[%s],"
" length %d, skb->len %d
\n
"
,
chunk
,
" length %d, skb->len %d
\n
"
,
chunk
,
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
)),
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
)),
ntohs
(
chunk
->
chunk_hdr
->
length
),
chunk
->
skb
->
len
);
ntohs
(
chunk
->
chunk_hdr
->
length
),
chunk
->
skb
->
len
);
...
@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
...
@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
/* Set a top-half handler.
/* Set a top-half handler.
*
*
* Originally, we the top-half handler was scheduled as a BH. We now
* Originally, we the top-half handler was scheduled as a BH. We now
* call the handler directly in sctp_
push_inqueue
() at a time that
* call the handler directly in sctp_
inq_push
() at a time that
* we know we are lock safe.
* we know we are lock safe.
* The intent is that this routine will pull stuff out of the
* The intent is that this routine will pull stuff out of the
* inqueue and process it.
* inqueue and process it.
*/
*/
void
sctp_inq
ueue_set_th_handler
(
sctp_inqueue_t
*
q
,
void
sctp_inq
_set_th_handler
(
struct
sctp_inq
*
q
,
void
(
*
callback
)(
void
*
),
void
*
arg
)
void
(
*
callback
)(
void
*
),
void
*
arg
)
{
{
INIT_WORK
(
&
q
->
immediate
,
callback
,
arg
);
INIT_WORK
(
&
q
->
immediate
,
callback
,
arg
);
...
...
net/sctp/ipv6.c
View file @
551c773f
...
@@ -444,7 +444,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
...
@@ -444,7 +444,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
}
}
/* Initialize a PF_INET msgname from a ulpevent. */
/* Initialize a PF_INET msgname from a ulpevent. */
static
void
sctp_inet6_event_msgname
(
s
ctp_ulpevent_
t
*
event
,
char
*
msgname
,
static
void
sctp_inet6_event_msgname
(
s
truct
sctp_ulpeven
t
*
event
,
char
*
msgname
,
int
*
addrlen
)
int
*
addrlen
)
{
{
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
...
...
net/sctp/protocol.c
View file @
551c773f
...
@@ -124,7 +124,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
...
@@ -124,7 +124,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Add the address to the local list. */
/* Add the address to the local list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
if
(
addr
)
{
if
(
addr
)
{
INIT_LIST_HEAD
(
&
addr
->
list
);
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_port
=
0
;
addr
->
a
.
v4
.
sin_port
=
0
;
addr
->
a
.
v4
.
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
addr
->
a
.
v4
.
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
...
@@ -557,7 +556,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
...
@@ -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. */
/* Copy the primary address of the peer primary address as the msg_name. */
static
void
sctp_inet_event_msgname
(
s
ctp_ulpevent_
t
*
event
,
char
*
msgname
,
static
void
sctp_inet_event_msgname
(
s
truct
sctp_ulpeven
t
*
event
,
char
*
msgname
,
int
*
addr_len
)
int
*
addr_len
)
{
{
struct
sockaddr_in
*
sin
,
*
sinfrom
;
struct
sockaddr_in
*
sin
,
*
sinfrom
;
...
...
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,
...
@@ -245,7 +245,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
retval
=
NULL
;
retval
=
NULL
;
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
priority
);
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
priority
);
if
(
!
addrs
.
v
)
if
(
!
addrs
.
v
)
goto
nomem_rawaddr
;
goto
nomem_rawaddr
;
...
...
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,
...
@@ -598,6 +598,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
t
->
rto_pending
=
1
;
t
->
rto_pending
=
1
;
break
;
break
;
case
SCTP_CMD_CHUNK_PD
:
/* Send a chunk to the sockets layer. */
sctp_ulpq_partial_delivery
(
&
asoc
->
ulpq
,
command
->
obj
.
ptr
,
GFP_ATOMIC
);
break
;
default:
default:
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
command
->
verb
,
command
->
obj
.
ptr
);
command
->
verb
,
command
->
obj
.
ptr
);
...
@@ -1014,7 +1021,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
...
@@ -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
,
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
asoc
)
sctp_association_t
*
asoc
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
0
,
...
@@ -1041,7 +1048,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
...
@@ -1041,7 +1048,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_subtype_t
subtype
,
sctp_subtype_t
subtype
,
sctp_chunk_t
*
chunk
)
sctp_chunk_t
*
chunk
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
__u16
error
=
0
;
__u16
error
=
0
;
switch
(
event_type
)
{
switch
(
event_type
)
{
...
@@ -1061,12 +1068,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
...
@@ -1061,12 +1068,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
break
;
break
;
}
}
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
/* Cancel any partial delivery in progress. */
0
,
sctp_ulpq_abort_pd
(
&
asoc
->
ulpq
,
GFP_ATOMIC
);
SCTP_COMM_LOST
,
error
,
0
,
0
,
GFP_ATOMIC
);
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_COMM_LOST
,
error
,
0
,
0
,
GFP_ATOMIC
);
if
(
event
)
if
(
event
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
SCTP_ULPEVENT
(
event
));
SCTP_ULPEVENT
(
event
));
...
@@ -1141,7 +1147,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
...
@@ -1141,7 +1147,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
if
(
del_timer
(
&
t
->
hb_timer
))
if
(
del_timer
(
&
t
->
hb_timer
))
sctp_transport_put
(
t
);
sctp_transport_put
(
t
);
}
}
}
}
/* Helper function to update the heartbeat timer. */
/* Helper function to update the heartbeat timer. */
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
...
...
net/sctp/sm_statefuns.c
View file @
551c773f
...
@@ -102,7 +102,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
...
@@ -102,7 +102,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* RFC 2960 6.10 Bundling
/* RFC 2960 6.10 Bundling
*
*
...
@@ -264,7 +264,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -264,7 +264,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if
(
sctp_assoc_set_bind_addr_from_ep
(
new_asoc
,
GFP_ATOMIC
)
<
0
)
if
(
sctp_assoc_set_bind_addr_from_ep
(
new_asoc
,
GFP_ATOMIC
)
<
0
)
goto
nomem_ack
;
goto
nomem_ack
;
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
,
len
);
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
,
len
);
if
(
!
repl
)
if
(
!
repl
)
goto
nomem_ack
;
goto
nomem_ack
;
...
@@ -504,7 +504,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
...
@@ -504,7 +504,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
;
sctp_association_t
*
new_asoc
;
sctp_init_chunk_t
*
peer_init
;
sctp_init_chunk_t
*
peer_init
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
int
error
=
0
;
int
error
=
0
;
sctp_chunk_t
*
err_chk_p
;
sctp_chunk_t
*
err_chk_p
;
...
@@ -636,7 +636,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
...
@@ -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
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* RFC 2960 5.1 Normal Establishment of an Association
/* RFC 2960 5.1 Normal Establishment of an Association
*
*
...
@@ -1355,7 +1355,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
...
@@ -1355,7 +1355,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
)
sctp_association_t
*
new_asoc
)
{
{
sctp_init_chunk_t
*
peer_init
;
sctp_init_chunk_t
*
peer_init
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
/* new_asoc is a brand-new association, so these are not yet
/* new_asoc is a brand-new association, so these are not yet
...
@@ -1421,7 +1421,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
...
@@ -1421,7 +1421,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
)
sctp_association_t
*
new_asoc
)
{
{
sctp_init_chunk_t
*
peer_init
;
sctp_init_chunk_t
*
peer_init
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
/* new_asoc is a brand-new association, so these are not yet
/* new_asoc is a brand-new association, so these are not yet
...
@@ -1503,7 +1503,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
...
@@ -1503,7 +1503,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
,
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
new_asoc
)
sctp_association_t
*
new_asoc
)
{
{
s
ctp_ulpevent_
t
*
ev
=
NULL
;
s
truct
sctp_ulpeven
t
*
ev
=
NULL
;
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
/* Clarification from Implementor's Guide:
/* Clarification from Implementor's Guide:
...
@@ -1540,11 +1540,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
...
@@ -1540,11 +1540,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
SCTP_ULPEVENT
(
ev
));
SCTP_ULPEVENT
(
ev
));
}
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSMIT
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSMIT
,
SCTP_NULL
());
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
if
(
!
repl
)
if
(
!
repl
)
goto
nomem
;
goto
nomem
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSMIT
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSMIT
,
SCTP_NULL
());
...
@@ -2241,6 +2241,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2241,6 +2241,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
sctp_datahdr_t
*
data_hdr
;
sctp_datahdr_t
*
data_hdr
;
sctp_chunk_t
*
err
;
sctp_chunk_t
*
err
;
size_t
datalen
;
size_t
datalen
;
sctp_verb_t
deliver
;
int
tmp
;
int
tmp
;
__u32
tsn
;
__u32
tsn
;
...
@@ -2307,10 +2308,32 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2307,10 +2308,32 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
datalen
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
datalen
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
datalen
-=
sizeof
(
sctp_data_chunk_t
);
datalen
-=
sizeof
(
sctp_data_chunk_t
);
deliver
=
SCTP_CMD_CHUNK_ULP
;
/* Think about partial delivery. */
if
((
datalen
>=
asoc
->
rwnd
)
&&
(
!
asoc
->
ulpq
.
pd_mode
))
{
/* Even if we don't accept this chunk there is
* memory pressure.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_CHUNK_PD
,
SCTP_NULL
());
}
if
(
asoc
->
rwnd_over
||
(
datalen
>
asoc
->
rwnd
+
asoc
->
frag_point
))
{
if
(
asoc
->
rwnd_over
||
(
datalen
>
asoc
->
rwnd
+
asoc
->
frag_point
))
{
SCTP_DEBUG_PRINTK
(
"Discarding tsn: %u datalen: %Zd, "
"rwnd: %d
\n
"
,
tsn
,
datalen
,
asoc
->
rwnd
);
goto
discard_force
;
/* There is absolutely no room, but this is the most
* important tsn that we are waiting on, try to
* to partial deliver or renege to make room.
*/
if
((
sctp_tsnmap_get_ctsn
(
&
asoc
->
peer
.
tsn_map
)
+
1
)
==
tsn
)
{
deliver
=
SCTP_CMD_CHUNK_PD
;
}
else
{
SCTP_DEBUG_PRINTK
(
"Discard tsn: %u len: %Zd, "
"rwnd: %d
\n
"
,
tsn
,
datalen
,
asoc
->
rwnd
);
goto
discard_force
;
}
}
}
/*
/*
...
@@ -2335,10 +2358,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2335,10 +2358,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
}
/* We are accepting this DATA chunk. */
/* If definately accepting the DATA chunk, record its TSN, otherwise
* wait for renege processing.
/* Record the fact that we have received this TSN. */
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPORT_TSN
,
SCTP_U32
(
tsn
));
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
/* 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,
...
@@ -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
,
err
=
sctp_make_op_error
(
asoc
,
chunk
,
SCTP_ERROR_INV_STRM
,
&
data_hdr
->
stream
,
&
data_hdr
->
stream
,
sizeof
(
data_hdr
->
stream
));
sizeof
(
data_hdr
->
stream
));
if
(
err
)
{
if
(
err
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
err
));
SCTP_CHUNK
(
err
));
}
goto
discard_noforce
;
goto
discard_noforce
;
}
}
...
@@ -2363,7 +2386,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -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
* SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
* chunk needs the updated rwnd.
* chunk needs the updated rwnd.
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_CHUNK_ULP
,
SCTP_CHUNK
(
chunk
));
sctp_add_cmd_sf
(
commands
,
deliver
,
SCTP_CHUNK
(
chunk
));
if
(
asoc
->
autoclose
)
{
if
(
asoc
->
autoclose
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_RESTART
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_RESTART
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_AUTOCLOSE
));
SCTP_TO
(
SCTP_EVENT_TIMEOUT_AUTOCLOSE
));
...
@@ -2726,7 +2750,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
...
@@ -2726,7 +2750,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
while
(
chunk
->
chunk_end
>
chunk
->
skb
->
data
)
{
while
(
chunk
->
chunk_end
>
chunk
->
skb
->
data
)
{
ev
=
sctp_ulpevent_make_remote_error
(
asoc
,
chunk
,
0
,
ev
=
sctp_ulpevent_make_remote_error
(
asoc
,
chunk
,
0
,
...
@@ -2764,7 +2788,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
...
@@ -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
*
chunk
=
arg
;
sctp_chunk_t
*
reply
;
sctp_chunk_t
*
reply
;
s
ctp_ulpevent_
t
*
ev
;
s
truct
sctp_ulpeven
t
*
ev
;
/* 10.2 H) SHUTDOWN COMPLETE notification
/* 10.2 H) SHUTDOWN COMPLETE notification
*
*
...
...
net/sctp/socket.c
View file @
551c773f
...
@@ -81,13 +81,13 @@
...
@@ -81,13 +81,13 @@
/* Forward declarations for internal helper functions. */
/* Forward declarations for internal helper functions. */
static
int
sctp_writeable
(
struct
sock
*
sk
);
static
int
sctp_writeable
(
struct
sock
*
sk
);
static
inline
int
sctp_wspace
(
s
ctp_association_t
*
asoc
);
static
inline
int
sctp_wspace
(
s
truct
sctp_association
*
asoc
);
static
inline
void
sctp_set_owner_w
(
sctp_chunk_t
*
chunk
);
static
inline
void
sctp_set_owner_w
(
sctp_chunk_t
*
chunk
);
static
void
sctp_wfree
(
struct
sk_buff
*
skb
);
static
void
sctp_wfree
(
struct
sk_buff
*
skb
);
static
int
sctp_wait_for_sndbuf
(
s
ctp_association_t
*
asoc
,
long
*
timeo_p
,
static
int
sctp_wait_for_sndbuf
(
s
truct
sctp_association
*
,
long
*
timeo_p
,
int
msg_len
);
int
msg_len
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
s
ctp_association_t
*
asoc
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
s
truct
sctp_association
*
,
long
*
timeo_p
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
...
@@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
...
@@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
/* Bind a local address either to an endpoint or to an association. */
/* Bind a local address either to an endpoint or to an association. */
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
...
@@ -454,7 +454,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
...
@@ -454,7 +454,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
*/
*/
int
sctp_bindx_rem
(
struct
sock
*
sk
,
struct
sockaddr_storage
*
addrs
,
int
addrcnt
)
int
sctp_bindx_rem
(
struct
sock
*
sk
,
struct
sockaddr_storage
*
addrs
,
int
addrcnt
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
int
cnt
;
int
cnt
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
...
@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
...
@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Clean up any skbs sitting on the receive queue. */
/* Clean up any skbs sitting on the receive queue. */
skb_queue_purge
(
&
sk
->
receive_queue
);
skb_queue_purge
(
&
sk
->
receive_queue
);
skb_queue_purge
(
&
sctp_sk
(
sk
)
->
pd_lobby
);
/* This will run the backlog queue. */
/* This will run the backlog queue. */
sctp_release_sock
(
sk
);
sctp_release_sock
(
sk
);
...
@@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
...
@@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
SCTP_STATIC
int
sctp_sendmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
SCTP_STATIC
int
sctp_sendmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
int
msg_len
)
struct
msghdr
*
msg
,
int
msg_len
)
{
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
...
@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* ASSERT: we have a valid association at this point. */
/* ASSERT: we have a valid association at this point. */
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
SCTP_DEBUG_PRINTK
(
"We have a valid association.
\n
"
);
if
(
!
sinfo
)
{
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo
.
sinfo_stream
=
asoc
->
defaults
.
stream
;
default_sinfo
.
sinfo_flags
=
asoc
->
defaults
.
flags
;
default_sinfo
.
sinfo_ppid
=
asoc
->
defaults
.
ppid
;
default_sinfo
.
sinfo_context
=
asoc
->
defaults
.
context
;
default_sinfo
.
sinfo_timetolive
=
asoc
->
defaults
.
timetolive
;
default_sinfo
.
sinfo_assoc_id
=
sctp_assoc2id
(
asoc
);
sinfo
=
&
default_sinfo
;
}
/* API 7.1.7, the sndbuf size per association bounds the
/* API 7.1.7, the sndbuf size per association bounds the
* maximum size of data that can be sent in a single send call.
* maximum size of data that can be sent in a single send call.
*/
*/
...
@@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
out_free
;
goto
out_free
;
}
}
}
else
{
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo
.
sinfo_stream
=
asoc
->
defaults
.
stream
;
default_sinfo
.
sinfo_ppid
=
asoc
->
defaults
.
ppid
;
sinfo
=
&
default_sinfo
;
}
}
timeo
=
sock_sndtimeo
(
sk
,
msg
->
msg_flags
&
MSG_DONTWAIT
);
timeo
=
sock_sndtimeo
(
sk
,
msg
->
msg_flags
&
MSG_DONTWAIT
);
...
@@ -1110,8 +1117,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
...
@@ -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
,
SCTP_STATIC
int
sctp_recvmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
int
len
,
int
noblock
,
int
flags
,
int
*
addr_len
)
int
len
,
int
noblock
,
int
flags
,
int
*
addr_len
)
{
{
s
ctp_ulpevent_
t
*
event
=
NULL
;
s
truct
sctp_ulpeven
t
*
event
=
NULL
;
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
int
copied
;
int
copied
;
int
err
=
0
;
int
err
=
0
;
...
@@ -1143,7 +1150,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -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
);
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
if
(
err
)
if
(
err
)
goto
out_free
;
goto
out_free
;
...
@@ -1170,7 +1177,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -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
/* If skb's length exceeds the user's buffer, update the skb and
* push it back to the receive_queue so that the next call to
* push it back to the receive_queue so that the next call to
* recvmsg() will return the remaining data. Don't set MSG_EOR.
* recvmsg() will return the remaining data. Don't set MSG_EOR.
* Otherwise, set MSG_EOR indicating the end of a message.
*/
*/
if
(
skb_len
>
copied
)
{
if
(
skb_len
>
copied
)
{
msg
->
msg_flags
&=
~
MSG_EOR
;
msg
->
msg_flags
&=
~
MSG_EOR
;
...
@@ -1178,6 +1184,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1178,6 +1184,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
goto
out_free
;
goto
out_free
;
sctp_skb_pull
(
skb
,
copied
);
sctp_skb_pull
(
skb
,
copied
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
/* When only partial message is copied to the user, increase
/* When only partial message is copied to the user, increase
* rwnd by that amount. If all the data in the skb is read,
* rwnd by that amount. If all the data in the skb is read,
* rwnd is updated when the skb's destructor is called via
* rwnd is updated when the skb's destructor is called via
...
@@ -1185,9 +1192,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1185,9 +1192,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
*/
*/
sctp_assoc_rwnd_increase
(
event
->
asoc
,
copied
);
sctp_assoc_rwnd_increase
(
event
->
asoc
,
copied
);
goto
out
;
goto
out
;
}
else
{
}
else
if
((
event
->
msg_flags
&
MSG_NOTIFICATION
)
||
msg
->
msg_flags
|=
MSG_EOR
;
(
event
->
msg_flags
&
MSG_EOR
))
}
msg
->
msg_flags
|=
MSG_EOR
;
else
msg
->
msg_flags
&=
~
MSG_EOR
;
out_free:
out_free:
sctp_ulpevent_free
(
event
);
/* Free the skb. */
sctp_ulpevent_free
(
event
);
/* Free the skb. */
...
@@ -1225,7 +1234,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
...
@@ -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
,
static
inline
int
sctp_setsockopt_autoclose
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
int
optlen
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
/* Applicable to UDP-style socket only */
/* Applicable to UDP-style socket only */
if
(
SCTP_SOCKET_TCP
==
sp
->
type
)
if
(
SCTP_SOCKET_TCP
==
sp
->
type
)
...
@@ -1310,6 +1319,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
...
@@ -1310,6 +1319,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
return
0
;
return
0
;
}
}
/*
*
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied
* through the inclusion of ancillary data. This socket option allows
* such an application to set the default sctp_sndrcvinfo structure.
* The application that wishes to use this socket option simply passes
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
* sinfo_timetolive. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*/
static
inline
int
sctp_setsockopt_set_default_send_param
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
struct
sctp_sndrcvinfo
info
;
sctp_association_t
*
asoc
;
if
(
optlen
!=
sizeof
(
struct
sctp_sndrcvinfo
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
info
,
optval
,
optlen
))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
info
.
sinfo_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
asoc
->
defaults
.
stream
=
info
.
sinfo_stream
;
asoc
->
defaults
.
flags
=
info
.
sinfo_flags
;
asoc
->
defaults
.
ppid
=
info
.
sinfo_ppid
;
asoc
->
defaults
.
context
=
info
.
sinfo_context
;
asoc
->
defaults
.
timetolive
=
info
.
sinfo_timetolive
;
return
0
;
}
/* API 6.2 setsockopt(), getsockopt()
/* API 6.2 setsockopt(), getsockopt()
*
*
* Applications use setsockopt() and getsockopt() to set or retrieve
* Applications use setsockopt() and getsockopt() to set or retrieve
...
@@ -1401,6 +1448,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1401,6 +1448,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval
=
sctp_setsockopt_initmsg
(
sk
,
optval
,
optlen
);
retval
=
sctp_setsockopt_initmsg
(
sk
,
optval
,
optlen
);
break
;
break
;
case
SCTP_SET_DEFAULT_SEND_PARAM
:
retval
=
sctp_setsockopt_set_default_send_param
(
sk
,
optval
,
optlen
);
break
;
default:
default:
retval
=
-
ENOPROTOOPT
;
retval
=
-
ENOPROTOOPT
;
break
;
break
;
...
@@ -1432,7 +1484,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -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
,
SCTP_STATIC
int
sctp_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
int
addr_len
)
{
{
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
...
@@ -1554,7 +1606,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1554,7 +1606,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
{
{
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
sctp_protocol_t
*
proto
;
sctp_protocol_t
*
proto
;
s
ctp_opt_
t
*
sp
;
s
truct
sctp_op
t
*
sp
;
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
...
@@ -1583,7 +1635,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1583,7 +1635,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Initialize default RTO related parameters. These parameters can
/* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option.
* be modified for with the SCTP_RTOINFO socket option.
* FIXME: Th
is
are not used yet.
* FIXME: Th
ese
are not used yet.
*/
*/
sp
->
rtoinfo
.
srto_initial
=
proto
->
rto_initial
;
sp
->
rtoinfo
.
srto_initial
=
proto
->
rto_initial
;
sp
->
rtoinfo
.
srto_max
=
proto
->
rto_max
;
sp
->
rtoinfo
.
srto_max
=
proto
->
rto_max
;
...
@@ -1620,6 +1672,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1620,6 +1672,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/
*/
sp
->
autoclose
=
0
;
sp
->
autoclose
=
0
;
sp
->
pf
=
sctp_get_pf_specific
(
sk
->
family
);
sp
->
pf
=
sctp_get_pf_specific
(
sk
->
family
);
/* Control variables for partial data delivery. */
sp
->
pd_mode
=
0
;
skb_queue_head_init
(
&
sp
->
pd_lobby
);
/* Create a per socket endpoint structure. Even if we
/* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still
* change the data structure relationships, this may still
* be useful for storing pre-connect address information.
* be useful for storing pre-connect address information.
...
@@ -1774,10 +1831,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1774,10 +1831,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
struct
sock
*
newsk
;
struct
sock
*
newsk
;
struct
socket
*
tmpsock
;
struct
socket
*
tmpsock
;
sctp_endpoint_t
*
newep
;
sctp_endpoint_t
*
newep
;
s
ctp_opt_
t
*
oldsp
=
sctp_sk
(
oldsk
);
s
truct
sctp_op
t
*
oldsp
=
sctp_sk
(
oldsk
);
s
ctp_opt_
t
*
newsp
;
s
truct
sctp_op
t
*
newsp
;
struct
sk_buff
*
skb
,
*
tmp
;
struct
sk_buff
*
skb
,
*
tmp
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
int
err
=
0
;
int
err
=
0
;
/* An association cannot be branched off from an already peeled-off
/* An association cannot be branched off from an already peeled-off
...
@@ -1811,13 +1868,50 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -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.
* peeled off association to the new socket's receive queue.
*/
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
if
(
event
->
asoc
==
assoc
)
{
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
}
}
/* Clean up an messages pending delivery due to partial
* delivery. Three cases:
* 1) No partial deliver; no work.
* 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
* 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
*/
skb_queue_head_init
(
&
newsp
->
pd_lobby
);
sctp_sk
(
newsk
)
->
pd_mode
=
assoc
->
ulpq
.
pd_mode
;;
if
(
sctp_sk
(
oldsk
)
->
pd_mode
)
{
struct
sk_buff_head
*
queue
;
/* Decide which queue to move pd_lobby skbs to. */
if
(
assoc
->
ulpq
.
pd_mode
)
{
queue
=
&
newsp
->
pd_lobby
;
}
else
queue
=
&
newsk
->
receive_queue
;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each
(
skb
,
&
oldsp
->
pd_lobby
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
queue
,
skb
);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if
(
assoc
->
ulpq
.
pd_mode
)
sctp_clear_pd
(
oldsk
);
}
/* Set the type of socket to indicate that it is peeled off from the
/* Set the type of socket to indicate that it is peeled off from the
* original socket.
* original socket.
*/
*/
...
@@ -2389,7 +2483,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
...
@@ -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
)
SCTP_STATIC
int
sctp_seqpacket_listen
(
struct
sock
*
sk
,
int
backlog
)
{
{
s
ctp_opt_
t
*
sp
=
sctp_sk
(
sk
);
s
truct
sctp_op
t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
/* Only UDP style sockets that are not peeled off are allowed to
/* Only UDP style sockets that are not peeled off are allowed to
...
...
net/sctp/ulpevent.c
View file @
551c773f
...
@@ -5,37 +5,37 @@
...
@@ -5,37 +5,37 @@
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2001 La Monte H.P. Yarroll
*
*
* These functions manipulate an sctp event. The s
ctp_ulpevent_
t is used
* These functions manipulate an sctp event. The s
truct ulpeven
t is used
* to carry notifications and data to the ULP (sockets).
* to carry notifications and data to the ULP (sockets).
* The SCTP reference implementation is free software;
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
* any later version.
*
*
* The SCTP reference implementation is distributed in the hope that it
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* See the GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Boston, MA 02111-1307, USA.
*
*
* Please send any bug reports or fixes you make to the
* Please send any bug reports or fixes you make to the
* email address(es):
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
*
* Or submit a bug report through the following website:
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
* http://www.sf.net/projects/lksctp
*
*
* Written or modified by:
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
* La Monte H.P. Yarroll <piggy@acm.org>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
*/
*/
...
@@ -47,58 +47,51 @@
...
@@ -47,58 +47,51 @@
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
s
ctp_association_t
*
asoc
);
s
truct
sctp_association
*
asoc
);
static
void
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
const
sctp_association_t
*
asoc
);
const
struct
sctp_association
*
asoc
);
/* Create a new sctp_ulpevent. */
/* Create a new sctp_ulpevent. */
s
ctp_ulpevent_
t
*
sctp_ulpevent_new
(
int
size
,
int
msg_flags
,
int
priority
)
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_new
(
int
size
,
int
msg_flags
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
skb
=
alloc_skb
(
size
,
priority
);
skb
=
alloc_skb
(
size
,
priority
);
if
(
!
skb
)
if
(
!
skb
)
goto
fail
;
goto
fail
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
msg_flags
);
event
=
sctp_ulpevent_init
(
event
,
msg_flags
);
if
(
!
event
)
if
(
!
event
)
goto
fail_init
;
goto
fail_init
;
event
->
malloced
=
1
;
return
event
;
return
event
;
fail_init:
fail_init:
kfree_skb
(
event
->
parent
);
kfree_skb
(
skb
);
fail:
fail:
return
NULL
;
return
NULL
;
}
}
/* Initialize an ULP event from an given skb. */
/* Initialize an ULP event from an given skb. */
sctp_ulpevent_t
*
sctp_ulpevent_init
(
sctp_ulpevent_t
*
event
,
struct
sctp_ulpevent
*
sctp_ulpevent_init
(
struct
sctp_ulpevent
*
event
,
struct
sk_buff
*
parent
,
int
msg_flags
)
int
msg_flags
)
{
{
memset
(
event
,
sizeof
(
s
ctp_ulpevent_
t
),
0x00
);
memset
(
event
,
sizeof
(
s
truct
sctp_ulpeven
t
),
0x00
);
event
->
msg_flags
=
msg_flags
;
event
->
msg_flags
=
msg_flags
;
event
->
parent
=
parent
;
event
->
malloced
=
0
;
return
event
;
return
event
;
}
}
/* Dispose of an event. */
/* Dispose of an event. */
void
sctp_ulpevent_free
(
s
ctp_ulpevent_
t
*
event
)
void
sctp_ulpevent_free
(
s
truct
sctp_ulpeven
t
*
event
)
{
{
if
(
event
->
malloced
)
kfree_skb
(
sctp_event2skb
(
event
));
kfree_skb
(
event
->
parent
);
}
}
/* Is this a MSG_NOTIFICATION? */
/* Is this a MSG_NOTIFICATION? */
int
sctp_ulpevent_is_notification
(
const
s
ctp_ulpevent_
t
*
event
)
int
sctp_ulpevent_is_notification
(
const
s
truct
sctp_ulpeven
t
*
event
)
{
{
return
event
->
msg_flags
&
MSG_NOTIFICATION
;
return
MSG_NOTIFICATION
==
(
event
->
msg_flags
&
MSG_NOTIFICATION
)
;
}
}
/* Create and initialize an SCTP_ASSOC_CHANGE event.
/* Create and initialize an SCTP_ASSOC_CHANGE event.
...
@@ -112,24 +105,22 @@ int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event)
...
@@ -112,24 +105,22 @@ int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event)
* Note: There is no field checking here. If a field is unused it will be
* Note: There is no field checking here. If a field is unused it will be
* zero'd out.
* zero'd out.
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_assoc_change
(
const
sctp_association_t
*
asoc
,
struct
sctp_ulpevent
*
sctp_ulpevent_make_assoc_change
(
__u16
flags
,
const
sctp_association_t
*
asoc
,
__u16
state
,
__u16
flags
,
__u16
state
,
__u16
error
,
__u16
outbound
,
__u16
error
,
__u16
inbound
,
int
priority
)
__u16
outbound
,
__u16
inbound
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_assoc_change
*
sac
;
struct
sctp_assoc_change
*
sac
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
skb
=
sctp_event2skb
(
event
);
sac
=
(
struct
sctp_assoc_change
*
)
sac
=
(
struct
sctp_assoc_change
*
)
skb_put
(
event
->
parent
,
sizeof
(
struct
sctp_assoc_change
));
skb_put
(
skb
,
sizeof
(
struct
sctp_assoc_change
));
/* Socket Extensions for SCTP
/* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE
* 5.3.1.1 SCTP_ASSOC_CHANGE
...
@@ -198,13 +189,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
...
@@ -198,13 +189,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
sac
->
sac_assoc_id
=
sctp_assoc2id
(
asoc
);
sac
->
sac_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
fail:
fail:
return
NULL
;
return
NULL
;
}
}
/* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
/* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
...
@@ -215,24 +206,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
...
@@ -215,24 +206,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* When a destination address on a multi-homed peer encounters a change
* When a destination address on a multi-homed peer encounters a change
* an interface details event is sent.
* an interface details event is sent.
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_peer_addr_change
(
struct
sctp_ulpevent
*
sctp_ulpevent_make_peer_addr_change
(
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
const
struct
sockaddr_storage
*
aaddr
,
const
struct
sockaddr_storage
*
aaddr
,
int
flags
,
int
state
,
int
error
,
int
priority
)
int
flags
,
int
state
,
int
error
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_paddr_change
*
spc
;
struct
sctp_paddr_change
*
spc
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_paddr_change
),
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_paddr_change
),
MSG_NOTIFICATION
,
priority
);
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
skb
=
sctp_event2skb
(
event
);
spc
=
(
struct
sctp_paddr_change
*
)
spc
=
(
struct
sctp_paddr_change
*
)
skb_put
(
event
->
parent
,
sizeof
(
struct
sctp_paddr_change
));
skb_put
(
skb
,
sizeof
(
struct
sctp_paddr_change
));
/* Sockets API Extensions for SCTP
/* Sockets API Extensions for SCTP
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
...
@@ -265,7 +254,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
...
@@ -265,7 +254,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
*
*
* spc_state: 32 bits (signed integer)
* spc_state: 32 bits (signed integer)
*
*
* This field holds one of a number of values that communicate the
* This field holds one of a number of values that communicate the
* event that happened to the address.
* event that happened to the address.
*/
*/
...
@@ -291,7 +280,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
...
@@ -291,7 +280,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
spc
->
spc_assoc_id
=
sctp_assoc2id
(
asoc
);
spc
->
spc_assoc_id
=
sctp_assoc2id
(
asoc
);
/* Sockets API Extensions for SCTP
/* Sockets API Extensions for SCTP
...
@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
...
@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* specification [SCTP] and any extensions for a list of possible
* specification [SCTP] and any extensions for a list of possible
* error formats.
* error formats.
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_remote_error
(
const
sctp_association_t
*
asoc
,
struct
sctp_ulpevent
*
sctp_ulpevent_make_remote_error
(
sctp_chunk_t
*
chunk
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
__u16
flags
,
int
priority
)
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_remote_error
*
sre
;
struct
sctp_remote_error
*
sre
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
sctp_errhdr_t
*
ch
;
sctp_errhdr_t
*
ch
;
...
@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
...
@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
goto
fail
;
goto
fail
;
/* Embed the event fields inside the cloned skb. */
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
MSG_NOTIFICATION
);
event
=
sctp_ulpevent_init
(
event
,
MSG_NOTIFICATION
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
event
->
malloced
=
1
;
sre
=
(
struct
sctp_remote_error
*
)
sre
=
(
struct
sctp_remote_error
*
)
skb_push
(
skb
,
sizeof
(
struct
sctp_remote_error
));
skb_push
(
skb
,
sizeof
(
struct
sctp_remote_error
));
...
@@ -416,7 +403,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
...
@@ -416,7 +403,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
skb
=
sctp_event2skb
(
event
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
sre
->
sre_assoc_id
=
sctp_assoc2id
(
asoc
);
sre
->
sre_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
...
@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
...
@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01
* Socket Extensions for SCTP - draft-01
* 5.3.1.4 SCTP_SEND_FAILED
* 5.3.1.4 SCTP_SEND_FAILED
*/
*/
sctp_ulpevent_t
*
sctp_ulpevent_make_send_failed
(
const
sctp_association_t
*
asoc
,
struct
sctp_ulpevent
*
sctp_ulpevent_make_send_failed
(
sctp_chunk_t
*
chunk
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
__u16
flags
,
__u16
flags
,
__u32
error
,
int
priority
)
__u32
error
,
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_send_failed
*
ssf
;
struct
sctp_send_failed
*
ssf
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
...
@@ -452,16 +438,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
...
@@ -452,16 +438,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
skb_pull
(
skb
,
sizeof
(
sctp_data_chunk_t
));
skb_pull
(
skb
,
sizeof
(
sctp_data_chunk_t
));
/* Embed the event fields inside the cloned skb. */
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
=
sctp_ulpevent_init
(
event
,
skb
,
MSG_NOTIFICATION
);
event
=
sctp_ulpevent_init
(
event
,
MSG_NOTIFICATION
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
/* Mark as malloced, even though the constructor was not
* called.
*/
event
->
malloced
=
1
;
ssf
=
(
struct
sctp_send_failed
*
)
ssf
=
(
struct
sctp_send_failed
*
)
skb_push
(
skb
,
sizeof
(
struct
sctp_send_failed
));
skb_push
(
skb
,
sizeof
(
struct
sctp_send_failed
));
...
@@ -525,7 +506,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
...
@@ -525,7 +506,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* same association identifier. For TCP style socket, this field is
* same association identifier. For TCP style socket, this field is
* ignored.
* ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
skb
=
sctp_event2skb
(
event
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
ssf
->
ssf_assoc_id
=
sctp_assoc2id
(
asoc
);
ssf
->
ssf_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
...
@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
...
@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01
* Socket Extensions for SCTP - draft-01
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
*/
*/
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_shutdown_event
(
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_shutdown_event
(
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
__u16
flags
,
__u16
flags
,
int
priority
)
int
priority
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
struct
sctp_shutdown_event
*
sse
;
struct
sctp_shutdown_event
*
sse
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
if
(
!
event
)
goto
fail
;
goto
fail
;
skb
=
sctp_event2skb
(
event
);
sse
=
(
struct
sctp_shutdown_event
*
)
sse
=
(
struct
sctp_shutdown_event
*
)
skb_put
(
event
->
parent
,
sizeof
(
struct
sctp_shutdown_event
));
skb_put
(
skb
,
sizeof
(
struct
sctp_shutdown_event
));
/* Socket Extensions for SCTP
/* Socket Extensions for SCTP
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
* 5.3.1.5 SCTP_SHUTDOWN_EVENT
...
@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
...
@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* All notifications for a given association have the same association
* All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored.
* identifier. For TCP style socket, this field is ignored.
*/
*/
sctp_ulpevent_set_owner
(
event
->
parent
,
asoc
);
sctp_ulpevent_set_owner
(
skb
,
asoc
);
sse
->
sse_assoc_id
=
sctp_assoc2id
(
asoc
);
sse
->
sse_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
return
event
;
...
@@ -600,13 +583,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
...
@@ -600,13 +583,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* to pass it to the upper layers. Go ahead and calculate the sndrcvinfo
* to pass it to the upper layers. Go ahead and calculate the sndrcvinfo
* even if filtered out later.
* even if filtered out later.
*
*
* Socket Extensions for SCTP
- draft-01
* Socket Extensions for SCTP
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
*/
*/
s
ctp_ulpevent_
t
*
sctp_ulpevent_make_rcvmsg
(
sctp_association_t
*
asoc
,
s
truct
sctp_ulpeven
t
*
sctp_ulpevent_make_rcvmsg
(
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
int
priority
)
sctp_chunk_t
*
chunk
,
int
priority
)
{
{
s
ctp_ulpevent_t
*
event
,
*
l
event
;
s
truct
sctp_ulpevent
*
event
;
struct
sctp_sndrcvinfo
*
info
;
struct
sctp_sndrcvinfo
*
info
;
struct
sk_buff
*
skb
,
*
list
;
struct
sk_buff
*
skb
,
*
list
;
size_t
padding
,
len
;
size_t
padding
,
len
;
...
@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_ulpevent_set_owner_r
(
skb
,
asoc
);
sctp_ulpevent_set_owner_r
(
skb
,
asoc
);
/* Embed the event fields inside the cloned skb. */
/* Embed the event fields inside the cloned skb. */
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
/* Initialize event with flags 0. */
/* Initialize event with flags 0. */
event
=
sctp_ulpevent_init
(
event
,
skb
,
0
);
event
=
sctp_ulpevent_init
(
event
,
0
);
if
(
!
event
)
if
(
!
event
)
goto
fail_init
;
goto
fail_init
;
event
->
malloced
=
1
;
/* Note: Not clearing the entire event struct as
* this is just a fragment of the real event. However,
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
* we still need to do rwnd accounting.
*/
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
sctp_ulpevent_set_owner_r
(
list
,
asoc
);
sctp_ulpevent_set_owner_r
(
list
,
asoc
);
/* Initialize event with flags 0. */
levent
=
sctp_ulpevent_init
(
event
,
skb
,
0
);
if
(
!
levent
)
goto
fail_init
;
levent
->
malloced
=
1
;
}
info
=
(
struct
sctp_sndrcvinfo
*
)
&
event
->
sndrcvinfo
;
info
=
(
struct
sctp_sndrcvinfo
*
)
&
event
->
sndrcvinfo
;
...
@@ -707,18 +685,26 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -707,18 +685,26 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
* MSG_UNORDERED - This flag is present when the message was sent
* MSG_UNORDERED - This flag is present when the message was sent
* non-ordered.
* non-ordered.
*/
*/
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
{
info
->
sinfo_flags
|=
MSG_UNORDERED
;
info
->
sinfo_flags
|=
MSG_UNORDERED
;
/* FIXME: For reassembly, we need to have the fragmentation bits.
/* sinfo_cumtsn: 32 bit (unsigned integer)
* This really does not belong in the event structure, but
*
* its difficult to fix everything at the same time. Eventually,
* This field will hold the current cumulative TSN as
* we should create and skb based chunk structure. This structure
* known by the underlying SCTP layer. Note this field is
* storage can be converted to an event. --jgrimm
* ignored when sending and only valid for a receive
* operation when sinfo_flags are set to MSG_UNORDERED.
*/
info
->
sinfo_cumtsn
=
sctp_tsnmap_get_ctsn
(
&
asoc
->
peer
.
tsn_map
);
}
/* Note: For reassembly, we need to have the fragmentation bits.
* For now, merge these into the msg_flags, since those bit
* possitions are not used.
*/
*/
event
->
chunk_flags
=
chunk
->
chunk_hdr
->
flags
;
event
->
msg_flags
|
=
chunk
->
chunk_hdr
->
flags
;
/* With
-
04 draft, tsn moves into sndrcvinfo. */
/* With 04 draft, tsn moves into sndrcvinfo. */
info
->
sinfo_tsn
=
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
);
info
->
sinfo_tsn
=
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
);
/* Context is not used on receive. */
/* Context is not used on receive. */
...
@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
return
NULL
;
return
NULL
;
}
}
/* Create a partial delivery related event.
*
* 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
*
* When a reciever is engaged in a partial delivery of a
* message this notification will be used to inidicate
* various events.
*/
struct
sctp_ulpevent
*
sctp_ulpevent_make_pdapi
(
const
sctp_association_t
*
asoc
,
__u32
indication
,
int
priority
)
{
struct
sctp_ulpevent
*
event
;
struct
sctp_rcv_pdapi_event
*
pd
;
struct
sk_buff
*
skb
;
event
=
sctp_ulpevent_new
(
sizeof
(
struct
sctp_assoc_change
),
MSG_NOTIFICATION
,
priority
);
if
(
!
event
)
goto
fail
;
skb
=
sctp_event2skb
(
event
);
pd
=
(
struct
sctp_rcv_pdapi_event
*
)
skb_put
(
skb
,
sizeof
(
struct
sctp_rcv_pdapi_event
));
/* pdapi_type
* It should be SCTP_PARTIAL_DELIVERY_EVENT
*
* pdapi_flags: 16 bits (unsigned integer)
* Currently unused.
*/
pd
->
pdapi_type
=
SCTP_PARTIAL_DELIVERY_EVENT
;
pd
->
pdapi_flags
=
0
;
/* pdapi_length: 32 bits (unsigned integer)
*
* This field is the total length of the notification data, including
* the notification header. It will generally be sizeof (struct
* sctp_rcv_pdapi_event).
*/
pd
->
pdapi_length
=
sizeof
(
struct
sctp_rcv_pdapi_event
);
/* pdapi_indication: 32 bits (unsigned integer)
*
* This field holds the indication being sent to the application.
*/
pd
->
pdapi_indication
=
indication
;
/* pdapi_assoc_id: sizeof (sctp_assoc_t)
*
* The association id field, holds the identifier for the association.
*/
pd
->
pdapi_assoc_id
=
sctp_assoc2id
(
asoc
);
return
event
;
fail:
return
NULL
;
}
/* Return the notification type, assuming this is a notification
/* Return the notification type, assuming this is a notification
* event.
* event.
*/
*/
__u16
sctp_ulpevent_get_notification_type
(
const
s
ctp_ulpevent_
t
*
event
)
__u16
sctp_ulpevent_get_notification_type
(
const
s
truct
sctp_ulpeven
t
*
event
)
{
{
union
sctp_notification
*
notification
;
union
sctp_notification
*
notification
;
struct
sk_buff
*
skb
;
notification
=
(
union
sctp_notification
*
)
event
->
parent
->
data
;
skb
=
sctp_event2skb
((
struct
sctp_ulpevent
*
)
event
);
notification
=
(
union
sctp_notification
*
)
skb
->
data
;
return
notification
->
h
.
sn_type
;
return
notification
->
h
.
sn_type
;
}
}
/* Copy out the sndrcvinfo into a msghdr. */
/* Copy out the sndrcvinfo into a msghdr. */
void
sctp_ulpevent_read_sndrcvinfo
(
const
s
ctp_ulpevent_
t
*
event
,
void
sctp_ulpevent_read_sndrcvinfo
(
const
s
truct
sctp_ulpeven
t
*
event
,
struct
msghdr
*
msghdr
)
struct
msghdr
*
msghdr
)
{
{
if
(
!
sctp_ulpevent_is_notification
(
event
))
{
if
(
!
sctp_ulpevent_is_notification
(
event
))
{
...
@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
...
@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
static
void
sctp_rcvmsg_rfree
(
struct
sk_buff
*
skb
)
static
void
sctp_rcvmsg_rfree
(
struct
sk_buff
*
skb
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* Current stack structures assume that the rcv buffer is
/* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as
* per socket. For UDP style sockets this is not true as
...
@@ -779,16 +825,17 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
...
@@ -779,16 +825,17 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
* Use the local private area of the skb to track the owning
* Use the local private area of the skb to track the owning
* association.
* association.
*/
*/
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
asoc
=
event
->
asoc
;
asoc
=
event
->
asoc
;
sctp_assoc_rwnd_increase
(
asoc
,
skb_headlen
(
skb
));
sctp_assoc_rwnd_increase
(
asoc
,
skb_headlen
(
skb
));
sctp_association_put
(
asoc
);
sctp_association_put
(
asoc
);
}
}
/* Charge receive window for bytes recieved. */
/* Charge receive window for bytes recieved. */
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
sctp_association_t
*
asoc
)
static
void
sctp_ulpevent_set_owner_r
(
struct
sk_buff
*
skb
,
sctp_association_t
*
asoc
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* The current stack structures assume that the rcv buffer is
/* The current stack structures assume that the rcv buffer is
* per socket. For UDP-style sockets this is not true as
* per socket. For UDP-style sockets this is not true as
...
@@ -798,7 +845,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
...
@@ -798,7 +845,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
*/
*/
sctp_association_hold
(
asoc
);
sctp_association_hold
(
asoc
);
skb
->
sk
=
asoc
->
base
.
sk
;
skb
->
sk
=
asoc
->
base
.
sk
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
->
asoc
=
asoc
;
event
->
asoc
=
asoc
;
skb
->
destructor
=
sctp_rcvmsg_rfree
;
skb
->
destructor
=
sctp_rcvmsg_rfree
;
...
@@ -809,26 +856,26 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
...
@@ -809,26 +856,26 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
/* A simple destructor to give up the reference to the association. */
/* A simple destructor to give up the reference to the association. */
static
void
sctp_ulpevent_rfree
(
struct
sk_buff
*
skb
)
static
void
sctp_ulpevent_rfree
(
struct
sk_buff
*
skb
)
{
{
s
ctp_ulpevent_t
*
event
;
s
truct
sctp_ulpevent
*
event
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
sctp_association_put
(
event
->
asoc
);
sctp_association_put
(
event
->
asoc
);
}
}
/* Hold the association in case the msg_name needs read out of
/* Hold the association in case the msg_name needs read out of
* the association.
* the association.
*/
*/
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
static
void
sctp_ulpevent_set_owner
(
struct
sk_buff
*
skb
,
const
s
ctp_association_t
*
asoc
)
const
s
truct
sctp_association
*
asoc
)
{
{
s
ctp_ulpevent_
t
*
event
;
s
truct
sctp_ulpeven
t
*
event
;
/* Cast away the const, as we are just wanting to
/* Cast away the const, as we are just wanting to
* bump the reference count.
* bump the reference count.
*/
*/
sctp_association_hold
((
s
ctp_association_t
*
)
asoc
);
sctp_association_hold
((
s
truct
sctp_association
*
)
asoc
);
skb
->
sk
=
asoc
->
base
.
sk
;
skb
->
sk
=
asoc
->
base
.
sk
;
event
=
(
sctp_ulpevent_t
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
event
->
asoc
=
(
s
ctp_association_t
*
)
asoc
;
event
->
asoc
=
(
s
truct
sctp_association
*
)
asoc
;
skb
->
destructor
=
sctp_ulpevent_rfree
;
skb
->
destructor
=
sctp_ulpevent_rfree
;
}
}
net/sctp/ulpqueue.c
View file @
551c773f
...
@@ -84,6 +84,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
...
@@ -84,6 +84,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
ulpq
->
asoc
=
asoc
;
ulpq
->
asoc
=
asoc
;
skb_queue_head_init
(
&
ulpq
->
reasm
);
skb_queue_head_init
(
&
ulpq
->
reasm
);
skb_queue_head_init
(
&
ulpq
->
lobby
);
skb_queue_head_init
(
&
ulpq
->
lobby
);
ulpq
->
pd_mode
=
0
;
ulpq
->
malloced
=
0
;
ulpq
->
malloced
=
0
;
return
ulpq
;
return
ulpq
;
...
@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
...
@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
sctp_ulpevent
*
event
;
struct
sctp_ulpevent
*
event
;
while
((
skb
=
skb_dequeue
(
&
ulpq
->
lobby
)))
{
while
((
skb
=
__
skb_dequeue
(
&
ulpq
->
lobby
)))
{
event
=
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
sctp_ulpevent_free
(
event
);
sctp_ulpevent_free
(
event
);
}
}
while
((
skb
=
skb_dequeue
(
&
ulpq
->
reasm
)))
{
while
((
skb
=
__
skb_dequeue
(
&
ulpq
->
reasm
)))
{
event
=
(
struct
sctp_ulpevent
*
)
skb
->
cb
;
event
=
sctp_skb2event
(
skb
)
;
sctp_ulpevent_free
(
event
);
sctp_ulpevent_free
(
event
);
}
}
}
}
/* Dispose of a ulpqueue. */
/* Dispose of a ulpqueue. */
...
@@ -117,7 +119,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
...
@@ -117,7 +119,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
/* Process an incoming DATA chunk. */
/* Process an incoming DATA chunk. */
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
ulpq
,
sctp_chunk_t
*
chunk
,
int
sctp_ulpq_tail_data
(
struct
sctp_ulpq
*
ulpq
,
sctp_chunk_t
*
chunk
,
int
priority
)
int
priority
)
{
{
struct
sk_buff_head
temp
;
struct
sk_buff_head
temp
;
sctp_data_chunk_t
*
hdr
;
sctp_data_chunk_t
*
hdr
;
...
@@ -125,12 +127,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
...
@@ -125,12 +127,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
hdr
=
(
sctp_data_chunk_t
*
)
chunk
->
chunk_hdr
;
hdr
=
(
sctp_data_chunk_t
*
)
chunk
->
chunk_hdr
;
/* FIXME: Instead of event being the skb clone, we really should
/* Create an event from the incoming chunk. */
* have a new skb based chunk structure that we can convert to
* an event. Temporarily, I'm carrying a few chunk fields in
* the event to allow reassembly. Its too painful to change
* everything at once. --jgrimm
*/
event
=
sctp_ulpevent_make_rcvmsg
(
chunk
->
asoc
,
chunk
,
priority
);
event
=
sctp_ulpevent_make_rcvmsg
(
chunk
->
asoc
,
chunk
,
priority
);
if
(
!
event
)
if
(
!
event
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
...
@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
event
=
sctp_ulpq_reasm
(
ulpq
,
event
);
event
=
sctp_ulpq_reasm
(
ulpq
,
event
);
/* Do ordering if needed. */
/* Do ordering if needed. */
if
(
event
)
{
if
(
(
event
)
&&
(
event
->
msg_flags
&
MSG_EOR
))
{
/* Create a temporary list to collect chunks on. */
/* Create a temporary list to collect chunks on. */
skb_queue_head_init
(
&
temp
);
skb_queue_head_init
(
&
temp
);
skb_queue_tail
(
&
temp
,
event
->
parent
);
__skb_queue_tail
(
&
temp
,
sctp_event2skb
(
event
)
);
event
=
sctp_ulpq_order
(
ulpq
,
event
);
event
=
sctp_ulpq_order
(
ulpq
,
event
);
}
}
...
@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
...
@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
return
0
;
return
0
;
}
}
/* Clear the partial delivery mode for this socket. Note: This
* assumes that no association is currently in partial delivery mode.
*/
int
sctp_clear_pd
(
struct
sock
*
sk
)
{
struct
sctp_opt
*
sp
;
sp
=
sctp_sk
(
sk
);
sp
->
pd_mode
=
0
;
if
(
!
skb_queue_empty
(
&
sp
->
pd_lobby
))
{
struct
list_head
*
list
;
sctp_skb_list_tail
(
&
sp
->
pd_lobby
,
&
sk
->
receive_queue
);
list
=
(
struct
list_head
*
)
&
sctp_sk
(
sk
)
->
pd_lobby
;
INIT_LIST_HEAD
(
list
);
return
1
;
}
return
0
;
}
/* Clear the pd_mode and restart any pending messages waiting for delivery. */
static
int
sctp_ulpq_clear_pd
(
struct
sctp_ulpq
*
ulpq
)
{
ulpq
->
pd_mode
=
0
;
return
sctp_clear_pd
(
ulpq
->
asoc
->
base
.
sk
);
}
/* Add a new event for propogation to the ULP. */
/* Add a new event for propogation to the ULP. */
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
int
sctp_ulpq_tail_event
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
{
{
struct
sock
*
sk
=
ulpq
->
asoc
->
base
.
sk
;
struct
sock
*
sk
=
ulpq
->
asoc
->
base
.
sk
;
struct
sk_buff_head
*
queue
;
int
clear_pd
=
0
;
/* If the socket is just going to throw this away, do not
/* If the socket is just going to throw this away, do not
* even try to deliver it.
* even try to deliver it.
...
@@ -169,29 +196,55 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
...
@@ -169,29 +196,55 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
if
(
!
sctp_ulpevent_is_enabled
(
event
,
&
sctp_sk
(
sk
)
->
subscribe
))
if
(
!
sctp_ulpevent_is_enabled
(
event
,
&
sctp_sk
(
sk
)
->
subscribe
))
goto
out_free
;
goto
out_free
;
/* If we are in partial delivery mode, post to the lobby until
* partial delivery is cleared, unless, of course _this_ is
* the association the cause of the partial delivery.
*/
if
(
!
sctp_sk
(
sk
)
->
pd_mode
)
{
queue
=
&
sk
->
receive_queue
;
}
else
if
(
ulpq
->
pd_mode
)
{
if
(
event
->
msg_flags
&
MSG_NOTIFICATION
)
queue
=
&
sctp_sk
(
sk
)
->
pd_lobby
;
else
{
clear_pd
=
event
->
msg_flags
&
MSG_EOR
;
queue
=
&
sk
->
receive_queue
;
}
}
else
queue
=
&
sctp_sk
(
sk
)
->
pd_lobby
;
/* If we are harvesting multiple skbs they will be
/* If we are harvesting multiple skbs they will be
* collected on a list.
* collected on a list.
*/
*/
if
(
event
->
parent
->
list
)
if
(
sctp_event2skb
(
event
)
->
list
)
sctp_skb_list_tail
(
event
->
parent
->
list
,
&
sk
->
receive_
queue
);
sctp_skb_list_tail
(
sctp_event2skb
(
event
)
->
list
,
queue
);
else
else
skb_queue_tail
(
&
sk
->
receive_queue
,
event
->
parent
);
skb_queue_tail
(
queue
,
sctp_event2skb
(
event
)
);
wake_up_interruptible
(
sk
->
sleep
);
/* Did we just complete partial delivery and need to get
* rolling again? Move pending data to the receive
* queue.
*/
if
(
clear_pd
)
sctp_ulpq_clear_pd
(
ulpq
);
if
(
queue
==
&
sk
->
receive_queue
)
wake_up_interruptible
(
sk
->
sleep
);
return
1
;
return
1
;
out_free:
out_free:
if
(
event
->
parent
->
list
)
if
(
sctp_event2skb
(
event
)
->
list
)
skb_queue_purge
(
event
->
parent
->
list
);
skb_queue_purge
(
sctp_event2skb
(
event
)
->
list
);
else
else
kfree_skb
(
event
->
parent
);
kfree_skb
(
sctp_event2skb
(
event
)
);
return
0
;
return
0
;
}
}
/* 2nd Level Abstractions */
/* 2nd Level Abstractions */
/* Helper function to store chunks that need to be reassembled. */
/* Helper function to store chunks that need to be reassembled. */
static
inline
void
sctp_ulpq_store_reasm
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_store_reasm
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
struct
sctp_ulpevent
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
...
@@ -202,7 +255,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
...
@@ -202,7 +255,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
/* Find the right place in this list. We store them by TSN. */
/* Find the right place in this list. We store them by TSN. */
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
(
struct
sctp_ulpevent
*
)
pos
->
cb
;
cevent
=
sctp_skb2event
(
pos
)
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
if
(
TSN_lt
(
tsn
,
ctsn
))
if
(
TSN_lt
(
tsn
,
ctsn
))
...
@@ -211,9 +264,10 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
...
@@ -211,9 +264,10 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
/* If the queue is empty, we have a different function to call. */
/* If the queue is empty, we have a different function to call. */
if
(
skb_peek
(
&
ulpq
->
reasm
))
if
(
skb_peek
(
&
ulpq
->
reasm
))
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
__skb_insert
(
sctp_event2skb
(
event
),
pos
->
prev
,
pos
,
&
ulpq
->
reasm
);
else
else
__skb_queue_tail
(
&
ulpq
->
reasm
,
event
->
parent
);
__skb_queue_tail
(
&
ulpq
->
reasm
,
sctp_event2skb
(
event
)
);
}
}
/* Helper function to return an event corresponding to the reassembled
/* Helper function to return an event corresponding to the reassembled
...
@@ -231,7 +285,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -231,7 +285,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
struct
sk_buff
*
list
=
skb_shinfo
(
f_frag
)
->
frag_list
;
struct
sk_buff
*
list
=
skb_shinfo
(
f_frag
)
->
frag_list
;
/* Store the pointer to the 2nd skb */
/* Store the pointer to the 2nd skb */
pos
=
f_frag
->
next
;
if
(
f_frag
==
l_frag
)
pos
=
NULL
;
else
pos
=
f_frag
->
next
;
/* Get the last skb in the f_frag's frag_list if present. */
/* Get the last skb in the f_frag's frag_list if present. */
for
(
last
=
list
;
list
;
last
=
list
,
list
=
list
->
next
);
for
(
last
=
list
;
list
;
last
=
list
,
list
=
list
->
next
);
...
@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
/* Remove the first fragment from the reassembly queue. */
/* Remove the first fragment from the reassembly queue. */
__skb_unlink
(
f_frag
,
f_frag
->
list
);
__skb_unlink
(
f_frag
,
f_frag
->
list
);
do
{
while
(
pos
)
{
pnext
=
pos
->
next
;
pnext
=
pos
->
next
;
/* Update the len and data_len fields of the first fragment. */
/* Update the len and data_len fields of the first fragment. */
...
@@ -262,25 +320,26 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -262,25 +320,26 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
pos
->
next
=
pnext
;
pos
->
next
=
pnext
;
pos
=
pnext
;
pos
=
pnext
;
}
while
(
1
)
;
};
event
=
(
sctp_ulpevent_t
*
)
f_frag
->
cb
;
event
=
sctp_skb2event
(
f_frag
)
;
return
event
;
return
event
;
}
}
/* Helper function to check if an incoming chunk has filled up the last
/* Helper function to check if an incoming chunk has filled up the last
* missing fragment in a SCTP datagram and return the corresponding event.
* missing fragment in a SCTP datagram and return the corresponding event.
*/
*/
static
inline
s
ctp_ulpevent_
t
*
sctp_ulpq_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
static
inline
s
truct
sctp_ulpeven
t
*
sctp_ulpq_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
struct
sk_buff
*
first_frag
=
NULL
;
struct
sk_buff
*
first_frag
=
NULL
;
__u32
ctsn
,
next_tsn
;
__u32
ctsn
,
next_tsn
;
s
ctp_ulpevent_
t
*
retval
=
NULL
;
s
truct
sctp_ulpeven
t
*
retval
=
NULL
;
/* Initialized to 0 just to avoid compiler warning message. Will
/* Initialized to 0 just to avoid compiler warning message.
Will
* never be used with this value. It is referenced only after it
* never be used with this value. It is referenced only after it
* is set when we find the first fragment of a message.
* is set when we find the first fragment of a message.
*/
*/
...
@@ -296,10 +355,10 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
...
@@ -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.
* start the next pass when we find another first fragment.
*/
*/
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
(
sctp_ulpevent_t
*
)
pos
->
cb
;
cevent
=
sctp_skb2event
(
pos
)
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
switch
(
cevent
->
chunk
_flags
&
SCTP_DATA_FRAG_MASK
)
{
switch
(
cevent
->
msg
_flags
&
SCTP_DATA_FRAG_MASK
)
{
case
SCTP_DATA_FIRST_FRAG
:
case
SCTP_DATA_FIRST_FRAG
:
first_frag
=
pos
;
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
next_tsn
=
ctsn
+
1
;
...
@@ -313,7 +372,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
...
@@ -313,7 +372,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
break
;
break
;
case
SCTP_DATA_LAST_FRAG
:
case
SCTP_DATA_LAST_FRAG
:
if
(
(
first_frag
)
&&
(
ctsn
==
next_tsn
))
if
(
first_frag
&&
(
ctsn
==
next_tsn
))
retval
=
sctp_make_reassembled_event
(
retval
=
sctp_make_reassembled_event
(
first_frag
,
pos
);
first_frag
,
pos
);
else
else
...
@@ -324,42 +383,170 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
...
@@ -324,42 +383,170 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
/* We have the reassembled event. There is no need to look
/* We have the reassembled event. There is no need to look
* further.
* further.
*/
*/
if
(
retval
)
if
(
retval
)
{
retval
->
msg_flags
|=
MSG_EOR
;
break
;
break
;
}
}
}
return
retval
;
return
retval
;
}
}
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
/* Retrieve the next set of fragments of a partial message. */
* need reassembling.
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_partial
(
struct
sctp_ulpq
*
ulpq
)
*/
static
inline
sctp_ulpevent_t
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_t
*
event
)
{
{
sctp_ulpevent_t
*
retval
=
NULL
;
struct
sk_buff
*
pos
,
*
tmp
,
*
last_frag
,
*
first_frag
;
struct
sctp_ulpevent
*
cevent
;
__u32
ctsn
,
next_tsn
;
int
is_last
;
struct
sctp_ulpevent
*
retval
;
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for the first
* sequence of fragmented chunks.
*/
if
(
skb_queue_empty
(
&
ulpq
->
reasm
))
return
NULL
;
last_frag
=
first_frag
=
NULL
;
retval
=
NULL
;
next_tsn
=
0
;
is_last
=
0
;
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
switch
(
cevent
->
msg_flags
&
SCTP_DATA_FRAG_MASK
)
{
case
SCTP_DATA_MIDDLE_FRAG
:
if
(
!
first_frag
)
{
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
last_frag
=
pos
;
}
else
if
(
next_tsn
==
ctsn
)
next_tsn
++
;
else
goto
done
;
break
;
case
SCTP_DATA_LAST_FRAG
:
if
(
!
first_frag
)
first_frag
=
pos
;
else
if
(
ctsn
!=
next_tsn
)
goto
done
;
last_frag
=
pos
;
is_last
=
1
;
goto
done
;
default:
return
NULL
;
};
}
/* FIXME: We should be using some new chunk structure here
/* We have the reassembled event. There is no need to look
* instead of carrying chunk fields in the event structure.
* further.
* This is temporary as it is too painful to change everything
* at once.
*/
*/
done:
retval
=
sctp_make_reassembled_event
(
first_frag
,
last_frag
);
if
(
is_last
)
retval
->
msg_flags
|=
MSG_EOR
;
return
retval
;
}
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
* need reassembling.
*/
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_reasm
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
{
struct
sctp_ulpevent
*
retval
=
NULL
;
/* Check if this is part of a fragmented message. */
/* Check if this is part of a fragmented message. */
if
(
SCTP_DATA_NOT_FRAG
==
(
event
->
chunk_flags
&
SCTP_DATA_FRAG_MASK
))
if
(
SCTP_DATA_NOT_FRAG
==
(
event
->
msg_flags
&
SCTP_DATA_FRAG_MASK
))
{
event
->
msg_flags
|=
MSG_EOR
;
return
event
;
return
event
;
}
sctp_ulpq_store_reasm
(
ulpq
,
event
);
sctp_ulpq_store_reasm
(
ulpq
,
event
);
retval
=
sctp_ulpq_retrieve_reassembled
(
ulpq
);
if
(
!
ulpq
->
pd_mode
)
retval
=
sctp_ulpq_retrieve_reassembled
(
ulpq
);
else
{
__u32
ctsn
,
ctsnap
;
/* Do not even bother unless this is the next tsn to
* be delivered.
*/
ctsn
=
event
->
sndrcvinfo
.
sinfo_tsn
;
ctsnap
=
sctp_tsnmap_get_ctsn
(
&
ulpq
->
asoc
->
peer
.
tsn_map
);
if
(
TSN_lte
(
ctsn
,
ctsnap
))
retval
=
sctp_ulpq_retrieve_partial
(
ulpq
);
}
return
retval
;
return
retval
;
}
}
/* Retrieve the first part (sequential fragments) for partial delivery. */
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_first
(
struct
sctp_ulpq
*
ulpq
)
{
struct
sk_buff
*
pos
,
*
tmp
,
*
last_frag
,
*
first_frag
;
struct
sctp_ulpevent
*
cevent
;
__u32
ctsn
,
next_tsn
;
struct
sctp_ulpevent
*
retval
;
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for a sequence of
* fragmented chunks that start a datagram.
*/
if
(
skb_queue_empty
(
&
ulpq
->
reasm
))
return
NULL
;
last_frag
=
first_frag
=
NULL
;
retval
=
NULL
;
next_tsn
=
0
;
sctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
switch
(
cevent
->
msg_flags
&
SCTP_DATA_FRAG_MASK
)
{
case
SCTP_DATA_FIRST_FRAG
:
if
(
!
first_frag
)
{
first_frag
=
pos
;
next_tsn
=
ctsn
+
1
;
last_frag
=
pos
;
}
else
goto
done
;
break
;
case
SCTP_DATA_MIDDLE_FRAG
:
if
(
!
first_frag
)
return
NULL
;
if
(
ctsn
==
next_tsn
)
{
next_tsn
++
;
last_frag
=
pos
;
}
else
goto
done
;
break
;
default:
return
NULL
;
};
}
/* We have the reassembled event. There is no need to look
* further.
*/
done:
retval
=
sctp_make_reassembled_event
(
first_frag
,
last_frag
);
return
retval
;
}
/* Helper function to gather skbs that have possibly become
/* Helper function to gather skbs that have possibly become
* ordered by an an incoming chunk.
* ordered by an an incoming chunk.
*/
*/
static
inline
void
sctp_ulpq_retrieve_ordered
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_retrieve_ordered
(
struct
sctp_ulpq
*
ulpq
,
s
ctp_ulpevent_
t
*
event
)
s
truct
sctp_ulpeven
t
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
...
@@ -373,7 +560,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
...
@@ -373,7 +560,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* We are holding the chunks by stream, by SSN. */
/* We are holding the chunks by stream, by SSN. */
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
cevent
=
(
s
ctp_ulpevent_
t
*
)
pos
->
cb
;
cevent
=
(
s
truct
sctp_ulpeven
t
*
)
pos
->
cb
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
@@ -390,32 +577,31 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
...
@@ -390,32 +577,31 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* Found it, so mark in the ssnmap. */
/* Found it, so mark in the ssnmap. */
sctp_ssn_next
(
in
,
sid
);
sctp_ssn_next
(
in
,
sid
);
__skb_unlink
(
pos
,
pos
->
list
);
__skb_unlink
(
pos
,
pos
->
list
);
/* Attach all gathered skbs to the event. */
/* Attach all gathered skbs to the event. */
__skb_queue_tail
(
event
->
parent
->
list
,
pos
);
__skb_queue_tail
(
sctp_event2skb
(
event
)
->
list
,
pos
);
}
}
}
}
/* Helper function to store chunks needing ordering. */
/* Helper function to store chunks needing ordering. */
static
inline
void
sctp_ulpq_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
s
ctp_ulpevent_
t
*
event
)
s
truct
sctp_ulpeven
t
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
,
*
tmp
;
s
ctp_ulpevent_
t
*
cevent
;
s
truct
sctp_ulpeven
t
*
cevent
;
__u16
sid
,
csid
;
__u16
sid
,
csid
;
__u16
ssn
,
cssn
;
__u16
ssn
,
cssn
;
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
sid
=
event
->
sndrcvinfo
.
sinfo_stream
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
ssn
=
event
->
sndrcvinfo
.
sinfo_ssn
;
/* Find the right place in this list. We store them by
/* Find the right place in this list. We store them by
* stream ID and then by SSN.
* stream ID and then by SSN.
*/
*/
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
sctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
cevent
=
(
s
ctp_ulpevent_
t
*
)
pos
->
cb
;
cevent
=
(
s
truct
sctp_ulpeven
t
*
)
pos
->
cb
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
@@ -427,25 +613,20 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
...
@@ -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 the queue is empty, we have a different function to call. */
if
(
skb_peek
(
&
ulpq
->
lobby
))
if
(
skb_peek
(
&
ulpq
->
lobby
))
__skb_insert
(
event
->
parent
,
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
__skb_insert
(
sctp_event2skb
(
event
),
pos
->
prev
,
pos
,
&
ulpq
->
lobby
);
else
else
__skb_queue_tail
(
&
ulpq
->
lobby
,
event
->
parent
);
__skb_queue_tail
(
&
ulpq
->
lobby
,
sctp_event2skb
(
event
)
);
}
}
static
inline
s
ctp_ulpevent_
t
*
sctp_ulpq_order
(
struct
sctp_ulpq
*
ulpq
,
static
inline
s
truct
sctp_ulpeven
t
*
sctp_ulpq_order
(
struct
sctp_ulpq
*
ulpq
,
sctp_ulpevent_
t
*
event
)
struct
sctp_ulpeven
t
*
event
)
{
{
__u16
sid
,
ssn
;
__u16
sid
,
ssn
;
struct
sctp_stream
*
in
;
struct
sctp_stream
*
in
;
/* FIXME: We should be using some new chunk structure here
* instead of carrying chunk fields in the event structure.
* This is temporary as it is too painful to change everything
* at once.
*/
/* Check if this message needs ordering. */
/* Check if this message needs ordering. */
if
(
SCTP_DATA_UNORDERED
&
event
->
chunk
_flags
)
if
(
SCTP_DATA_UNORDERED
&
event
->
msg
_flags
)
return
event
;
return
event
;
/* Note: The stream ID must be verified before this routine. */
/* Note: The stream ID must be verified before this routine. */
...
@@ -472,3 +653,54 @@ static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq,
...
@@ -472,3 +653,54 @@ static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq,
return
event
;
return
event
;
}
}
/* Partial deliver the first message as there is pressure on rwnd. */
void
sctp_ulpq_partial_delivery
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_chunk
*
chunk
,
int
priority
)
{
struct
sctp_ulpevent
*
event
;
/* Are we already in partial delivery mode? */
if
(
!
sctp_sk
(
ulpq
->
asoc
->
base
.
sk
)
->
pd_mode
)
{
/* Is partial delivery possible? */
event
=
sctp_ulpq_retrieve_first
(
ulpq
);
/* Send event to the ULP. */
if
(
event
)
{
sctp_ulpq_tail_event
(
ulpq
,
event
);
sctp_sk
(
ulpq
->
asoc
->
base
.
sk
)
->
pd_mode
=
1
;
ulpq
->
pd_mode
=
1
;
return
;
}
}
/* Assert: Either already in partial delivery mode or partial
* delivery wasn't possible, so now the only recourse is
* to renege. FIXME: Add renege support starts here.
*/
}
/* Notify the application if an association is aborted and in
* partial delivery mode. Send up any pending received messages.
*/
void
sctp_ulpq_abort_pd
(
struct
sctp_ulpq
*
ulpq
,
int
priority
)
{
struct
sctp_ulpevent
*
ev
=
NULL
;
struct
sock
*
sk
;
if
(
!
ulpq
->
pd_mode
)
return
;
sk
=
ulpq
->
asoc
->
base
.
sk
;
if
(
sctp_ulpevent_type_enabled
(
SCTP_PARTIAL_DELIVERY_EVENT
,
&
sctp_sk
(
sk
)
->
subscribe
))
ev
=
sctp_ulpevent_make_pdapi
(
ulpq
->
asoc
,
SCTP_PARTIAL_DELIVERY_ABORTED
,
priority
);
if
(
ev
)
skb_queue_tail
(
&
sk
->
receive_queue
,
sctp_event2skb
(
ev
));
/* If there is data waiting, send it up the socket now. */
if
(
sctp_ulpq_clear_pd
(
ulpq
)
||
ev
)
wake_up_interruptible
(
sk
->
sleep
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment