Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
e5e956d0
Commit
e5e956d0
authored
Mar 05, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Plain Diff
Merge us.ibm.com:/home/sridhar/BK/linux-2.5.64
into us.ibm.com:/home/sridhar/BK/lksctp-2.5.64
parents
236b5445
56d10bed
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1057 additions
and
529 deletions
+1057
-529
include/net/sctp/command.h
include/net/sctp/command.h
+8
-8
include/net/sctp/constants.h
include/net/sctp/constants.h
+14
-8
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+13
-36
include/net/sctp/sm.h
include/net/sctp/sm.h
+23
-23
include/net/sctp/structs.h
include/net/sctp/structs.h
+27
-29
include/net/sctp/user.h
include/net/sctp/user.h
+2
-0
net/sctp/associola.c
net/sctp/associola.c
+48
-23
net/sctp/bind_addr.c
net/sctp/bind_addr.c
+1
-1
net/sctp/endpointola.c
net/sctp/endpointola.c
+5
-2
net/sctp/ipv6.c
net/sctp/ipv6.c
+87
-4
net/sctp/output.c
net/sctp/output.c
+60
-43
net/sctp/outqueue.c
net/sctp/outqueue.c
+80
-55
net/sctp/protocol.c
net/sctp/protocol.c
+107
-24
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+24
-30
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+30
-10
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+16
-18
net/sctp/socket.c
net/sctp/socket.c
+485
-185
net/sctp/sysctl.c
net/sctp/sysctl.c
+1
-1
net/sctp/transport.c
net/sctp/transport.c
+2
-2
net/sctp/tsnmap.c
net/sctp/tsnmap.c
+2
-2
net/sctp/ulpqueue.c
net/sctp/ulpqueue.c
+22
-25
No files found.
include/net/sctp/command.h
View file @
e5e956d0
...
@@ -110,13 +110,13 @@ typedef union {
...
@@ -110,13 +110,13 @@ typedef union {
sctp_event_timeout_t
to
;
sctp_event_timeout_t
to
;
sctp_counter_t
counter
;
sctp_counter_t
counter
;
void
*
ptr
;
void
*
ptr
;
s
ctp_chunk_t
*
chunk
;
s
truct
sctp_chunk
*
chunk
;
s
ctp_association_t
*
asoc
;
s
truct
sctp_association
*
asoc
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
s
ctp_bind_addr_t
*
bp
;
s
truct
sctp_bind_addr
*
bp
;
sctp_init_chunk_t
*
init
;
sctp_init_chunk_t
*
init
;
struct
sctp_ulpevent
*
ulpevent
;
struct
sctp_ulpevent
*
ulpevent
;
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
sctp_sackhdr_t
*
sackh
;
sctp_sackhdr_t
*
sackh
;
}
sctp_arg_t
;
}
sctp_arg_t
;
...
@@ -158,13 +158,13 @@ SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state)
...
@@ -158,13 +158,13 @@ SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state)
SCTP_ARG_CONSTRUCTOR
(
COUNTER
,
sctp_counter_t
,
counter
)
SCTP_ARG_CONSTRUCTOR
(
COUNTER
,
sctp_counter_t
,
counter
)
SCTP_ARG_CONSTRUCTOR
(
TO
,
sctp_event_timeout_t
,
to
)
SCTP_ARG_CONSTRUCTOR
(
TO
,
sctp_event_timeout_t
,
to
)
SCTP_ARG_CONSTRUCTOR
(
PTR
,
void
*
,
ptr
)
SCTP_ARG_CONSTRUCTOR
(
PTR
,
void
*
,
ptr
)
SCTP_ARG_CONSTRUCTOR
(
CHUNK
,
s
ctp_chunk_t
*
,
chunk
)
SCTP_ARG_CONSTRUCTOR
(
CHUNK
,
s
truct
sctp_chunk
*
,
chunk
)
SCTP_ARG_CONSTRUCTOR
(
ASOC
,
s
ctp_association_t
*
,
asoc
)
SCTP_ARG_CONSTRUCTOR
(
ASOC
,
s
truct
sctp_association
*
,
asoc
)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
TRANSPORT
,
struct
sctp_transport
*
,
transport
)
SCTP_ARG_CONSTRUCTOR
(
BA
,
s
ctp_bind_addr_t
*
,
bp
)
SCTP_ARG_CONSTRUCTOR
(
BA
,
s
truct
sctp_bind_addr
*
,
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
,
struct
sctp_ulpevent
*
,
ulpevent
)
SCTP_ARG_CONSTRUCTOR
(
ULPEVENT
,
struct
sctp_ulpevent
*
,
ulpevent
)
SCTP_ARG_CONSTRUCTOR
(
PACKET
,
s
ctp_packet_
t
*
,
packet
)
SCTP_ARG_CONSTRUCTOR
(
PACKET
,
s
truct
sctp_packe
t
*
,
packet
)
SCTP_ARG_CONSTRUCTOR
(
SACKH
,
sctp_sackhdr_t
*
,
sackh
)
SCTP_ARG_CONSTRUCTOR
(
SACKH
,
sctp_sackhdr_t
*
,
sackh
)
typedef
struct
{
typedef
struct
{
...
...
include/net/sctp/constants.h
View file @
e5e956d0
...
@@ -210,14 +210,19 @@ typedef enum {
...
@@ -210,14 +210,19 @@ typedef enum {
/* These are values for sk->state.
/* These are values for sk->state.
* For a UDP-style SCTP socket, the states are defined as follows
* For a UDP-style SCTP socket, the states are defined as follows
* (at this point of time, may change later after more discussions: FIXME)
* - A socket in SCTP_SS_CLOSED state indicates that it is not willing to
* A socket in SCTP_SS_UNCONNECTED state indicates that it is not willing
* accept new associations, but it can initiate the creation of new ones.
* to accept new associations, but it can initiate the creation of new
* - A socket in SCTP_SS_LISTENING state indicates that it is willing to
* ones.
* A socket in SCTP_SS_LISTENING state indicates that it is willing to
* accept new associations and can initiate the creation of new ones.
* accept new associations and can initiate the creation of new ones.
* A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off
*
-
A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off
* socket with one association.
* socket with one association.
* For a TCP-style SCTP socket, the states are defined as follows
* - A socket in SCTP_SS_CLOSED state indicates that it is not willing to
* accept new associations, but it can initiate the creation of new ones.
* - A socket in SCTP_SS_LISTENING state indicates that it is willing to
* accept new associations, but cannot initiate the creation of new ones.
* - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single
* association in ESTABLISHED state.
*/
*/
typedef
enum
{
typedef
enum
{
SCTP_SS_CLOSED
=
TCP_CLOSE
,
SCTP_SS_CLOSED
=
TCP_CLOSE
,
...
@@ -345,6 +350,7 @@ typedef enum {
...
@@ -345,6 +350,7 @@ typedef enum {
SCTP_XMIT_PMTU_FULL
,
SCTP_XMIT_PMTU_FULL
,
SCTP_XMIT_RWND_FULL
,
SCTP_XMIT_RWND_FULL
,
SCTP_XMIT_MUST_FRAG
,
SCTP_XMIT_MUST_FRAG
,
SCTP_XMIT_NAGLE_DELAY
,
}
sctp_xmit_t
;
}
sctp_xmit_t
;
/* These are the commands for manipulating transports. */
/* These are the commands for manipulating transports. */
...
...
include/net/sctp/sctp.h
View file @
e5e956d0
...
@@ -121,9 +121,10 @@
...
@@ -121,9 +121,10 @@
/*
/*
* sctp_protocol.c
* sctp_protocol.c
*/
*/
extern
s
ctp_protocol_t
sctp_proto
;
extern
s
truct
sctp_protocol
sctp_proto
;
extern
struct
sock
*
sctp_get_ctl_sock
(
void
);
extern
struct
sock
*
sctp_get_ctl_sock
(
void
);
extern
int
sctp_copy_local_addr_list
(
sctp_protocol_t
*
,
sctp_bind_addr_t
*
,
extern
int
sctp_copy_local_addr_list
(
struct
sctp_protocol
*
,
struct
sctp_bind_addr
*
,
sctp_scope_t
,
int
priority
,
int
flags
);
sctp_scope_t
,
int
priority
,
int
flags
);
extern
struct
sctp_pf
*
sctp_get_pf_specific
(
sa_family_t
family
);
extern
struct
sctp_pf
*
sctp_get_pf_specific
(
sa_family_t
family
);
extern
int
sctp_register_pf
(
struct
sctp_pf
*
,
sa_family_t
);
extern
int
sctp_register_pf
(
struct
sctp_pf
*
,
sa_family_t
);
...
@@ -312,30 +313,21 @@ static inline void sctp_sysctl_unregister(void) { return; }
...
@@ -312,30 +313,21 @@ static inline void sctp_sysctl_unregister(void) { return; }
#endif
#endif
/* Size of Supported Address Parameter for 'x' address types. */
#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
extern
int
sctp_v6_init
(
void
);
extern
int
sctp_v6_init
(
void
);
extern
void
sctp_v6_exit
(
void
);
extern
void
sctp_v6_exit
(
void
);
static
inline
int
sctp_ipv6_addr_type
(
const
struct
in6_addr
*
addr
)
static
inline
int
sctp_ipv6_addr_type
(
const
struct
in6_addr
*
addr
)
{
{
return
ipv6_addr_type
((
struct
in6_addr
*
)
addr
);
return
ipv6_addr_type
((
struct
in6_addr
*
)
addr
);
}
}
#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(__u16))
/* Note: These V6 macros are obsolescent. */
/* Use this macro to enclose code fragments which are V6-dependent. */
#define SCTP_V6(m...) m
#define SCTP_V6_SUPPORT 1
#else
/* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
#else
/* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
#define sctp_ipv6_addr_type(a) 0
#define sctp_ipv6_addr_type(a) 0
#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(__u16))
#define SCTP_V6(m...)
/* Do nothing. */
#undef SCTP_V6_SUPPORT
static
inline
int
sctp_v6_init
(
void
)
{
return
0
;
}
static
inline
int
sctp_v6_init
(
void
)
{
return
0
;
}
static
inline
void
sctp_v6_exit
(
void
)
{
return
;
}
static
inline
void
sctp_v6_exit
(
void
)
{
return
;
}
...
@@ -348,25 +340,10 @@ static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc)
...
@@ -348,25 +340,10 @@ static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc)
return
(
sctp_assoc_t
)
asoc
;
return
(
sctp_assoc_t
)
asoc
;
}
}
/* Look up the association by its id. */
static
inline
sctp_association_t
*
sctp_id2assoc
(
const
struct
sock
*
sk
,
sctp_assoc_t
id
)
{
sctp_association_t
*
asoc
=
NULL
;
/* First, verify that this is a kernel address. */
if
(
sctp_is_valid_kaddr
((
unsigned
long
)
id
))
{
sctp_association_t
*
temp
=
(
sctp_association_t
*
)
id
;
/* Verify that this _is_ an sctp_association_t
/* Look up the association by its id. */
* data structure and if so, that the socket matches.
sctp_association_t
*
sctp_id2assoc
(
struct
sock
*
sk
,
sctp_assoc_t
id
);
*/
if
((
SCTP_ASSOC_EYECATCHER
==
temp
->
eyecatcher
)
&&
(
temp
->
base
.
sk
==
sk
))
asoc
=
temp
;
}
return
asoc
;
}
/* A macro to walk a list of skbs. */
/* A macro to walk a list of skbs. */
#define sctp_skb_for_each(pos, head, tmp) \
#define sctp_skb_for_each(pos, head, tmp) \
...
@@ -494,7 +471,7 @@ extern void sctp_put_port(struct sock *sk);
...
@@ -494,7 +471,7 @@ extern void sctp_put_port(struct sock *sk);
/* Static inline functions. */
/* Static inline functions. */
/* Return the SCTP protocol structure. */
/* Return the SCTP protocol structure. */
static
inline
s
ctp_protocol_t
*
sctp_get_protocol
(
void
)
static
inline
s
truct
sctp_protocol
*
sctp_get_protocol
(
void
)
{
{
return
&
sctp_proto
;
return
&
sctp_proto
;
}
}
...
@@ -523,21 +500,21 @@ static inline int ipver2af(__u8 ipver)
...
@@ -523,21 +500,21 @@ static inline int ipver2af(__u8 ipver)
/* This is the hash function for the SCTP port hash table. */
/* This is the hash function for the SCTP port hash table. */
static
inline
int
sctp_phashfn
(
__u16
lport
)
static
inline
int
sctp_phashfn
(
__u16
lport
)
{
{
s
ctp_protocol_t
*
sctp_proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
return
(
lport
&
(
sctp_proto
->
port_hashsize
-
1
));
return
(
lport
&
(
sctp_proto
->
port_hashsize
-
1
));
}
}
/* This is the hash function for the endpoint hash table. */
/* This is the hash function for the endpoint hash table. */
static
inline
int
sctp_ep_hashfn
(
__u16
lport
)
static
inline
int
sctp_ep_hashfn
(
__u16
lport
)
{
{
s
ctp_protocol_t
*
sctp_proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
return
(
lport
&
(
sctp_proto
->
ep_hashsize
-
1
));
return
(
lport
&
(
sctp_proto
->
ep_hashsize
-
1
));
}
}
/* This is the hash function for the association hash table. */
/* This is the hash function for the association hash table. */
static
inline
int
sctp_assoc_hashfn
(
__u16
lport
,
__u16
rport
)
static
inline
int
sctp_assoc_hashfn
(
__u16
lport
,
__u16
rport
)
{
{
s
ctp_protocol_t
*
sctp_proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
int
h
=
(
lport
<<
16
)
+
rport
;
int
h
=
(
lport
<<
16
)
+
rport
;
h
^=
h
>>
8
;
h
^=
h
>>
8
;
return
(
h
&
(
sctp_proto
->
assoc_hashsize
-
1
));
return
(
h
&
(
sctp_proto
->
assoc_hashsize
-
1
));
...
@@ -549,7 +526,7 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
...
@@ -549,7 +526,7 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
*/
*/
static
inline
int
sctp_vtag_hashfn
(
__u16
lport
,
__u16
rport
,
__u32
vtag
)
static
inline
int
sctp_vtag_hashfn
(
__u16
lport
,
__u16
rport
,
__u32
vtag
)
{
{
s
ctp_protocol_t
*
sctp_proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
int
h
=
(
lport
<<
16
)
+
rport
;
int
h
=
(
lport
<<
16
)
+
rport
;
h
^=
vtag
;
h
^=
vtag
;
return
(
h
&
(
sctp_proto
->
assoc_hashsize
-
1
));
return
(
h
&
(
sctp_proto
->
assoc_hashsize
-
1
));
...
...
include/net/sctp/sm.h
View file @
e5e956d0
...
@@ -313,18 +313,18 @@ void sctp_generate_t3_rtx_event(unsigned long peer);
...
@@ -313,18 +313,18 @@ void sctp_generate_t3_rtx_event(unsigned long peer);
void
sctp_generate_heartbeat_event
(
unsigned
long
peer
);
void
sctp_generate_heartbeat_event
(
unsigned
long
peer
);
sctp_sackhdr_t
*
sctp_sm_pull_sack
(
sctp_chunk_t
*
);
sctp_sackhdr_t
*
sctp_sm_pull_sack
(
sctp_chunk_t
*
);
s
ctp_packet_t
*
sctp_abort_pkt_new
(
const
sctp_endpoint_t
*
ep
,
s
truct
sctp_packet
*
sctp_abort_pkt_new
(
const
struct
sctp_endpoint
*
,
const
sctp_association_t
*
asoc
,
const
struct
sctp_association
*
,
sctp_chunk_t
*
chunk
,
struct
sctp_chunk
*
chunk
,
const
void
*
payload
,
const
void
*
payload
,
size_t
paylen
);
size_t
paylen
);
s
ctp_packet_t
*
sctp_ootb_pkt_new
(
const
sctp_association_t
*
asoc
,
s
truct
sctp_packet
*
sctp_ootb_pkt_new
(
const
struct
sctp_association
*
,
const
sctp_chunk_t
*
chunk
);
const
struct
sctp_chunk
*
);
void
sctp_ootb_pkt_free
(
s
ctp_packet_t
*
packet
);
void
sctp_ootb_pkt_free
(
s
truct
sctp_packet
*
);
sctp_cookie_param_t
*
sctp_cookie_param_t
*
sctp_pack_cookie
(
const
s
ctp_endpoint_t
*
,
const
sctp_association_t
*
,
sctp_pack_cookie
(
const
s
truct
sctp_endpoint
*
,
const
struct
sctp_association
*
,
const
s
ctp_chunk_t
*
,
int
*
cookie_len
,
const
s
truct
sctp_chunk
*
,
int
*
cookie_len
,
const
__u8
*
,
int
addrs_len
);
const
__u8
*
,
int
addrs_len
);
sctp_association_t
*
sctp_unpack_cookie
(
const
sctp_endpoint_t
*
,
sctp_association_t
*
sctp_unpack_cookie
(
const
sctp_endpoint_t
*
,
const
sctp_association_t
*
,
const
sctp_association_t
*
,
...
...
include/net/sctp/structs.h
View file @
e5e956d0
...
@@ -86,10 +86,8 @@ struct sctp_opt;
...
@@ -86,10 +86,8 @@ 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_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_chunk
sctp_chunk_t
;
typedef
struct
sctp_chunk
sctp_chunk_t
;
typedef
struct
sctp_bind_addr
sctp_bind_addr_t
;
typedef
struct
sctp_bind_addr
sctp_bind_addr_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
typedef
struct
sctp_endpoint_common
sctp_endpoint_common_t
;
...
@@ -262,6 +260,9 @@ struct sctp_pf {
...
@@ -262,6 +260,9 @@ struct sctp_pf {
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
struct
sctp_opt
*
);
struct
sctp_opt
*
);
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
int
(
*
supported_addrs
)(
const
struct
sctp_opt
*
,
__u16
*
);
struct
sock
*
(
*
create_accept_sk
)
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
);
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
};
};
...
@@ -366,8 +367,6 @@ typedef struct sctp_signed_cookie {
...
@@ -366,8 +367,6 @@ typedef struct sctp_signed_cookie {
sctp_cookie_t
c
;
sctp_cookie_t
c
;
}
sctp_signed_cookie_t
;
}
sctp_signed_cookie_t
;
/* This is another convenience type to allocate memory for address
/* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around
* params for the maximum size and pass such structures around
* internally.
* internally.
...
@@ -604,26 +603,26 @@ struct sctp_packet {
...
@@ -604,26 +603,26 @@ struct sctp_packet {
typedef
int
(
sctp_outq_thandler_t
)(
struct
sctp_outq
*
,
void
*
);
typedef
int
(
sctp_outq_thandler_t
)(
struct
sctp_outq
*
,
void
*
);
typedef
int
(
sctp_outq_ehandler_t
)(
struct
sctp_outq
*
);
typedef
int
(
sctp_outq_ehandler_t
)(
struct
sctp_outq
*
);
typedef
s
ctp_packet_
t
*
(
sctp_outq_ohandler_init_t
)
typedef
s
truct
sctp_packe
t
*
(
sctp_outq_ohandler_init_t
)
(
s
ctp_packet_
t
*
,
(
s
truct
sctp_packe
t
*
,
struct
sctp_transport
*
,
struct
sctp_transport
*
,
__u16
sport
,
__u16
sport
,
__u16
dport
);
__u16
dport
);
typedef
s
ctp_packet_
t
*
(
sctp_outq_ohandler_config_t
)
typedef
s
truct
sctp_packe
t
*
(
sctp_outq_ohandler_config_t
)
(
s
ctp_packet_
t
*
,
(
s
truct
sctp_packe
t
*
,
__u32
vtag
,
__u32
vtag
,
int
ecn_capable
,
int
ecn_capable
,
sctp_packet_phandler_t
*
get_prepend_chunk
);
sctp_packet_phandler_t
*
get_prepend_chunk
);
typedef
sctp_xmit_t
(
sctp_outq_ohandler_t
)(
s
ctp_packet_
t
*
,
typedef
sctp_xmit_t
(
sctp_outq_ohandler_t
)(
s
truct
sctp_packe
t
*
,
sctp_chunk_t
*
);
sctp_chunk_t
*
);
typedef
int
(
sctp_outq_ohandler_force_t
)(
s
ctp_packet_
t
*
);
typedef
int
(
sctp_outq_ohandler_force_t
)(
s
truct
sctp_packe
t
*
);
sctp_outq_ohandler_init_t
sctp_packet_init
;
sctp_outq_ohandler_init_t
sctp_packet_init
;
sctp_outq_ohandler_config_t
sctp_packet_config
;
sctp_outq_ohandler_config_t
sctp_packet_config
;
sctp_outq_ohandler_t
sctp_packet_append_chunk
;
sctp_outq_ohandler_t
sctp_packet_append_chunk
;
sctp_outq_ohandler_t
sctp_packet_transmit_chunk
;
sctp_outq_ohandler_t
sctp_packet_transmit_chunk
;
sctp_outq_ohandler_force_t
sctp_packet_transmit
;
sctp_outq_ohandler_force_t
sctp_packet_transmit
;
void
sctp_packet_free
(
s
ctp_packet_
t
*
);
void
sctp_packet_free
(
s
truct
sctp_packe
t
*
);
/* This represents a remote transport address.
/* This represents a remote transport address.
...
@@ -789,7 +788,7 @@ struct sctp_transport {
...
@@ -789,7 +788,7 @@ struct sctp_transport {
struct
list_head
transmitted
;
struct
list_head
transmitted
;
/* We build bundle-able packets for this transport here. */
/* We build bundle-able packets for this transport here. */
s
ctp_packet_
t
packet
;
s
truct
sctp_packe
t
packet
;
/* This is the list of transports that have chunks to send. */
/* This is the list of transports that have chunks to send. */
struct
list_head
send_ready
;
struct
list_head
send_ready
;
...
@@ -865,12 +864,11 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
...
@@ -865,12 +864,11 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
struct
sctp_outq
{
struct
sctp_outq
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
/* BUG: This really should be an array of streams.
/* Data pending that has never been transmitted. */
* This really holds a list of chunks (one stream).
* FIXME: If true, why so?
*/
struct
sk_buff_head
out
;
struct
sk_buff_head
out
;
unsigned
out_qlen
;
/* Total length of queued data chunks. */
/* These are control chunks we want to send. */
/* These are control chunks we want to send. */
struct
sk_buff_head
control
;
struct
sk_buff_head
control
;
...
@@ -885,7 +883,7 @@ struct sctp_outq {
...
@@ -885,7 +883,7 @@ struct sctp_outq {
struct
list_head
retransmit
;
struct
list_head
retransmit
;
/* Call these functions to send chunks down to the next lower
/* Call these functions to send chunks down to the next lower
* layer. This is always
SCTP
_packet, but we separate the two
* layer. This is always
sctp
_packet, but we separate the two
* structures to make testing simpler.
* structures to make testing simpler.
*/
*/
sctp_outq_ohandler_init_t
*
init_output
;
sctp_outq_ohandler_init_t
*
init_output
;
...
@@ -1098,8 +1096,9 @@ static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base)
...
@@ -1098,8 +1096,9 @@ static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base)
}
}
/* These are function signatures for manipulating endpoints. */
/* These are function signatures for manipulating endpoints. */
sctp_endpoint_t
*
sctp_endpoint_new
(
sctp_protocol_t
*
,
struct
sock
*
,
int
);
sctp_endpoint_t
*
sctp_endpoint_new
(
struct
sctp_protocol
*
,
struct
sock
*
,
int
);
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
,
sctp_protocol_t
*
,
sctp_endpoint_t
*
sctp_endpoint_init
(
struct
sctp_endpoint
*
,
struct
sctp_protocol
*
,
struct
sock
*
,
int
priority
);
struct
sock
*
,
int
priority
);
void
sctp_endpoint_free
(
sctp_endpoint_t
*
);
void
sctp_endpoint_free
(
sctp_endpoint_t
*
);
void
sctp_endpoint_put
(
sctp_endpoint_t
*
);
void
sctp_endpoint_put
(
sctp_endpoint_t
*
);
...
@@ -1111,7 +1110,6 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
...
@@ -1111,7 +1110,6 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
int
sctp_endpoint_is_peeled_off
(
sctp_endpoint_t
*
,
const
union
sctp_addr
*
);
int
sctp_endpoint_is_peeled_off
(
sctp_endpoint_t
*
,
const
union
sctp_addr
*
);
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
const
union
sctp_addr
*
);
const
union
sctp_addr
*
);
int
sctp_has_association
(
const
union
sctp_addr
*
laddr
,
int
sctp_has_association
(
const
union
sctp_addr
*
laddr
,
const
union
sctp_addr
*
paddr
);
const
union
sctp_addr
*
paddr
);
...
@@ -1587,7 +1585,7 @@ struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *,
...
@@ -1587,7 +1585,7 @@ struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *,
struct
sctp_transport
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
struct
sctp_transport
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
const
union
sctp_addr
*
address
,
const
union
sctp_addr
*
address
,
const
int
priority
);
const
int
priority
);
void
sctp_assoc_control_transport
(
s
ctp_association_t
*
,
void
sctp_assoc_control_transport
(
s
truct
sctp_association
*
,
struct
sctp_transport
*
,
struct
sctp_transport
*
,
sctp_transport_cmd_t
,
sctp_sn_error_t
);
sctp_transport_cmd_t
,
sctp_sn_error_t
);
struct
sctp_transport
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
,
__u32
);
struct
sctp_transport
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
,
__u32
);
...
@@ -1597,14 +1595,14 @@ struct sctp_transport *sctp_assoc_is_match(sctp_association_t *,
...
@@ -1597,14 +1595,14 @@ struct sctp_transport *sctp_assoc_is_match(sctp_association_t *,
void
sctp_assoc_migrate
(
sctp_association_t
*
,
struct
sock
*
);
void
sctp_assoc_migrate
(
sctp_association_t
*
,
struct
sock
*
);
void
sctp_assoc_update
(
sctp_association_t
*
dst
,
sctp_association_t
*
src
);
void
sctp_assoc_update
(
sctp_association_t
*
dst
,
sctp_association_t
*
src
);
__u32
__sctp_association_get_next_tsn
(
sctp_association_t
*
);
__u32
sctp_association_get_next_tsn
(
struct
sctp_association
*
);
__u32
__sctp_association_get_tsn_block
(
sctp_association_t
*
,
int
);
__u32
sctp_association_get_tsn_block
(
struct
sctp_association
*
,
int
);
__u16
__sctp_association_get_next_ssn
(
sctp_association_t
*
,
__u16
sid
);
void
sctp_assoc_sync_pmtu
(
sctp_association_t
*
);
void
sctp_assoc_rwnd_increase
(
sctp_association_t
*
,
int
);
void
sctp_assoc_rwnd_decrease
(
sctp_association_t
*
,
int
);
void
sctp_assoc_sync_pmtu
(
struct
sctp_association
*
);
void
sctp_assoc_rwnd_increase
(
struct
sctp_association
*
,
int
);
void
sctp_assoc_rwnd_decrease
(
struct
sctp_association
*
,
int
);
void
sctp_assoc_set_primary
(
struct
sctp_association
*
,
struct
sctp_transport
*
);
int
sctp_assoc_set_bind_addr_from_ep
(
sctp_association_t
*
,
int
);
int
sctp_assoc_set_bind_addr_from_ep
(
sctp_association_t
*
,
int
);
int
sctp_assoc_set_bind_addr_from_cookie
(
sctp_association_t
*
,
int
sctp_assoc_set_bind_addr_from_cookie
(
sctp_association_t
*
,
sctp_cookie_t
*
,
int
);
sctp_cookie_t
*
,
int
);
...
...
include/net/sctp/user.h
View file @
e5e956d0
...
@@ -108,6 +108,8 @@ enum sctp_optname {
...
@@ -108,6 +108,8 @@ enum sctp_optname {
#define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM
#define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM
SCTP_GET_LOCAL_ADDRS
,
/* Get all local addresss. */
SCTP_GET_LOCAL_ADDRS
,
/* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
SCTP_NODELAY
,
/* Get/set nodelay option. */
#define SCTP_NODELAY SCTP_NODELAY
};
};
...
...
net/sctp/associola.c
View file @
e5e956d0
...
@@ -181,7 +181,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -181,7 +181,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
else
else
asoc
->
rwnd
=
sk
->
rcvbuf
;
asoc
->
rwnd
=
sk
->
rcvbuf
;
asoc
->
a_rwnd
=
0
;
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
rwnd_over
=
0
;
asoc
->
rwnd_over
=
0
;
...
@@ -360,9 +360,25 @@ static void sctp_association_destroy(sctp_association_t *asoc)
...
@@ -360,9 +360,25 @@ static void sctp_association_destroy(sctp_association_t *asoc)
}
}
}
}
/* Change the primary destination address for the peer. */
void
sctp_assoc_set_primary
(
struct
sctp_association
*
asoc
,
struct
sctp_transport
*
transport
)
{
asoc
->
peer
.
primary_path
=
transport
;
/* Set a default msg_name for events. */
memcpy
(
&
asoc
->
peer
.
primary_addr
,
&
transport
->
ipaddr
,
sizeof
(
union
sctp_addr
));
/* If the primary path is changing, assume that the
* user wants to use this new path.
*/
if
(
transport
->
active
)
asoc
->
peer
.
active_path
=
transport
;
}
/* Add a transport address to an association. */
/* Add a transport address to an association. */
struct
sctp_transport
*
sctp_assoc_add_peer
(
s
ctp_association_t
*
asoc
,
struct
sctp_transport
*
sctp_assoc_add_peer
(
s
truct
sctp_association
*
asoc
,
const
union
sctp_addr
*
addr
,
const
union
sctp_addr
*
addr
,
int
priority
)
int
priority
)
{
{
...
@@ -397,17 +413,16 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -397,17 +413,16 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
* If not and the current association PMTU is higher than the new
* If not and the current association PMTU is higher than the new
* peer's PMTU, reset the association PMTU to the new peer's PMTU.
* peer's PMTU, reset the association PMTU to the new peer's PMTU.
*/
*/
if
(
asoc
->
pmtu
)
{
if
(
asoc
->
pmtu
)
asoc
->
pmtu
=
min_t
(
int
,
peer
->
pmtu
,
asoc
->
pmtu
);
asoc
->
pmtu
=
min_t
(
int
,
peer
->
pmtu
,
asoc
->
pmtu
);
}
else
{
else
asoc
->
pmtu
=
peer
->
pmtu
;
asoc
->
pmtu
=
peer
->
pmtu
;
}
SCTP_DEBUG_PRINTK
(
"sctp_assoc_add_peer:association %p PMTU set to "
SCTP_DEBUG_PRINTK
(
"sctp_assoc_add_peer:association %p PMTU set to "
"%d
\n
"
,
asoc
,
asoc
->
pmtu
);
"%d
\n
"
,
asoc
,
asoc
->
pmtu
);
asoc
->
frag_point
=
asoc
->
pmtu
-
asoc
->
frag_point
=
asoc
->
pmtu
;
(
SCTP_IP_OVERHEAD
+
sizeof
(
sctp_data_chunk_t
)
);
asoc
->
frag_point
-=
SCTP_IP_OVERHEAD
+
sizeof
(
struct
sctp_data_chunk
);
/* The asoc->peer.port might not be meaningful yet, but
/* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway.
* initialize the packet structure anyway.
...
@@ -460,11 +475,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -460,11 +475,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
/* If we do not yet have a primary path, set one. */
/* If we do not yet have a primary path, set one. */
if
(
NULL
==
asoc
->
peer
.
primary_path
)
{
if
(
NULL
==
asoc
->
peer
.
primary_path
)
{
asoc
->
peer
.
primary_path
=
peer
;
sctp_assoc_set_primary
(
asoc
,
peer
);
/* Set a default msg_name for events. */
memcpy
(
&
asoc
->
peer
.
primary_addr
,
&
peer
->
ipaddr
,
sizeof
(
union
sctp_addr
));
asoc
->
peer
.
active_path
=
peer
;
asoc
->
peer
.
retran_path
=
peer
;
asoc
->
peer
.
retran_path
=
peer
;
}
}
...
@@ -603,7 +614,7 @@ void sctp_association_put(sctp_association_t *asoc)
...
@@ -603,7 +614,7 @@ void sctp_association_put(sctp_association_t *asoc)
/* Allocate the next TSN, Transmission Sequence Number, for the given
/* Allocate the next TSN, Transmission Sequence Number, for the given
* association.
* association.
*/
*/
__u32
__
sctp_association_get_next_tsn
(
sctp_association_t
*
asoc
)
__u32
sctp_association_get_next_tsn
(
sctp_association_t
*
asoc
)
{
{
/* From Section 1.6 Serial Number Arithmetic:
/* From Section 1.6 Serial Number Arithmetic:
* Transmission Sequence Numbers wrap around when they reach
* Transmission Sequence Numbers wrap around when they reach
...
@@ -618,7 +629,7 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *asoc)
...
@@ -618,7 +629,7 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *asoc)
}
}
/* Allocate 'num' TSNs by incrementing the association's TSN by num. */
/* Allocate 'num' TSNs by incrementing the association's TSN by num. */
__u32
__
sctp_association_get_tsn_block
(
sctp_association_t
*
asoc
,
int
num
)
__u32
sctp_association_get_tsn_block
(
sctp_association_t
*
asoc
,
int
num
)
{
{
__u32
retval
=
asoc
->
next_tsn
;
__u32
retval
=
asoc
->
next_tsn
;
...
@@ -983,6 +994,24 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
...
@@ -983,6 +994,24 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
__FUNCTION__
,
asoc
,
asoc
->
pmtu
,
asoc
->
frag_point
);
__FUNCTION__
,
asoc
,
asoc
->
pmtu
,
asoc
->
frag_point
);
}
}
/* Should we send a SACK to update our peer? */
static
inline
int
sctp_peer_needs_update
(
struct
sctp_association
*
asoc
)
{
switch
(
asoc
->
state
)
{
case
SCTP_STATE_ESTABLISHED
:
case
SCTP_STATE_SHUTDOWN_PENDING
:
case
SCTP_STATE_SHUTDOWN_RECEIVED
:
if
((
asoc
->
rwnd
>
asoc
->
a_rwnd
)
&&
((
asoc
->
rwnd
-
asoc
->
a_rwnd
)
>=
min_t
(
__u32
,
(
asoc
->
base
.
sk
->
rcvbuf
>>
1
),
asoc
->
pmtu
)))
return
1
;
break
;
default:
break
;
}
return
0
;
}
/* Increase asoc's rwnd by len and send any window update SACK if needed. */
/* Increase asoc's rwnd by len and send any window update SACK if needed. */
void
sctp_assoc_rwnd_increase
(
sctp_association_t
*
asoc
,
int
len
)
void
sctp_assoc_rwnd_increase
(
sctp_association_t
*
asoc
,
int
len
)
{
{
...
@@ -1009,10 +1038,8 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -1009,10 +1038,8 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
* 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
(
sctp_peer_needs_update
(
asoc
))
{
(
asoc
->
rwnd
>
asoc
->
a_rwnd
)
&&
asoc
->
a_rwnd
=
asoc
->
rwnd
;
((
asoc
->
rwnd
-
asoc
->
a_rwnd
)
>=
min_t
(
__u32
,
(
asoc
->
base
.
sk
->
rcvbuf
>>
1
),
asoc
->
pmtu
)))
{
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
SCTP_DEBUG_PRINTK
(
"%s: Sending window update SACK- asoc: %p "
"rwnd: %u a_rwnd: %u
\n
"
,
__FUNCTION__
,
"rwnd: %u a_rwnd: %u
\n
"
,
__FUNCTION__
,
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
asoc
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
...
@@ -1020,9 +1047,6 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
...
@@ -1020,9 +1047,6 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
if
(
!
sack
)
if
(
!
sack
)
return
;
return
;
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
sack_needed
=
0
;
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
...
@@ -1046,7 +1070,8 @@ void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len)
...
@@ -1046,7 +1070,8 @@ void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len)
asoc
->
rwnd
=
0
;
asoc
->
rwnd
=
0
;
}
}
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd decreased by %d to (%u, %u)
\n
"
,
SCTP_DEBUG_PRINTK
(
"%s: asoc %p rwnd decreased by %d to (%u, %u)
\n
"
,
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
);
__FUNCTION__
,
asoc
,
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
);
}
}
/* Build the bind address list for the association based on info from the
/* Build the bind address list for the association based on info from the
...
...
net/sctp/bind_addr.c
View file @
e5e956d0
...
@@ -302,7 +302,7 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
...
@@ -302,7 +302,7 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
dest
,
union
sctp_addr
*
addr
,
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
dest
,
union
sctp_addr
*
addr
,
sctp_scope_t
scope
,
int
priority
,
int
flags
)
sctp_scope_t
scope
,
int
priority
,
int
flags
)
{
{
s
ctp_protocol_t
*
proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
proto
=
sctp_get_protocol
();
int
error
=
0
;
int
error
=
0
;
if
(
sctp_is_any
(
addr
))
{
if
(
sctp_is_any
(
addr
))
{
...
...
net/sctp/endpointola.c
View file @
e5e956d0
...
@@ -65,7 +65,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep);
...
@@ -65,7 +65,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep);
/* Create a sctp_endpoint_t with all that boring stuff initialized.
/* Create a sctp_endpoint_t with all that boring stuff initialized.
* Returns NULL if there isn't enough memory.
* Returns NULL if there isn't enough memory.
*/
*/
sctp_endpoint_t
*
sctp_endpoint_new
(
s
ctp_protocol_t
*
proto
,
sctp_endpoint_t
*
sctp_endpoint_new
(
s
truct
sctp_protocol
*
proto
,
struct
sock
*
sk
,
int
priority
)
struct
sock
*
sk
,
int
priority
)
{
{
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
...
@@ -89,7 +89,8 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
...
@@ -89,7 +89,8 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
/*
/*
* Initialize the base fields of the endpoint structure.
* Initialize the base fields of the endpoint structure.
*/
*/
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
ep
,
sctp_protocol_t
*
proto
,
sctp_endpoint_t
*
sctp_endpoint_init
(
sctp_endpoint_t
*
ep
,
struct
sctp_protocol
*
proto
,
struct
sock
*
sk
,
int
priority
)
struct
sock
*
sk
,
int
priority
)
{
{
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
...
@@ -194,6 +195,8 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
...
@@ -194,6 +195,8 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
{
{
SCTP_ASSERT
(
ep
->
base
.
dead
,
"Endpoint is not dead"
,
return
);
SCTP_ASSERT
(
ep
->
base
.
dead
,
"Endpoint is not dead"
,
return
);
ep
->
base
.
sk
->
state
=
SCTP_SS_CLOSED
;
/* Unlink this endpoint, so we can't find it again! */
/* Unlink this endpoint, so we can't find it again! */
sctp_unhash_endpoint
(
ep
);
sctp_unhash_endpoint
(
ep
);
...
...
net/sctp/ipv6.c
View file @
e5e956d0
...
@@ -432,6 +432,62 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
...
@@ -432,6 +432,62 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
return
retval
;
return
retval
;
}
}
/* Create and initialize a new sk for the socket to be returned by accept(). */
struct
sock
*
sctp_v6_create_accept_sk
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
sock
*
newsk
;
struct
inet_opt
*
newinet
;
struct
ipv6_pinfo
*
newnp
,
*
np
=
inet6_sk
(
sk
);
struct
sctp6_sock
*
newsctp6sk
;
newsk
=
sk_alloc
(
PF_INET6
,
GFP_KERNEL
,
sizeof
(
struct
sctp6_sock
),
sk
->
slab
);
if
(
!
newsk
)
goto
out
;
sock_init_data
(
NULL
,
newsk
);
newsk
->
type
=
SOCK_STREAM
;
newsk
->
prot
=
sk
->
prot
;
newsk
->
no_check
=
sk
->
no_check
;
newsk
->
reuse
=
sk
->
reuse
;
newsk
->
destruct
=
inet_sock_destruct
;
newsk
->
zapped
=
0
;
newsk
->
family
=
PF_INET6
;
newsk
->
protocol
=
IPPROTO_SCTP
;
newsk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
newsctp6sk
=
(
struct
sctp6_sock
*
)
newsk
;
newsctp6sk
->
pinet6
=
&
newsctp6sk
->
inet6
;
newinet
=
inet_sk
(
newsk
);
newnp
=
inet6_sk
(
newsk
);
memcpy
(
newnp
,
np
,
sizeof
(
struct
ipv6_pinfo
));
ipv6_addr_copy
(
&
newnp
->
daddr
,
&
asoc
->
peer
.
primary_addr
.
v6
.
sin6_addr
);
newinet
->
sport
=
inet
->
sport
;
newinet
->
dport
=
asoc
->
peer
.
port
;
#ifdef INET_REFCNT_DEBUG
atomic_inc
(
&
inet6_sock_nr
);
atomic_inc
(
&
inet_sock_nr
);
#endif
if
(
0
!=
newsk
->
prot
->
init
(
newsk
))
{
inet_sock_release
(
newsk
);
newsk
=
NULL
;
}
out:
return
newsk
;
}
/* Initialize a PF_INET6 socket msg_name. */
/* Initialize a PF_INET6 socket msg_name. */
static
void
sctp_inet6_msgname
(
char
*
msgname
,
int
*
addr_len
)
static
void
sctp_inet6_msgname
(
char
*
msgname
,
int
*
addr_len
)
{
{
...
@@ -564,6 +620,20 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
...
@@ -564,6 +620,20 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return
af
->
available
(
addr
);
return
af
->
available
(
addr
);
}
}
/* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Note: In the future, we may want to look at sock options
* to determine whether a PF_INET6 socket really wants to have IPV4
* addresses.
* Returns number of addresses supported.
*/
static
int
sctp_inet6_supported_addrs
(
const
struct
sctp_opt
*
opt
,
__u16
*
types
)
{
types
[
0
]
=
SCTP_PARAM_IPV4_ADDRESS
;
types
[
1
]
=
SCTP_PARAM_IPV6_ADDRESS
;
return
2
;
}
static
struct
proto_ops
inet6_seqpacket_ops
=
{
static
struct
proto_ops
inet6_seqpacket_ops
=
{
.
family
=
PF_INET6
,
.
family
=
PF_INET6
,
.
release
=
inet6_release
,
.
release
=
inet6_release
,
...
@@ -583,7 +653,7 @@ static struct proto_ops inet6_seqpacket_ops = {
...
@@ -583,7 +653,7 @@ static struct proto_ops inet6_seqpacket_ops = {
.
mmap
=
sock_no_mmap
,
.
mmap
=
sock_no_mmap
,
};
};
static
struct
inet_protosw
sctpv6_protosw
=
{
static
struct
inet_protosw
sctpv6_
seqpacket_
protosw
=
{
.
type
=
SOCK_SEQPACKET
,
.
type
=
SOCK_SEQPACKET
,
.
protocol
=
IPPROTO_SCTP
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
prot
=
&
sctp_prot
,
...
@@ -592,6 +662,15 @@ static struct inet_protosw sctpv6_protosw = {
...
@@ -592,6 +662,15 @@ static struct inet_protosw sctpv6_protosw = {
.
no_check
=
0
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
.
flags
=
SCTP_PROTOSW_FLAG
};
};
static
struct
inet_protosw
sctpv6_stream_protosw
=
{
.
type
=
SOCK_STREAM
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
ops
=
&
inet6_seqpacket_ops
,
.
capability
=
-
1
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
};
static
struct
inet6_protocol
sctpv6_protocol
=
{
static
struct
inet6_protocol
sctpv6_protocol
=
{
.
handler
=
sctp_rcv
,
.
handler
=
sctp_rcv
,
...
@@ -626,6 +705,8 @@ static struct sctp_pf sctp_pf_inet6_specific = {
...
@@ -626,6 +705,8 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.
af_supported
=
sctp_inet6_af_supported
,
.
af_supported
=
sctp_inet6_af_supported
,
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
bind_verify
=
sctp_inet6_bind_verify
,
.
bind_verify
=
sctp_inet6_bind_verify
,
.
supported_addrs
=
sctp_inet6_supported_addrs
,
.
create_accept_sk
=
sctp_v6_create_accept_sk
,
.
af
=
&
sctp_ipv6_specific
,
.
af
=
&
sctp_ipv6_specific
,
};
};
...
@@ -636,8 +717,9 @@ int sctp_v6_init(void)
...
@@ -636,8 +717,9 @@ int sctp_v6_init(void)
if
(
inet6_add_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
)
<
0
)
if
(
inet6_add_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
return
-
EAGAIN
;
/* Add SCTPv6 to inetsw6 linked list. */
/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
inet6_register_protosw
(
&
sctpv6_protosw
);
inet6_register_protosw
(
&
sctpv6_seqpacket_protosw
);
inet6_register_protosw
(
&
sctpv6_stream_protosw
);
/* Register the SCTP specfic PF_INET6 functions. */
/* Register the SCTP specfic PF_INET6 functions. */
sctp_register_pf
(
&
sctp_pf_inet6_specific
,
PF_INET6
);
sctp_register_pf
(
&
sctp_pf_inet6_specific
,
PF_INET6
);
...
@@ -656,6 +738,7 @@ void sctp_v6_exit(void)
...
@@ -656,6 +738,7 @@ void sctp_v6_exit(void)
{
{
list_del
(
&
sctp_ipv6_specific
.
list
);
list_del
(
&
sctp_ipv6_specific
.
list
);
inet6_del_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
);
inet6_del_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
);
inet6_unregister_protosw
(
&
sctpv6_protosw
);
inet6_unregister_protosw
(
&
sctpv6_seqpacket_protosw
);
inet6_unregister_protosw
(
&
sctpv6_stream_protosw
);
unregister_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
unregister_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
}
}
net/sctp/output.c
View file @
e5e956d0
...
@@ -62,16 +62,15 @@
...
@@ -62,16 +62,15 @@
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
/* Forward declarations for private helpers. */
/* Forward declarations for private helpers. */
static
void
sctp_packet_reset
(
s
ctp_packet_
t
*
packet
);
static
void
sctp_packet_reset
(
s
truct
sctp_packe
t
*
packet
);
static
sctp_xmit_t
sctp_packet_append_data
(
s
ctp_packet_
t
*
packet
,
static
sctp_xmit_t
sctp_packet_append_data
(
s
truct
sctp_packe
t
*
packet
,
s
ctp_chunk_t
*
chunk
);
s
truct
sctp_chunk
*
chunk
);
/* Config a packet.
/* Config a packet.
* This appears to be a followup set of initializations.)
* This appears to be a followup set of initializations.)
*/
*/
sctp_packet_t
*
sctp_packet_config
(
sctp_packet_t
*
packet
,
struct
sctp_packet
*
sctp_packet_config
(
struct
sctp_packet
*
packet
,
__u32
vtag
,
__u32
vtag
,
int
ecn_capable
,
int
ecn_capable
,
sctp_packet_phandler_t
*
prepend_handler
)
sctp_packet_phandler_t
*
prepend_handler
)
{
{
int
packet_empty
=
(
packet
->
size
==
SCTP_IP_OVERHEAD
);
int
packet_empty
=
(
packet
->
size
==
SCTP_IP_OVERHEAD
);
...
@@ -89,10 +88,9 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
...
@@ -89,10 +88,9 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
}
}
/* Initialize the packet structure. */
/* Initialize the packet structure. */
s
ctp_packet_t
*
sctp_packet_init
(
sctp_packet_
t
*
packet
,
s
truct
sctp_packet
*
sctp_packet_init
(
struct
sctp_packe
t
*
packet
,
struct
sctp_transport
*
transport
,
struct
sctp_transport
*
transport
,
__u16
sport
,
__u16
sport
,
__u16
dport
)
__u16
dport
)
{
{
packet
->
transport
=
transport
;
packet
->
transport
=
transport
;
packet
->
source_port
=
sport
;
packet
->
source_port
=
sport
;
...
@@ -109,14 +107,12 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
...
@@ -109,14 +107,12 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
}
}
/* Free a packet. */
/* Free a packet. */
void
sctp_packet_free
(
s
ctp_packet_
t
*
packet
)
void
sctp_packet_free
(
s
truct
sctp_packe
t
*
packet
)
{
{
s
ctp_chunk_t
*
chunk
;
s
truct
sctp_chunk
*
chunk
;
while
(
NULL
!=
while
((
chunk
=
(
struct
sctp_chunk
*
)
__skb_dequeue
(
&
packet
->
chunks
)))
(
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
&
packet
->
chunks
)))
{
sctp_free_chunk
(
chunk
);
sctp_free_chunk
(
chunk
);
}
if
(
packet
->
malloced
)
if
(
packet
->
malloced
)
kfree
(
packet
);
kfree
(
packet
);
...
@@ -129,8 +125,8 @@ void sctp_packet_free(sctp_packet_t *packet)
...
@@ -129,8 +125,8 @@ void sctp_packet_free(sctp_packet_t *packet)
* as it can fit in the packet, but any more data that does not fit in this
* as it can fit in the packet, but any more data that does not fit in this
* packet can be sent only after receiving the COOKIE_ACK.
* packet can be sent only after receiving the COOKIE_ACK.
*/
*/
sctp_xmit_t
sctp_packet_transmit_chunk
(
s
ctp_packet_
t
*
packet
,
sctp_xmit_t
sctp_packet_transmit_chunk
(
s
truct
sctp_packe
t
*
packet
,
s
ctp_chunk_t
*
chunk
)
s
truct
sctp_chunk
*
chunk
)
{
{
sctp_xmit_t
retval
;
sctp_xmit_t
retval
;
int
error
=
0
;
int
error
=
0
;
...
@@ -152,6 +148,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
...
@@ -152,6 +148,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
case
SCTP_XMIT_MUST_FRAG
:
case
SCTP_XMIT_MUST_FRAG
:
case
SCTP_XMIT_RWND_FULL
:
case
SCTP_XMIT_RWND_FULL
:
case
SCTP_XMIT_OK
:
case
SCTP_XMIT_OK
:
case
SCTP_XMIT_NAGLE_DELAY
:
break
;
break
;
};
};
...
@@ -161,7 +158,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
...
@@ -161,7 +158,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
/* Append a chunk to the offered packet reporting back any inability to do
/* Append a chunk to the offered packet reporting back any inability to do
* so.
* so.
*/
*/
sctp_xmit_t
sctp_packet_append_chunk
(
sctp_packet_t
*
packet
,
sctp_chunk_t
*
chunk
)
sctp_xmit_t
sctp_packet_append_chunk
(
struct
sctp_packet
*
packet
,
struct
sctp_chunk
*
chunk
)
{
{
sctp_xmit_t
retval
=
SCTP_XMIT_OK
;
sctp_xmit_t
retval
=
SCTP_XMIT_OK
;
__u16
chunk_len
=
WORD_ROUND
(
ntohs
(
chunk
->
chunk_hdr
->
length
));
__u16
chunk_len
=
WORD_ROUND
(
ntohs
(
chunk
->
chunk_hdr
->
length
));
...
@@ -223,7 +221,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
...
@@ -223,7 +221,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
}
}
/* It is OK to send this chunk. */
/* It is OK to send this chunk. */
skb_queue_tail
(
&
packet
->
chunks
,
(
struct
sk_buff
*
)
chunk
);
__
skb_queue_tail
(
&
packet
->
chunks
,
(
struct
sk_buff
*
)
chunk
);
packet
->
size
+=
chunk_len
;
packet
->
size
+=
chunk_len
;
finish:
finish:
return
retval
;
return
retval
;
...
@@ -234,18 +232,18 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
...
@@ -234,18 +232,18 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
*
*
* The return value is a normal kernel error return value.
* The return value is a normal kernel error return value.
*/
*/
int
sctp_packet_transmit
(
s
ctp_packet_
t
*
packet
)
int
sctp_packet_transmit
(
s
truct
sctp_packe
t
*
packet
)
{
{
struct
sctp_transport
*
transport
=
packet
->
transport
;
struct
sctp_transport
*
transport
=
packet
->
transport
;
s
ctp_association_t
*
asoc
=
transport
->
asoc
;
s
truct
sctp_association
*
asoc
=
transport
->
asoc
;
struct
sctphdr
*
sh
;
struct
sctphdr
*
sh
;
__u32
crc32
;
__u32
crc32
;
struct
sk_buff
*
nskb
;
struct
sk_buff
*
nskb
;
s
ctp_chunk_t
*
chunk
;
s
truct
sctp_chunk
*
chunk
;
struct
sock
*
sk
;
struct
sock
*
sk
;
int
err
=
0
;
int
err
=
0
;
int
padding
;
/* How much padding do we need? */
int
padding
;
/* How much padding do we need? */
__u8
packet_
has_data
=
0
;
__u8
has_data
=
0
;
struct
dst_entry
*
dst
;
struct
dst_entry
*
dst
;
/* Do NOT generate a chunkless packet... */
/* Do NOT generate a chunkless packet... */
...
@@ -253,7 +251,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -253,7 +251,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
return
err
;
return
err
;
/* Set up convenience variables... */
/* Set up convenience variables... */
chunk
=
(
s
ctp_chunk_t
*
)
(
packet
->
chunks
.
next
);
chunk
=
(
s
truct
sctp_chunk
*
)
(
packet
->
chunks
.
next
);
sk
=
chunk
->
skb
->
sk
;
sk
=
chunk
->
skb
->
sk
;
/* Allocate the new skb. */
/* Allocate the new skb. */
...
@@ -291,8 +289,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -291,8 +289,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
* [This whole comment explains WORD_ROUND() below.]
* [This whole comment explains WORD_ROUND() below.]
*/
*/
SCTP_DEBUG_PRINTK
(
"***sctp_transmit_packet***
\n
"
);
SCTP_DEBUG_PRINTK
(
"***sctp_transmit_packet***
\n
"
);
while
(
NULL
!=
(
chunk
=
(
sctp_chunk_t
*
)
while
((
chunk
=
(
struct
sctp_chunk
*
)
__skb_dequeue
(
&
packet
->
chunks
)))
{
skb_dequeue
(
&
packet
->
chunks
)))
{
chunk
->
num_times_sent
++
;
chunk
->
num_times_sent
++
;
chunk
->
sent_at
=
jiffies
;
chunk
->
sent_at
=
jiffies
;
if
(
sctp_chunk_is_data
(
chunk
))
{
if
(
sctp_chunk_is_data
(
chunk
))
{
...
@@ -309,7 +306,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -309,7 +306,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
chunk
->
rtt_in_progress
=
1
;
chunk
->
rtt_in_progress
=
1
;
transport
->
rto_pending
=
1
;
transport
->
rto_pending
=
1
;
}
}
packet_
has_data
=
1
;
has_data
=
1
;
}
}
memcpy
(
skb_put
(
nskb
,
chunk
->
skb
->
len
),
memcpy
(
skb_put
(
nskb
,
chunk
->
skb
->
len
),
chunk
->
skb
->
data
,
chunk
->
skb
->
len
);
chunk
->
skb
->
data
,
chunk
->
skb
->
len
);
...
@@ -399,7 +396,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -399,7 +396,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
asoc
->
peer
.
last_sent_to
=
transport
;
asoc
->
peer
.
last_sent_to
=
transport
;
}
}
if
(
packet_
has_data
)
{
if
(
has_data
)
{
struct
timer_list
*
timer
;
struct
timer_list
*
timer
;
unsigned
long
timeout
;
unsigned
long
timeout
;
...
@@ -456,9 +453,9 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -456,9 +453,9 @@ int sctp_packet_transmit(sctp_packet_t *packet)
/*
/*
* This private function resets the packet to a fresh state.
* This private function resets the packet to a fresh state.
*/
*/
static
void
sctp_packet_reset
(
s
ctp_packet_
t
*
packet
)
static
void
sctp_packet_reset
(
s
truct
sctp_packe
t
*
packet
)
{
{
s
ctp_chunk_t
*
chunk
=
NULL
;
s
truct
sctp_chunk
*
chunk
=
NULL
;
packet
->
size
=
SCTP_IP_OVERHEAD
;
packet
->
size
=
SCTP_IP_OVERHEAD
;
...
@@ -473,13 +470,16 @@ static void sctp_packet_reset(sctp_packet_t *packet)
...
@@ -473,13 +470,16 @@ static void sctp_packet_reset(sctp_packet_t *packet)
}
}
/* This private function handles the specifics of appending DATA chunks. */
/* This private function handles the specifics of appending DATA chunks. */
static
sctp_xmit_t
sctp_packet_append_data
(
s
ctp_packet_t
*
packet
,
static
sctp_xmit_t
sctp_packet_append_data
(
s
truct
sctp_packet
*
packet
,
s
ctp_chunk_t
*
chunk
)
s
truct
sctp_chunk
*
chunk
)
{
{
sctp_xmit_t
retval
=
SCTP_XMIT_OK
;
sctp_xmit_t
retval
=
SCTP_XMIT_OK
;
size_t
datasize
,
rwnd
,
inflight
;
size_t
datasize
,
rwnd
,
inflight
;
struct
sctp_transport
*
transport
=
packet
->
transport
;
struct
sctp_transport
*
transport
=
packet
->
transport
;
__u32
max_burst_bytes
;
__u32
max_burst_bytes
;
struct
sctp_association
*
asoc
=
transport
->
asoc
;
struct
sctp_opt
*
sp
=
sctp_sk
(
asoc
->
base
.
sk
);
struct
sctp_outq
*
q
=
&
asoc
->
outqueue
;
/* RFC 2960 6.1 Transmission of DATA Chunks
/* RFC 2960 6.1 Transmission of DATA Chunks
*
*
...
@@ -494,8 +494,8 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
...
@@ -494,8 +494,8 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
* receiver to the data sender.
* receiver to the data sender.
*/
*/
rwnd
=
transport
->
asoc
->
peer
.
rwnd
;
rwnd
=
asoc
->
peer
.
rwnd
;
inflight
=
transport
->
asoc
->
outqueue
.
outstanding_bytes
;
inflight
=
asoc
->
outqueue
.
outstanding_bytes
;
datasize
=
sctp_data_size
(
chunk
);
datasize
=
sctp_data_size
(
chunk
);
...
@@ -517,7 +517,7 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
...
@@ -517,7 +517,7 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
* if ((flightsize + Max.Burst * MTU) < cwnd)
* if ((flightsize + Max.Burst * MTU) < cwnd)
* cwnd = flightsize + Max.Burst * MTU
* cwnd = flightsize + Max.Burst * MTU
*/
*/
max_burst_bytes
=
transport
->
asoc
->
max_burst
*
transport
->
asoc
->
pmtu
;
max_burst_bytes
=
asoc
->
max_burst
*
asoc
->
pmtu
;
if
((
transport
->
flight_size
+
max_burst_bytes
)
<
transport
->
cwnd
)
{
if
((
transport
->
flight_size
+
max_burst_bytes
)
<
transport
->
cwnd
)
{
transport
->
cwnd
=
transport
->
flight_size
+
max_burst_bytes
;
transport
->
cwnd
=
transport
->
flight_size
+
max_burst_bytes
;
SCTP_DEBUG_PRINTK
(
"%s: cwnd limited by max_burst: "
SCTP_DEBUG_PRINTK
(
"%s: cwnd limited by max_burst: "
...
@@ -543,27 +543,44 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
...
@@ -543,27 +543,44 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
* When a Fast Retransmit is being performed the sender SHOULD
* When a Fast Retransmit is being performed the sender SHOULD
* ignore the value of cwnd and SHOULD NOT delay retransmission.
* ignore the value of cwnd and SHOULD NOT delay retransmission.
*/
*/
if
(
!
chunk
->
fast_retransmit
)
{
if
(
!
chunk
->
fast_retransmit
)
if
(
transport
->
flight_size
>=
transport
->
cwnd
)
{
if
(
transport
->
flight_size
>=
transport
->
cwnd
)
{
retval
=
SCTP_XMIT_RWND_FULL
;
retval
=
SCTP_XMIT_RWND_FULL
;
goto
finish
;
goto
finish
;
}
}
/* Nagle's algorithm to solve small-packet problem:
* Inhibit the sending of new chunks when new outgoing data arrives
* if any previously transmitted data on the connection remains
* unacknowledged.
*/
if
(
!
sp
->
nodelay
&&
SCTP_IP_OVERHEAD
==
packet
->
size
&&
q
->
outstanding_bytes
&&
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
{
unsigned
len
=
datasize
+
q
->
out_qlen
;
/* Check whether this chunk and all the rest of pending
* data will fit or delay in hopes of bundling a full
* sized packet.
*/
if
(
len
<
asoc
->
pmtu
-
SCTP_IP_OVERHEAD
)
{
retval
=
SCTP_XMIT_NAGLE_DELAY
;
goto
finish
;
}
}
}
/* Keep track of how many bytes are in flight over this transport. */
/* Keep track of how many bytes are in flight over this transport. */
transport
->
flight_size
+=
datasize
;
transport
->
flight_size
+=
datasize
;
/* Keep track of how many bytes are in flight to the receiver. */
/* Keep track of how many bytes are in flight to the receiver. */
transport
->
asoc
->
outqueue
.
outstanding_bytes
+=
datasize
;
asoc
->
outqueue
.
outstanding_bytes
+=
datasize
;
/* Update our view of the receiver's rwnd. */
/* Update our view of the receiver's rwnd. */
if
(
datasize
<
rwnd
)
{
if
(
datasize
<
rwnd
)
rwnd
-=
datasize
;
rwnd
-=
datasize
;
}
else
{
else
rwnd
=
0
;
rwnd
=
0
;
}
transport
->
asoc
->
peer
.
rwnd
=
rwnd
;
asoc
->
peer
.
rwnd
=
rwnd
;
finish:
finish:
return
retval
;
return
retval
;
...
...
net/sctp/outqueue.c
View file @
e5e956d0
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001
-2003
Intel Corp.
* Copyright (c) 2001-2003 International Business Machines Corp.
* Copyright (c) 2001-2003 International Business Machines Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
* This file is part of the SCTP kernel reference Implementation
...
@@ -62,6 +62,43 @@ static void sctp_check_transmitted(struct sctp_outq *q,
...
@@ -62,6 +62,43 @@ static void sctp_check_transmitted(struct sctp_outq *q,
sctp_sackhdr_t
*
sack
,
sctp_sackhdr_t
*
sack
,
__u32
highest_new_tsn
);
__u32
highest_new_tsn
);
/* Add data to the front of the queue. */
static
inline
void
sctp_outq_head_data
(
struct
sctp_outq
*
q
,
struct
sctp_chunk
*
ch
)
{
__skb_queue_head
(
&
q
->
out
,
(
struct
sk_buff
*
)
ch
);
q
->
out_qlen
+=
ch
->
skb
->
len
;
return
;
}
/* Take data from the front of the queue. */
static
inline
struct
sctp_chunk
*
sctp_outq_dequeue_data
(
struct
sctp_outq
*
q
)
{
struct
sctp_chunk
*
ch
;
ch
=
(
struct
sctp_chunk
*
)
__skb_dequeue
(
&
q
->
out
);
if
(
ch
)
q
->
out_qlen
-=
ch
->
skb
->
len
;
return
ch
;
}
/* Add data chunk to the end of the queue. */
static
inline
void
sctp_outq_tail_data
(
struct
sctp_outq
*
q
,
struct
sctp_chunk
*
ch
)
{
__skb_queue_tail
(
&
q
->
out
,
(
struct
sk_buff
*
)
ch
);
q
->
out_qlen
+=
ch
->
skb
->
len
;
return
;
}
/* Insert a chunk behind chunk 'pos'. */
static
inline
void
sctp_outq_insert_data
(
struct
sctp_outq
*
q
,
struct
sctp_chunk
*
ch
,
struct
sctp_chunk
*
pos
)
{
__skb_insert
((
struct
sk_buff
*
)
ch
,
(
struct
sk_buff
*
)
pos
->
prev
,
(
struct
sk_buff
*
)
pos
,
pos
->
list
);
q
->
out_qlen
+=
ch
->
skb
->
len
;
}
/* Generate a new outqueue. */
/* Generate a new outqueue. */
struct
sctp_outq
*
sctp_outq_new
(
sctp_association_t
*
asoc
)
struct
sctp_outq
*
sctp_outq_new
(
sctp_association_t
*
asoc
)
{
{
...
@@ -97,6 +134,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
...
@@ -97,6 +134,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
q
->
empty
=
1
;
q
->
empty
=
1
;
q
->
malloced
=
0
;
q
->
malloced
=
0
;
q
->
out_qlen
=
0
;
}
}
/* Free the outqueue structure and any related pending chunks.
/* Free the outqueue structure and any related pending chunks.
...
@@ -133,7 +171,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
...
@@ -133,7 +171,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
}
}
/* Throw away any leftover data chunks. */
/* Throw away any leftover data chunks. */
while
((
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
&
q
->
out
)))
while
((
chunk
=
sctp_outq_dequeue_data
(
q
)))
sctp_free_chunk
(
chunk
);
sctp_free_chunk
(
chunk
);
/* Throw away any leftover control chunks. */
/* Throw away any leftover control chunks. */
...
@@ -192,7 +230,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
...
@@ -192,7 +230,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
))
sctp_cname
(
SCTP_ST_CHUNK
(
chunk
->
chunk_hdr
->
type
))
:
"Illegal Chunk"
);
:
"Illegal Chunk"
);
s
kb_queue_tail
(
&
q
->
out
,
(
struct
sk_buff
*
)
chunk
);
s
ctp_outq_tail_data
(
q
,
chunk
);
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
if
(
chunk
->
chunk_hdr
->
flags
&
SCTP_DATA_UNORDERED
)
SCTP_INC_STATS
(
SctpOutUnorderChunks
);
SCTP_INC_STATS
(
SctpOutUnorderChunks
);
else
else
...
@@ -201,7 +239,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
...
@@ -201,7 +239,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
break
;
break
;
};
};
}
else
{
}
else
{
skb_queue_tail
(
&
q
->
control
,
(
struct
sk_buff
*
)
chunk
);
__
skb_queue_tail
(
&
q
->
control
,
(
struct
sk_buff
*
)
chunk
);
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
SCTP_INC_STATS
(
SctpOutCtrlChunks
);
}
}
...
@@ -351,7 +389,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
...
@@ -351,7 +389,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
*
*
* The return value is a normal kernel error return value.
* The return value is a normal kernel error return value.
*/
*/
static
int
sctp_outq_flush_rtx
(
struct
sctp_outq
*
q
,
s
ctp_packet_
t
*
pkt
,
static
int
sctp_outq_flush_rtx
(
struct
sctp_outq
*
q
,
s
truct
sctp_packe
t
*
pkt
,
int
rtx_timeout
,
int
*
start_timer
)
int
rtx_timeout
,
int
*
start_timer
)
{
{
struct
list_head
*
lqueue
;
struct
list_head
*
lqueue
;
...
@@ -385,17 +423,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
...
@@ -385,17 +423,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
while
(
lchunk
)
{
while
(
lchunk
)
{
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
#if 0
/* If a chunk has been tried for more than SCTP_DEF_MAX_SEND
* times, discard it, and check the empty flag of the outqueue.
*
* --xguo
*/
if (chunk->snd_count > SCTP_DEF_MAX_SEND) {
sctp_free_chunk(chunk);
continue;
}
#endif
/* Make sure that Gap Acked TSNs are not retransmitted. A
/* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the
* simple approach is just to move such TSNs out of the
...
@@ -461,8 +488,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
...
@@ -461,8 +488,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
* queue. 'pos' points to the next chunk in the output queue after the
* queue. 'pos' points to the next chunk in the output queue after the
* chunk that is currently in the process of fragmentation.
* chunk that is currently in the process of fragmentation.
*/
*/
void
sctp_xmit_frag
(
struct
sctp_outq
*
q
,
struct
s
k_buff
*
pos
,
void
sctp_xmit_frag
(
struct
sctp_outq
*
q
,
struct
s
ctp_chunk
*
pos
,
sctp_packet_t
*
packet
,
sctp_chunk_t
*
frag
,
__u32
tsn
)
struct
sctp_packet
*
packet
,
struct
sctp_chunk
*
frag
,
__u32
tsn
)
{
{
struct
sctp_transport
*
transport
=
packet
->
transport
;
struct
sctp_transport
*
transport
=
packet
->
transport
;
struct
sk_buff_head
*
queue
=
&
q
->
out
;
struct
sk_buff_head
*
queue
=
&
q
->
out
;
...
@@ -480,11 +507,10 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
...
@@ -480,11 +507,10 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: q not empty. "
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: q not empty. "
"adding 0x%x to outqueue
\n
"
,
"adding 0x%x to outqueue
\n
"
,
ntohl
(
frag
->
subh
.
data_hdr
->
tsn
));
ntohl
(
frag
->
subh
.
data_hdr
->
tsn
));
if
(
pos
)
{
if
(
pos
)
skb_insert
(
pos
,
(
struct
sk_buff
*
)
frag
);
sctp_outq_insert_data
(
q
,
frag
,
pos
);
}
else
{
else
skb_queue_tail
(
queue
,
(
struct
sk_buff
*
)
frag
);
sctp_outq_tail_data
(
q
,
frag
);
}
return
;
return
;
}
}
...
@@ -496,11 +522,10 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
...
@@ -496,11 +522,10 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: rwnd full. "
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: rwnd full. "
"adding 0x%x to outqueue
\n
"
,
"adding 0x%x to outqueue
\n
"
,
ntohl
(
frag
->
subh
.
data_hdr
->
tsn
));
ntohl
(
frag
->
subh
.
data_hdr
->
tsn
));
if
(
pos
)
{
if
(
pos
)
skb_insert
(
pos
,
(
struct
sk_buff
*
)
frag
);
sctp_outq_insert_data
(
q
,
frag
,
pos
);
}
else
{
else
skb_queue_tail
(
queue
,
(
struct
sk_buff
*
)
frag
);
sctp_outq_tail_data
(
q
,
frag
);
}
break
;
break
;
case
SCTP_XMIT_OK
:
case
SCTP_XMIT_OK
:
...
@@ -512,11 +537,10 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
...
@@ -512,11 +537,10 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: force output "
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: force output "
"failed. adding 0x%x to outqueue
\n
"
,
"failed. adding 0x%x to outqueue
\n
"
,
ntohl
(
frag
->
subh
.
data_hdr
->
tsn
));
ntohl
(
frag
->
subh
.
data_hdr
->
tsn
));
if
(
pos
)
{
if
(
pos
)
skb_insert
(
pos
,
(
struct
sk_buff
*
)
frag
);
sctp_outq_insert_data
(
q
,
frag
,
pos
);
}
else
{
else
skb_queue_tail
(
queue
,
(
struct
sk_buff
*
)
frag
);
sctp_outq_tail_data
(
q
,
frag
);
}
}
else
{
}
else
{
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: force output "
SCTP_DEBUG_PRINTK
(
"sctp_xmit_frag: force output "
"success. 0x%x sent
\n
"
,
"success. 0x%x sent
\n
"
,
...
@@ -537,14 +561,14 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
...
@@ -537,14 +561,14 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
* The argument 'frag' point to the first fragment and it holds the list
* The argument 'frag' point to the first fragment and it holds the list
* of all the other fragments in the 'frag_list' field.
* of all the other fragments in the 'frag_list' field.
*/
*/
void
sctp_xmit_fragmented_chunks
(
struct
sctp_outq
*
q
,
s
ctp_packet_t
*
packe
t
,
void
sctp_xmit_fragmented_chunks
(
struct
sctp_outq
*
q
,
s
truct
sctp_packet
*
pk
t
,
sctp_chunk_t
*
frag
)
sctp_chunk_t
*
frag
)
{
{
sctp_association_t
*
asoc
=
frag
->
asoc
;
sctp_association_t
*
asoc
=
frag
->
asoc
;
struct
list_head
*
lfrag
,
*
frag_list
;
struct
list_head
*
lfrag
,
*
frag_list
;
__u32
tsn
;
__u32
tsn
;
int
nfrags
=
1
;
int
nfrags
=
1
;
struct
s
k_buff
*
pos
;
struct
s
ctp_chunk
*
pos
;
/* Count the number of fragments. */
/* Count the number of fragments. */
frag_list
=
&
frag
->
frag_list
;
frag_list
=
&
frag
->
frag_list
;
...
@@ -553,17 +577,17 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet,
...
@@ -553,17 +577,17 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet,
}
}
/* Get a TSN block of nfrags TSNs. */
/* Get a TSN block of nfrags TSNs. */
tsn
=
__
sctp_association_get_tsn_block
(
asoc
,
nfrags
);
tsn
=
sctp_association_get_tsn_block
(
asoc
,
nfrags
);
pos
=
skb_peek
(
&
q
->
out
);
pos
=
(
struct
sctp_chunk
*
)
skb_peek
(
&
q
->
out
);
/* Transmit the first fragment. */
/* Transmit the first fragment. */
sctp_xmit_frag
(
q
,
pos
,
p
acke
t
,
frag
,
tsn
++
);
sctp_xmit_frag
(
q
,
pos
,
p
k
t
,
frag
,
tsn
++
);
/* Transmit the rest of fragments. */
/* Transmit the rest of fragments. */
frag_list
=
&
frag
->
frag_list
;
frag_list
=
&
frag
->
frag_list
;
list_for_each
(
lfrag
,
frag_list
)
{
list_for_each
(
lfrag
,
frag_list
)
{
frag
=
list_entry
(
lfrag
,
sctp_chunk_t
,
frag_list
);
frag
=
list_entry
(
lfrag
,
sctp_chunk_t
,
frag_list
);
sctp_xmit_frag
(
q
,
pos
,
p
acke
t
,
frag
,
tsn
++
);
sctp_xmit_frag
(
q
,
pos
,
p
k
t
,
frag
,
tsn
++
);
}
}
}
}
...
@@ -672,15 +696,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
...
@@ -672,15 +696,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
*
*
* Description: Send everything in q which we legally can, subject to
* Description: Send everything in q which we legally can, subject to
* congestion limitations.
* congestion limitations.
*
* * Note: This function can be called from multiple contexts so appropriate
* Note: This function can be called from multiple contexts so appropriate
* locking concerns must be made. Today we use the sock lock to protect
* locking concerns must be made. Today we use the sock lock to protect
* this function.
* this function.
*/
*/
int
sctp_outq_flush
(
struct
sctp_outq
*
q
,
int
rtx_timeout
)
int
sctp_outq_flush
(
struct
sctp_outq
*
q
,
int
rtx_timeout
)
{
{
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
s
ctp_packet_
t
singleton
;
s
truct
sctp_packe
t
singleton
;
sctp_association_t
*
asoc
=
q
->
asoc
;
sctp_association_t
*
asoc
=
q
->
asoc
;
int
ecn_capable
=
asoc
->
peer
.
ecn_capable
;
int
ecn_capable
=
asoc
->
peer
.
ecn_capable
;
__u16
sport
=
asoc
->
base
.
bind_addr
.
port
;
__u16
sport
=
asoc
->
base
.
bind_addr
.
port
;
...
@@ -719,7 +742,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -719,7 +742,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
}
}
queue
=
&
q
->
control
;
queue
=
&
q
->
control
;
while
(
NULL
!=
(
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
queue
)))
{
while
((
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
queue
)))
{
/* Pick the right transport to use. */
/* Pick the right transport to use. */
new_transport
=
chunk
->
transport
;
new_transport
=
chunk
->
transport
;
...
@@ -852,7 +875,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -852,7 +875,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
/* Finally, transmit new packets. */
/* Finally, transmit new packets. */
start_timer
=
0
;
start_timer
=
0
;
queue
=
&
q
->
out
;
queue
=
&
q
->
out
;
while
(
NULL
!=
(
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
queue
)))
{
while
(
NULL
!=
(
chunk
=
sctp_outq_dequeue_data
(
q
)))
{
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier.
* stream identifier.
*/
*/
...
@@ -925,6 +949,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -925,6 +949,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
switch
(
status
)
{
switch
(
status
)
{
case
SCTP_XMIT_PMTU_FULL
:
case
SCTP_XMIT_PMTU_FULL
:
case
SCTP_XMIT_RWND_FULL
:
case
SCTP_XMIT_RWND_FULL
:
case
SCTP_XMIT_NAGLE_DELAY
:
/* We could not append this chunk, so put
/* We could not append this chunk, so put
* the chunk back on the output queue.
* the chunk back on the output queue.
*/
*/
...
@@ -932,7 +957,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -932,7 +957,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
"not transmit TSN: 0x%x, status: %d
\n
"
,
"not transmit TSN: 0x%x, status: %d
\n
"
,
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
),
ntohl
(
chunk
->
subh
.
data_hdr
->
tsn
),
status
);
status
);
s
kb_queue_head
(
queue
,
(
struct
sk_buff
*
)
chunk
);
s
ctp_outq_head_data
(
q
,
chunk
);
goto
sctp_flush_out
;
goto
sctp_flush_out
;
break
;
break
;
...
@@ -994,6 +1019,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -994,6 +1019,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
}
}
sctp_flush_out:
sctp_flush_out:
/* Before returning, examine all the transports touched in
/* Before returning, examine all the transports touched in
* this call. Right now, we bluntly force clear all the
* this call. Right now, we bluntly force clear all the
* transports. Things might change after we implement Nagle.
* transports. Things might change after we implement Nagle.
...
@@ -1163,11 +1189,10 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
...
@@ -1163,11 +1189,10 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
sack_a_rwnd
=
ntohl
(
sack
->
a_rwnd
);
sack_a_rwnd
=
ntohl
(
sack
->
a_rwnd
);
outstanding
=
q
->
outstanding_bytes
;
outstanding
=
q
->
outstanding_bytes
;
if
(
outstanding
<
sack_a_rwnd
)
{
if
(
outstanding
<
sack_a_rwnd
)
sack_a_rwnd
-=
outstanding
;
sack_a_rwnd
-=
outstanding
;
}
else
{
else
sack_a_rwnd
=
0
;
sack_a_rwnd
=
0
;
}
asoc
->
peer
.
rwnd
=
sack_a_rwnd
;
asoc
->
peer
.
rwnd
=
sack_a_rwnd
;
...
...
net/sctp/protocol.c
View file @
e5e956d0
...
@@ -58,7 +58,7 @@
...
@@ -58,7 +58,7 @@
#include <net/inet_common.h>
#include <net/inet_common.h>
/* Global data structures. */
/* Global data structures. */
s
ctp_protocol_t
sctp_proto
;
s
truct
sctp_protocol
sctp_proto
;
struct
proc_dir_entry
*
proc_net_sctp
;
struct
proc_dir_entry
*
proc_net_sctp
;
DEFINE_SNMP_STAT
(
struct
sctp_mib
,
sctp_statistics
);
DEFINE_SNMP_STAT
(
struct
sctp_mib
,
sctp_statistics
);
...
@@ -152,7 +152,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
...
@@ -152,7 +152,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Extract our IP addresses from the system and stash them in the
/* Extract our IP addresses from the system and stash them in the
* protocol structure.
* protocol structure.
*/
*/
static
void
__sctp_get_local_addr_list
(
s
ctp_protocol_t
*
proto
)
static
void
__sctp_get_local_addr_list
(
s
truct
sctp_protocol
*
proto
)
{
{
struct
net_device
*
dev
;
struct
net_device
*
dev
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
...
@@ -168,7 +168,7 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
...
@@ -168,7 +168,7 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
read_unlock
(
&
dev_base_lock
);
read_unlock
(
&
dev_base_lock
);
}
}
static
void
sctp_get_local_addr_list
(
s
ctp_protocol_t
*
proto
)
static
void
sctp_get_local_addr_list
(
s
truct
sctp_protocol
*
proto
)
{
{
long
flags
__attribute__
((
unused
));
long
flags
__attribute__
((
unused
));
...
@@ -178,7 +178,7 @@ static void sctp_get_local_addr_list(sctp_protocol_t *proto)
...
@@ -178,7 +178,7 @@ static void sctp_get_local_addr_list(sctp_protocol_t *proto)
}
}
/* Free the existing local addresses. */
/* Free the existing local addresses. */
static
void
__sctp_free_local_addr_list
(
s
ctp_protocol_t
*
proto
)
static
void
__sctp_free_local_addr_list
(
s
truct
sctp_protocol
*
proto
)
{
{
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
struct
list_head
*
pos
,
*
temp
;
struct
list_head
*
pos
,
*
temp
;
...
@@ -191,7 +191,7 @@ static void __sctp_free_local_addr_list(sctp_protocol_t *proto)
...
@@ -191,7 +191,7 @@ static void __sctp_free_local_addr_list(sctp_protocol_t *proto)
}
}
/* Free the existing local addresses. */
/* Free the existing local addresses. */
static
void
sctp_free_local_addr_list
(
s
ctp_protocol_t
*
proto
)
static
void
sctp_free_local_addr_list
(
s
truct
sctp_protocol
*
proto
)
{
{
long
flags
__attribute__
((
unused
));
long
flags
__attribute__
((
unused
));
...
@@ -201,8 +201,9 @@ static void sctp_free_local_addr_list(sctp_protocol_t *proto)
...
@@ -201,8 +201,9 @@ static void sctp_free_local_addr_list(sctp_protocol_t *proto)
}
}
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
int
sctp_copy_local_addr_list
(
sctp_protocol_t
*
proto
,
sctp_bind_addr_t
*
bp
,
int
sctp_copy_local_addr_list
(
struct
sctp_protocol
*
proto
,
sctp_scope_t
scope
,
int
priority
,
int
copy_flags
)
struct
sctp_bind_addr
*
bp
,
sctp_scope_t
scope
,
int
priority
,
int
copy_flags
)
{
{
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
int
error
=
0
;
int
error
=
0
;
...
@@ -479,6 +480,61 @@ void sctp_v4_get_saddr(sctp_association_t *asoc,
...
@@ -479,6 +480,61 @@ void sctp_v4_get_saddr(sctp_association_t *asoc,
}
}
/* Create and initialize a new sk for the socket returned by accept(). */
struct
sock
*
sctp_v4_create_accept_sk
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
)
{
struct
sock
*
newsk
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
inet_opt
*
newinet
;
newsk
=
sk_alloc
(
PF_INET
,
GFP_KERNEL
,
sizeof
(
struct
sctp_sock
),
sk
->
slab
);
if
(
!
newsk
)
goto
out
;
sock_init_data
(
NULL
,
newsk
);
newsk
->
type
=
SOCK_STREAM
;
newsk
->
prot
=
sk
->
prot
;
newsk
->
no_check
=
sk
->
no_check
;
newsk
->
reuse
=
sk
->
reuse
;
newsk
->
destruct
=
inet_sock_destruct
;
newsk
->
zapped
=
0
;
newsk
->
family
=
PF_INET
;
newsk
->
protocol
=
IPPROTO_SCTP
;
newsk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
newinet
=
inet_sk
(
newsk
);
newinet
->
sport
=
inet
->
sport
;
newinet
->
saddr
=
inet
->
saddr
;
newinet
->
rcv_saddr
=
inet
->
saddr
;
newinet
->
dport
=
asoc
->
peer
.
port
;
newinet
->
daddr
=
asoc
->
peer
.
primary_addr
.
v4
.
sin_addr
.
s_addr
;
newinet
->
pmtudisc
=
inet
->
pmtudisc
;
newinet
->
id
=
0
;
newinet
->
ttl
=
sysctl_ip_default_ttl
;
newinet
->
mc_loop
=
1
;
newinet
->
mc_ttl
=
1
;
newinet
->
mc_index
=
0
;
newinet
->
mc_list
=
NULL
;
#ifdef INET_REFCNT_DEBUG
atomic_inc
(
&
inet_sock_nr
);
#endif
if
(
0
!=
newsk
->
prot
->
init
(
newsk
))
{
inet_sock_release
(
newsk
);
newsk
=
NULL
;
}
out:
return
newsk
;
}
/* Event handler for inet address addition/deletion events.
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
* Basically, whenever there is an event, we re-build our local address list.
*/
*/
...
@@ -501,10 +557,13 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event,
...
@@ -501,10 +557,13 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event,
*/
*/
int
sctp_ctl_sock_init
(
void
)
int
sctp_ctl_sock_init
(
void
)
{
{
int
err
=
0
;
int
err
;
int
family
=
PF_INET
;
sa_family_t
family
;
SCTP_V6
(
family
=
PF_INET6
;)
if
(
sctp_get_pf_specific
(
PF_INET6
))
family
=
PF_INET6
;
else
family
=
PF_INET
;
err
=
sock_create
(
family
,
SOCK_SEQPACKET
,
IPPROTO_SCTP
,
err
=
sock_create
(
family
,
SOCK_SEQPACKET
,
IPPROTO_SCTP
,
&
sctp_ctl_socket
);
&
sctp_ctl_socket
);
...
@@ -630,6 +689,16 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
...
@@ -630,6 +689,16 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return
sctp_v4_available
(
addr
);
return
sctp_v4_available
(
addr
);
}
}
/* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Returns number of addresses supported.
*/
static
int
sctp_inet_supported_addrs
(
const
struct
sctp_opt
*
opt
,
__u16
*
types
)
{
types
[
0
]
=
SCTP_PARAM_IPV4_ADDRESS
;
return
1
;
}
/* Wrapper routine that calls the ip transmit routine. */
/* Wrapper routine that calls the ip transmit routine. */
static
inline
int
sctp_v4_xmit
(
struct
sk_buff
*
skb
,
static
inline
int
sctp_v4_xmit
(
struct
sk_buff
*
skb
,
struct
sctp_transport
*
transport
,
int
ipfragok
)
struct
sctp_transport
*
transport
,
int
ipfragok
)
...
@@ -652,6 +721,8 @@ static struct sctp_pf sctp_pf_inet = {
...
@@ -652,6 +721,8 @@ static struct sctp_pf sctp_pf_inet = {
.
af_supported
=
sctp_inet_af_supported
,
.
af_supported
=
sctp_inet_af_supported
,
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
bind_verify
=
sctp_inet_bind_verify
,
.
bind_verify
=
sctp_inet_bind_verify
,
.
supported_addrs
=
sctp_inet_supported_addrs
,
.
create_accept_sk
=
sctp_v4_create_accept_sk
,
.
af
=
&
sctp_ipv4_specific
,
.
af
=
&
sctp_ipv4_specific
,
};
};
...
@@ -682,7 +753,7 @@ struct proto_ops inet_seqpacket_ops = {
...
@@ -682,7 +753,7 @@ struct proto_ops inet_seqpacket_ops = {
};
};
/* Registration with AF_INET family. */
/* Registration with AF_INET family. */
st
ruct
inet_protosw
sctp
_protosw
=
{
st
atic
struct
inet_protosw
sctp_seqpacket
_protosw
=
{
.
type
=
SOCK_SEQPACKET
,
.
type
=
SOCK_SEQPACKET
,
.
protocol
=
IPPROTO_SCTP
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
prot
=
&
sctp_prot
,
...
@@ -691,6 +762,15 @@ struct inet_protosw sctp_protosw = {
...
@@ -691,6 +762,15 @@ struct inet_protosw sctp_protosw = {
.
no_check
=
0
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
.
flags
=
SCTP_PROTOSW_FLAG
};
};
static
struct
inet_protosw
sctp_stream_protosw
=
{
.
type
=
SOCK_STREAM
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
ops
=
&
inet_seqpacket_ops
,
.
capability
=
-
1
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
};
/* Register with IP layer. */
/* Register with IP layer. */
static
struct
inet_protocol
sctp_protocol
=
{
static
struct
inet_protocol
sctp_protocol
=
{
...
@@ -797,8 +877,9 @@ __init int sctp_init(void)
...
@@ -797,8 +877,9 @@ __init int sctp_init(void)
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
return
-
EAGAIN
;
/* Add SCTP to inetsw linked list. */
/* Add SCTP(TCP and UDP style) to inetsw linked list. */
inet_register_protosw
(
&
sctp_protosw
);
inet_register_protosw
(
&
sctp_seqpacket_protosw
);
inet_register_protosw
(
&
sctp_stream_protosw
);
/* Allocate and initialise sctp mibs. */
/* Allocate and initialise sctp mibs. */
status
=
init_sctp_mibs
();
status
=
init_sctp_mibs
();
...
@@ -944,7 +1025,8 @@ __init int sctp_init(void)
...
@@ -944,7 +1025,8 @@ __init int sctp_init(void)
cleanup_sctp_mibs
();
cleanup_sctp_mibs
();
err_init_mibs:
err_init_mibs:
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_unregister_protosw
(
&
sctp_protosw
);
inet_unregister_protosw
(
&
sctp_seqpacket_protosw
);
inet_unregister_protosw
(
&
sctp_stream_protosw
);
return
status
;
return
status
;
}
}
...
@@ -977,7 +1059,8 @@ __exit void sctp_exit(void)
...
@@ -977,7 +1059,8 @@ __exit void sctp_exit(void)
cleanup_sctp_mibs
();
cleanup_sctp_mibs
();
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_unregister_protosw
(
&
sctp_protosw
);
inet_unregister_protosw
(
&
sctp_seqpacket_protosw
);
inet_unregister_protosw
(
&
sctp_stream_protosw
);
}
}
module_init
(
sctp_init
);
module_init
(
sctp_init
);
...
...
net/sctp/sm_make_chunk.c
View file @
e5e956d0
...
@@ -66,29 +66,6 @@
...
@@ -66,29 +66,6 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
* Note 4: This parameter, when present, specifies all the
* address types the sending endpoint can support. The absence
* of this parameter indicates that the sending endpoint can
* support any address type.
*/
static
const
sctp_supported_addrs_param_t
sat_param
=
{
{
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES
,
__constant_htons
(
SCTP_SAT_LEN
),
}
};
/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above
* structure is split and the address types array is initialized using a
* fixed length array.
*/
static
const
__u16
sat_addr_types
[
2
]
=
{
SCTP_PARAM_IPV4_ADDRESS
,
SCTP_V6
(
SCTP_PARAM_IPV6_ADDRESS
,)
};
/* RFC 2960 3.3.2 Initiation (INIT) (1)
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
*
* Note 2: The ECN capable field is reserved for future use of
* Note 2: The ECN capable field is reserved for future use of
...
@@ -174,7 +151,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -174,7 +151,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
union
sctp_params
addrs
;
union
sctp_params
addrs
;
size_t
chunksize
;
size_t
chunksize
;
sctp_chunk_t
*
retval
=
NULL
;
sctp_chunk_t
*
retval
=
NULL
;
int
addrs_len
=
0
;
int
num_types
,
addrs_len
=
0
;
struct
sctp_opt
*
sp
;
sctp_supported_addrs_param_t
sat
;
__u16
types
[
2
];
/* RFC 2960 3.3.2 Initiation (INIT) (1)
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
*
...
@@ -195,7 +175,11 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -195,7 +175,11 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
init
.
num_inbound_streams
=
htons
(
asoc
->
c
.
sinit_max_instreams
);
init
.
num_inbound_streams
=
htons
(
asoc
->
c
.
sinit_max_instreams
);
init
.
initial_tsn
=
htonl
(
asoc
->
c
.
initial_tsn
);
init
.
initial_tsn
=
htonl
(
asoc
->
c
.
initial_tsn
);
chunksize
=
sizeof
(
init
)
+
addrs_len
+
SCTP_SAT_LEN
;
/* How many address types are needed? */
sp
=
sctp_sk
(
asoc
->
base
.
sk
);
num_types
=
sp
->
pf
->
supported_addrs
(
sp
,
types
);
chunksize
=
sizeof
(
init
)
+
addrs_len
+
SCTP_SAT_LEN
(
num_types
);
chunksize
+=
sizeof
(
ecap_param
);
chunksize
+=
sizeof
(
ecap_param
);
chunksize
+=
vparam_len
;
chunksize
+=
vparam_len
;
...
@@ -220,8 +204,18 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -220,8 +204,18 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
retval
->
param_hdr
.
v
=
retval
->
param_hdr
.
v
=
sctp_addto_chunk
(
retval
,
addrs_len
,
addrs
.
v
);
sctp_addto_chunk
(
retval
,
addrs_len
,
addrs
.
v
);
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_paramhdr_t
),
&
sat_param
);
/* RFC 2960 3.3.2 Initiation (INIT) (1)
sctp_addto_chunk
(
retval
,
sizeof
(
sat_addr_types
),
sat_addr_types
);
*
* Note 4: This parameter, when present, specifies all the
* address types the sending endpoint can support. The absence
* of this parameter indicates that the sending endpoint can
* support any address type.
*/
sat
.
param_hdr
.
type
=
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES
;
sat
.
param_hdr
.
length
=
htons
(
SCTP_SAT_LEN
(
num_types
));
sctp_addto_chunk
(
retval
,
sizeof
(
sat
),
&
sat
);
sctp_addto_chunk
(
retval
,
num_types
*
sizeof
(
__u16
),
&
types
);
sctp_addto_chunk
(
retval
,
sizeof
(
ecap_param
),
&
ecap_param
);
sctp_addto_chunk
(
retval
,
sizeof
(
ecap_param
),
&
ecap_param
);
nodata:
nodata:
if
(
addrs
.
v
)
if
(
addrs
.
v
)
...
@@ -604,7 +598,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
...
@@ -604,7 +598,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Initialize the SACK header. */
/* Initialize the SACK header. */
sack
.
cum_tsn_ack
=
htonl
(
ctsn
);
sack
.
cum_tsn_ack
=
htonl
(
ctsn
);
sack
.
a_rwnd
=
htonl
(
asoc
->
rwnd
);
sack
.
a_rwnd
=
htonl
(
asoc
->
a_
rwnd
);
sack
.
num_gap_ack_blocks
=
htons
(
num_gabs
);
sack
.
num_gap_ack_blocks
=
htons
(
num_gabs
);
sack
.
num_dup_tsns
=
htons
(
num_dup_tsns
);
sack
.
num_dup_tsns
=
htons
(
num_dup_tsns
);
...
@@ -1159,7 +1153,7 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
...
@@ -1159,7 +1153,7 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
first_len
=
max
;
first_len
=
max
;
/* Encourage Cookie-ECHO bundling. */
/* Encourage Cookie-ECHO bundling. */
if
(
asoc
->
state
<
SCTP_STATE_
ESTABLISH
ED
)
{
if
(
asoc
->
state
<
SCTP_STATE_
COOKIE_ECHO
ED
)
{
whole
=
msg_len
/
(
max
-
SCTP_ARBITRARY_COOKIE_ECHO_LEN
);
whole
=
msg_len
/
(
max
-
SCTP_ARBITRARY_COOKIE_ECHO_LEN
);
/* Account for the DATA to be bundled with the COOKIE-ECHO. */
/* Account for the DATA to be bundled with the COOKIE-ECHO. */
...
@@ -1282,7 +1276,7 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
...
@@ -1282,7 +1276,7 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
* assign a TSN.
* assign a TSN.
*/
*/
chunk
->
subh
.
data_hdr
->
tsn
=
chunk
->
subh
.
data_hdr
->
tsn
=
htonl
(
__
sctp_association_get_next_tsn
(
chunk
->
asoc
));
htonl
(
sctp_association_get_next_tsn
(
chunk
->
asoc
));
chunk
->
has_tsn
=
1
;
chunk
->
has_tsn
=
1
;
}
}
}
}
...
...
net/sctp/sm_sideeffect.c
View file @
e5e956d0
...
@@ -105,8 +105,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *, sctp_association_t *,
...
@@ -105,8 +105,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *, sctp_association_t *,
#define DEBUG_POST_SFX \
#define DEBUG_POST_SFX \
SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
error, asoc, \
error, asoc, \
sctp_state_tbl[sctp_id2assoc(ep->base.sk, \
sctp_state_tbl[asoc?asoc->state:SCTP_STATE_CLOSED])
sctp_assoc2id(asoc))?asoc->state:SCTP_STATE_CLOSED])
/*
/*
* This is the master state machine processing function.
* This is the master state machine processing function.
...
@@ -256,7 +255,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -256,7 +255,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_cmd_t
*
cmd
;
sctp_cmd_t
*
cmd
;
sctp_chunk_t
*
new_obj
;
sctp_chunk_t
*
new_obj
;
sctp_chunk_t
*
chunk
=
NULL
;
sctp_chunk_t
*
chunk
=
NULL
;
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
struct
timer_list
*
timer
;
struct
timer_list
*
timer
;
unsigned
long
timeout
;
unsigned
long
timeout
;
...
@@ -716,13 +715,12 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
...
@@ -716,13 +715,12 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
asoc
->
peer
.
sack_needed
=
1
;
asoc
->
peer
.
sack_needed
=
1
;
goto
out
;
goto
out
;
}
else
{
}
else
{
if
(
asoc
->
a_rwnd
>
asoc
->
rwnd
)
asoc
->
a_rwnd
=
asoc
->
rwnd
;
sack
=
sctp_make_sack
(
asoc
);
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
if
(
!
sack
)
goto
nomem
;
goto
nomem
;
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
sack_needed
=
0
;
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
...
@@ -1223,13 +1221,35 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
...
@@ -1223,13 +1221,35 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_state_t
state
)
sctp_state_t
state
)
{
{
struct
sock
*
sk
=
asoc
->
base
.
sk
;
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
asoc
->
state
=
state
;
asoc
->
state
=
state
;
asoc
->
state_timestamp
=
jiffies
;
asoc
->
state_timestamp
=
jiffies
;
/* Wake up any process waiting for the association to
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
||
* get established.
(
SCTP_STATE_CLOSED
==
asoc
->
state
))
{
/* Wake up any processes waiting in the asoc's wait queue in
* sctp_wait_for_connect() or sctp_wait_for_sndbuf().
*/
*/
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
&&
if
(
waitqueue_active
(
&
asoc
->
wait
))
(
waitqueue_active
(
&
asoc
->
wait
)))
wake_up_interruptible
(
&
asoc
->
wait
);
wake_up_interruptible
(
&
asoc
->
wait
);
/* Wake up any processes waiting in the sk's sleep queue of
* a TCP-style or UDP-style peeled-off socket in
* sctp_wait_for_accept() or sctp_wait_for_packet().
* For a UDP-style socket, the waiters are woken up by the
* notifications.
*/
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
sk
->
state_change
(
sk
);
}
/* Change the sk->state of a TCP-style socket that has sucessfully
* completed a connect() call.
*/
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
&&
(
SCTP_SOCKET_TCP
==
sp
->
type
)
&&
(
SCTP_SS_CLOSED
==
sk
->
state
))
sk
->
state
=
SCTP_SS_ESTABLISHED
;
}
}
net/sctp/sm_statefuns.c
View file @
e5e956d0
...
@@ -189,7 +189,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -189,7 +189,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
sctp_association_t
*
new_asoc
;
sctp_association_t
*
new_asoc
;
sctp_chunk_t
*
err_chunk
;
sctp_chunk_t
*
err_chunk
;
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
sctp_unrecognized_param_t
*
unk_param
;
sctp_unrecognized_param_t
*
unk_param
;
int
len
;
int
len
;
...
@@ -354,10 +354,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
...
@@ -354,10 +354,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
sctp_init_chunk_t
*
initchunk
;
sctp_init_chunk_t
*
initchunk
;
__u32
init_tag
;
__u32
init_tag
;
sctp_chunk_t
*
err_chunk
;
sctp_chunk_t
*
err_chunk
;
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
sctp_disposition_t
ret
;
sctp_disposition_t
ret
;
/* 6.10 Bundling
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
* SHUTDOWN COMPLETE with any other chunks.
...
@@ -912,14 +911,14 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
...
@@ -912,14 +911,14 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
int
len
;
int
len
;
s
ctp_packet_
t
*
pkt
;
s
truct
sctp_packe
t
*
pkt
;
sctp_addr_param_t
*
addrparm
;
sctp_addr_param_t
*
addrparm
;
sctp_errhdr_t
*
errhdr
;
sctp_errhdr_t
*
errhdr
;
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
char
buffer
[
sizeof
(
sctp_errhdr_t
)
+
sizeof
(
sctp_addr_param_t
)];
char
buffer
[
sizeof
(
sctp_errhdr_t
)
+
sizeof
(
sctp_addr_param_t
)];
/* Build the error on the stack. We are way to malloc
/* Build the error on the stack. We are way to malloc
crazy
*
malloc crazy
throughout the code today.
* throughout the code today.
*/
*/
errhdr
=
(
sctp_errhdr_t
*
)
buffer
;
errhdr
=
(
sctp_errhdr_t
*
)
buffer
;
addrparm
=
(
sctp_addr_param_t
*
)
errhdr
->
variable
;
addrparm
=
(
sctp_addr_param_t
*
)
errhdr
->
variable
;
...
@@ -1105,11 +1104,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
...
@@ -1105,11 +1104,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
sctp_chunk_t
*
repl
;
sctp_chunk_t
*
repl
;
sctp_association_t
*
new_asoc
;
sctp_association_t
*
new_asoc
;
sctp_chunk_t
*
err_chunk
;
sctp_chunk_t
*
err_chunk
;
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
sctp_unrecognized_param_t
*
unk_param
;
sctp_unrecognized_param_t
*
unk_param
;
int
len
;
int
len
;
/* 6.10 Bundling
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
* SHUTDOWN COMPLETE with any other chunks.
...
@@ -2751,7 +2749,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
...
@@ -2751,7 +2749,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
void
*
arg
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
s
ctp_packet_
t
*
packet
=
NULL
;
s
truct
sctp_packe
t
*
packet
=
NULL
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
abort
;
sctp_chunk_t
*
abort
;
...
@@ -2953,7 +2951,7 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
...
@@ -2953,7 +2951,7 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
void
*
arg
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
s
ctp_packet_
t
*
packet
=
NULL
;
s
truct
sctp_packe
t
*
packet
=
NULL
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
shut
;
sctp_chunk_t
*
shut
;
...
@@ -4377,13 +4375,13 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
...
@@ -4377,13 +4375,13 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
/* Create an ABORT packet to be sent as a response, with the specified
/* Create an ABORT packet to be sent as a response, with the specified
* error causes.
* error causes.
*/
*/
s
ctp_packet_
t
*
sctp_abort_pkt_new
(
const
sctp_endpoint_t
*
ep
,
s
truct
sctp_packe
t
*
sctp_abort_pkt_new
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
const
void
*
payload
,
const
void
*
payload
,
size_t
paylen
)
size_t
paylen
)
{
{
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
sctp_chunk_t
*
abort
;
sctp_chunk_t
*
abort
;
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
...
@@ -4413,10 +4411,10 @@ sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
...
@@ -4413,10 +4411,10 @@ sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
}
}
/* Allocate a packet for responding in the OOTB conditions. */
/* Allocate a packet for responding in the OOTB conditions. */
s
ctp_packet_
t
*
sctp_ootb_pkt_new
(
const
sctp_association_t
*
asoc
,
s
truct
sctp_packe
t
*
sctp_ootb_pkt_new
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
)
const
sctp_chunk_t
*
chunk
)
{
{
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
__u16
sport
;
__u16
sport
;
__u16
dport
;
__u16
dport
;
...
@@ -4449,7 +4447,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
...
@@ -4449,7 +4447,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
goto
nomem
;
goto
nomem
;
/* Allocate a new packet for sending the response. */
/* Allocate a new packet for sending the response. */
packet
=
t_new
(
s
ctp_packet_
t
,
GFP_ATOMIC
);
packet
=
t_new
(
s
truct
sctp_packe
t
,
GFP_ATOMIC
);
if
(
!
packet
)
if
(
!
packet
)
goto
nomem_packet
;
goto
nomem_packet
;
...
@@ -4471,7 +4469,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
...
@@ -4471,7 +4469,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
}
}
/* Free the packet allocated earlier for responding in the OOTB condition. */
/* Free the packet allocated earlier for responding in the OOTB condition. */
void
sctp_ootb_pkt_free
(
s
ctp_packet_
t
*
packet
)
void
sctp_ootb_pkt_free
(
s
truct
sctp_packe
t
*
packet
)
{
{
sctp_transport_free
(
packet
->
transport
);
sctp_transport_free
(
packet
->
transport
);
sctp_packet_free
(
packet
);
sctp_packet_free
(
packet
);
...
@@ -4484,7 +4482,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
...
@@ -4484,7 +4482,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
,
sctp_cmd_seq_t
*
commands
,
sctp_chunk_t
*
err_chunk
)
sctp_chunk_t
*
err_chunk
)
{
{
s
ctp_packet_
t
*
packet
;
s
truct
sctp_packe
t
*
packet
;
if
(
err_chunk
)
{
if
(
err_chunk
)
{
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
...
...
net/sctp/socket.c
View file @
e5e956d0
...
@@ -88,12 +88,46 @@ static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
...
@@ -88,12 +88,46 @@ static int sctp_wait_for_sndbuf(struct 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
(
struct
sctp_association
*
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
struct
sctp_association
*
,
long
*
timeo_p
);
static
int
sctp_wait_for_accept
(
struct
sock
*
sk
,
long
timeo
);
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
);
static
int
sctp_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
static
void
sctp_sock_migrate
(
struct
sock
*
,
struct
sock
*
,
struct
sctp_association
*
,
sctp_socket_type_t
);
/* Look up the association by its id. If this is not a UDP-style
* socket, the ID field is always ignored.
*/
sctp_association_t
*
sctp_id2assoc
(
struct
sock
*
sk
,
sctp_assoc_t
id
)
{
sctp_association_t
*
asoc
=
NULL
;
/* If this is not a UDP-style socket, assoc id should be
* ignored.
*/
if
(
SCTP_SOCKET_UDP
!=
sctp_sk
(
sk
)
->
type
)
{
if
(
!
list_empty
(
&
sctp_sk
(
sk
)
->
ep
->
asocs
))
asoc
=
list_entry
(
sctp_sk
(
sk
)
->
ep
->
asocs
.
next
,
sctp_association_t
,
asocs
);
return
asoc
;
}
/* First, verify that this is a kernel address. */
if
(
sctp_is_valid_kaddr
((
unsigned
long
)
id
))
{
sctp_association_t
*
temp
=
(
sctp_association_t
*
)
id
;
/* Verify that this _is_ an sctp_association_t
* data structure and if so, that the socket matches.
*/
if
((
SCTP_ASSOC_EYECATCHER
==
temp
->
eyecatcher
)
&&
(
temp
->
base
.
sk
==
sk
))
asoc
=
temp
;
}
return
asoc
;
}
/* API 3.1.2 bind() - UDP Style Syntax
/* API 3.1.2 bind() - UDP Style Syntax
* The syntax of bind() is,
* The syntax of bind() is,
...
@@ -818,19 +852,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -818,19 +852,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
}
}
}
}
else
{
}
else
{
/* For a peeled-off socket, ignore any associd specified by
* the user with SNDRCVINFO.
*/
if
(
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
==
sp
->
type
)
{
if
(
list_empty
(
&
ep
->
asocs
))
{
err
=
-
EINVAL
;
goto
out_unlock
;
}
asoc
=
list_entry
(
ep
->
asocs
.
next
,
sctp_association_t
,
asocs
);
}
else
if
(
associd
)
{
asoc
=
sctp_id2assoc
(
sk
,
associd
);
asoc
=
sctp_id2assoc
(
sk
,
associd
);
}
if
(
!
asoc
)
{
if
(
!
asoc
)
{
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
out_unlock
;
goto
out_unlock
;
...
@@ -1126,17 +1148,19 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1126,17 +1148,19 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
int
err
=
0
;
int
err
=
0
;
int
skb_len
;
int
skb_len
;
SCTP_DEBUG_PRINTK
(
"sctp_recvmsg("
SCTP_DEBUG_PRINTK
(
"sctp_recvmsg(%s: %p, %s: %p, %s: %d, %s: %d, %s: "
"%s: %p, %s: %p, %s: %d, %s: %d, %s: "
"0x%x, %s: %p)
\n
"
,
"sk"
,
sk
,
"msghdr"
,
msg
,
"0x%x, %s: %p)
\n
"
,
"len"
,
len
,
"knoblauch"
,
noblock
,
"sk"
,
sk
,
"flags"
,
flags
,
"addr_len"
,
addr_len
);
"msghdr"
,
msg
,
"len"
,
len
,
"knoblauch"
,
noblock
,
"flags"
,
flags
,
"addr_len"
,
addr_len
);
sctp_lock_sock
(
sk
);
sctp_lock_sock
(
sk
);
if
((
SCTP_SOCKET_TCP
==
sp
->
type
)
&&
(
SCTP_SS_ESTABLISHED
!=
sk
->
state
))
{
err
=
-
ENOTCONN
;
goto
out
;
}
skb
=
sctp_skb_recv_datagram
(
sk
,
flags
,
noblock
,
&
err
);
skb
=
sctp_skb_recv_datagram
(
sk
,
flags
,
noblock
,
&
err
);
if
(
!
skb
)
if
(
!
skb
)
goto
out
;
goto
out
;
...
@@ -1207,7 +1231,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1207,7 +1231,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
return
err
;
return
err
;
}
}
static
in
line
in
t
sctp_setsockopt_disable_fragments
(
struct
sock
*
sk
,
static
int
sctp_setsockopt_disable_fragments
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
char
*
optval
,
int
optlen
)
{
{
int
val
;
int
val
;
...
@@ -1223,7 +1247,7 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk,
...
@@ -1223,7 +1247,7 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk,
return
0
;
return
0
;
}
}
static
in
line
int
sctp_setsockopt_se
t_events
(
struct
sock
*
sk
,
char
*
optval
,
static
in
t
sctp_setsockop
t_events
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
int
optlen
)
{
{
if
(
optlen
!=
sizeof
(
struct
sctp_event_subscribe
))
if
(
optlen
!=
sizeof
(
struct
sctp_event_subscribe
))
...
@@ -1233,7 +1257,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
...
@@ -1233,7 +1257,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
return
0
;
return
0
;
}
}
static
in
line
in
t
sctp_setsockopt_autoclose
(
struct
sock
*
sk
,
char
*
optval
,
static
int
sctp_setsockopt_autoclose
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
int
optlen
)
{
{
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
...
@@ -1250,9 +1274,8 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
...
@@ -1250,9 +1274,8 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return
0
;
return
0
;
}
}
static
inline
int
sctp_setsockopt_set_peer_addr_params
(
struct
sock
*
sk
,
static
int
sctp_setsockopt_peer_addr_params
(
struct
sock
*
sk
,
char
*
optval
,
char
*
optval
,
int
optlen
)
int
optlen
)
{
{
struct
sctp_paddrparams
params
;
struct
sctp_paddrparams
params
;
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
...
@@ -1290,8 +1313,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
...
@@ -1290,8 +1313,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
error
=
sctp_primitive_REQUESTHEARTBEAT
(
asoc
,
trans
);
error
=
sctp_primitive_REQUESTHEARTBEAT
(
asoc
,
trans
);
if
(
error
)
if
(
error
)
return
error
;
return
error
;
}
}
else
{
else
{
/* The value of the heartbeat interval, in milliseconds. A value of 0,
/* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this
* when modifying the parameter, specifies that the heartbeat on this
* address should be disabled.
* address should be disabled.
...
@@ -1311,7 +1333,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
...
@@ -1311,7 +1333,7 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
return
0
;
return
0
;
}
}
static
in
line
in
t
sctp_setsockopt_initmsg
(
struct
sock
*
sk
,
char
*
optval
,
static
int
sctp_setsockopt_initmsg
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
int
optlen
)
{
{
if
(
optlen
!=
sizeof
(
struct
sctp_initmsg
))
if
(
optlen
!=
sizeof
(
struct
sctp_initmsg
))
...
@@ -1336,7 +1358,7 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
...
@@ -1336,7 +1358,7 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
* sinfo_timetolive. The user must provide the sinfo_assoc_id field in
* sinfo_timetolive. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
* to this call if the caller is using the UDP model.
*/
*/
static
in
line
int
sctp_setsockopt_se
t_default_send_param
(
struct
sock
*
sk
,
static
in
t
sctp_setsockop
t_default_send_param
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
char
*
optval
,
int
optlen
)
{
{
struct
sctp_sndrcvinfo
info
;
struct
sctp_sndrcvinfo
info
;
...
@@ -1359,6 +1381,66 @@ static inline int sctp_setsockopt_set_default_send_param(struct sock *sk,
...
@@ -1359,6 +1381,66 @@ static inline int sctp_setsockopt_set_default_send_param(struct sock *sk,
return
0
;
return
0
;
}
}
/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
*
* Requests that the local SCTP stack use the enclosed peer address as
* the association primary. The enclosed address must be one of the
* association peer's addresses.
*/
static
int
sctp_setsockopt_peer_prim
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
struct
sctp_setpeerprim
prim
;
struct
sctp_association
*
asoc
;
union
sctp_addr
*
addr
;
struct
sctp_transport
*
trans
;
if
(
optlen
!=
sizeof
(
struct
sctp_setpeerprim
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
prim
,
optval
,
sizeof
(
struct
sctp_setpeerprim
)))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
prim
.
sspp_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
/* Find the requested address. */
addr
=
(
union
sctp_addr
*
)
&
(
prim
.
sspp_addr
);
trans
=
sctp_assoc_lookup_paddr
(
asoc
,
addr
);
if
(
!
trans
)
return
-
ENOENT
;
sctp_assoc_set_primary
(
asoc
,
trans
);
return
0
;
}
/*
*
* 7.1.5 SCTP_NODELAY
*
* Turn on/off any Nagle-like algorithm. This means that packets are
* generally sent as soon as possible and no unnecessary delays are
* introduced, at the cost of more packets in the network. Expects an
* integer boolean flag.
*/
static
int
sctp_setsockopt_nodelay
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
__u8
val
;
if
(
optlen
<
sizeof
(
__u8
))
return
-
EINVAL
;
if
(
get_user
(
val
,
(
__u8
*
)
optval
))
return
-
EFAULT
;
sctp_sk
(
sk
)
->
nodelay
=
(
val
==
0
)
?
0
:
1
;
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
...
@@ -1434,7 +1516,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1434,7 +1516,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
break
;
break
;
case
SCTP_SET_EVENTS
:
case
SCTP_SET_EVENTS
:
retval
=
sctp_setsockopt_
set_
events
(
sk
,
optval
,
optlen
);
retval
=
sctp_setsockopt_events
(
sk
,
optval
,
optlen
);
break
;
break
;
case
SCTP_AUTOCLOSE
:
case
SCTP_AUTOCLOSE
:
...
@@ -1442,8 +1524,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1442,8 +1524,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
break
;
break
;
case
SCTP_SET_PEER_ADDR_PARAMS
:
case
SCTP_SET_PEER_ADDR_PARAMS
:
retval
=
sctp_setsockopt_set_peer_addr_params
(
sk
,
optval
,
retval
=
sctp_setsockopt_peer_addr_params
(
sk
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_INITMSG
:
case
SCTP_INITMSG
:
...
@@ -1451,8 +1532,16 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1451,8 +1532,16 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
break
;
break
;
case
SCTP_SET_DEFAULT_SEND_PARAM
:
case
SCTP_SET_DEFAULT_SEND_PARAM
:
retval
=
sctp_setsockopt_set_default_send_param
(
sk
,
retval
=
sctp_setsockopt_default_send_param
(
sk
,
optval
,
optval
,
optlen
);
optlen
);
break
;
case
SCTP_SET_PEER_PRIMARY_ADDR
:
retval
=
sctp_setsockopt_peer_prim
(
sk
,
optval
,
optlen
);
break
;
case
SCTP_NODELAY
:
retval
=
sctp_setsockopt_nodelay
(
sk
,
optval
,
optlen
);
break
;
break
;
default:
default:
...
@@ -1503,8 +1592,14 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
...
@@ -1503,8 +1592,14 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
sp
=
sctp_sk
(
sk
);
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
ep
=
sp
->
ep
;
/* connect() cannot be done on a peeled-off socket. */
/* connect() cannot be done on a socket that is already in ESTABLISHED
if
(
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
==
sp
->
type
)
{
* state - UDP-style peeled off socket or a TCP-style socket that
* is already connected.
* It cannot be done even on a TCP-style listening socket.
*/
if
((
SCTP_SS_ESTABLISHED
==
sk
->
state
)
||
((
SCTP_SOCKET_TCP
==
sp
->
type
)
&&
(
SCTP_SS_LISTENING
==
sk
->
state
)))
{
err
=
-
EISCONN
;
err
=
-
EISCONN
;
goto
out_unlock
;
goto
out_unlock
;
}
}
...
@@ -1513,6 +1608,8 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
...
@@ -1513,6 +1608,8 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
if
(
err
)
if
(
err
)
goto
out_unlock
;
goto
out_unlock
;
if
(
addr_len
>
sizeof
(
to
))
addr_len
=
sizeof
(
to
);
memcpy
(
&
to
,
uaddr
,
addr_len
);
memcpy
(
&
to
,
uaddr
,
addr_len
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
...
@@ -1585,13 +1682,63 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags)
...
@@ -1585,13 +1682,63 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags)
return
-
EOPNOTSUPP
;
/* STUB */
return
-
EOPNOTSUPP
;
/* STUB */
}
}
/* FIXME: Write comments. */
/* 4.1.4 accept() - TCP Style Syntax
*
* Applications use accept() call to remove an established SCTP
* association from the accept queue of the endpoint. A new socket
* descriptor will be returned from accept() to represent the newly
* formed association.
*/
SCTP_STATIC
struct
sock
*
sctp_accept
(
struct
sock
*
sk
,
int
flags
,
int
*
err
)
SCTP_STATIC
struct
sock
*
sctp_accept
(
struct
sock
*
sk
,
int
flags
,
int
*
err
)
{
{
int
error
=
-
EOPNOTSUPP
;
struct
sctp_opt
*
sp
;
struct
sctp_endpoint
*
ep
;
struct
sock
*
newsk
=
NULL
;
struct
sctp_association
*
assoc
;
long
timeo
;
int
error
=
0
;
sctp_lock_sock
(
sk
);
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
if
(
SCTP_SOCKET_TCP
!=
sp
->
type
)
{
error
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
SCTP_SS_LISTENING
!=
sk
->
state
)
{
error
=
-
EINVAL
;
goto
out
;
}
timeo
=
sock_rcvtimeo
(
sk
,
sk
->
socket
->
file
->
f_flags
&
O_NONBLOCK
);
error
=
sctp_wait_for_accept
(
sk
,
timeo
);
if
(
error
)
goto
out
;
/* We treat the list of associations on the endpoint as the accept
* queue and pick the first association on the list.
*/
assoc
=
list_entry
(
ep
->
asocs
.
next
,
struct
sctp_association
,
asocs
);
newsk
=
sp
->
pf
->
create_accept_sk
(
sk
,
assoc
);
if
(
!
newsk
)
{
error
=
-
ENOMEM
;
goto
out
;
}
/* Populate the fields of the newsk from the oldsk and migrate the
* assoc to the newsk.
*/
sctp_sock_migrate
(
sk
,
newsk
,
assoc
,
SCTP_SOCKET_TCP
);
out:
sctp_release_sock
(
sk
);
*
err
=
error
;
*
err
=
error
;
return
NULL
;
return
newsk
;
}
}
/* FIXME: Write Comments. */
/* FIXME: Write Comments. */
...
@@ -1607,7 +1754,7 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
...
@@ -1607,7 +1754,7 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
SCTP_STATIC
int
sctp_init_sock
(
struct
sock
*
sk
)
SCTP_STATIC
int
sctp_init_sock
(
struct
sock
*
sk
)
{
{
sctp_endpoint_t
*
ep
;
sctp_endpoint_t
*
ep
;
s
ctp_protocol_t
*
proto
;
s
truct
sctp_protocol
*
proto
;
struct
sctp_opt
*
sp
;
struct
sctp_opt
*
sp
;
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
...
@@ -1617,7 +1764,16 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1617,7 +1764,16 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp
=
sctp_sk
(
sk
);
sp
=
sctp_sk
(
sk
);
/* Initialize the SCTP per socket area. */
/* Initialize the SCTP per socket area. */
switch
(
sk
->
type
)
{
case
SOCK_SEQPACKET
:
sp
->
type
=
SCTP_SOCKET_UDP
;
sp
->
type
=
SCTP_SOCKET_UDP
;
break
;
case
SOCK_STREAM
:
sp
->
type
=
SCTP_SOCKET_TCP
;
break
;
default:
return
-
ESOCKTNOSUPPORT
;
}
/* FIXME: The next draft (04) of the SCTP Sockets Extensions
/* FIXME: The next draft (04) of the SCTP Sockets Extensions
* should include a socket option for manipulating these
* should include a socket option for manipulating these
...
@@ -1665,7 +1821,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1665,7 +1821,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp
->
disable_fragments
=
0
;
sp
->
disable_fragments
=
0
;
/* Turn on/off any Nagle-like algorithm. */
/* Turn on/off any Nagle-like algorithm. */
sp
->
nodelay
=
0
;
sp
->
nodelay
=
1
;
/* Auto-close idle associations after the configured
/* Auto-close idle associations after the configured
* number of seconds. A value of 0 disables this
* number of seconds. A value of 0 disables this
...
@@ -1714,11 +1870,17 @@ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
...
@@ -1714,11 +1870,17 @@ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
/* STUB */
/* STUB */
}
}
/* 7.2.1 Association Status (SCTP_STATUS)
* Applications can retrieve current status information about an
* association, including association state, peer receiver window size,
* number of unacked data chunks, and number of data chunks pending
* receipt. This information is read-only.
*/
static
int
sctp_getsockopt_sctp_status
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
static
int
sctp_getsockopt_sctp_status
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
int
*
optlen
)
{
{
struct
sctp_status
status
;
struct
sctp_status
status
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
assoc
=
NULL
;
sctp_association_t
*
assoc
=
NULL
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_assoc_t
associd
;
sctp_assoc_t
associd
;
...
@@ -1735,21 +1897,11 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1735,21 +1897,11 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
}
}
associd
=
status
.
sstat_assoc_id
;
associd
=
status
.
sstat_assoc_id
;
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sctp_sk
(
sk
)
->
type
)
&&
associd
)
{
assoc
=
sctp_id2assoc
(
sk
,
associd
);
assoc
=
sctp_id2assoc
(
sk
,
associd
);
if
(
!
assoc
)
{
if
(
!
assoc
)
{
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
goto
out
;
goto
out
;
}
}
}
else
{
ep
=
sctp_sk
(
sk
)
->
ep
;
if
(
list_empty
(
&
ep
->
asocs
))
{
retval
=
-
EINVAL
;
goto
out
;
}
assoc
=
list_entry
(
ep
->
asocs
.
next
,
sctp_association_t
,
asocs
);
}
transport
=
assoc
->
peer
.
primary_path
;
transport
=
assoc
->
peer
.
primary_path
;
...
@@ -1788,7 +1940,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1788,7 +1940,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
return
(
retval
);
return
(
retval
);
}
}
static
in
line
in
t
sctp_getsockopt_disable_fragments
(
struct
sock
*
sk
,
int
len
,
static
int
sctp_getsockopt_disable_fragments
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
int
val
;
int
val
;
...
@@ -1805,7 +1957,7 @@ static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
...
@@ -1805,7 +1957,7 @@ static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
return
0
;
return
0
;
}
}
static
in
line
in
t
sctp_getsockopt_set_events
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
static
int
sctp_getsockopt_set_events
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
{
if
(
len
!=
sizeof
(
struct
sctp_event_subscribe
))
if
(
len
!=
sizeof
(
struct
sctp_event_subscribe
))
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -1814,7 +1966,7 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt
...
@@ -1814,7 +1966,7 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt
return
0
;
return
0
;
}
}
static
in
line
in
t
sctp_getsockopt_autoclose
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
static
int
sctp_getsockopt_autoclose
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
{
/* Applicable to UDP-style socket only */
/* Applicable to UDP-style socket only */
if
(
SCTP_SOCKET_TCP
==
sctp_sk
(
sk
)
->
type
)
if
(
SCTP_SOCKET_TCP
==
sctp_sk
(
sk
)
->
type
)
...
@@ -1832,11 +1984,6 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1832,11 +1984,6 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
struct
sock
*
oldsk
=
assoc
->
base
.
sk
;
struct
sock
*
oldsk
=
assoc
->
base
.
sk
;
struct
sock
*
newsk
;
struct
sock
*
newsk
;
struct
socket
*
tmpsock
;
struct
socket
*
tmpsock
;
sctp_endpoint_t
*
newep
;
struct
sctp_opt
*
oldsp
=
sctp_sk
(
oldsk
);
struct
sctp_opt
*
newsp
;
struct
sk_buff
*
skb
,
*
tmp
;
struct
sctp_ulpevent
*
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
...
@@ -1846,88 +1993,24 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1846,88 +1993,24 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
return
-
EOPNOTSUPP
;
return
-
EOPNOTSUPP
;
/* Create a new socket. */
/* Create a new socket. */
err
=
sock_create
(
PF_INET
,
SOCK_SEQPACKET
,
IPPROTO_SCTP
,
&
tmpsock
);
err
=
sock_create
(
oldsk
->
family
,
SOCK_SEQPACKET
,
IPPROTO_SCTP
,
&
tmpsock
);
if
(
err
<
0
)
if
(
err
<
0
)
return
err
;
return
err
;
newsk
=
tmpsock
->
sk
;
newsk
=
tmpsock
->
sk
;
newsp
=
sctp_sk
(
newsk
);
newep
=
newsp
->
ep
;
/* Migrate socket buffer sizes and all the socket level options to the
* new socket.
*/
newsk
->
sndbuf
=
oldsk
->
sndbuf
;
newsk
->
rcvbuf
=
oldsk
->
rcvbuf
;
*
newsp
=
*
oldsp
;
/* Restore the ep value that was overwritten with the above structure
* copy.
*/
newsp
->
ep
=
newep
;
/* Move any messages in the old socket's receive queue that are for the
* peeled off association to the new socket's receive queue.
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
/* Clean up an messages pending delivery due to partial
/* Populate the fields of the newsk from the oldsk and migrate the
* delivery. Three cases:
* assoc to the newsk.
* 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_sock_migrate
(
oldsk
,
newsk
,
assoc
,
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
);
sctp_sk
(
newsk
)
->
pd_mode
=
assoc
->
ulpq
.
pd_mode
;;
if
(
sctp_sk
(
oldsk
)
->
pd_mode
)
{
struct
sk_buff_head
*
queue
;
/* Decide which queue to move pd_lobby skbs to. */
if
(
assoc
->
ulpq
.
pd_mode
)
{
queue
=
&
newsp
->
pd_lobby
;
}
else
queue
=
&
newsk
->
receive_queue
;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each
(
skb
,
&
oldsp
->
pd_lobby
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
queue
,
skb
);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if
(
assoc
->
ulpq
.
pd_mode
)
sctp_clear_pd
(
oldsk
);
}
/* Set the type of socket to indicate that it is peeled off from the
* original socket.
*/
newsp
->
type
=
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
;
/* Migrate the association to the new socket. */
sctp_assoc_migrate
(
assoc
,
newsk
);
*
newsock
=
tmpsock
;
*
newsock
=
tmpsock
;
return
err
;
return
err
;
}
}
static
in
line
in
t
sctp_getsockopt_peeloff
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
static
int
sctp_getsockopt_peeloff
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
{
sctp_peeloff_arg_t
peeloff
;
sctp_peeloff_arg_t
peeloff
;
struct
socket
*
newsock
;
struct
socket
*
newsock
;
...
@@ -1970,8 +2053,8 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
...
@@ -1970,8 +2053,8 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
return
retval
;
return
retval
;
}
}
static
in
line
int
sctp_getsockopt_get_peer_addr_params
(
struct
sock
*
sk
,
static
in
t
sctp_getsockopt_peer_addr_params
(
struct
sock
*
sk
,
int
len
,
int
len
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
struct
sctp_paddrparams
params
;
struct
sctp_paddrparams
params
;
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
...
@@ -2014,7 +2097,7 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
...
@@ -2014,7 +2097,7 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
return
0
;
return
0
;
}
}
static
in
line
in
t
sctp_getsockopt_initmsg
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
static
int
sctp_getsockopt_initmsg
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
{
if
(
len
!=
sizeof
(
struct
sctp_initmsg
))
if
(
len
!=
sizeof
(
struct
sctp_initmsg
))
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -2023,7 +2106,7 @@ static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval
...
@@ -2023,7 +2106,7 @@ static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval
return
0
;
return
0
;
}
}
static
in
line
int
sctp_getsockopt_get_peer_addrs_num
(
struct
sock
*
sk
,
int
len
,
static
in
t
sctp_getsockopt_peer_addrs_num
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
sctp_assoc_t
id
;
sctp_assoc_t
id
;
...
@@ -2053,7 +2136,7 @@ static inline int sctp_getsockopt_get_peer_addrs_num(struct sock *sk, int len,
...
@@ -2053,7 +2136,7 @@ static inline int sctp_getsockopt_get_peer_addrs_num(struct sock *sk, int len,
return
0
;
return
0
;
}
}
static
in
line
int
sctp_getsockopt_ge
t_peer_addrs
(
struct
sock
*
sk
,
int
len
,
static
in
t
sctp_getsockop
t_peer_addrs
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
...
@@ -2093,7 +2176,7 @@ static inline int sctp_getsockopt_get_peer_addrs(struct sock *sk, int len,
...
@@ -2093,7 +2176,7 @@ static inline int sctp_getsockopt_get_peer_addrs(struct sock *sk, int len,
return
0
;
return
0
;
}
}
static
in
line
int
sctp_getsockopt_ge
t_local_addrs_num
(
struct
sock
*
sk
,
int
len
,
static
in
t
sctp_getsockop
t_local_addrs_num
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
sctp_assoc_t
id
;
sctp_assoc_t
id
;
...
@@ -2132,7 +2215,7 @@ static inline int sctp_getsockopt_get_local_addrs_num(struct sock *sk, int len,
...
@@ -2132,7 +2215,7 @@ static inline int sctp_getsockopt_get_local_addrs_num(struct sock *sk, int len,
return
0
;
return
0
;
}
}
static
in
line
int
sctp_getsockopt_ge
t_local_addrs
(
struct
sock
*
sk
,
int
len
,
static
in
t
sctp_getsockop
t_local_addrs
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
sctp_bind_addr_t
*
bp
;
sctp_bind_addr_t
*
bp
;
...
@@ -2183,6 +2266,40 @@ static inline int sctp_getsockopt_get_local_addrs(struct sock *sk, int len,
...
@@ -2183,6 +2266,40 @@ static inline int sctp_getsockopt_get_local_addrs(struct sock *sk, int len,
return
0
;
return
0
;
}
}
/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
*
* Requests that the local SCTP stack use the enclosed peer address as
* the association primary. The enclosed address must be one of the
* association peer's addresses.
*/
static
int
sctp_getsockopt_peer_prim
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
struct
sctp_setpeerprim
prim
;
struct
sctp_association
*
asoc
;
if
(
len
!=
sizeof
(
struct
sctp_setpeerprim
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
prim
,
optval
,
sizeof
(
struct
sctp_setpeerprim
)))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
prim
.
sspp_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
if
(
!
asoc
->
peer
.
primary_path
)
return
-
ENOTCONN
;
memcpy
(
&
prim
.
sspp_addr
,
&
asoc
->
peer
.
primary_path
->
ipaddr
,
sizeof
(
union
sctp_addr
));
if
(
copy_to_user
(
optval
,
&
prim
,
sizeof
(
struct
sctp_setpeerprim
)))
return
-
EFAULT
;
return
0
;
}
/*
/*
*
*
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
...
@@ -2200,7 +2317,7 @@ static inline int sctp_getsockopt_get_local_addrs(struct sock *sk, int len,
...
@@ -2200,7 +2317,7 @@ static inline int sctp_getsockopt_get_local_addrs(struct sock *sk, int len,
*
*
* For getsockopt, it get the default sctp_sndrcvinfo structure.
* For getsockopt, it get the default sctp_sndrcvinfo structure.
*/
*/
static
in
line
int
sctp_getsockopt_se
t_default_send_param
(
struct
sock
*
sk
,
static
in
t
sctp_getsockop
t_default_send_param
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
int
len
,
char
*
optval
,
int
*
optlen
)
{
{
struct
sctp_sndrcvinfo
info
;
struct
sctp_sndrcvinfo
info
;
...
@@ -2227,6 +2344,33 @@ static inline int sctp_getsockopt_set_default_send_param(struct sock *sk,
...
@@ -2227,6 +2344,33 @@ static inline int sctp_getsockopt_set_default_send_param(struct sock *sk,
return
0
;
return
0
;
}
}
/*
*
* 7.1.5 SCTP_NODELAY
*
* Turn on/off any Nagle-like algorithm. This means that packets are
* generally sent as soon as possible and no unnecessary delays are
* introduced, at the cost of more packets in the network. Expects an
* integer boolean flag.
*/
static
int
sctp_getsockopt_nodelay
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
__u8
val
;
if
(
len
<
sizeof
(
__u8
))
return
-
EINVAL
;
len
=
sizeof
(
__u8
);
val
=
(
sctp_sk
(
sk
)
->
nodelay
==
1
);
if
(
put_user
(
len
,
optlen
))
return
-
EFAULT
;
if
(
copy_to_user
(
optval
,
&
val
,
len
))
return
-
EFAULT
;
return
0
;
}
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
...
@@ -2257,58 +2401,52 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
...
@@ -2257,58 +2401,52 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case
SCTP_STATUS
:
case
SCTP_STATUS
:
retval
=
sctp_getsockopt_sctp_status
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_sctp_status
(
sk
,
len
,
optval
,
optlen
);
break
;
break
;
case
SCTP_DISABLE_FRAGMENTS
:
case
SCTP_DISABLE_FRAGMENTS
:
retval
=
sctp_getsockopt_disable_fragments
(
sk
,
len
,
optval
,
retval
=
sctp_getsockopt_disable_fragments
(
sk
,
len
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_SET_EVENTS
:
case
SCTP_SET_EVENTS
:
retval
=
sctp_getsockopt_set_events
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_set_events
(
sk
,
len
,
optval
,
optlen
);
break
;
break
;
case
SCTP_AUTOCLOSE
:
case
SCTP_AUTOCLOSE
:
retval
=
sctp_getsockopt_autoclose
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_autoclose
(
sk
,
len
,
optval
,
optlen
);
break
;
break
;
case
SCTP_SOCKOPT_PEELOFF
:
case
SCTP_SOCKOPT_PEELOFF
:
retval
=
sctp_getsockopt_peeloff
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_peeloff
(
sk
,
len
,
optval
,
optlen
);
break
;
break
;
case
SCTP_GET_PEER_ADDR_PARAMS
:
case
SCTP_GET_PEER_ADDR_PARAMS
:
retval
=
sctp_getsockopt_
get_
peer_addr_params
(
sk
,
len
,
optval
,
retval
=
sctp_getsockopt_peer_addr_params
(
sk
,
len
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_INITMSG
:
case
SCTP_INITMSG
:
retval
=
sctp_getsockopt_initmsg
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_initmsg
(
sk
,
len
,
optval
,
optlen
);
break
;
break
;
case
SCTP_GET_PEER_ADDRS_NUM
:
case
SCTP_GET_PEER_ADDRS_NUM
:
retval
=
sctp_getsockopt_
get_peer_addrs_num
(
sk
,
len
,
optval
,
retval
=
sctp_getsockopt_
peer_addrs_num
(
sk
,
len
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_GET_LOCAL_ADDRS_NUM
:
case
SCTP_GET_LOCAL_ADDRS_NUM
:
retval
=
sctp_getsockopt_
get_
local_addrs_num
(
sk
,
len
,
optval
,
retval
=
sctp_getsockopt_local_addrs_num
(
sk
,
len
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_GET_PEER_ADDRS
:
case
SCTP_GET_PEER_ADDRS
:
retval
=
sctp_getsockopt_
get_
peer_addrs
(
sk
,
len
,
optval
,
retval
=
sctp_getsockopt_peer_addrs
(
sk
,
len
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_GET_LOCAL_ADDRS
:
case
SCTP_GET_LOCAL_ADDRS
:
retval
=
sctp_getsockopt_
get_
local_addrs
(
sk
,
len
,
optval
,
retval
=
sctp_getsockopt_local_addrs
(
sk
,
len
,
optval
,
optlen
);
optlen
);
break
;
break
;
case
SCTP_SET_DEFAULT_SEND_PARAM
:
case
SCTP_SET_DEFAULT_SEND_PARAM
:
retval
=
sctp_getsockopt_
set_
default_send_param
(
sk
,
len
,
retval
=
sctp_getsockopt_default_send_param
(
sk
,
len
,
optval
,
optlen
);
optval
,
optlen
);
break
;
break
;
case
SCTP_SET_PEER_PRIMARY_ADDR
:
retval
=
sctp_getsockopt_peer_prim
(
sk
,
len
,
optval
,
optlen
);
break
;
case
SCTP_NODELAY
:
retval
=
sctp_getsockopt_nodelay
(
sk
,
len
,
optval
,
optlen
);
break
;
default:
default:
retval
=
-
ENOPROTOOPT
;
retval
=
-
ENOPROTOOPT
;
break
;
break
;
...
@@ -2331,7 +2469,7 @@ static void sctp_unhash(struct sock *sk)
...
@@ -2331,7 +2469,7 @@ static void sctp_unhash(struct sock *sk)
/* Check if port is acceptable. Possibly find first available port.
/* Check if port is acceptable. Possibly find first available port.
*
*
* The port hash table (contained in the 'global' SCTP protocol storage
* The port hash table (contained in the 'global' SCTP protocol storage
* returned by s
ctp_protocol_t *
sctp_get_protocol()). The hash
* returned by s
truct sctp_protocol *
sctp_get_protocol()). The hash
* table is an array of 4096 lists (sctp_bind_hashbucket_t). Each
* table is an array of 4096 lists (sctp_bind_hashbucket_t). Each
* list (the list number is the port number hashed out, so as you
* list (the list number is the port number hashed out, so as you
* would expect from a hash function, all the ports in a given list have
* would expect from a hash function, all the ports in a given list have
...
@@ -2346,7 +2484,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
...
@@ -2346,7 +2484,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
{
{
sctp_bind_hashbucket_t
*
head
;
/* hash list */
sctp_bind_hashbucket_t
*
head
;
/* hash list */
sctp_bind_bucket_t
*
pp
;
/* hash list port iterator */
sctp_bind_bucket_t
*
pp
;
/* hash list port iterator */
s
ctp_protocol_t
*
sctp
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
sctp
=
sctp_get_protocol
();
unsigned
short
snum
;
unsigned
short
snum
;
int
ret
;
int
ret
;
...
@@ -2543,6 +2681,9 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
...
@@ -2543,6 +2681,9 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
sk
->
state
==
SCTP_SS_LISTENING
)
return
0
;
/*
/*
* If a bind() or sctp_bindx() is not called prior to a listen()
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
* call that allows new associations to be accepted, the system
...
@@ -2562,6 +2703,40 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
...
@@ -2562,6 +2703,40 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
return
0
;
return
0
;
}
}
/*
* 4.1.3 listen() - TCP Style Syntax
*
* Applications uses listen() to ready the SCTP endpoint for accepting
* inbound associations.
*/
SCTP_STATIC
int
sctp_stream_listen
(
struct
sock
*
sk
,
int
backlog
)
{
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
if
(
sk
->
state
==
SCTP_SS_LISTENING
)
return
0
;
/*
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
* picks an ephemeral port and will choose an address set equivalent
* to binding with a wildcard address.
*
* This is not currently spelled out in the SCTP sockets
* extensions draft, but follows the practice as seen in TCP
* sockets.
*/
if
(
!
ep
->
base
.
bind_addr
.
port
)
{
if
(
sctp_autobind
(
sk
))
return
-
EAGAIN
;
}
sk
->
state
=
SCTP_SS_LISTENING
;
sk
->
max_ack_backlog
=
backlog
;
sctp_hash_endpoint
(
ep
);
return
0
;
}
/*
/*
* Move a socket to LISTENING state.
* Move a socket to LISTENING state.
*/
*/
...
@@ -2579,10 +2754,9 @@ int sctp_inet_listen(struct socket *sock, int backlog)
...
@@ -2579,10 +2754,9 @@ int sctp_inet_listen(struct socket *sock, int backlog)
case
SOCK_SEQPACKET
:
case
SOCK_SEQPACKET
:
err
=
sctp_seqpacket_listen
(
sk
,
backlog
);
err
=
sctp_seqpacket_listen
(
sk
,
backlog
);
break
;
break
;
case
SOCK_STREAM
:
case
SOCK_STREAM
:
/* FIXME for TCP-style sockets. */
err
=
sctp_stream_listen
(
sk
,
backlog
);
err
=
-
EOPNOTSUPP
;
break
;
default:
default:
goto
out
;
goto
out
;
...
@@ -2684,7 +2858,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi
...
@@ -2684,7 +2858,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi
/* FIXME: Commments! */
/* FIXME: Commments! */
static
__inline__
void
__sctp_put_port
(
struct
sock
*
sk
)
static
__inline__
void
__sctp_put_port
(
struct
sock
*
sk
)
{
{
s
ctp_protocol_t
*
sctp_proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
sctp_bind_hashbucket_t
*
head
=
sctp_bind_hashbucket_t
*
head
=
&
sctp_proto
->
port_hashtable
[
sctp_phashfn
(
inet_sk
(
sk
)
->
num
)];
&
sctp_proto
->
port_hashtable
[
sctp_phashfn
(
inet_sk
(
sk
)
->
num
)];
sctp_bind_bucket_t
*
pp
;
sctp_bind_bucket_t
*
pp
;
...
@@ -2967,7 +3141,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
...
@@ -2967,7 +3141,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
}
}
/* Verify that this is a valid address. */
/* Verify that this is a valid address. */
static
int
sctp_verify_addr
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
static
inline
int
sctp_verify_addr
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
{
{
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
...
@@ -3213,7 +3388,7 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
...
@@ -3213,7 +3388,7 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
return
err
;
return
err
;
do_error:
do_error:
err
=
-
ECONN
ABORT
ED
;
err
=
-
ECONN
REFUS
ED
;
goto
out
;
goto
out
;
do_interrupted:
do_interrupted:
...
@@ -3225,6 +3400,131 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
...
@@ -3225,6 +3400,131 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
goto
out
;
goto
out
;
}
}
static
int
sctp_wait_for_accept
(
struct
sock
*
sk
,
long
timeo
)
{
struct
sctp_endpoint
*
ep
;
int
err
=
0
;
DECLARE_WAITQUEUE
(
wait
,
current
);
ep
=
sctp_sk
(
sk
)
->
ep
;
add_wait_queue_exclusive
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
__set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
list_empty
(
&
ep
->
asocs
))
{
sctp_release_sock
(
sk
);
timeo
=
schedule_timeout
(
timeo
);
sctp_lock_sock
(
sk
);
}
err
=
-
EINVAL
;
if
(
sk
->
state
!=
SCTP_SS_LISTENING
)
break
;
err
=
0
;
if
(
!
list_empty
(
&
ep
->
asocs
))
break
;
err
=
sock_intr_errno
(
timeo
);
if
(
signal_pending
(
current
))
break
;
err
=
-
EAGAIN
;
if
(
!
timeo
)
break
;
}
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
__set_current_state
(
TASK_RUNNING
);
return
err
;
}
/* Populate the fields of the newsk from the oldsk and migrate the assoc
* and its messages to the newsk.
*/
void
sctp_sock_migrate
(
struct
sock
*
oldsk
,
struct
sock
*
newsk
,
struct
sctp_association
*
assoc
,
sctp_socket_type_t
type
)
{
struct
sctp_opt
*
oldsp
=
sctp_sk
(
oldsk
);
struct
sctp_opt
*
newsp
=
sctp_sk
(
newsk
);
sctp_endpoint_t
*
newep
=
newsp
->
ep
;
struct
sk_buff
*
skb
,
*
tmp
;
struct
sctp_ulpevent
*
event
;
/* Migrate socket buffer sizes and all the socket level options to the
* new socket.
*/
newsk
->
sndbuf
=
oldsk
->
sndbuf
;
newsk
->
rcvbuf
=
oldsk
->
rcvbuf
;
*
newsp
=
*
oldsp
;
/* Restore the ep value that was overwritten with the above structure
* copy.
*/
newsp
->
ep
=
newep
;
/* Move any messages in the old socket's receive queue that are for the
* peeled off association to the new socket's receive queue.
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
/* Clean up any messages pending delivery due to partial
* delivery. Three cases:
* 1) No partial deliver; no work.
* 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
* 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
*/
skb_queue_head_init
(
&
newsp
->
pd_lobby
);
sctp_sk
(
newsk
)
->
pd_mode
=
assoc
->
ulpq
.
pd_mode
;;
if
(
sctp_sk
(
oldsk
)
->
pd_mode
)
{
struct
sk_buff_head
*
queue
;
/* Decide which queue to move pd_lobby skbs to. */
if
(
assoc
->
ulpq
.
pd_mode
)
{
queue
=
&
newsp
->
pd_lobby
;
}
else
queue
=
&
newsk
->
receive_queue
;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each
(
skb
,
&
oldsp
->
pd_lobby
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
queue
,
skb
);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if
(
assoc
->
ulpq
.
pd_mode
)
sctp_clear_pd
(
oldsk
);
}
/* Set the type of socket to indicate that it is peeled off from the
* original UDP-style socket or created with the accept() call on a
* TCP-style socket..
*/
newsp
->
type
=
type
;
/* Migrate the association to the new socket. */
sctp_assoc_migrate
(
assoc
,
newsk
);
newsk
->
state
=
SCTP_SS_ESTABLISHED
;
}
/* This proto struct describes the ULP interface for SCTP. */
/* This proto struct describes the ULP interface for SCTP. */
struct
proto
sctp_prot
=
{
struct
proto
sctp_prot
=
{
.
name
=
"SCTP"
,
.
name
=
"SCTP"
,
...
...
net/sctp/sysctl.c
View file @
e5e956d0
...
@@ -42,7 +42,7 @@
...
@@ -42,7 +42,7 @@
#include <net/sctp/structs.h>
#include <net/sctp/structs.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
extern
s
ctp_protocol_t
sctp_proto
;
extern
s
truct
sctp_protocol
sctp_proto
;
static
ctl_table
sctp_table
[]
=
{
static
ctl_table
sctp_table
[]
=
{
{
{
...
...
net/sctp/transport.c
View file @
e5e956d0
...
@@ -83,7 +83,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
...
@@ -83,7 +83,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const
union
sctp_addr
*
addr
,
const
union
sctp_addr
*
addr
,
int
priority
)
int
priority
)
{
{
s
ctp_protocol_t
*
proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
proto
=
sctp_get_protocol
();
/* Copy in the address. */
/* Copy in the address. */
peer
->
ipaddr
=
*
addr
;
peer
->
ipaddr
=
*
addr
;
...
@@ -262,7 +262,7 @@ void sctp_transport_put(struct sctp_transport *transport)
...
@@ -262,7 +262,7 @@ void sctp_transport_put(struct sctp_transport *transport)
/* Update transport's RTO based on the newly calculated RTT. */
/* Update transport's RTO based on the newly calculated RTT. */
void
sctp_transport_update_rto
(
struct
sctp_transport
*
tp
,
__u32
rtt
)
void
sctp_transport_update_rto
(
struct
sctp_transport
*
tp
,
__u32
rtt
)
{
{
s
ctp_protocol_t
*
proto
=
sctp_get_protocol
();
s
truct
sctp_protocol
*
proto
=
sctp_get_protocol
();
/* Check for valid transport. */
/* Check for valid transport. */
SCTP_ASSERT
(
tp
,
"NULL transport"
,
return
);
SCTP_ASSERT
(
tp
,
"NULL transport"
,
return
);
...
...
net/sctp/tsnmap.c
View file @
e5e956d0
...
@@ -250,7 +250,7 @@ int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
...
@@ -250,7 +250,7 @@ int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
/* The Gap Ack Block happens to end at the end of the
/* The Gap Ack Block happens to end at the end of the
* overflow map.
* overflow map.
*/
*/
if
(
started
&
!
ended
)
{
if
(
started
&
&
!
ended
)
{
ended
++
;
ended
++
;
_end
=
map
->
len
+
map
->
len
-
1
;
_end
=
map
->
len
+
map
->
len
-
1
;
}
}
...
...
net/sctp/ulpqueue.c
View file @
e5e956d0
...
@@ -220,7 +220,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
...
@@ -220,7 +220,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
if
(
sctp_event2skb
(
event
)
->
list
)
if
(
sctp_event2skb
(
event
)
->
list
)
sctp_skb_list_tail
(
sctp_event2skb
(
event
)
->
list
,
queue
);
sctp_skb_list_tail
(
sctp_event2skb
(
event
)
->
list
,
queue
);
else
else
skb_queue_tail
(
queue
,
sctp_event2skb
(
event
));
__
skb_queue_tail
(
queue
,
sctp_event2skb
(
event
));
/* Did we just complete partial delivery and need to get
/* Did we just complete partial delivery and need to get
* rolling again? Move pending data to the receive
* rolling again? Move pending data to the receive
...
@@ -230,7 +230,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
...
@@ -230,7 +230,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
sctp_ulpq_clear_pd
(
ulpq
);
sctp_ulpq_clear_pd
(
ulpq
);
if
(
queue
==
&
sk
->
receive_queue
)
if
(
queue
==
&
sk
->
receive_queue
)
wake_up_interruptible
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
0
);
return
1
;
return
1
;
out_free:
out_free:
...
@@ -247,14 +247,14 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
...
@@ -247,14 +247,14 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
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
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
__u32
tsn
,
ctsn
;
__u32
tsn
,
ctsn
;
tsn
=
event
->
sndrcvinfo
.
sinfo_tsn
;
tsn
=
event
->
sndrcvinfo
.
sinfo_tsn
;
/* Find the right place in this list. We store them by TSN. */
/* Find the right place in this list. We store them by TSN. */
s
ctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
s
kb_queue_walk
(
&
ulpq
->
reasm
,
pos
)
{
cevent
=
sctp_skb2event
(
pos
);
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
...
@@ -334,7 +334,7 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
...
@@ -334,7 +334,7 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
*/
*/
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_reassembled
(
struct
sctp_ulpq
*
ulpq
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
struct
sk_buff
*
first_frag
=
NULL
;
struct
sk_buff
*
first_frag
=
NULL
;
__u32
ctsn
,
next_tsn
;
__u32
ctsn
,
next_tsn
;
...
@@ -355,7 +355,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_u
...
@@ -355,7 +355,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_u
* fragment in order. If not, first_frag is reset to NULL and we
* fragment in order. If not, first_frag is reset to NULL and we
* start the next pass when we find another first fragment.
* start the next pass when we find another first fragment.
*/
*/
s
ctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
s
kb_queue_walk
(
&
ulpq
->
reasm
,
pos
)
{
cevent
=
sctp_skb2event
(
pos
);
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
...
@@ -374,29 +374,26 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_u
...
@@ -374,29 +374,26 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_u
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
(
goto
found
;
first_frag
,
pos
);
else
else
first_frag
=
NULL
;
first_frag
=
NULL
;
break
;
break
;
};
};
/* We have the reassembled event. There is no need to look
* further.
*/
if
(
retval
)
{
retval
->
msg_flags
|=
MSG_EOR
;
break
;
}
}
}
done:
return
retval
;
return
retval
;
found:
retval
=
sctp_make_reassembled_event
(
first_frag
,
pos
);
if
(
retval
)
retval
->
msg_flags
|=
MSG_EOR
;
goto
done
;
}
}
/* Retrieve the next set of fragments of a partial message. */
/* Retrieve the next set of fragments of a partial message. */
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_partial
(
struct
sctp_ulpq
*
ulpq
)
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_partial
(
struct
sctp_ulpq
*
ulpq
)
{
{
struct
sk_buff
*
pos
,
*
tmp
,
*
last_frag
,
*
first_frag
;
struct
sk_buff
*
pos
,
*
last_frag
,
*
first_frag
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
__u32
ctsn
,
next_tsn
;
__u32
ctsn
,
next_tsn
;
int
is_last
;
int
is_last
;
...
@@ -415,7 +412,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq
...
@@ -415,7 +412,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq
next_tsn
=
0
;
next_tsn
=
0
;
is_last
=
0
;
is_last
=
0
;
s
ctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
s
kb_queue_walk
(
&
ulpq
->
reasm
,
pos
)
{
cevent
=
sctp_skb2event
(
pos
);
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
...
@@ -448,7 +445,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq
...
@@ -448,7 +445,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq
*/
*/
done:
done:
retval
=
sctp_make_reassembled_event
(
first_frag
,
last_frag
);
retval
=
sctp_make_reassembled_event
(
first_frag
,
last_frag
);
if
(
is_last
)
if
(
retval
&&
is_last
)
retval
->
msg_flags
|=
MSG_EOR
;
retval
->
msg_flags
|=
MSG_EOR
;
return
retval
;
return
retval
;
...
@@ -490,7 +487,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
...
@@ -490,7 +487,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
/* Retrieve the first part (sequential fragments) for partial delivery. */
/* Retrieve the first part (sequential fragments) for partial delivery. */
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_first
(
struct
sctp_ulpq
*
ulpq
)
static
inline
struct
sctp_ulpevent
*
sctp_ulpq_retrieve_first
(
struct
sctp_ulpq
*
ulpq
)
{
{
struct
sk_buff
*
pos
,
*
tmp
,
*
last_frag
,
*
first_frag
;
struct
sk_buff
*
pos
,
*
last_frag
,
*
first_frag
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
__u32
ctsn
,
next_tsn
;
__u32
ctsn
,
next_tsn
;
struct
sctp_ulpevent
*
retval
;
struct
sctp_ulpevent
*
retval
;
...
@@ -507,7 +504,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *u
...
@@ -507,7 +504,7 @@ static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *u
retval
=
NULL
;
retval
=
NULL
;
next_tsn
=
0
;
next_tsn
=
0
;
s
ctp_skb_for_each
(
pos
,
&
ulpq
->
reasm
,
tmp
)
{
s
kb_queue_walk
(
&
ulpq
->
reasm
,
pos
)
{
cevent
=
sctp_skb2event
(
pos
);
cevent
=
sctp_skb2event
(
pos
);
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
ctsn
=
cevent
->
sndrcvinfo
.
sinfo_tsn
;
...
@@ -590,7 +587,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
...
@@ -590,7 +587,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
static
inline
void
sctp_ulpq_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
static
inline
void
sctp_ulpq_store_ordered
(
struct
sctp_ulpq
*
ulpq
,
struct
sctp_ulpevent
*
event
)
struct
sctp_ulpevent
*
event
)
{
{
struct
sk_buff
*
pos
,
*
tmp
;
struct
sk_buff
*
pos
;
struct
sctp_ulpevent
*
cevent
;
struct
sctp_ulpevent
*
cevent
;
__u16
sid
,
csid
;
__u16
sid
,
csid
;
__u16
ssn
,
cssn
;
__u16
ssn
,
cssn
;
...
@@ -601,7 +598,7 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
...
@@ -601,7 +598,7 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
/* 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.
*/
*/
s
ctp_skb_for_each
(
pos
,
&
ulpq
->
lobby
,
tmp
)
{
s
kb_queue_walk
(
&
ulpq
->
lobby
,
pos
)
{
cevent
=
(
struct
sctp_ulpevent
*
)
pos
->
cb
;
cevent
=
(
struct
sctp_ulpevent
*
)
pos
->
cb
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
csid
=
cevent
->
sndrcvinfo
.
sinfo_stream
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
cssn
=
cevent
->
sndrcvinfo
.
sinfo_ssn
;
...
@@ -786,9 +783,9 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
...
@@ -786,9 +783,9 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
SCTP_PARTIAL_DELIVERY_ABORTED
,
SCTP_PARTIAL_DELIVERY_ABORTED
,
priority
);
priority
);
if
(
ev
)
if
(
ev
)
skb_queue_tail
(
&
sk
->
receive_queue
,
sctp_event2skb
(
ev
));
__
skb_queue_tail
(
&
sk
->
receive_queue
,
sctp_event2skb
(
ev
));
/* If there is data waiting, send it up the socket now. */
/* If there is data waiting, send it up the socket now. */
if
(
sctp_ulpq_clear_pd
(
ulpq
)
||
ev
)
if
(
sctp_ulpq_clear_pd
(
ulpq
)
||
ev
)
wake_up_interruptible
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
0
);
}
}
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