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
381a2af8
Commit
381a2af8
authored
Apr 04, 2003
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-lksctp.bkbits.net/lksctp-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
850e6bc2
7019ed1f
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1592 additions
and
1392 deletions
+1592
-1392
include/net/sctp/constants.h
include/net/sctp/constants.h
+3
-5
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+58
-46
include/net/sctp/sm.h
include/net/sctp/sm.h
+6
-7
include/net/sctp/structs.h
include/net/sctp/structs.h
+71
-66
include/net/sctp/ulpevent.h
include/net/sctp/ulpevent.h
+3
-3
net/sctp/associola.c
net/sctp/associola.c
+32
-40
net/sctp/bind_addr.c
net/sctp/bind_addr.c
+15
-15
net/sctp/endpointola.c
net/sctp/endpointola.c
+7
-0
net/sctp/input.c
net/sctp/input.c
+117
-71
net/sctp/ipv6.c
net/sctp/ipv6.c
+149
-40
net/sctp/output.c
net/sctp/output.c
+45
-3
net/sctp/outqueue.c
net/sctp/outqueue.c
+27
-9
net/sctp/protocol.c
net/sctp/protocol.c
+26
-7
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+53
-43
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+911
-1007
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+61
-25
net/sctp/socket.c
net/sctp/socket.c
+7
-5
net/sctp/ulpevent.c
net/sctp/ulpevent.c
+1
-0
No files found.
include/net/sctp/constants.h
View file @
381a2af8
...
@@ -138,12 +138,10 @@ typedef enum {
...
@@ -138,12 +138,10 @@ typedef enum {
*/
*/
typedef
union
{
typedef
union
{
sctp_cid_t
chunk
;
sctp_cid_t
chunk
;
sctp_event_timeout_t
timeout
;
sctp_event_timeout_t
timeout
;
sctp_event_other_t
other
;
sctp_event_other_t
other
;
sctp_event_primitive_t
primitive
;
sctp_event_primitive_t
primitive
;
}
sctp_subtype_t
;
}
sctp_subtype_t
;
#define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \
#define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \
...
@@ -421,9 +419,9 @@ typedef enum {
...
@@ -421,9 +419,9 @@ typedef enum {
/* Reasons to retransmit. */
/* Reasons to retransmit. */
typedef
enum
{
typedef
enum
{
SCTP_R
ETRANSMIT
_T3_RTX
,
SCTP_R
TXR
_T3_RTX
,
SCTP_R
ETRANSMIT
_FAST_RTX
,
SCTP_R
TXR
_FAST_RTX
,
SCTP_R
ETRANSMIT_PMTU_DISCOVERY
,
SCTP_R
TXR_PMTUD
,
}
sctp_retransmit_reason_t
;
}
sctp_retransmit_reason_t
;
/* Reasons to lower cwnd. */
/* Reasons to lower cwnd. */
...
...
include/net/sctp/sctp.h
View file @
381a2af8
...
@@ -130,7 +130,7 @@ extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
...
@@ -130,7 +130,7 @@ 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
);
/*
/*
* sctp
_
socket.c
* sctp
/
socket.c
*/
*/
extern
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
sctp_backlog_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
sctp_inet_listen
(
struct
socket
*
sock
,
int
backlog
);
extern
int
sctp_inet_listen
(
struct
socket
*
sock
,
int
backlog
);
...
@@ -139,7 +139,7 @@ extern unsigned int sctp_poll(struct file *file, struct socket *sock,
...
@@ -139,7 +139,7 @@ extern unsigned int sctp_poll(struct file *file, struct socket *sock,
poll_table
*
wait
);
poll_table
*
wait
);
/*
/*
* sctp
_
primitive.c
* sctp
/
primitive.c
*/
*/
extern
int
sctp_primitive_ASSOCIATE
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_ASSOCIATE
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_SHUTDOWN
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_SHUTDOWN
(
sctp_association_t
*
,
void
*
arg
);
...
@@ -148,14 +148,14 @@ extern int sctp_primitive_SEND(sctp_association_t *, void *arg);
...
@@ -148,14 +148,14 @@ extern int sctp_primitive_SEND(sctp_association_t *, void *arg);
extern
int
sctp_primitive_REQUESTHEARTBEAT
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_REQUESTHEARTBEAT
(
sctp_association_t
*
,
void
*
arg
);
/*
/*
* sctp
_
crc32c.c
* sctp
/
crc32c.c
*/
*/
extern
__u32
sctp_start_cksum
(
__u8
*
ptr
,
__u16
count
);
extern
__u32
sctp_start_cksum
(
__u8
*
ptr
,
__u16
count
);
extern
__u32
sctp_update_cksum
(
__u8
*
ptr
,
__u16
count
,
__u32
cksum
);
extern
__u32
sctp_update_cksum
(
__u8
*
ptr
,
__u16
count
,
__u32
cksum
);
extern
__u32
sctp_end_cksum
(
__u32
cksum
);
extern
__u32
sctp_end_cksum
(
__u32
cksum
);
/*
/*
* sctp
_
input.c
* sctp
/
input.c
*/
*/
extern
int
sctp_rcv
(
struct
sk_buff
*
skb
);
extern
int
sctp_rcv
(
struct
sk_buff
*
skb
);
extern
void
sctp_v4_err
(
struct
sk_buff
*
skb
,
u32
info
);
extern
void
sctp_v4_err
(
struct
sk_buff
*
skb
,
u32
info
);
...
@@ -170,9 +170,16 @@ extern void __sctp_unhash_endpoint(sctp_endpoint_t *);
...
@@ -170,9 +170,16 @@ extern void __sctp_unhash_endpoint(sctp_endpoint_t *);
extern
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
,
extern
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
struct
sctp_transport
**
);
struct
sctp_transport
**
);
extern
struct
sock
*
sctp_err_lookup
(
int
family
,
struct
sk_buff
*
,
struct
sctphdr
*
,
struct
sctp_endpoint
**
,
struct
sctp_association
**
,
struct
sctp_transport
**
);
extern
void
sctp_err_finish
(
struct
sock
*
,
struct
sctp_endpoint
*
,
struct
sctp_association
*
);
extern
void
sctp_icmp_frag_needed
(
struct
sock
*
,
struct
sctp_association
*
,
struct
sctp_transport
*
t
,
__u32
pmtu
);
/*
/*
* sctp
_
hashdriver.c
* sctp
/
hashdriver.c
*/
*/
extern
void
sctp_hash_digest
(
const
char
*
secret
,
const
int
secret_len
,
extern
void
sctp_hash_digest
(
const
char
*
secret
,
const
int
secret_len
,
const
char
*
text
,
const
int
text_len
,
const
char
*
text
,
const
int
text_len
,
...
@@ -184,9 +191,7 @@ extern void sctp_hash_digest(const char *secret, const int secret_len,
...
@@ -184,9 +191,7 @@ extern void sctp_hash_digest(const char *secret, const int secret_len,
#ifdef TEST_FRAME
#ifdef TEST_FRAME
#include <test_frame.h>
#include <test_frame.h>
#else
#else
/* spin lock wrappers. */
/* spin lock wrappers. */
...
@@ -312,7 +317,6 @@ static inline void sctp_sysctl_register(void) { return; }
...
@@ -312,7 +317,6 @@ static inline void sctp_sysctl_register(void) { return; }
static
inline
void
sctp_sysctl_unregister
(
void
)
{
return
;
}
static
inline
void
sctp_sysctl_unregister
(
void
)
{
return
;
}
#endif
#endif
/* Size of Supported Address Parameter for 'x' address types. */
/* Size of Supported Address Parameter for 'x' address types. */
#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
...
@@ -320,19 +324,15 @@ static inline void sctp_sysctl_unregister(void) { return; }
...
@@ -320,19 +324,15 @@ static inline void sctp_sysctl_unregister(void) { return; }
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
)
extern
void
sctp_v6_err
(
struct
sk_buff
*
skb
,
struct
inet6_skb_parm
*
opt
,
{
int
type
,
int
code
,
int
offset
,
__u32
info
);
return
ipv6_addr_type
((
struct
in6_addr
*
)
addr
);
}
#else
/* #ifdef defined(CONFIG_IPV6)
|| defined(CONFIG_IPV6_MODULE)
*/
#else
/* #ifdef defined(CONFIG_IPV6) */
#define sctp_ipv6_addr_type(a) 0
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
;
}
#endif
/* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
#endif
/* #if defined(CONFIG_IPV6) */
/* Map an association to an assoc_id. */
/* Map an association to an assoc_id. */
static
inline
sctp_assoc_t
sctp_assoc2id
(
const
sctp_association_t
*
asoc
)
static
inline
sctp_assoc_t
sctp_assoc2id
(
const
sctp_association_t
*
asoc
)
...
@@ -421,6 +421,15 @@ static inline __s32 sctp_jitter(__u32 rto)
...
@@ -421,6 +421,15 @@ static inline __s32 sctp_jitter(__u32 rto)
return
ret
;
return
ret
;
}
}
/* Break down data chunks at this point. */
static
inline
int
sctp_frag_point
(
int
pmtu
)
{
pmtu
-=
SCTP_IP_OVERHEAD
+
sizeof
(
struct
sctp_data_chunk
);
pmtu
-=
sizeof
(
struct
sctp_sack_chunk
);
return
pmtu
;
}
/* Walk through a list of TLV parameters. Don't trust the
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
* the chunk length to indicate when to stop. Make sure
...
@@ -479,21 +488,24 @@ static inline struct sctp_protocol *sctp_get_protocol(void)
...
@@ -479,21 +488,24 @@ static inline struct sctp_protocol *sctp_get_protocol(void)
/* Convert from an IP version number to an Address Family symbol. */
/* Convert from an IP version number to an Address Family symbol. */
static
inline
int
ipver2af
(
__u8
ipver
)
static
inline
int
ipver2af
(
__u8
ipver
)
{
{
int
family
;
switch
(
ipver
)
{
switch
(
ipver
)
{
case
4
:
case
4
:
family
=
AF_INET
;
return
AF_INET
;
break
;
case
6
:
case
6
:
family
=
AF_INET6
;
return
AF_INET6
;
break
;
default:
default:
family
=
0
;
return
0
;
break
;
};
};
}
/* Perform some sanity checks. */
static
inline
int
sctp_sanity_check
(
void
)
{
SCTP_ASSERT
(
sizeof
(
struct
sctp_ulpevent
)
<=
sizeof
(((
struct
sk_buff
*
)
0
)
->
cb
),
"SCTP: ulpevent does not fit in skb!
\n
"
,
return
0
);
return
family
;
return
1
;
}
}
/* Warning: The following hash functions assume a power of two 'size'. */
/* Warning: The following hash functions assume a power of two 'size'. */
...
@@ -537,7 +549,7 @@ struct sctp_sock {
...
@@ -537,7 +549,7 @@ struct sctp_sock {
struct
sock
sk
;
struct
sock
sk
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
ipv6_pinfo
*
pinet6
;
struct
ipv6_pinfo
*
pinet6
;
#endif
/* CONFIG_IPV6
|| CONFIG_IPV6_MODULE
*/
#endif
/* CONFIG_IPV6 */
struct
inet_opt
inet
;
struct
inet_opt
inet
;
struct
sctp_opt
sctp
;
struct
sctp_opt
sctp
;
};
};
...
@@ -550,7 +562,7 @@ struct sctp6_sock {
...
@@ -550,7 +562,7 @@ struct sctp6_sock {
struct
sctp_opt
sctp
;
struct
sctp_opt
sctp
;
struct
ipv6_pinfo
inet6
;
struct
ipv6_pinfo
inet6
;
};
};
#endif
/* CONFIG_IPV6
|| CONFIG_IPV6_MODULE
*/
#endif
/* CONFIG_IPV6 */
#define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp)
#define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp)
...
...
include/net/sctp/sm.h
View file @
381a2af8
...
@@ -197,15 +197,14 @@ sctp_state_fn_t sctp_addip_do_asconf;
...
@@ -197,15 +197,14 @@ sctp_state_fn_t sctp_addip_do_asconf;
sctp_state_fn_t
sctp_addip_do_asconf_ack
;
sctp_state_fn_t
sctp_addip_do_asconf_ack
;
/* Prototypes for utility support functions. */
/* Prototypes for utility support functions. */
__u8
sctp_get_chunk_type
(
s
ctp_chunk_t
*
chunk
);
__u8
sctp_get_chunk_type
(
s
truct
sctp_chunk
*
chunk
);
sctp_sm_table_entry_t
*
sctp_sm_lookup_event
(
sctp_event_t
event_type
,
sctp_sm_table_entry_t
*
sctp_sm_lookup_event
(
sctp_event_t
event_type
,
sctp_state_t
state
,
sctp_state_t
state
,
sctp_subtype_t
event_subtype
);
sctp_subtype_t
event_subtype
);
int
sctp_chunk_iif
(
const
struct
sctp_chunk
*
);
time_t
timeval_sub
(
struct
timeval
*
,
struct
timeval
*
);
struct
sctp_association
*
sctp_make_temp_asoc
(
const
struct
sctp_endpoint
*
,
sctp_association_t
*
sctp_make_temp_asoc
(
const
sctp_endpoint_t
*
,
struct
sctp_chunk
*
,
sctp_chunk_t
*
,
int
gfp
);
const
int
priority
);
__u32
sctp_generate_verification_tag
(
void
);
__u32
sctp_generate_verification_tag
(
void
);
void
sctp_populate_tie_tags
(
__u8
*
cookie
,
__u32
curTag
,
__u32
hisTag
);
void
sctp_populate_tie_tags
(
__u8
*
cookie
,
__u32
curTag
,
__u32
hisTag
);
...
@@ -344,7 +343,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *);
...
@@ -344,7 +343,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *);
/* 4th level prototypes */
/* 4th level prototypes */
void
sctp_param2sockaddr
(
union
sctp_addr
*
addr
,
sctp_addr_param_t
*
,
void
sctp_param2sockaddr
(
union
sctp_addr
*
addr
,
sctp_addr_param_t
*
,
__u16
port
);
__u16
port
,
int
iif
);
int
sctp_addr2sockaddr
(
const
union
sctp_params
,
union
sctp_addr
*
);
int
sctp_addr2sockaddr
(
const
union
sctp_params
,
union
sctp_addr
*
);
int
sockaddr2sctp_addr
(
const
union
sctp_addr
*
,
sctp_addr_param_t
*
);
int
sockaddr2sctp_addr
(
const
union
sctp_addr
*
,
sctp_addr_param_t
*
);
...
...
include/net/sctp/structs.h
View file @
381a2af8
...
@@ -242,6 +242,7 @@ struct sctp_af {
...
@@ -242,6 +242,7 @@ struct sctp_af {
void
(
*
inaddr_any
)
(
union
sctp_addr
*
,
unsigned
short
);
void
(
*
inaddr_any
)
(
union
sctp_addr
*
,
unsigned
short
);
int
(
*
is_any
)
(
const
union
sctp_addr
*
);
int
(
*
is_any
)
(
const
union
sctp_addr
*
);
int
(
*
available
)
(
const
union
sctp_addr
*
);
int
(
*
available
)
(
const
union
sctp_addr
*
);
int
(
*
skb_iif
)
(
const
struct
sk_buff
*
sk
);
__u16
net_header_len
;
__u16
net_header_len
;
int
sockaddr_len
;
int
sockaddr_len
;
sa_family_t
sa_family
;
sa_family_t
sa_family
;
...
@@ -260,6 +261,7 @@ struct sctp_pf {
...
@@ -260,6 +261,7 @@ 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
(
*
send_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
int
(
*
supported_addrs
)(
const
struct
sctp_opt
*
,
__u16
*
);
int
(
*
supported_addrs
)(
const
struct
sctp_opt
*
,
__u16
*
);
struct
sock
*
(
*
create_accept_sk
)
(
struct
sock
*
sk
,
struct
sock
*
(
*
create_accept_sk
)
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
);
struct
sctp_association
*
asoc
);
...
@@ -430,7 +432,7 @@ struct sctp_ssnmap {
...
@@ -430,7 +432,7 @@ struct sctp_ssnmap {
};
};
struct
sctp_ssnmap
*
sctp_ssnmap_init
(
struct
sctp_ssnmap
*
,
__u16
,
__u16
);
struct
sctp_ssnmap
*
sctp_ssnmap_init
(
struct
sctp_ssnmap
*
,
__u16
,
__u16
);
struct
sctp_ssnmap
*
sctp_ssnmap_new
(
__u16
in
,
__u16
out
,
int
priority
);
struct
sctp_ssnmap
*
sctp_ssnmap_new
(
__u16
in
,
__u16
out
,
int
gfp
);
void
sctp_ssnmap_free
(
struct
sctp_ssnmap
*
map
);
void
sctp_ssnmap_free
(
struct
sctp_ssnmap
*
map
);
void
sctp_ssnmap_clear
(
struct
sctp_ssnmap
*
map
);
void
sctp_ssnmap_clear
(
struct
sctp_ssnmap
*
map
);
...
@@ -509,7 +511,7 @@ struct sctp_chunk {
...
@@ -509,7 +511,7 @@ struct sctp_chunk {
struct
sctp_sndrcvinfo
sinfo
;
struct
sctp_sndrcvinfo
sinfo
;
/* Which association does this belong to? */
/* Which association does this belong to? */
s
ctp_association_t
*
asoc
;
s
truct
sctp_association
*
asoc
;
/* What endpoint received this chunk? */
/* What endpoint received this chunk? */
sctp_endpoint_common_t
*
rcvr
;
sctp_endpoint_common_t
*
rcvr
;
...
@@ -541,11 +543,11 @@ struct sctp_chunk {
...
@@ -541,11 +543,11 @@ struct sctp_chunk {
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
};
};
sctp_chunk_t
*
sctp_make_chunk
(
const
s
ctp_association_t
*
,
__u8
type
,
sctp_chunk_t
*
sctp_make_chunk
(
const
s
truct
sctp_association
*
,
__u8
type
,
__u8
flags
,
int
size
);
__u8
flags
,
int
size
);
void
sctp_free_chunk
(
sctp_chunk_t
*
);
void
sctp_free_chunk
(
sctp_chunk_t
*
);
void
*
sctp_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
const
void
*
data
);
void
*
sctp_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
const
void
*
data
);
sctp_chunk_t
*
sctp_chunkify
(
struct
sk_buff
*
,
const
s
ctp_association_t
*
,
sctp_chunk_t
*
sctp_chunkify
(
struct
sk_buff
*
,
const
s
truct
sctp_association
*
,
struct
sock
*
);
struct
sock
*
);
void
sctp_init_addrs
(
sctp_chunk_t
*
,
union
sctp_addr
*
,
union
sctp_addr
*
);
void
sctp_init_addrs
(
sctp_chunk_t
*
,
union
sctp_addr
*
,
union
sctp_addr
*
);
const
union
sctp_addr
*
sctp_source
(
const
sctp_chunk_t
*
chunk
);
const
union
sctp_addr
*
sctp_source
(
const
sctp_chunk_t
*
chunk
);
...
@@ -560,7 +562,7 @@ struct sockaddr_storage_list {
...
@@ -560,7 +562,7 @@ struct sockaddr_storage_list {
union
sctp_addr
a
;
union
sctp_addr
a
;
};
};
typedef
sctp_chunk_t
*
(
sctp_packet_phandler_t
)(
s
ctp_association_t
*
);
typedef
sctp_chunk_t
*
(
sctp_packet_phandler_t
)(
s
truct
sctp_association
*
);
/* This structure holds lists of chunks as we are assembling for
/* This structure holds lists of chunks as we are assembling for
* transmission.
* transmission.
...
@@ -590,13 +592,16 @@ struct sctp_packet {
...
@@ -590,13 +592,16 @@ struct sctp_packet {
/* This packet should advertise ECN capability to the network
/* This packet should advertise ECN capability to the network
* via the ECT bit.
* via the ECT bit.
*/
*/
int
ecn_capable
;
char
ecn_capable
;
/* This packet contains a COOKIE-ECHO chunk. */
/* This packet contains a COOKIE-ECHO chunk. */
int
has_cookie_echo
;
char
has_cookie_echo
;
/* This packet containsa SACK chunk. */
char
has_sack
;
/* SCTP cannot fragment this packet. So let ip fragment it. */
/* SCTP cannot fragment this packet. So let ip fragment it. */
int
ipfragok
;
char
ipfragok
;
int
malloced
;
int
malloced
;
};
};
...
@@ -660,7 +665,7 @@ struct sctp_transport {
...
@@ -660,7 +665,7 @@ struct sctp_transport {
struct
sctp_af
*
af_specific
;
struct
sctp_af
*
af_specific
;
/* Which association do we belong to? */
/* Which association do we belong to? */
s
ctp_association_t
*
asoc
;
s
truct
sctp_association
*
asoc
;
/* RFC2960
/* RFC2960
*
*
...
@@ -799,7 +804,8 @@ struct sctp_transport {
...
@@ -799,7 +804,8 @@ struct sctp_transport {
struct
sctp_transport
*
sctp_transport_new
(
const
union
sctp_addr
*
,
int
);
struct
sctp_transport
*
sctp_transport_new
(
const
union
sctp_addr
*
,
int
);
struct
sctp_transport
*
sctp_transport_init
(
struct
sctp_transport
*
,
struct
sctp_transport
*
sctp_transport_init
(
struct
sctp_transport
*
,
const
union
sctp_addr
*
,
int
);
const
union
sctp_addr
*
,
int
);
void
sctp_transport_set_owner
(
struct
sctp_transport
*
,
sctp_association_t
*
);
void
sctp_transport_set_owner
(
struct
sctp_transport
*
,
struct
sctp_association
*
);
void
sctp_transport_route
(
struct
sctp_transport
*
,
union
sctp_addr
*
,
void
sctp_transport_route
(
struct
sctp_transport
*
,
union
sctp_addr
*
,
struct
sctp_opt
*
);
struct
sctp_opt
*
);
void
sctp_transport_pmtu
(
struct
sctp_transport
*
);
void
sctp_transport_pmtu
(
struct
sctp_transport
*
);
...
@@ -862,13 +868,16 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
...
@@ -862,13 +868,16 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
* When free()'d, it empties itself out via output_handler().
* When free()'d, it empties itself out via output_handler().
*/
*/
struct
sctp_outq
{
struct
sctp_outq
{
s
ctp_association_t
*
asoc
;
s
truct
sctp_association
*
asoc
;
/* Data pending that has never been transmitted. */
/* Data pending that has never been transmitted. */
struct
sk_buff_head
out
;
struct
sk_buff_head
out
;
unsigned
out_qlen
;
/* Total length of queued data chunks. */
unsigned
out_qlen
;
/* Total length of queued data chunks. */
/* Error of send failed, may used in SCTP_SEND_FAILED event. */
unsigned
error
;
/* 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
;
...
@@ -902,8 +911,8 @@ struct sctp_outq {
...
@@ -902,8 +911,8 @@ struct sctp_outq {
int
malloced
;
int
malloced
;
};
};
struct
sctp_outq
*
sctp_outq_new
(
s
ctp_association_t
*
);
struct
sctp_outq
*
sctp_outq_new
(
s
truct
sctp_association
*
);
void
sctp_outq_init
(
s
ctp_association_t
*
,
struct
sctp_outq
*
);
void
sctp_outq_init
(
s
truct
sctp_association
*
,
struct
sctp_outq
*
);
void
sctp_outq_teardown
(
struct
sctp_outq
*
);
void
sctp_outq_teardown
(
struct
sctp_outq
*
);
void
sctp_outq_free
(
struct
sctp_outq
*
);
void
sctp_outq_free
(
struct
sctp_outq
*
);
int
sctp_outq_tail
(
struct
sctp_outq
*
,
sctp_chunk_t
*
chunk
);
int
sctp_outq_tail
(
struct
sctp_outq
*
,
sctp_chunk_t
*
chunk
);
...
@@ -947,20 +956,16 @@ sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask);
...
@@ -947,20 +956,16 @@ sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask);
void
sctp_bind_addr_init
(
sctp_bind_addr_t
*
,
__u16
port
);
void
sctp_bind_addr_init
(
sctp_bind_addr_t
*
,
__u16
port
);
void
sctp_bind_addr_free
(
sctp_bind_addr_t
*
);
void
sctp_bind_addr_free
(
sctp_bind_addr_t
*
);
int
sctp_bind_addr_copy
(
sctp_bind_addr_t
*
dest
,
const
sctp_bind_addr_t
*
src
,
int
sctp_bind_addr_copy
(
sctp_bind_addr_t
*
dest
,
const
sctp_bind_addr_t
*
src
,
sctp_scope_t
scope
,
int
priority
,
int
flags
);
sctp_scope_t
scope
,
int
gfp
,
int
flags
);
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
,
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
,
int
priority
);
int
gfp
);
int
sctp_del_bind_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
);
int
sctp_del_bind_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
);
int
sctp_bind_addr_match
(
sctp_bind_addr_t
*
,
const
union
sctp_addr
*
,
int
sctp_bind_addr_match
(
sctp_bind_addr_t
*
,
const
union
sctp_addr
*
,
struct
sctp_opt
*
);
struct
sctp_opt
*
);
union
sctp_params
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
union
sctp_params
sctp_bind_addrs_to_raw
(
const
struct
sctp_bind_addr
*
bp
,
int
*
addrs_len
,
int
*
addrs_len
,
int
gfp
);
int
priority
);
int
sctp_raw_to_bind_addrs
(
struct
sctp_bind_addr
*
bp
,
__u8
*
raw
,
int
len
,
int
sctp_raw_to_bind_addrs
(
sctp_bind_addr_t
*
bp
,
__u16
port
,
int
gfp
);
__u8
*
raw_addr_list
,
int
addrs_len
,
unsigned
short
port
,
int
priority
);
sctp_scope_t
sctp_scope
(
const
union
sctp_addr
*
);
sctp_scope_t
sctp_scope
(
const
union
sctp_addr
*
);
int
sctp_in_scope
(
const
union
sctp_addr
*
addr
,
const
sctp_scope_t
scope
);
int
sctp_in_scope
(
const
union
sctp_addr
*
addr
,
const
sctp_scope_t
scope
);
...
@@ -1063,7 +1068,7 @@ struct sctp_endpoint {
...
@@ -1063,7 +1068,7 @@ struct sctp_endpoint {
* pointer, or table pointers dependent on how SCTP
* pointer, or table pointers dependent on how SCTP
* is implemented.
* is implemented.
*/
*/
/* This is really a list of s
ctp_association_t
entries. */
/* This is really a list of s
truct sctp_association
entries. */
struct
list_head
asocs
;
struct
list_head
asocs
;
/* Secret Key: A secret key used by this endpoint to compute
/* Secret Key: A secret key used by this endpoint to compute
...
@@ -1099,12 +1104,12 @@ static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base)
...
@@ -1099,12 +1104,12 @@ static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base)
sctp_endpoint_t
*
sctp_endpoint_new
(
struct
sctp_protocol
*
,
struct
sock
*
,
int
);
sctp_endpoint_t
*
sctp_endpoint_new
(
struct
sctp_protocol
*
,
struct
sock
*
,
int
);
sctp_endpoint_t
*
sctp_endpoint_init
(
struct
sctp_endpoint
*
,
sctp_endpoint_t
*
sctp_endpoint_init
(
struct
sctp_endpoint
*
,
struct
sctp_protocol
*
,
struct
sctp_protocol
*
,
struct
sock
*
,
int
priority
);
struct
sock
*
,
int
gfp
);
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
*
);
void
sctp_endpoint_hold
(
sctp_endpoint_t
*
);
void
sctp_endpoint_hold
(
sctp_endpoint_t
*
);
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
,
s
ctp_association_t
*
asoc
);
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
,
s
truct
sctp_association
*
asoc
);
s
ctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
s
truct
sctp_association
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
const
union
sctp_addr
*
paddr
,
const
union
sctp_addr
*
paddr
,
struct
sctp_transport
**
);
struct
sctp_transport
**
);
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
*
);
...
@@ -1113,18 +1118,16 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *,
...
@@ -1113,18 +1118,16 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *,
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
);
int
sctp_verify_init
(
const
sctp_association_t
*
asoc
,
int
sctp_verify_init
(
const
struct
sctp_association
*
asoc
,
sctp_cid_t
,
sctp_cid_t
cid
,
sctp_init_chunk_t
*
peer_init
,
struct
sctp_chunk
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
struct
sctp_chunk
**
err_chunk
);
sctp_chunk_t
*
chunk
,
int
sctp_process_init
(
struct
sctp_association
*
,
sctp_cid_t
cid
,
sctp_chunk_t
**
err_chunk
);
const
union
sctp_addr
*
peer
,
int
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
sctp_init_chunk_t
*
init
,
int
gfp
);
const
union
sctp_addr
*
peer_addr
,
int
sctp_process_param
(
struct
sctp_association
*
,
union
sctp_params
param
,
sctp_init_chunk_t
*
peer_init
,
int
priority
);
const
union
sctp_addr
*
from
,
int
gfp
);
int
sctp_process_param
(
sctp_association_t
*
asoc
,
union
sctp_params
param
,
__u32
sctp_generate_tag
(
const
sctp_endpoint_t
*
);
const
union
sctp_addr
*
peer_addr
,
int
priority
);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
);
__u32
sctp_generate_tag
(
const
sctp_endpoint_t
*
ep
);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
ep
);
/* RFC2960
/* RFC2960
...
@@ -1153,7 +1156,7 @@ struct sctp_association {
...
@@ -1153,7 +1156,7 @@ struct sctp_association {
struct
list_head
asocs
;
struct
list_head
asocs
;
/* This is a signature that lets us know that this is a
/* This is a signature that lets us know that this is a
* s
ctp_association_t
data structure. Used for mapping an
* s
truct sctp_association
data structure. Used for mapping an
* association id to an association.
* association id to an association.
*/
*/
__u32
eyecatcher
;
__u32
eyecatcher
;
...
@@ -1556,44 +1559,46 @@ enum {
...
@@ -1556,44 +1559,46 @@ enum {
};
};
/* Recover the outter association structure. */
/* Recover the outter association structure. */
static
inline
s
ctp_association_t
*
sctp_assoc
(
sctp_endpoint_common_t
*
base
)
static
inline
s
truct
sctp_association
*
sctp_assoc
(
sctp_endpoint_common_t
*
base
)
{
{
s
ctp_association_t
*
asoc
;
s
truct
sctp_association
*
asoc
;
asoc
=
container_of
(
base
,
s
ctp_association_t
,
base
);
asoc
=
container_of
(
base
,
s
truct
sctp_association
,
base
);
return
asoc
;
return
asoc
;
}
}
/* These are function signatures for manipulating associations. */
/* These are function signatures for manipulating associations. */
s
ctp_association_t
*
s
truct
sctp_association
*
sctp_association_new
(
const
sctp_endpoint_t
*
,
const
struct
sock
*
,
sctp_association_new
(
const
sctp_endpoint_t
*
,
const
struct
sock
*
,
sctp_scope_t
scope
,
int
priority
);
sctp_scope_t
scope
,
int
gfp
);
s
ctp_association_t
*
s
truct
sctp_association
*
sctp_association_init
(
s
ctp_association_t
*
,
const
sctp_endpoint_t
*
,
sctp_association_init
(
s
truct
sctp_association
*
,
const
sctp_endpoint_t
*
,
const
struct
sock
*
,
sctp_scope_t
scope
,
const
struct
sock
*
,
sctp_scope_t
scope
,
int
priority
);
int
gfp
);
void
sctp_association_free
(
sctp_association_t
*
);
void
sctp_association_free
(
struct
sctp_association
*
);
void
sctp_association_put
(
sctp_association_t
*
);
void
sctp_association_put
(
struct
sctp_association
*
);
void
sctp_association_hold
(
sctp_association_t
*
);
void
sctp_association_hold
(
struct
sctp_association
*
);
struct
sctp_transport
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
struct
sctp_transport
*
sctp_assoc_choose_shutdown_transport
(
void
sctp_assoc_update_retran_path
(
sctp_association_t
*
);
struct
sctp_association
*
);
struct
sctp_transport
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
void
sctp_assoc_update_retran_path
(
struct
sctp_association
*
);
struct
sctp_transport
*
sctp_assoc_lookup_paddr
(
const
struct
sctp_association
*
,
const
union
sctp_addr
*
);
const
union
sctp_addr
*
);
struct
sctp_transport
*
sctp_assoc_add_peer
(
s
ctp_association_t
*
,
struct
sctp_transport
*
sctp_assoc_add_peer
(
s
truct
sctp_association
*
,
const
union
sctp_addr
*
address
,
const
union
sctp_addr
*
address
,
const
int
priority
);
const
int
gfp
);
void
sctp_assoc_control_transport
(
struct
sctp_association
*
,
void
sctp_assoc_control_transport
(
struct
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
(
s
ctp_association_t
*
,
__u32
);
struct
sctp_transport
*
sctp_assoc_lookup_tsn
(
s
truct
sctp_association
*
,
__u32
);
struct
sctp_transport
*
sctp_assoc_is_match
(
s
ctp_association_t
*
,
struct
sctp_transport
*
sctp_assoc_is_match
(
s
truct
sctp_association
*
,
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
const
union
sctp_addr
*
);
const
union
sctp_addr
*
);
void
sctp_assoc_migrate
(
sctp_association_t
*
,
struct
sock
*
);
void
sctp_assoc_migrate
(
struct
sctp_association
*
,
struct
sock
*
);
void
sctp_assoc_update
(
sctp_association_t
*
dst
,
sctp_association_t
*
src
);
void
sctp_assoc_update
(
struct
sctp_association
*
old
,
struct
sctp_association
*
new
);
__u32
sctp_association_get_next_tsn
(
struct
sctp_association
*
);
__u32
sctp_association_get_next_tsn
(
struct
sctp_association
*
);
__u32
sctp_association_get_tsn_block
(
struct
sctp_association
*
,
int
);
__u32
sctp_association_get_tsn_block
(
struct
sctp_association
*
,
int
);
...
@@ -1603,14 +1608,14 @@ void sctp_assoc_rwnd_increase(struct sctp_association *, int);
...
@@ -1603,14 +1608,14 @@ void sctp_assoc_rwnd_increase(struct sctp_association *, int);
void
sctp_assoc_rwnd_decrease
(
struct
sctp_association
*
,
int
);
void
sctp_assoc_rwnd_decrease
(
struct
sctp_association
*
,
int
);
void
sctp_assoc_set_primary
(
struct
sctp_association
*
,
void
sctp_assoc_set_primary
(
struct
sctp_association
*
,
struct
sctp_transport
*
);
struct
sctp_transport
*
);
int
sctp_assoc_set_bind_addr_from_ep
(
s
ctp_association_t
*
,
int
);
int
sctp_assoc_set_bind_addr_from_ep
(
s
truct
sctp_association
*
,
int
);
int
sctp_assoc_set_bind_addr_from_cookie
(
s
ctp_association_t
*
,
int
sctp_assoc_set_bind_addr_from_cookie
(
s
truct
sctp_association
*
,
sctp_cookie_t
*
,
int
);
sctp_cookie_t
*
,
int
gfp
);
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
const
union
sctp_addr
*
ss2
);
const
union
sctp_addr
*
ss2
);
sctp_chunk_t
*
sctp_get_ecne_prepend
(
s
ctp_association_t
*
asoc
);
sctp_chunk_t
*
sctp_get_ecne_prepend
(
s
truct
sctp_association
*
asoc
);
sctp_chunk_t
*
sctp_get_no_prepend
(
s
ctp_association_t
*
asoc
);
sctp_chunk_t
*
sctp_get_no_prepend
(
s
truct
sctp_association
*
asoc
);
/* A convenience structure to parse out SCTP specific CMSGs. */
/* A convenience structure to parse out SCTP specific CMSGs. */
typedef
struct
sctp_cmsgs
{
typedef
struct
sctp_cmsgs
{
...
...
include/net/sctp/ulpevent.h
View file @
381a2af8
...
@@ -38,7 +38,6 @@
...
@@ -38,7 +38,6 @@
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
*/
*/
#ifndef __sctp_ulpevent_h__
#ifndef __sctp_ulpevent_h__
#define __sctp_ulpevent_h__
#define __sctp_ulpevent_h__
...
@@ -50,6 +49,7 @@ struct sctp_ulpevent {
...
@@ -50,6 +49,7 @@ struct sctp_ulpevent {
struct
sctp_association
*
asoc
;
struct
sctp_association
*
asoc
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
struct
sctp_sndrcvinfo
sndrcvinfo
;
int
msg_flags
;
int
msg_flags
;
int
iif
;
};
};
/* Retrieve the skb this event sits inside of. */
/* Retrieve the skb this event sits inside of. */
...
...
net/sctp/associola.c
View file @
381a2af8
...
@@ -290,14 +290,18 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
...
@@ -290,14 +290,18 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
*/
*/
void
sctp_association_free
(
sctp_association_t
*
asoc
)
void
sctp_association_free
(
sctp_association_t
*
asoc
)
{
{
struct
sock
*
sk
=
asoc
->
base
.
sk
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_endpoint_t
*
ep
;
struct
list_head
*
pos
,
*
temp
;
struct
list_head
*
pos
,
*
temp
;
int
i
;
int
i
;
ep
=
asoc
->
ep
;
list_del
(
&
asoc
->
asocs
);
list_del
(
&
asoc
->
asocs
);
/* Decrement the backlog value for a TCP-style listening socket. */
if
((
SCTP_SOCKET_TCP
==
sctp_sk
(
sk
)
->
type
)
&&
(
SCTP_SS_LISTENING
==
sk
->
state
))
sk
->
ack_backlog
--
;
/* Mark as dead, so other users can know this structure is
/* Mark as dead, so other users can know this structure is
* going away.
* going away.
*/
*/
...
@@ -421,8 +425,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
...
@@ -421,8 +425,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
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
=
sctp_frag_point
(
asoc
->
pmtu
);
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.
...
@@ -642,8 +645,6 @@ __u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
...
@@ -642,8 +645,6 @@ __u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
/* Compare two addresses to see if they match. Wildcard addresses
/* Compare two addresses to see if they match. Wildcard addresses
* only match themselves.
* only match themselves.
*
* FIXME: We do not match address scopes correctly.
*/
*/
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
const
union
sctp_addr
*
ss2
)
const
union
sctp_addr
*
ss2
)
...
@@ -651,38 +652,27 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1,
...
@@ -651,38 +652,27 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1,
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
af
=
sctp_get_af_specific
(
ss1
->
sa
.
sa_family
);
af
=
sctp_get_af_specific
(
ss1
->
sa
.
sa_family
);
if
(
!
af
)
if
(
unlikely
(
!
af
)
)
return
0
;
return
0
;
return
af
->
cmp_addr
(
ss1
,
ss2
);
return
af
->
cmp_addr
(
ss1
,
ss2
);
}
}
/* Return an ecne chunk to get prepended to a packet.
/* Return an ecne chunk to get prepended to a packet.
* Note: We are sly and return a shared, prealloced chunk.
* Note: We are sly and return a shared, prealloced chunk. FIXME:
* No we don't, but we could/should.
*/
*/
sctp_chunk_t
*
sctp_get_ecne_prepend
(
s
ctp_association_t
*
asoc
)
sctp_chunk_t
*
sctp_get_ecne_prepend
(
s
truct
sctp_association
*
asoc
)
{
{
sctp_chunk_t
*
chunk
;
struct
sctp_chunk
*
chunk
;
int
need_ecne
;
__u32
lowest_tsn
;
/* Can be called from task or bh. Both need_ecne and
* last_ecne_tsn are written during bh.
*/
need_ecne
=
asoc
->
need_ecne
;
lowest_tsn
=
asoc
->
last_ecne_tsn
;
if
(
need_ecne
)
{
chunk
=
sctp_make_ecne
(
asoc
,
lowest_tsn
);
/* ECNE is not mandatory to the flow. Being unable to
/* Send ECNE if needed.
* alloc mem is not deadly. We are just unable to help
* Not being able to allocate a chunk here is not deadly.
* out the network. If we run out of memory, just return
* NULL.
*/
*/
}
else
{
if
(
asoc
->
need_ecne
)
chunk
=
sctp_make_ecne
(
asoc
,
asoc
->
last_ecne_tsn
);
else
chunk
=
NULL
;
chunk
=
NULL
;
}
return
chunk
;
return
chunk
;
}
}
...
@@ -832,12 +822,17 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -832,12 +822,17 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
void
sctp_assoc_migrate
(
sctp_association_t
*
assoc
,
struct
sock
*
newsk
)
void
sctp_assoc_migrate
(
sctp_association_t
*
assoc
,
struct
sock
*
newsk
)
{
{
struct
sctp_opt
*
newsp
=
sctp_sk
(
newsk
);
struct
sctp_opt
*
newsp
=
sctp_sk
(
newsk
);
struct
sock
*
oldsk
=
assoc
->
base
.
sk
;
/* Delete the association from the old endpoint's list of
/* Delete the association from the old endpoint's list of
* associations.
* associations.
*/
*/
list_del
(
&
assoc
->
asocs
);
list_del
(
&
assoc
->
asocs
);
/* Decrement the backlog value for a TCP-style socket. */
if
(
SCTP_SOCKET_TCP
==
sctp_sk
(
oldsk
)
->
type
)
oldsk
->
ack_backlog
--
;
/* Release references to the old endpoint and the sock. */
/* Release references to the old endpoint and the sock. */
sctp_endpoint_put
(
assoc
->
ep
);
sctp_endpoint_put
(
assoc
->
ep
);
sock_put
(
assoc
->
base
.
sk
);
sock_put
(
assoc
->
base
.
sk
);
...
@@ -986,8 +981,7 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
...
@@ -986,8 +981,7 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
if
(
pmtu
)
{
if
(
pmtu
)
{
asoc
->
pmtu
=
pmtu
;
asoc
->
pmtu
=
pmtu
;
asoc
->
frag_point
=
pmtu
-
(
SCTP_IP_OVERHEAD
+
asoc
->
frag_point
=
sctp_frag_point
(
pmtu
);
sizeof
(
sctp_data_chunk_t
));
}
}
SCTP_DEBUG_PRINTK
(
"%s: asoc:%p, pmtu:%d, frag_point:%d
\n
"
,
SCTP_DEBUG_PRINTK
(
"%s: asoc:%p, pmtu:%d, frag_point:%d
\n
"
,
...
@@ -1077,7 +1071,7 @@ void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len)
...
@@ -1077,7 +1071,7 @@ void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len)
/* 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
* local endpoint and the remote peer.
* local endpoint and the remote peer.
*/
*/
int
sctp_assoc_set_bind_addr_from_ep
(
s
ctp_association_t
*
asoc
,
int
priority
)
int
sctp_assoc_set_bind_addr_from_ep
(
s
truct
sctp_association
*
asoc
,
int
gfp
)
{
{
sctp_scope_t
scope
;
sctp_scope_t
scope
;
int
flags
;
int
flags
;
...
@@ -1094,19 +1088,17 @@ int sctp_assoc_set_bind_addr_from_ep(sctp_association_t *asoc, int priority)
...
@@ -1094,19 +1088,17 @@ int sctp_assoc_set_bind_addr_from_ep(sctp_association_t *asoc, int priority)
return
sctp_bind_addr_copy
(
&
asoc
->
base
.
bind_addr
,
return
sctp_bind_addr_copy
(
&
asoc
->
base
.
bind_addr
,
&
asoc
->
ep
->
base
.
bind_addr
,
&
asoc
->
ep
->
base
.
bind_addr
,
scope
,
priority
,
flags
);
scope
,
gfp
,
flags
);
}
}
/* Build the association's bind address list from the cookie. */
/* Build the association's bind address list from the cookie. */
int
sctp_assoc_set_bind_addr_from_cookie
(
sctp_association_t
*
asoc
,
int
sctp_assoc_set_bind_addr_from_cookie
(
sctp_association_t
*
asoc
,
sctp_cookie_t
*
cookie
,
int
priority
)
sctp_cookie_t
*
cookie
,
int
gfp
)
{
{
int
var_size2
=
ntohs
(
cookie
->
peer_init
->
chunk_hdr
.
length
);
int
var_size2
=
ntohs
(
cookie
->
peer_init
->
chunk_hdr
.
length
);
int
var_size3
=
cookie
->
raw_addr_list_len
;
int
var_size3
=
cookie
->
raw_addr_list_len
;
__u8
*
raw_addr_list
=
(
__u8
*
)
cookie
+
sizeof
(
sctp_cookie_t
)
+
__u8
*
raw
=
(
__u8
*
)
cookie
+
sizeof
(
sctp_cookie_t
)
+
var_size2
;
var_size2
;
return
sctp_raw_to_bind_addrs
(
&
asoc
->
base
.
bind_addr
,
raw_addr_list
,
return
sctp_raw_to_bind_addrs
(
&
asoc
->
base
.
bind_addr
,
raw
,
var_size3
,
var_size3
,
asoc
->
ep
->
base
.
bind_addr
.
port
,
asoc
->
ep
->
base
.
bind_addr
.
port
,
gfp
);
priority
);
}
}
net/sctp/bind_addr.c
View file @
381a2af8
...
@@ -53,7 +53,7 @@
...
@@ -53,7 +53,7 @@
/* Forward declarations for internal helpers. */
/* Forward declarations for internal helpers. */
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
,
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
,
sctp_scope_t
scope
,
int
priority
,
int
flags
);
sctp_scope_t
scope
,
int
gfp
,
int
flags
);
static
void
sctp_bind_addr_clean
(
sctp_bind_addr_t
*
);
static
void
sctp_bind_addr_clean
(
sctp_bind_addr_t
*
);
/* First Level Abstractions. */
/* First Level Abstractions. */
...
@@ -62,7 +62,7 @@ static void sctp_bind_addr_clean(sctp_bind_addr_t *);
...
@@ -62,7 +62,7 @@ static void sctp_bind_addr_clean(sctp_bind_addr_t *);
* in 'src' which have a broader scope than 'scope'.
* in 'src' which have a broader scope than 'scope'.
*/
*/
int
sctp_bind_addr_copy
(
sctp_bind_addr_t
*
dest
,
const
sctp_bind_addr_t
*
src
,
int
sctp_bind_addr_copy
(
sctp_bind_addr_t
*
dest
,
const
sctp_bind_addr_t
*
src
,
sctp_scope_t
scope
,
int
priority
,
int
flags
)
sctp_scope_t
scope
,
int
gfp
,
int
flags
)
{
{
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
...
@@ -75,7 +75,7 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
...
@@ -75,7 +75,7 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
list_for_each
(
pos
,
&
src
->
address_list
)
{
list_for_each
(
pos
,
&
src
->
address_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
error
=
sctp_copy_one_addr
(
dest
,
&
addr
->
a
,
scope
,
error
=
sctp_copy_one_addr
(
dest
,
&
addr
->
a
,
scope
,
priority
,
flags
);
gfp
,
flags
);
if
(
error
<
0
)
if
(
error
<
0
)
goto
out
;
goto
out
;
}
}
...
@@ -88,11 +88,11 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
...
@@ -88,11 +88,11 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
}
}
/* Create a new SCTP_bind_addr from nothing. */
/* Create a new SCTP_bind_addr from nothing. */
sctp_bind_addr_t
*
sctp_bind_addr_new
(
int
priority
)
sctp_bind_addr_t
*
sctp_bind_addr_new
(
int
gfp
)
{
{
sctp_bind_addr_t
*
retval
;
sctp_bind_addr_t
*
retval
;
retval
=
t_new
(
sctp_bind_addr_t
,
priority
);
retval
=
t_new
(
sctp_bind_addr_t
,
gfp
);
if
(
!
retval
)
if
(
!
retval
)
goto
nomem
;
goto
nomem
;
...
@@ -144,12 +144,12 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp)
...
@@ -144,12 +144,12 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp)
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
bp
,
union
sctp_addr
*
new
,
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
bp
,
union
sctp_addr
*
new
,
int
priority
)
int
gfp
)
{
{
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
/* Add the address to the bind address list. */
/* Add the address to the bind address list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
priority
);
addr
=
t_new
(
struct
sockaddr_storage_list
,
gfp
);
if
(
!
addr
)
if
(
!
addr
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -197,7 +197,7 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr)
...
@@ -197,7 +197,7 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr)
* The second argument is the return value for the length.
* The second argument is the return value for the length.
*/
*/
union
sctp_params
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
union
sctp_params
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
int
*
addrs_len
,
int
priority
)
int
*
addrs_len
,
int
gfp
)
{
{
union
sctp_params
addrparms
;
union
sctp_params
addrparms
;
union
sctp_params
retval
;
union
sctp_params
retval
;
...
@@ -214,7 +214,7 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
...
@@ -214,7 +214,7 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
len
+=
sizeof
(
sctp_addr_param_t
);
len
+=
sizeof
(
sctp_addr_param_t
);
}
}
retval
.
v
=
kmalloc
(
len
,
priority
);
retval
.
v
=
kmalloc
(
len
,
gfp
);
if
(
!
retval
.
v
)
if
(
!
retval
.
v
)
goto
end_raw
;
goto
end_raw
;
...
@@ -238,7 +238,7 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
...
@@ -238,7 +238,7 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
* address parameters).
* address parameters).
*/
*/
int
sctp_raw_to_bind_addrs
(
sctp_bind_addr_t
*
bp
,
__u8
*
raw_addr_list
,
int
sctp_raw_to_bind_addrs
(
sctp_bind_addr_t
*
bp
,
__u8
*
raw_addr_list
,
int
addrs_len
,
__u16
port
,
int
priority
)
int
addrs_len
,
__u16
port
,
int
gfp
)
{
{
sctp_addr_param_t
*
rawaddr
;
sctp_addr_param_t
*
rawaddr
;
sctp_paramhdr_t
*
param
;
sctp_paramhdr_t
*
param
;
...
@@ -254,8 +254,8 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
...
@@ -254,8 +254,8 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
switch
(
param
->
type
)
{
switch
(
param
->
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV6_ADDRESS
:
case
SCTP_PARAM_IPV6_ADDRESS
:
sctp_param2sockaddr
(
&
addr
,
rawaddr
,
port
);
sctp_param2sockaddr
(
&
addr
,
rawaddr
,
port
,
0
);
retval
=
sctp_add_bind_addr
(
bp
,
&
addr
,
priority
);
retval
=
sctp_add_bind_addr
(
bp
,
&
addr
,
gfp
);
if
(
retval
)
{
if
(
retval
)
{
/* Can't finish building the list, clean up. */
/* Can't finish building the list, clean up. */
sctp_bind_addr_clean
(
bp
);
sctp_bind_addr_clean
(
bp
);
...
@@ -300,14 +300,14 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
...
@@ -300,14 +300,14 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
/* Copy out addresses from the global local address list. */
/* Copy out addresses from the global local address list. */
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
gfp
,
int
flags
)
{
{
struct
sctp_protocol
*
proto
=
sctp_get_protocol
();
struct
sctp_protocol
*
proto
=
sctp_get_protocol
();
int
error
=
0
;
int
error
=
0
;
if
(
sctp_is_any
(
addr
))
{
if
(
sctp_is_any
(
addr
))
{
error
=
sctp_copy_local_addr_list
(
proto
,
dest
,
scope
,
error
=
sctp_copy_local_addr_list
(
proto
,
dest
,
scope
,
priority
,
flags
);
gfp
,
flags
);
}
else
if
(
sctp_in_scope
(
addr
,
scope
))
{
}
else
if
(
sctp_in_scope
(
addr
,
scope
))
{
/* Now that the address is in scope, check to see if
/* Now that the address is in scope, check to see if
* the address type is supported by local sock as
* the address type is supported by local sock as
...
@@ -318,7 +318,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
...
@@ -318,7 +318,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
(((
AF_INET6
==
addr
->
sa
.
sa_family
)
&&
(((
AF_INET6
==
addr
->
sa
.
sa_family
)
&&
(
flags
&
SCTP_ADDR6_ALLOWED
)
&&
(
flags
&
SCTP_ADDR6_ALLOWED
)
&&
(
flags
&
SCTP_ADDR6_PEERSUPP
))))
(
flags
&
SCTP_ADDR6_PEERSUPP
))))
error
=
sctp_add_bind_addr
(
dest
,
addr
,
priority
);
error
=
sctp_add_bind_addr
(
dest
,
addr
,
gfp
);
}
}
return
error
;
return
error
;
...
...
net/sctp/endpointola.c
View file @
381a2af8
...
@@ -177,8 +177,15 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
...
@@ -177,8 +177,15 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
/* Add an association to an endpoint. */
/* Add an association to an endpoint. */
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
ep
,
sctp_association_t
*
asoc
)
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
ep
,
sctp_association_t
*
asoc
)
{
{
struct
sock
*
sk
=
ep
->
base
.
sk
;
/* Now just add it to our list of asocs */
/* Now just add it to our list of asocs */
list_add_tail
(
&
asoc
->
asocs
,
&
ep
->
asocs
);
list_add_tail
(
&
asoc
->
asocs
,
&
ep
->
asocs
);
/* Increment the backlog value for a TCP-style listening socket. */
if
((
SCTP_SOCKET_TCP
==
sctp_sk
(
sk
)
->
type
)
&&
(
SCTP_SS_LISTENING
==
sk
->
state
))
sk
->
ack_backlog
++
;
}
}
/* Free the endpoint structure. Delay cleanup until
/* Free the endpoint structure. Delay cleanup until
...
...
net/sctp/input.c
View file @
381a2af8
...
@@ -207,21 +207,19 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -207,21 +207,19 @@ int sctp_rcv(struct sk_buff *skb)
*/
*/
sctp_bh_lock_sock
(
sk
);
sctp_bh_lock_sock
(
sk
);
if
(
sock_owned_by_user
(
sk
))
{
if
(
sock_owned_by_user
(
sk
))
sk_add_backlog
(
sk
,
(
struct
sk_buff
*
)
chunk
);
sk_add_backlog
(
sk
,
(
struct
sk_buff
*
)
chunk
);
}
else
{
else
sctp_backlog_rcv
(
sk
,
(
struct
sk_buff
*
)
chunk
);
sctp_backlog_rcv
(
sk
,
(
struct
sk_buff
*
)
chunk
);
}
/* Release the sock and any reference counts we took in the
/* Release the sock and any reference counts we took in the
* lookup calls.
* lookup calls.
*/
*/
sctp_bh_unlock_sock
(
sk
);
sctp_bh_unlock_sock
(
sk
);
if
(
asoc
)
{
if
(
asoc
)
sctp_association_put
(
asoc
);
sctp_association_put
(
asoc
);
}
else
{
else
sctp_endpoint_put
(
ep
);
sctp_endpoint_put
(
ep
);
}
sock_put
(
sk
);
sock_put
(
sk
);
return
ret
;
return
ret
;
...
@@ -268,10 +266,8 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
...
@@ -268,10 +266,8 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
}
}
/* Handle icmp frag needed error. */
/* Handle icmp frag needed error. */
static
inline
void
sctp_icmp_frag_needed
(
struct
sock
*
sk
,
void
sctp_icmp_frag_needed
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
,
sctp_association_t
*
asoc
,
struct
sctp_transport
*
t
,
__u32
pmtu
)
struct
sctp_transport
*
transport
,
__u32
pmtu
)
{
{
if
(
unlikely
(
pmtu
<
SCTP_DEFAULT_MINSEGMENT
))
{
if
(
unlikely
(
pmtu
<
SCTP_DEFAULT_MINSEGMENT
))
{
printk
(
KERN_WARNING
"%s: Reported pmtu %d too low, "
printk
(
KERN_WARNING
"%s: Reported pmtu %d too low, "
...
@@ -280,54 +276,38 @@ static inline void sctp_icmp_frag_needed(struct sock *sk,
...
@@ -280,54 +276,38 @@ static inline void sctp_icmp_frag_needed(struct sock *sk,
pmtu
=
SCTP_DEFAULT_MINSEGMENT
;
pmtu
=
SCTP_DEFAULT_MINSEGMENT
;
}
}
if
(
!
sock_owned_by_user
(
sk
)
&&
t
ransport
&&
(
transpor
t
->
pmtu
!=
pmtu
))
{
if
(
!
sock_owned_by_user
(
sk
)
&&
t
&&
(
t
->
pmtu
!=
pmtu
))
{
t
ransport
->
pmtu
=
pmtu
;
t
->
pmtu
=
pmtu
;
sctp_assoc_sync_pmtu
(
asoc
);
sctp_assoc_sync_pmtu
(
asoc
);
sctp_retransmit
(
&
asoc
->
outqueue
,
transport
,
sctp_retransmit
(
&
asoc
->
outqueue
,
t
,
SCTP_RTXR_PMTUD
);
SCTP_RETRANSMIT_PMTU_DISCOVERY
);
}
}
}
}
/*
/* Common lookup code for icmp/icmpv6 error handler. */
* This routine is called by the ICMP module when it gets some
struct
sock
*
sctp_err_lookup
(
int
family
,
struct
sk_buff
*
skb
,
* sort of error condition. If err < 0 then the socket should
struct
sctphdr
*
sctphdr
,
* be closed and the error returned to the user. If err > 0
struct
sctp_endpoint
**
epp
,
* it's just the icmp type << 8 | icmp code. After adjustment
struct
sctp_association
**
app
,
* header points to the first 8 bytes of the sctp header. We need
struct
sctp_transport
**
tpp
)
* to find the appropriate port.
*
* The locking strategy used here is very "optimistic". When
* someone else accesses the socket the ICMP is just dropped
* and for some paths there is no check at all.
* A more general error queue to queue errors for later handling
* is probably better.
*
*/
void
sctp_v4_err
(
struct
sk_buff
*
skb
,
__u32
info
)
{
{
struct
iphdr
*
iph
=
(
struct
iphdr
*
)
skb
->
data
;
union
sctp_addr
saddr
;
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)(
skb
->
data
+
(
iph
->
ihl
<<
2
));
union
sctp_addr
daddr
;
int
type
=
skb
->
h
.
icmph
->
type
;
struct
sctp_af
*
af
;
int
code
=
skb
->
h
.
icmph
->
code
;
union
sctp_addr
saddr
,
daddr
;
struct
inet_opt
*
inet
;
struct
sock
*
sk
=
NULL
;
struct
sock
*
sk
=
NULL
;
sctp_endpoint_t
*
ep
=
NULL
;
struct
sctp_endpoint
*
ep
=
NULL
;
sctp_association_t
*
asoc
=
NULL
;
struct
sctp_association
*
asoc
=
NULL
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
=
NULL
;
int
err
;
if
(
skb
->
len
<
((
iph
->
ihl
<<
2
)
+
8
))
{
*
app
=
NULL
;
*
epp
=
NULL
;
*
tpp
=
NULL
;
ICMP_INC_STATS_BH
(
IcmpInErrors
);
return
;
af
=
sctp_get_af_specific
(
family
);
if
(
unlikely
(
!
af
))
{
return
NULL
;
}
}
saddr
.
v4
.
sin_family
=
AF_INET
;
/* Initialize local addresses for lookups. */
saddr
.
v4
.
sin_port
=
ntohs
(
sh
->
source
);
af
->
from_skb
(
&
saddr
,
skb
,
1
);
memcpy
(
&
saddr
.
v4
.
sin_addr
.
s_addr
,
&
iph
->
saddr
,
sizeof
(
struct
in_addr
));
af
->
from_skb
(
&
daddr
,
skb
,
0
);
daddr
.
v4
.
sin_family
=
AF_INET
;
daddr
.
v4
.
sin_port
=
ntohs
(
sh
->
dest
);
memcpy
(
&
daddr
.
v4
.
sin_addr
.
s_addr
,
&
iph
->
daddr
,
sizeof
(
struct
in_addr
));
/* Look for an association that matches the incoming ICMP error
/* Look for an association that matches the incoming ICMP error
* packet.
* packet.
...
@@ -340,13 +320,12 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
...
@@ -340,13 +320,12 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
*/
*/
ep
=
__sctp_rcv_lookup_endpoint
(
&
daddr
);
ep
=
__sctp_rcv_lookup_endpoint
(
&
daddr
);
if
(
!
ep
)
{
if
(
!
ep
)
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
return
NULL
;
return
;
}
}
}
}
if
(
asoc
)
{
if
(
asoc
)
{
if
(
ntohl
(
s
h
->
vtag
)
!=
asoc
->
c
.
peer_vtag
)
{
if
(
ntohl
(
s
ctphdr
->
vtag
)
!=
asoc
->
c
.
peer_vtag
)
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
ICMP_INC_STATS_BH
(
IcmpInErrors
);
goto
out
;
goto
out
;
}
}
...
@@ -355,12 +334,90 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
...
@@ -355,12 +334,90 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
sk
=
ep
->
base
.
sk
;
sk
=
ep
->
base
.
sk
;
sctp_bh_lock_sock
(
sk
);
sctp_bh_lock_sock
(
sk
);
/* If too many ICMPs get dropped on busy
/* If too many ICMPs get dropped on busy
* servers this needs to be solved differently.
* servers this needs to be solved differently.
*/
*/
if
(
sock_owned_by_user
(
sk
))
if
(
sock_owned_by_user
(
sk
))
NET_INC_STATS_BH
(
LockDroppedIcmps
);
NET_INC_STATS_BH
(
LockDroppedIcmps
);
*
epp
=
ep
;
*
app
=
asoc
;
*
tpp
=
transport
;
return
sk
;
out:
sock_put
(
sk
);
if
(
asoc
)
sctp_association_put
(
asoc
);
if
(
ep
)
sctp_endpoint_put
(
ep
);
return
NULL
;
}
/* Common cleanup code for icmp/icmpv6 error handler. */
void
sctp_err_finish
(
struct
sock
*
sk
,
struct
sctp_endpoint
*
ep
,
struct
sctp_association
*
asoc
)
{
sctp_bh_unlock_sock
(
sk
);
sock_put
(
sk
);
if
(
asoc
)
sctp_association_put
(
asoc
);
if
(
ep
)
sctp_endpoint_put
(
ep
);
}
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
* be closed and the error returned to the user. If err > 0
* it's just the icmp type << 8 | icmp code. After adjustment
* header points to the first 8 bytes of the sctp header. We need
* to find the appropriate port.
*
* The locking strategy used here is very "optimistic". When
* someone else accesses the socket the ICMP is just dropped
* and for some paths there is no check at all.
* A more general error queue to queue errors for later handling
* is probably better.
*
*/
void
sctp_v4_err
(
struct
sk_buff
*
skb
,
__u32
info
)
{
struct
iphdr
*
iph
=
(
struct
iphdr
*
)
skb
->
data
;
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)(
skb
->
data
+
(
iph
->
ihl
<<
2
));
int
type
=
skb
->
h
.
icmph
->
type
;
int
code
=
skb
->
h
.
icmph
->
code
;
struct
sock
*
sk
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
struct
sctp_transport
*
transport
;
struct
inet_opt
*
inet
;
char
*
saveip
,
*
savesctp
;
int
err
;
if
(
skb
->
len
<
((
iph
->
ihl
<<
2
)
+
8
))
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
return
;
}
/* Fix up skb to look at the embedded net header. */
saveip
=
skb
->
nh
.
raw
;
savesctp
=
skb
->
h
.
raw
;
skb
->
nh
.
iph
=
iph
;
skb
->
h
.
raw
=
(
char
*
)
sh
;
sk
=
sctp_err_lookup
(
AF_INET
,
skb
,
sh
,
&
ep
,
&
asoc
,
&
transport
);
/* Put back, the original pointers. */
skb
->
nh
.
raw
=
saveip
;
skb
->
h
.
raw
=
savesctp
;
if
(
!
sk
)
{
ICMP_INC_STATS_BH
(
IcmpInErrors
);
return
;
}
/* Warning: The sock lock is held. Remember to call
* sctp_err_finish!
*/
switch
(
type
)
{
switch
(
type
)
{
case
ICMP_PARAMETERPROB
:
case
ICMP_PARAMETERPROB
:
err
=
EPROTO
;
err
=
EPROTO
;
...
@@ -399,13 +456,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
...
@@ -399,13 +456,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
}
}
out_unlock:
out_unlock:
sctp_bh_unlock_sock
(
sk
);
sctp_err_finish
(
sk
,
ep
,
asoc
);
out:
sock_put
(
sk
);
if
(
asoc
)
sctp_association_put
(
asoc
);
if
(
ep
)
sctp_endpoint_put
(
ep
);
}
}
/*
/*
...
@@ -623,9 +674,9 @@ void __sctp_unhash_established(sctp_association_t *asoc)
...
@@ -623,9 +674,9 @@ void __sctp_unhash_established(sctp_association_t *asoc)
}
}
/* Look up an association. */
/* Look up an association. */
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
l
addr
,
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
l
ocal
,
const
union
sctp_addr
*
p
add
r
,
const
union
sctp_addr
*
p
ee
r
,
struct
sctp_transport
**
transportp
)
struct
sctp_transport
**
pt
)
{
{
sctp_hashbucket_t
*
head
;
sctp_hashbucket_t
*
head
;
sctp_endpoint_common_t
*
epb
;
sctp_endpoint_common_t
*
epb
;
...
@@ -636,12 +687,12 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
...
@@ -636,12 +687,12 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
/* Optimize here for direct hit, only listening connections can
/* Optimize here for direct hit, only listening connections can
* have wildcards anyways.
* have wildcards anyways.
*/
*/
hash
=
sctp_assoc_hashfn
(
l
addr
->
v4
.
sin_port
,
padd
r
->
v4
.
sin_port
);
hash
=
sctp_assoc_hashfn
(
l
ocal
->
v4
.
sin_port
,
pee
r
->
v4
.
sin_port
);
head
=
&
sctp_proto
.
assoc_hashbucket
[
hash
];
head
=
&
sctp_proto
.
assoc_hashbucket
[
hash
];
read_lock
(
&
head
->
lock
);
read_lock
(
&
head
->
lock
);
for
(
epb
=
head
->
chain
;
epb
;
epb
=
epb
->
next
)
{
for
(
epb
=
head
->
chain
;
epb
;
epb
=
epb
->
next
)
{
asoc
=
sctp_assoc
(
epb
);
asoc
=
sctp_assoc
(
epb
);
transport
=
sctp_assoc_is_match
(
asoc
,
l
addr
,
padd
r
);
transport
=
sctp_assoc_is_match
(
asoc
,
l
ocal
,
pee
r
);
if
(
transport
)
if
(
transport
)
goto
hit
;
goto
hit
;
}
}
...
@@ -651,7 +702,7 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
...
@@ -651,7 +702,7 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
return
NULL
;
return
NULL
;
hit:
hit:
*
transportp
=
transport
;
*
pt
=
transport
;
sctp_association_hold
(
asoc
);
sctp_association_hold
(
asoc
);
sock_hold
(
epb
->
sk
);
sock_hold
(
epb
->
sk
);
read_unlock
(
&
head
->
lock
);
read_unlock
(
&
head
->
lock
);
...
@@ -754,7 +805,7 @@ static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
...
@@ -754,7 +805,7 @@ static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
(
SCTP_PARAM_IPV6_ADDRESS
!=
params
.
p
->
type
))
(
SCTP_PARAM_IPV6_ADDRESS
!=
params
.
p
->
type
))
continue
;
continue
;
sctp_param2sockaddr
(
paddr
,
params
.
addr
,
ntohs
(
sh
->
source
));
sctp_param2sockaddr
(
paddr
,
params
.
addr
,
ntohs
(
sh
->
source
)
,
0
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
if
(
asoc
)
if
(
asoc
)
return
asoc
;
return
asoc
;
...
@@ -782,8 +833,3 @@ sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
...
@@ -782,8 +833,3 @@ sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
return
asoc
;
return
asoc
;
}
}
net/sctp/ipv6.c
View file @
381a2af8
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2002 International Business Machines, Corp.
* Copyright (c) 2002
-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
*
*
...
@@ -88,17 +88,62 @@ extern struct notifier_block sctp_inetaddr_notifier;
...
@@ -88,17 +88,62 @@ extern struct notifier_block sctp_inetaddr_notifier;
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
ntohs((addr)->s6_addr16[7])
/* FIXME: Comments. */
/* ICMP error handler. */
static
inline
void
sctp_v6_err
(
struct
sk_buff
*
skb
,
void
sctp_v6_err
(
struct
sk_buff
*
skb
,
struct
inet6_skb_parm
*
opt
,
struct
inet6_skb_parm
*
opt
,
int
type
,
int
code
,
int
offset
,
__u32
info
)
int
type
,
int
code
,
int
offset
,
__u32
info
)
{
{
/* BUG. WRITE ME. */
struct
ipv6hdr
*
iph
=
(
struct
ipv6hdr
*
)
skb
->
data
;
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)(
skb
->
data
+
offset
);
struct
sock
*
sk
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
struct
sctp_transport
*
transport
;
struct
ipv6_pinfo
*
np
;
char
*
saveip
,
*
savesctp
;
int
err
;
/* Fix up skb to look at the embedded net header. */
saveip
=
skb
->
nh
.
raw
;
savesctp
=
skb
->
h
.
raw
;
skb
->
nh
.
ipv6h
=
iph
;
skb
->
h
.
raw
=
(
char
*
)
sh
;
sk
=
sctp_err_lookup
(
AF_INET6
,
skb
,
sh
,
&
ep
,
&
asoc
,
&
transport
);
/* Put back, the original pointers. */
skb
->
nh
.
raw
=
saveip
;
skb
->
h
.
raw
=
savesctp
;
if
(
!
sk
)
{
ICMP6_INC_STATS_BH
(
Icmp6InErrors
);
return
;
}
/* Warning: The sock lock is held. Remember to call
* sctp_err_finish!
*/
switch
(
type
)
{
case
ICMPV6_PKT_TOOBIG
:
sctp_icmp_frag_needed
(
sk
,
asoc
,
transport
,
ntohl
(
info
));
goto
out_unlock
;
default:
break
;
}
np
=
inet6_sk
(
sk
);
icmpv6_err_convert
(
type
,
code
,
&
err
);
if
(
!
sock_owned_by_user
(
sk
)
&&
np
->
recverr
)
{
sk
->
err
=
err
;
sk
->
error_report
(
sk
);
}
else
{
/* Only an error on timeout */
sk
->
err_soft
=
err
;
}
out_unlock:
sctp_err_finish
(
sk
,
ep
,
asoc
);
}
}
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
static
in
line
int
sctp_v6_xmit
(
struct
sk_buff
*
skb
,
static
in
t
sctp_v6_xmit
(
struct
sk_buff
*
skb
,
struct
sctp_transport
*
transport
,
struct
sctp_transport
*
transport
,
int
ipfragok
)
int
ipfragok
)
{
{
struct
sock
*
sk
=
skb
->
sk
;
struct
sock
*
sk
=
skb
->
sk
;
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
...
@@ -116,9 +161,12 @@ static inline int sctp_v6_xmit(struct sk_buff *skb,
...
@@ -116,9 +161,12 @@ static inline int sctp_v6_xmit(struct sk_buff *skb,
fl
.
fl6_flowlabel
=
np
->
flow_label
;
fl
.
fl6_flowlabel
=
np
->
flow_label
;
IP6_ECN_flow_xmit
(
sk
,
fl
.
fl6_flowlabel
);
IP6_ECN_flow_xmit
(
sk
,
fl
.
fl6_flowlabel
);
if
(
ipv6_addr_type
(
fl
.
fl6_src
)
&
IPV6_ADDR_LINKLOCAL
)
fl
.
oif
=
transport
->
saddr
.
v6
.
sin6_scope_id
;
else
fl
.
oif
=
sk
->
bound_dev_if
;
fl
.
oif
=
sk
->
bound_dev_if
;
fl
.
uli_u
.
ports
.
sport
=
inet_sk
(
sk
)
->
sport
;
fl
.
uli_u
.
ports
.
sport
=
inet_sk
(
sk
)
->
sport
;
fl
.
uli_u
.
ports
.
dport
=
inet_sk
(
sk
)
->
d
port
;
fl
.
uli_u
.
ports
.
dport
=
transport
->
ipaddr
.
v6
.
sin6_
port
;
if
(
np
->
opt
&&
np
->
opt
->
srcrt
)
{
if
(
np
->
opt
&&
np
->
opt
->
srcrt
)
{
struct
rt0_hdr
*
rt0
=
(
struct
rt0_hdr
*
)
np
->
opt
->
srcrt
;
struct
rt0_hdr
*
rt0
=
(
struct
rt0_hdr
*
)
np
->
opt
->
srcrt
;
...
@@ -214,7 +262,7 @@ void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst,
...
@@ -214,7 +262,7 @@ void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst,
__FUNCTION__
,
asoc
,
dst
,
NIP6
(
&
daddr
->
v6
.
sin6_addr
));
__FUNCTION__
,
asoc
,
dst
,
NIP6
(
&
daddr
->
v6
.
sin6_addr
));
if
(
!
asoc
)
{
if
(
!
asoc
)
{
ipv6_get_saddr
(
dst
,
&
daddr
->
v6
.
sin6_addr
,
&
saddr
->
v6
.
sin6_addr
);
ipv6_get_saddr
(
dst
,
&
daddr
->
v6
.
sin6_addr
,
&
saddr
->
v6
.
sin6_addr
);
SCTP_DEBUG_PRINTK
(
"saddr from ipv6_get_saddr: "
SCTP_DEBUG_PRINTK
(
"saddr from ipv6_get_saddr: "
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
NIP6
(
&
saddr
->
v6
.
sin6_addr
));
NIP6
(
&
saddr
->
v6
.
sin6_addr
));
...
@@ -279,6 +327,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
...
@@ -279,6 +327,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
addr
->
a
.
v6
.
sin6_family
=
AF_INET6
;
addr
->
a
.
v6
.
sin6_family
=
AF_INET6
;
addr
->
a
.
v6
.
sin6_port
=
0
;
addr
->
a
.
v6
.
sin6_port
=
0
;
addr
->
a
.
v6
.
sin6_addr
=
ifp
->
addr
;
addr
->
a
.
v6
.
sin6_addr
=
ifp
->
addr
;
addr
->
a
.
v6
.
sin6_scope_id
=
dev
->
ifindex
;
INIT_LIST_HEAD
(
&
addr
->
list
);
INIT_LIST_HEAD
(
&
addr
->
list
);
list_add_tail
(
&
addr
->
list
,
addrlist
);
list_add_tail
(
&
addr
->
list
,
addrlist
);
}
}
...
@@ -299,7 +348,7 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
...
@@ -299,7 +348,7 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
port
=
&
addr
->
v6
.
sin6_port
;
port
=
&
addr
->
v6
.
sin6_port
;
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_flowinfo
=
0
;
/* FIXME */
addr
->
v6
.
sin6_flowinfo
=
0
;
/* FIXME */
addr
->
v6
.
sin6_scope_id
=
0
;
/* FIXME */
addr
->
v6
.
sin6_scope_id
=
((
struct
inet6_skb_parm
*
)
skb
->
cb
)
->
iif
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
if
(
is_saddr
)
{
if
(
is_saddr
)
{
...
@@ -336,19 +385,25 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
...
@@ -336,19 +385,25 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
ipv6_addr_copy
(
&
addr
->
v6
.
sin6_addr
,
&
rt
->
rt6i_src
.
addr
);
ipv6_addr_copy
(
&
addr
->
v6
.
sin6_addr
,
&
rt
->
rt6i_src
.
addr
);
}
}
/* Compare addresses exactly.
Well.. almost exactly; ignore scope_id
/* Compare addresses exactly.
*
for now.
FIXME: v4-mapped-v6.
* FIXME: v4-mapped-v6.
*/
*/
static
int
sctp_v6_cmp_addr
(
const
union
sctp_addr
*
addr1
,
static
int
sctp_v6_cmp_addr
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
)
const
union
sctp_addr
*
addr2
)
{
{
int
match
;
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
return
0
;
match
=
!
ipv6_addr_cmp
((
struct
in6_addr
*
)
&
addr1
->
v6
.
sin6_addr
,
if
(
ipv6_addr_cmp
(
&
addr1
->
v6
.
sin6_addr
,
&
addr2
->
v6
.
sin6_addr
))
(
struct
in6_addr
*
)
&
addr2
->
v6
.
sin6_addr
);
return
0
;
/* If this is a linklocal address, compare the scope_id. */
if
(
ipv6_addr_type
(
&
addr1
->
v6
.
sin6_addr
)
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
addr1
->
v6
.
sin6_scope_id
&&
addr2
->
v6
.
sin6_scope_id
&&
(
addr1
->
v6
.
sin6_scope_id
!=
addr2
->
v6
.
sin6_scope_id
))
{
return
0
;
}
}
return
match
;
return
1
;
}
}
/* Initialize addr struct to INADDR_ANY. */
/* Initialize addr struct to INADDR_ANY. */
...
@@ -382,7 +437,6 @@ static int sctp_v6_available(const union sctp_addr *addr)
...
@@ -382,7 +437,6 @@ static int sctp_v6_available(const union sctp_addr *addr)
return
ipv6_chk_addr
(
in6
,
NULL
);
return
ipv6_chk_addr
(
in6
,
NULL
);
}
}
/* This function checks if the address is a valid address to be used for
/* This function checks if the address is a valid address to be used for
* SCTP.
* SCTP.
*
*
...
@@ -488,6 +542,13 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk,
...
@@ -488,6 +542,13 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk,
return
newsk
;
return
newsk
;
}
}
/* Where did this skb come from? */
static
int
sctp_v6_skb_iif
(
const
struct
sk_buff
*
skb
)
{
struct
inet6_skb_parm
*
opt
=
(
struct
inet6_skb_parm
*
)
skb
->
cb
;
return
opt
->
iif
;
}
/* 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
)
{
{
...
@@ -496,13 +557,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
...
@@ -496,13 +557,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
sin6
=
(
struct
sockaddr_in6
*
)
msgname
;
sin6
=
(
struct
sockaddr_in6
*
)
msgname
;
sin6
->
sin6_family
=
AF_INET6
;
sin6
->
sin6_family
=
AF_INET6
;
sin6
->
sin6_flowinfo
=
0
;
sin6
->
sin6_flowinfo
=
0
;
sin6
->
sin6_scope_id
=
0
;
sin6
->
sin6_scope_id
=
0
;
/*FIXME */
*
addr_len
=
sizeof
(
struct
sockaddr_in6
);
*
addr_len
=
sizeof
(
struct
sockaddr_in6
);
}
}
/* Initialize a PF_INET msgname from a ulpevent. */
/* Initialize a PF_INET msgname from a ulpevent. */
static
void
sctp_inet6_event_msgname
(
struct
sctp_ulpevent
*
event
,
char
*
msgname
,
static
void
sctp_inet6_event_msgname
(
struct
sctp_ulpevent
*
event
,
int
*
addrlen
)
char
*
msgname
,
int
*
addrlen
)
{
{
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
...
@@ -528,6 +589,8 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname,
...
@@ -528,6 +589,8 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname,
sin6from
=
&
event
->
asoc
->
peer
.
primary_addr
.
v6
;
sin6from
=
&
event
->
asoc
->
peer
.
primary_addr
.
v6
;
ipv6_addr_copy
(
&
sin6
->
sin6_addr
,
&
sin6from
->
sin6_addr
);
ipv6_addr_copy
(
&
sin6
->
sin6_addr
,
&
sin6from
->
sin6_addr
);
if
(
ipv6_addr_type
(
&
sin6
->
sin6_addr
)
&
IPV6_ADDR_LINKLOCAL
)
sin6
->
sin6_scope_id
=
sin6from
->
sin6_scope_id
;
}
}
}
}
...
@@ -546,8 +609,8 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
...
@@ -546,8 +609,8 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
/* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */
/* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */
if
(
__constant_htons
(
ETH_P_IP
)
==
skb
->
protocol
)
{
if
(
__constant_htons
(
ETH_P_IP
)
==
skb
->
protocol
)
{
/* FIXME:
Easy, but there was no way to test this
/* FIXME:
The latest I-D added options for two
*
yet
.
*
behaviors
.
*/
*/
return
;
return
;
}
}
...
@@ -556,9 +619,8 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
...
@@ -556,9 +619,8 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
ipv6_addr_copy
(
&
sin6
->
sin6_addr
,
&
skb
->
nh
.
ipv6h
->
saddr
);
ipv6_addr_copy
(
&
sin6
->
sin6_addr
,
&
skb
->
nh
.
ipv6h
->
saddr
);
if
(
ipv6_addr_type
(
&
sin6
->
sin6_addr
)
&
IPV6_ADDR_LINKLOCAL
)
{
if
(
ipv6_addr_type
(
&
sin6
->
sin6_addr
)
&
IPV6_ADDR_LINKLOCAL
)
{
struct
inet6_skb_parm
*
opt
=
struct
sctp_ulpevent
*
ev
=
sctp_skb2event
(
skb
);
(
struct
inet6_skb_parm
*
)
skb
->
cb
;
sin6
->
sin6_scope_id
=
ev
->
iif
;
sin6
->
sin6_scope_id
=
opt
->
iif
;
}
}
}
}
}
}
...
@@ -612,14 +674,59 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
...
@@ -612,14 +674,59 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
/* ASSERT: address family has already been verified. */
/* ASSERT: address family has already been verified. */
if
(
addr
->
sa
.
sa_family
!=
AF_INET6
)
{
if
(
addr
->
sa
.
sa_family
!=
AF_INET6
)
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
}
else
else
{
af
=
opt
->
pf
->
af
;
struct
sock
*
sk
;
int
type
=
ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
);
sk
=
&
container_of
(
opt
,
struct
sctp6_sock
,
sctp
)
->
sk
;
if
(
type
&
IPV6_ADDR_LINKLOCAL
)
{
/* Note: Behavior similar to af_inet6.c:
* 1) Overrides previous bound_dev_if
* 2) Destructive even if bind isn't successful.
*/
if
(
addr
->
v6
.
sin6_scope_id
)
sk
->
bound_dev_if
=
addr
->
v6
.
sin6_scope_id
;
if
(
!
sk
->
bound_dev_if
)
return
0
;
}
af
=
opt
->
pf
->
af
;
}
return
af
->
available
(
addr
);
return
af
->
available
(
addr
);
}
}
/* Verify that the provided sockaddr looks bindable. Common verification,
* has already been taken care of.
*/
static
int
sctp_inet6_send_verify
(
struct
sctp_opt
*
opt
,
union
sctp_addr
*
addr
)
{
struct
sctp_af
*
af
=
NULL
;
/* ASSERT: address family has already been verified. */
if
(
addr
->
sa
.
sa_family
!=
AF_INET6
)
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
else
{
struct
sock
*
sk
;
int
type
=
ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
);
sk
=
&
container_of
(
opt
,
struct
sctp6_sock
,
sctp
)
->
sk
;
if
(
type
&
IPV6_ADDR_LINKLOCAL
)
{
/* Note: Behavior similar to af_inet6.c:
* 1) Overrides previous bound_dev_if
* 2) Destructive even if bind isn't successful.
*/
if
(
addr
->
v6
.
sin6_scope_id
)
sk
->
bound_dev_if
=
addr
->
v6
.
sin6_scope_id
;
if
(
!
sk
->
bound_dev_if
)
return
0
;
}
af
=
opt
->
pf
->
af
;
}
return
af
!=
NULL
;
}
/* Fill in Supported Address Type information for INIT and INIT-ACK
/* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Note: In the future, we may want to look at sock options
* 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
* to determine whether a PF_INET6 socket really wants to have IPV4
...
@@ -700,6 +807,7 @@ static struct sctp_af sctp_ipv6_specific = {
...
@@ -700,6 +807,7 @@ static struct sctp_af sctp_ipv6_specific = {
.
inaddr_any
=
sctp_v6_inaddr_any
,
.
inaddr_any
=
sctp_v6_inaddr_any
,
.
is_any
=
sctp_v6_is_any
,
.
is_any
=
sctp_v6_is_any
,
.
available
=
sctp_v6_available
,
.
available
=
sctp_v6_available
,
.
skb_iif
=
sctp_v6_skb_iif
,
.
net_header_len
=
sizeof
(
struct
ipv6hdr
),
.
net_header_len
=
sizeof
(
struct
ipv6hdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in6
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in6
),
.
sa_family
=
AF_INET6
,
.
sa_family
=
AF_INET6
,
...
@@ -711,6 +819,7 @@ static struct sctp_pf sctp_pf_inet6_specific = {
...
@@ -711,6 +819,7 @@ 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
,
.
send_verify
=
sctp_inet6_send_verify
,
.
supported_addrs
=
sctp_inet6_supported_addrs
,
.
supported_addrs
=
sctp_inet6_supported_addrs
,
.
create_accept_sk
=
sctp_v6_create_accept_sk
,
.
create_accept_sk
=
sctp_v6_create_accept_sk
,
.
af
=
&
sctp_ipv6_specific
,
.
af
=
&
sctp_ipv6_specific
,
...
...
net/sctp/output.c
View file @
381a2af8
...
@@ -79,6 +79,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
...
@@ -79,6 +79,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
packet
->
ecn_capable
=
ecn_capable
;
packet
->
ecn_capable
=
ecn_capable
;
packet
->
get_prepend_chunk
=
prepend_handler
;
packet
->
get_prepend_chunk
=
prepend_handler
;
packet
->
has_cookie_echo
=
0
;
packet
->
has_cookie_echo
=
0
;
packet
->
has_sack
=
0
;
packet
->
ipfragok
=
0
;
packet
->
ipfragok
=
0
;
/* We might need to call the prepend_handler right away. */
/* We might need to call the prepend_handler right away. */
...
@@ -100,6 +101,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
...
@@ -100,6 +101,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet
->
ecn_capable
=
0
;
packet
->
ecn_capable
=
0
;
packet
->
get_prepend_chunk
=
NULL
;
packet
->
get_prepend_chunk
=
NULL
;
packet
->
has_cookie_echo
=
0
;
packet
->
has_cookie_echo
=
0
;
packet
->
has_sack
=
0
;
packet
->
ipfragok
=
0
;
packet
->
ipfragok
=
0
;
packet
->
malloced
=
0
;
packet
->
malloced
=
0
;
sctp_packet_reset
(
packet
);
sctp_packet_reset
(
packet
);
...
@@ -155,6 +157,37 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
...
@@ -155,6 +157,37 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
return
retval
;
return
retval
;
}
}
/* Try to bundle a SACK with the packet. */
static
sctp_xmit_t
sctp_packet_bundle_sack
(
struct
sctp_packet
*
pkt
,
struct
sctp_chunk
*
chunk
)
{
sctp_xmit_t
retval
=
SCTP_XMIT_OK
;
/* If sending DATA and haven't aleady bundled a SACK, try to
* bundle one in to the packet.
*/
if
(
sctp_chunk_is_data
(
chunk
)
&&
!
pkt
->
has_sack
&&
!
pkt
->
has_cookie_echo
)
{
struct
sctp_association
*
asoc
;
asoc
=
pkt
->
transport
->
asoc
;
if
(
asoc
->
a_rwnd
>
asoc
->
rwnd
)
{
struct
sctp_chunk
*
sack
;
asoc
->
a_rwnd
=
asoc
->
rwnd
;
sack
=
sctp_make_sack
(
asoc
);
if
(
sack
)
{
struct
timer_list
*
timer
;
retval
=
sctp_packet_append_chunk
(
pkt
,
sack
);
asoc
->
peer
.
sack_needed
=
0
;
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
}
}
}
return
retval
;
}
/* 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.
*/
*/
...
@@ -163,10 +196,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
...
@@ -163,10 +196,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
{
{
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
));
size_t
psize
=
packet
->
size
;
size_t
psize
;
size_t
pmtu
;
size_t
pmtu
;
int
too_big
;
int
too_big
;
retval
=
sctp_packet_bundle_sack
(
packet
,
chunk
);
psize
=
packet
->
size
;
if
(
retval
!=
SCTP_XMIT_OK
)
goto
finish
;
pmtu
=
((
packet
->
transport
->
asoc
)
?
pmtu
=
((
packet
->
transport
->
asoc
)
?
(
packet
->
transport
->
asoc
->
pmtu
)
:
(
packet
->
transport
->
asoc
->
pmtu
)
:
(
packet
->
transport
->
pmtu
));
(
packet
->
transport
->
pmtu
));
...
@@ -214,11 +253,14 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
...
@@ -214,11 +253,14 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
*/
*/
if
(
sctp_chunk_is_data
(
chunk
))
{
if
(
sctp_chunk_is_data
(
chunk
))
{
retval
=
sctp_packet_append_data
(
packet
,
chunk
);
retval
=
sctp_packet_append_data
(
packet
,
chunk
);
/* Disallow SACK bundling after DATA. */
packet
->
has_sack
=
1
;
if
(
SCTP_XMIT_OK
!=
retval
)
if
(
SCTP_XMIT_OK
!=
retval
)
goto
finish
;
goto
finish
;
}
else
if
(
SCTP_CID_COOKIE_ECHO
==
chunk
->
chunk_hdr
->
type
)
{
}
else
if
(
SCTP_CID_COOKIE_ECHO
==
chunk
->
chunk_hdr
->
type
)
packet
->
has_cookie_echo
=
1
;
packet
->
has_cookie_echo
=
1
;
}
else
if
(
SCTP_CID_SACK
==
chunk
->
chunk_hdr
->
type
)
packet
->
has_sack
=
1
;
/* 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
);
...
...
net/sctp/outqueue.c
View file @
381a2af8
...
@@ -138,13 +138,13 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
...
@@ -138,13 +138,13 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
}
}
/* Free the outqueue structure and any related pending chunks.
/* Free the outqueue structure and any related pending chunks.
* FIXME: Add SEND_FAILED support.
*/
*/
void
sctp_outq_teardown
(
struct
sctp_outq
*
q
)
void
sctp_outq_teardown
(
struct
sctp_outq
*
q
)
{
{
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
struct
list_head
*
lchunk
,
*
pos
,
*
temp
;
struct
list_head
*
lchunk
,
*
pos
,
*
temp
;
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
struct
sctp_ulpevent
*
ev
;
/* Throw away unacknowledged chunks. */
/* Throw away unacknowledged chunks. */
list_for_each
(
pos
,
&
q
->
asoc
->
peer
.
transport_addr_list
)
{
list_for_each
(
pos
,
&
q
->
asoc
->
peer
.
transport_addr_list
)
{
...
@@ -152,6 +152,14 @@ void sctp_outq_teardown(struct sctp_outq *q)
...
@@ -152,6 +152,14 @@ void sctp_outq_teardown(struct sctp_outq *q)
while
((
lchunk
=
sctp_list_dequeue
(
&
transport
->
transmitted
)))
{
while
((
lchunk
=
sctp_list_dequeue
(
&
transport
->
transmitted
)))
{
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
chunk
=
list_entry
(
lchunk
,
sctp_chunk_t
,
transmitted_list
);
transmitted_list
);
/* Generate a SEND FAILED event. */
ev
=
sctp_ulpevent_make_send_failed
(
q
->
asoc
,
chunk
,
SCTP_DATA_SENT
,
q
->
error
,
GFP_ATOMIC
);
if
(
ev
)
sctp_ulpq_tail_event
(
&
q
->
asoc
->
ulpq
,
ev
);
sctp_free_chunk
(
chunk
);
sctp_free_chunk
(
chunk
);
}
}
}
}
...
@@ -171,8 +179,19 @@ void sctp_outq_teardown(struct sctp_outq *q)
...
@@ -171,8 +179,19 @@ void sctp_outq_teardown(struct sctp_outq *q)
}
}
/* Throw away any leftover data chunks. */
/* Throw away any leftover data chunks. */
while
((
chunk
=
sctp_outq_dequeue_data
(
q
)))
while
((
chunk
=
sctp_outq_dequeue_data
(
q
)))
{
/* Generate a SEND FAILED event. */
ev
=
sctp_ulpevent_make_send_failed
(
q
->
asoc
,
chunk
,
SCTP_DATA_UNSENT
,
q
->
error
,
GFP_ATOMIC
);
if
(
ev
)
sctp_ulpq_tail_event
(
&
q
->
asoc
->
ulpq
,
ev
);
sctp_free_chunk
(
chunk
);
sctp_free_chunk
(
chunk
);
}
q
->
error
=
0
;
/* Throw away any leftover control chunks. */
/* Throw away any leftover control chunks. */
while
((
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
&
q
->
control
)))
while
((
chunk
=
(
sctp_chunk_t
*
)
skb_dequeue
(
&
q
->
control
)))
...
@@ -357,7 +376,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
...
@@ -357,7 +376,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
__u8
fast_retransmit
=
0
;
__u8
fast_retransmit
=
0
;
switch
(
reason
)
{
switch
(
reason
)
{
case
SCTP_R
ETRANSMIT
_T3_RTX
:
case
SCTP_R
TXR
_T3_RTX
:
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_T3_RTX
);
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_T3_RTX
);
/* Update the retran path if the T3-rtx timer has expired for
/* Update the retran path if the T3-rtx timer has expired for
* the current retran path.
* the current retran path.
...
@@ -365,10 +384,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
...
@@ -365,10 +384,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
if
(
transport
==
transport
->
asoc
->
peer
.
retran_path
)
if
(
transport
==
transport
->
asoc
->
peer
.
retran_path
)
sctp_assoc_update_retran_path
(
transport
->
asoc
);
sctp_assoc_update_retran_path
(
transport
->
asoc
);
break
;
break
;
case
SCTP_R
ETRANSMIT
_FAST_RTX
:
case
SCTP_R
TXR
_FAST_RTX
:
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_FAST_RTX
);
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_FAST_RTX
);
fast_retransmit
=
1
;
fast_retransmit
=
1
;
break
;
break
;
case
SCTP_RTXR_PMTUD
:
default:
default:
break
;
break
;
}
}
...
@@ -876,7 +896,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -876,7 +896,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
start_timer
=
0
;
start_timer
=
0
;
queue
=
&
q
->
out
;
queue
=
&
q
->
out
;
while
(
NULL
!=
(
chunk
=
sctp_outq_dequeue_data
(
q
)))
{
while
((
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.
*/
*/
...
@@ -891,9 +911,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
...
@@ -891,9 +911,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
if
(
ev
)
if
(
ev
)
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
ev
);
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
ev
);
/* Free the chunk. This chunk is not on any
/* Free the chunk. */
* list yet, just free it.
*/
sctp_free_chunk
(
chunk
);
sctp_free_chunk
(
chunk
);
continue
;
continue
;
}
}
...
@@ -1572,7 +1590,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
...
@@ -1572,7 +1590,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
if
(
transport
)
{
if
(
transport
)
{
if
(
do_fast_retransmit
)
if
(
do_fast_retransmit
)
sctp_retransmit
(
q
,
transport
,
SCTP_R
ETRANSMIT
_FAST_RTX
);
sctp_retransmit
(
q
,
transport
,
SCTP_R
TXR
_FAST_RTX
);
SCTP_DEBUG_PRINTK
(
"%s: transport: %p, cwnd: %d, "
SCTP_DEBUG_PRINTK
(
"%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d
\n
"
,
"ssthresh: %d, flight_size: %d, pba: %d
\n
"
,
...
...
net/sctp/protocol.c
View file @
381a2af8
...
@@ -170,7 +170,7 @@ static void __sctp_get_local_addr_list(struct sctp_protocol *proto)
...
@@ -170,7 +170,7 @@ static void __sctp_get_local_addr_list(struct sctp_protocol *proto)
static
void
sctp_get_local_addr_list
(
struct
sctp_protocol
*
proto
)
static
void
sctp_get_local_addr_list
(
struct
sctp_protocol
*
proto
)
{
{
long
flags
__attribute__
((
unused
))
;
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
sctp_proto
.
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
sctp_proto
.
local_addr_lock
,
flags
);
__sctp_get_local_addr_list
(
&
sctp_proto
);
__sctp_get_local_addr_list
(
&
sctp_proto
);
...
@@ -193,7 +193,7 @@ static void __sctp_free_local_addr_list(struct sctp_protocol *proto)
...
@@ -193,7 +193,7 @@ static void __sctp_free_local_addr_list(struct sctp_protocol *proto)
/* Free the existing local addresses. */
/* Free the existing local addresses. */
static
void
sctp_free_local_addr_list
(
struct
sctp_protocol
*
proto
)
static
void
sctp_free_local_addr_list
(
struct
sctp_protocol
*
proto
)
{
{
long
flags
__attribute__
((
unused
))
;
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
proto
->
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
proto
->
local_addr_lock
,
flags
);
__sctp_free_local_addr_list
(
proto
);
__sctp_free_local_addr_list
(
proto
);
...
@@ -208,7 +208,7 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
...
@@ -208,7 +208,7 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
int
error
=
0
;
int
error
=
0
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
long
flags
__attribute__
((
unused
))
;
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
proto
->
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
proto
->
local_addr_lock
,
flags
);
list_for_each
(
pos
,
&
proto
->
local_addr_list
)
{
list_for_each
(
pos
,
&
proto
->
local_addr_list
)
{
...
@@ -233,7 +233,6 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
...
@@ -233,7 +233,6 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
end_copy:
end_copy:
sctp_spin_unlock_irqrestore
(
&
proto
->
local_addr_lock
,
flags
);
sctp_spin_unlock_irqrestore
(
&
proto
->
local_addr_lock
,
flags
);
return
error
;
return
error
;
}
}
...
@@ -383,7 +382,7 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
...
@@ -383,7 +382,7 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
* addresses. If an association is passed, trys to get a dst entry with a
* addresses. If an association is passed, trys to get a dst entry with a
* source adddress that matches an address in the bind address list.
* source adddress that matches an address in the bind address list.
*/
*/
struct
dst_entry
*
sctp_v4_get_dst
(
s
ctp_association_t
*
asoc
,
struct
dst_entry
*
sctp_v4_get_dst
(
s
truct
sctp_association
*
asoc
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
daddr
,
union
sctp_addr
*
saddr
)
union
sctp_addr
*
saddr
)
{
{
...
@@ -480,6 +479,12 @@ void sctp_v4_get_saddr(sctp_association_t *asoc,
...
@@ -480,6 +479,12 @@ void sctp_v4_get_saddr(sctp_association_t *asoc,
}
}
/* What interface did this skb arrive on? */
int
sctp_v4_skb_iif
(
const
struct
sk_buff
*
skb
)
{
return
((
struct
rtable
*
)
skb
->
dst
)
->
rt_iif
;
}
/* Create and initialize a new sk for the socket returned by accept(). */
/* Create and initialize a new sk for the socket returned by accept(). */
struct
sock
*
sctp_v4_create_accept_sk
(
struct
sock
*
sk
,
struct
sock
*
sctp_v4_create_accept_sk
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
)
struct
sctp_association
*
asoc
)
...
@@ -538,10 +543,10 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk,
...
@@ -538,10 +543,10 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk,
/* 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.
*/
*/
static
int
sctp_inetaddr_event
(
struct
notifier_block
*
this
,
unsigned
long
ev
ent
,
static
int
sctp_inetaddr_event
(
struct
notifier_block
*
this
,
unsigned
long
ev
,
void
*
ptr
)
void
*
ptr
)
{
{
long
flags
__attribute__
((
unused
))
;
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
sctp_proto
.
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
sctp_proto
.
local_addr_lock
,
flags
);
__sctp_free_local_addr_list
(
&
sctp_proto
);
__sctp_free_local_addr_list
(
&
sctp_proto
);
...
@@ -689,6 +694,14 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
...
@@ -689,6 +694,14 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return
sctp_v4_available
(
addr
);
return
sctp_v4_available
(
addr
);
}
}
/* Verify that sockaddr looks sendable. Common verification has already
* been taken care of.
*/
static
int
sctp_inet_send_verify
(
struct
sctp_opt
*
opt
,
union
sctp_addr
*
addr
)
{
return
1
;
}
/* Fill in Supported Address Type information for INIT and INIT-ACK
/* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Returns number of addresses supported.
* chunks. Returns number of addresses supported.
*/
*/
...
@@ -721,6 +734,7 @@ static struct sctp_pf sctp_pf_inet = {
...
@@ -721,6 +734,7 @@ 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
,
.
send_verify
=
sctp_inet_send_verify
,
.
supported_addrs
=
sctp_inet_supported_addrs
,
.
supported_addrs
=
sctp_inet_supported_addrs
,
.
create_accept_sk
=
sctp_v4_create_accept_sk
,
.
create_accept_sk
=
sctp_v4_create_accept_sk
,
.
af
=
&
sctp_ipv4_specific
,
.
af
=
&
sctp_ipv4_specific
,
...
@@ -797,6 +811,7 @@ struct sctp_af sctp_ipv4_specific = {
...
@@ -797,6 +811,7 @@ struct sctp_af sctp_ipv4_specific = {
.
is_any
=
sctp_v4_is_any
,
.
is_any
=
sctp_v4_is_any
,
.
available
=
sctp_v4_available
,
.
available
=
sctp_v4_available
,
.
scope
=
sctp_v4_scope
,
.
scope
=
sctp_v4_scope
,
.
skb_iif
=
sctp_v4_skb_iif
,
.
net_header_len
=
sizeof
(
struct
iphdr
),
.
net_header_len
=
sizeof
(
struct
iphdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in
),
.
sa_family
=
AF_INET
,
.
sa_family
=
AF_INET
,
...
@@ -874,6 +889,10 @@ __init int sctp_init(void)
...
@@ -874,6 +889,10 @@ __init int sctp_init(void)
int
i
;
int
i
;
int
status
=
0
;
int
status
=
0
;
/* SCTP_DEBUG sanity check. */
if
(
!
sctp_sanity_check
())
return
-
EINVAL
;
/* Add SCTP to inet_protos hash table. */
/* Add SCTP to inet_protos hash table. */
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
return
-
EAGAIN
;
...
...
net/sctp/sm_make_chunk.c
View file @
381a2af8
...
@@ -66,6 +66,19 @@
...
@@ -66,6 +66,19 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
/* What was the inbound interface for this chunk? */
int
sctp_chunk_iif
(
const
struct
sctp_chunk
*
chunk
)
{
struct
sctp_af
*
af
;
int
iif
=
0
;
af
=
sctp_get_af_specific
(
ipver2af
(
chunk
->
skb
->
nh
.
iph
->
version
));
if
(
af
)
iif
=
af
->
skb_iif
(
chunk
->
skb
);
return
iif
;
}
/* 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
...
@@ -145,7 +158,7 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
...
@@ -145,7 +158,7 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
*/
*/
sctp_chunk_t
*
sctp_make_init
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
sctp_make_init
(
const
sctp_association_t
*
asoc
,
const
sctp_bind_addr_t
*
bp
,
const
sctp_bind_addr_t
*
bp
,
int
priority
,
int
vparam_len
)
int
gfp
,
int
vparam_len
)
{
{
sctp_inithdr_t
init
;
sctp_inithdr_t
init
;
union
sctp_params
addrs
;
union
sctp_params
addrs
;
...
@@ -165,7 +178,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -165,7 +178,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
addrs
.
v
=
NULL
;
addrs
.
v
=
NULL
;
/* Convert the provided bind address list to raw format */
/* Convert the provided bind address list to raw format */
addrs
=
sctp_bind_addrs_to_raw
(
bp
,
&
addrs_len
,
priority
);
addrs
=
sctp_bind_addrs_to_raw
(
bp
,
&
addrs_len
,
gfp
);
if
(
!
addrs
.
v
)
if
(
!
addrs
.
v
)
goto
nodata
;
goto
nodata
;
...
@@ -225,7 +238,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -225,7 +238,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
sctp_chunk_t
*
sctp_make_init_ack
(
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
sctp_make_init_ack
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
,
const
sctp_chunk_t
*
chunk
,
int
priority
,
int
unkparam_len
)
int
gfp
,
int
unkparam_len
)
{
{
sctp_inithdr_t
initack
;
sctp_inithdr_t
initack
;
sctp_chunk_t
*
retval
;
sctp_chunk_t
*
retval
;
...
@@ -237,8 +250,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
...
@@ -237,8 +250,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
retval
=
NULL
;
retval
=
NULL
;
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
addrs
=
sctp_bind_addrs_to_raw
(
&
asoc
->
base
.
bind_addr
,
&
addrs_len
,
gfp
);
priority
);
if
(
!
addrs
.
v
)
if
(
!
addrs
.
v
)
goto
nomem_rawaddr
;
goto
nomem_rawaddr
;
...
@@ -1019,21 +1031,18 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc,
...
@@ -1019,21 +1031,18 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc,
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
sock
*
sk
;
struct
sock
*
sk
;
skb
=
dev_alloc_skb
(
WORD_ROUND
(
sizeof
(
sctp_chunkhdr_t
)
+
paylen
));
/* No need to allocate LL here, as this is only a chunk. */
skb
=
alloc_skb
(
WORD_ROUND
(
sizeof
(
sctp_chunkhdr_t
)
+
paylen
),
GFP_ATOMIC
);
if
(
!
skb
)
if
(
!
skb
)
goto
nodata
;
goto
nodata
;
/* Make room for the chunk header. */
/* Make room for the chunk header. */
chunk_hdr
=
(
sctp_chunkhdr_t
*
)
skb_put
(
skb
,
sizeof
(
sctp_chunkhdr_t
));
chunk_hdr
=
(
sctp_chunkhdr_t
*
)
skb_put
(
skb
,
sizeof
(
sctp_chunkhdr_t
));
skb_pull
(
skb
,
sizeof
(
sctp_chunkhdr_t
));
chunk_hdr
->
type
=
type
;
chunk_hdr
->
type
=
type
;
chunk_hdr
->
flags
=
flags
;
chunk_hdr
->
flags
=
flags
;
chunk_hdr
->
length
=
htons
(
sizeof
(
sctp_chunkhdr_t
));
chunk_hdr
->
length
=
htons
(
sizeof
(
sctp_chunkhdr_t
));
/* Move the data pointer back up to the start of the chunk. */
skb_push
(
skb
,
sizeof
(
sctp_chunkhdr_t
));
sk
=
asoc
?
asoc
->
base
.
sk
:
NULL
;
sk
=
asoc
?
asoc
->
base
.
sk
:
NULL
;
retval
=
sctp_chunkify
(
skb
,
asoc
,
sk
);
retval
=
sctp_chunkify
(
skb
,
asoc
,
sk
);
if
(
!
retval
)
{
if
(
!
retval
)
{
...
@@ -1282,26 +1291,26 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
...
@@ -1282,26 +1291,26 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
}
}
/* Create a CLOSED association to use with an incoming packet. */
/* Create a CLOSED association to use with an incoming packet. */
sctp_association_t
*
sctp_make_temp_asoc
(
const
sctp_endpoint_t
*
ep
,
sctp_association_t
*
sctp_make_temp_asoc
(
const
struct
sctp_endpoint
*
ep
,
sctp_chunk_t
*
chunk
,
struct
sctp_chunk
*
chunk
,
int
gfp
)
int
priority
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
struct
sk_buff
*
skb
;
sctp_scope_t
scope
;
sctp_scope_t
scope
;
/* Create the bare association. */
/* Create the bare association. */
scope
=
sctp_scope
(
sctp_source
(
chunk
));
scope
=
sctp_scope
(
sctp_source
(
chunk
));
asoc
=
sctp_association_new
(
ep
,
ep
->
base
.
sk
,
scope
,
priority
);
asoc
=
sctp_association_new
(
ep
,
ep
->
base
.
sk
,
scope
,
gfp
);
if
(
!
asoc
)
if
(
!
asoc
)
goto
nodata
;
goto
nodata
;
skb
=
chunk
->
skb
;
/* Create an entry for the source address of the packet. */
/* Create an entry for the source address of the packet. */
switch
(
chunk
->
skb
->
nh
.
iph
->
version
)
{
/* FIXME: Use the af specific helpers. */
switch
(
skb
->
nh
.
iph
->
version
)
{
case
4
:
case
4
:
asoc
->
c
.
peer_addr
.
v4
.
sin_family
=
AF_INET
;
asoc
->
c
.
peer_addr
.
v4
.
sin_family
=
AF_INET
;
asoc
->
c
.
peer_addr
.
v4
.
sin_port
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
asoc
->
c
.
peer_addr
.
v4
.
sin_port
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
asoc
->
c
.
peer_addr
.
v4
.
sin_addr
.
s_addr
=
asoc
->
c
.
peer_addr
.
v4
.
sin_addr
.
s_addr
=
skb
->
nh
.
iph
->
saddr
;
chunk
->
skb
->
nh
.
iph
->
saddr
;
break
;
break
;
case
6
:
case
6
:
...
@@ -1309,8 +1318,9 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *ep,
...
@@ -1309,8 +1318,9 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *ep,
asoc
->
c
.
peer_addr
.
v6
.
sin6_port
asoc
->
c
.
peer_addr
.
v6
.
sin6_port
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
asoc
->
c
.
peer_addr
.
v6
.
sin6_flowinfo
=
0
;
/* BUG BUG BUG */
asoc
->
c
.
peer_addr
.
v6
.
sin6_flowinfo
=
0
;
/* BUG BUG BUG */
asoc
->
c
.
peer_addr
.
v6
.
sin6_addr
=
chunk
->
skb
->
nh
.
ipv6h
->
saddr
;
asoc
->
c
.
peer_addr
.
v6
.
sin6_addr
=
skb
->
nh
.
ipv6h
->
saddr
;
asoc
->
c
.
peer_addr
.
v6
.
sin6_scope_id
=
0
;
/* BUG BUG BUG */
asoc
->
c
.
peer_addr
.
v6
.
sin6_scope_id
=
((
struct
inet6_skb_parm
*
)
skb
->
cb
)
->
iif
;
break
;
break
;
default:
default:
...
@@ -1397,7 +1407,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep,
...
@@ -1397,7 +1407,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep,
/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */
/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */
sctp_association_t
*
sctp_unpack_cookie
(
const
sctp_endpoint_t
*
ep
,
sctp_association_t
*
sctp_unpack_cookie
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
int
priority
,
sctp_chunk_t
*
chunk
,
int
gfp
,
int
*
error
,
sctp_chunk_t
**
err_chk_p
)
int
*
error
,
sctp_chunk_t
**
err_chk_p
)
{
{
sctp_association_t
*
retval
=
NULL
;
sctp_association_t
*
retval
=
NULL
;
...
@@ -1408,6 +1418,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
...
@@ -1408,6 +1418,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
__u8
digest_buf
[
SCTP_SIGNATURE_SIZE
];
__u8
digest_buf
[
SCTP_SIGNATURE_SIZE
];
int
secret
;
int
secret
;
sctp_scope_t
scope
;
sctp_scope_t
scope
;
struct
sk_buff
*
skb
=
chunk
->
skb
;
headersize
=
sizeof
(
sctp_chunkhdr_t
)
+
SCTP_SECRET_SIZE
;
headersize
=
sizeof
(
sctp_chunkhdr_t
)
+
SCTP_SECRET_SIZE
;
bodysize
=
ntohs
(
chunk
->
chunk_hdr
->
length
)
-
headersize
;
bodysize
=
ntohs
(
chunk
->
chunk_hdr
->
length
)
-
headersize
;
...
@@ -1450,7 +1461,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
...
@@ -1450,7 +1461,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* an association, there is no need to check cookie's expiration
* an association, there is no need to check cookie's expiration
* for init collision case of lost COOKIE ACK.
* for init collision case of lost COOKIE ACK.
*/
*/
if
(
!
asoc
&&
tv_lt
(
bear_cookie
->
expiration
,
chunk
->
skb
->
stamp
))
{
if
(
!
asoc
&&
tv_lt
(
bear_cookie
->
expiration
,
skb
->
stamp
))
{
__u16
len
;
__u16
len
;
/*
/*
* Section 3.3.10.3 Stale Cookie Error (3)
* Section 3.3.10.3 Stale Cookie Error (3)
...
@@ -1463,9 +1474,9 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
...
@@ -1463,9 +1474,9 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
len
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
len
=
ntohs
(
chunk
->
chunk_hdr
->
length
);
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
len
);
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
len
);
if
(
*
err_chk_p
)
{
if
(
*
err_chk_p
)
{
suseconds_t
usecs
=
(
chunk
->
skb
->
stamp
.
tv_sec
-
suseconds_t
usecs
=
(
skb
->
stamp
.
tv_sec
-
bear_cookie
->
expiration
.
tv_sec
)
*
1000000L
+
bear_cookie
->
expiration
.
tv_sec
)
*
1000000L
+
chunk
->
skb
->
stamp
.
tv_usec
-
skb
->
stamp
.
tv_usec
-
bear_cookie
->
expiration
.
tv_usec
;
bear_cookie
->
expiration
.
tv_usec
;
usecs
=
htonl
(
usecs
);
usecs
=
htonl
(
usecs
);
...
@@ -1480,7 +1491,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
...
@@ -1480,7 +1491,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
/* Make a new base association. */
/* Make a new base association. */
scope
=
sctp_scope
(
sctp_source
(
chunk
));
scope
=
sctp_scope
(
sctp_source
(
chunk
));
retval
=
sctp_association_new
(
ep
,
ep
->
base
.
sk
,
scope
,
priority
);
retval
=
sctp_association_new
(
ep
,
ep
->
base
.
sk
,
scope
,
gfp
);
if
(
!
retval
)
{
if
(
!
retval
)
{
*
error
=
-
SCTP_IERROR_NOMEM
;
*
error
=
-
SCTP_IERROR_NOMEM
;
goto
fail
;
goto
fail
;
...
@@ -1522,13 +1533,14 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
...
@@ -1522,13 +1533,14 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions
* 3rd Level Abstractions
********************************************************************/
********************************************************************/
/*
* Report a missing mandatory parameter.
*/
struct
__sctp_missing
{
struct
__sctp_missing
{
__u32
num_missing
;
__u32
num_missing
;
__u16
type
;
__u16
type
;
}
__attribute__
((
packed
));;
}
__attribute__
((
packed
));;
/*
* Report a missing mandatory parameter.
*/
static
int
sctp_process_missing_param
(
const
sctp_association_t
*
asoc
,
static
int
sctp_process_missing_param
(
const
sctp_association_t
*
asoc
,
sctp_param_t
paramtype
,
sctp_param_t
paramtype
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
...
@@ -1774,8 +1786,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
...
@@ -1774,8 +1786,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
*/
*/
int
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
int
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
const
union
sctp_addr
*
peer_addr
,
const
union
sctp_addr
*
peer_addr
,
sctp_init_chunk_t
*
peer_init
,
sctp_init_chunk_t
*
peer_init
,
int
gfp
)
int
priority
)
{
{
union
sctp_params
param
;
union
sctp_params
param
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
...
@@ -1793,14 +1804,14 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1793,14 +1804,14 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* be a a better choice than any of the embedded addresses.
* be a a better choice than any of the embedded addresses.
*/
*/
if
(
peer_addr
)
if
(
peer_addr
)
if
(
!
sctp_assoc_add_peer
(
asoc
,
peer_addr
,
priority
))
if
(
!
sctp_assoc_add_peer
(
asoc
,
peer_addr
,
gfp
))
goto
nomem
;
goto
nomem
;
/* Process the initialization parameters. */
/* Process the initialization parameters. */
sctp_walk_params
(
param
,
peer_init
,
init_hdr
.
params
)
{
sctp_walk_params
(
param
,
peer_init
,
init_hdr
.
params
)
{
if
(
!
sctp_process_param
(
asoc
,
param
,
peer_addr
,
priority
))
if
(
!
sctp_process_param
(
asoc
,
param
,
peer_addr
,
gfp
))
goto
clean_up
;
goto
clean_up
;
}
}
...
@@ -1842,7 +1853,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1842,7 +1853,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
/* Copy cookie in case we need to resend COOKIE-ECHO. */
/* Copy cookie in case we need to resend COOKIE-ECHO. */
cookie
=
asoc
->
peer
.
cookie
;
cookie
=
asoc
->
peer
.
cookie
;
if
(
cookie
)
{
if
(
cookie
)
{
asoc
->
peer
.
cookie
=
kmalloc
(
asoc
->
peer
.
cookie_len
,
priority
);
asoc
->
peer
.
cookie
=
kmalloc
(
asoc
->
peer
.
cookie_len
,
gfp
);
if
(
!
asoc
->
peer
.
cookie
)
if
(
!
asoc
->
peer
.
cookie
)
goto
clean_up
;
goto
clean_up
;
memcpy
(
asoc
->
peer
.
cookie
,
cookie
,
asoc
->
peer
.
cookie_len
);
memcpy
(
asoc
->
peer
.
cookie
,
cookie
,
asoc
->
peer
.
cookie_len
);
...
@@ -1871,8 +1882,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1871,8 +1882,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
/* Allocate storage for the negotiated streams. */
/* Allocate storage for the negotiated streams. */
asoc
->
ssnmap
=
sctp_ssnmap_new
(
asoc
->
peer
.
i
.
num_outbound_streams
,
asoc
->
ssnmap
=
sctp_ssnmap_new
(
asoc
->
peer
.
i
.
num_outbound_streams
,
asoc
->
c
.
sinit_num_ostreams
,
asoc
->
c
.
sinit_num_ostreams
,
gfp
);
priority
);
if
(
!
asoc
->
ssnmap
)
if
(
!
asoc
->
ssnmap
)
goto
nomem_ssnmap
;
goto
nomem_ssnmap
;
...
@@ -1914,7 +1924,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1914,7 +1924,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* structures for the addresses.
* structures for the addresses.
*/
*/
int
sctp_process_param
(
sctp_association_t
*
asoc
,
union
sctp_params
param
,
int
sctp_process_param
(
sctp_association_t
*
asoc
,
union
sctp_params
param
,
const
union
sctp_addr
*
peer_addr
,
int
priority
)
const
union
sctp_addr
*
peer_addr
,
int
gfp
)
{
{
union
sctp_addr
addr
;
union
sctp_addr
addr
;
int
i
;
int
i
;
...
@@ -1933,10 +1943,10 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
...
@@ -1933,10 +1943,10 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
break
;
break
;
/* Fall through. */
/* Fall through. */
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV4_ADDRESS
:
sctp_param2sockaddr
(
&
addr
,
param
.
addr
,
asoc
->
peer
.
port
);
sctp_param2sockaddr
(
&
addr
,
param
.
addr
,
asoc
->
peer
.
port
,
0
);
scope
=
sctp_scope
(
peer_addr
);
scope
=
sctp_scope
(
peer_addr
);
if
(
sctp_in_scope
(
&
addr
,
scope
))
if
(
sctp_in_scope
(
&
addr
,
scope
))
if
(
!
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
))
if
(
!
sctp_assoc_add_peer
(
asoc
,
&
addr
,
gfp
))
return
0
;
return
0
;
break
;
break
;
...
@@ -2051,7 +2061,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
...
@@ -2051,7 +2061,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
/* Convert from an SCTP IP parameter to a union sctp_addr. */
/* Convert from an SCTP IP parameter to a union sctp_addr. */
void
sctp_param2sockaddr
(
union
sctp_addr
*
addr
,
sctp_addr_param_t
*
param
,
void
sctp_param2sockaddr
(
union
sctp_addr
*
addr
,
sctp_addr_param_t
*
param
,
__u16
port
)
__u16
port
,
int
iif
)
{
{
switch
(
param
->
v4
.
param_hdr
.
type
)
{
switch
(
param
->
v4
.
param_hdr
.
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV4_ADDRESS
:
...
@@ -2065,7 +2075,7 @@ void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param,
...
@@ -2065,7 +2075,7 @@ void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param,
addr
->
v6
.
sin6_port
=
port
;
addr
->
v6
.
sin6_port
=
port
;
addr
->
v6
.
sin6_flowinfo
=
0
;
/* BUG */
addr
->
v6
.
sin6_flowinfo
=
0
;
/* BUG */
addr
->
v6
.
sin6_addr
=
param
->
v6
.
addr
;
addr
->
v6
.
sin6_addr
=
param
->
v6
.
addr
;
addr
->
v6
.
sin6_scope_id
=
0
;
/* BUG */
addr
->
v6
.
sin6_scope_id
=
iif
;
break
;
break
;
default:
default:
...
...
net/sctp/sm_sideeffect.c
View file @
381a2af8
...
@@ -55,1202 +55,1106 @@
...
@@ -55,1202 +55,1106 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
/* Do forward declarations of static functions. */
/********************************************************************
static
void
sctp_do_ecn_ce_work
(
sctp_association_t
*
,
__u32
lowest_tsn
);
* Helper functions
static
sctp_chunk_t
*
sctp_do_ecn_ecne_work
(
sctp_association_t
*
asoc
,
********************************************************************/
__u32
lowest_tsn
,
sctp_chunk_t
*
);
static
void
sctp_do_ecn_cwr_work
(
sctp_association_t
*
,
__u32
lowest_tsn
);
static
void
sctp_do_8_2_transport_strike
(
sctp_association_t
*
,
struct
sctp_transport
*
);
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_event_t
,
sctp_subtype_t
,
sctp_chunk_t
*
chunk
);
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_chunk_t
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
int
priority
);
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_hb_timers_stop
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
struct
sctp_transport
*
);
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
struct
sctp_transport
*
);
static
void
sctp_cmd_transport_on
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
struct
sctp_transport
*
,
sctp_chunk_t
*
);
static
int
sctp_cmd_process_sack
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_sackhdr_t
*
);
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_chunk_t
*
);
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_state_t
);
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* functionality there.
*/
#define DEBUG_PRE \
SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \
"ep %p, %s, %s, asoc %p[%s], %s\n", \
ep, sctp_evttype_tbl[event_type], \
(*debug_fn)(subtype), asoc, \
sctp_state_tbl[state], state_fn->name)
#define DEBUG_POST \
/* A helper function for delayed processing of INET ECN CE bit. */
SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \
static
void
sctp_do_ecn_ce_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
)
"asoc %p, status: %s\n", \
{
asoc, sctp_status_tbl[status])
/* Save the TSN away for comparison when we receive CWR */
#define DEBUG_POST_SFX \
asoc
->
last_ecne_tsn
=
lowest_tsn
;
SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
asoc
->
need_ecne
=
1
;
error, asoc, \
}
sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \
sctp_assoc2id(asoc)))?asoc->state:SCTP_STATE_CLOSED])
/*
/*
Helper function for delayed processing of SCTP ECNE chunk. */
* This is the master state machine processing function.
/* RFC 2960 Appendix A
*
*
* If you want to understand all of lksctp, this is a
* RFC 2481 details a specific bit for a sender to send in
* good place to start.
* the header of its next outbound TCP segment to indicate to
* its peer that it has reduced its congestion window. This
* is termed the CWR bit. For SCTP the same indication is made
* by including the CWR chunk. This chunk contains one data
* element, i.e. the TSN number that was sent in the ECNE chunk.
* This element represents the lowest TSN number in the datagram
* that was originally marked with the CE bit.
*/
*/
int
sctp_do_sm
(
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
static
sctp_chunk_t
*
sctp_do_ecn_ecne_work
(
sctp_association_t
*
asoc
,
sctp_state_t
state
,
__u32
lowest_tsn
,
sctp_endpoint_t
*
ep
,
sctp_chunk_t
*
chunk
)
sctp_association_t
*
asoc
,
void
*
event_arg
,
int
priority
)
{
{
sctp_cmd_seq_t
commands
;
sctp_chunk_t
*
repl
;
sctp_sm_table_entry_t
*
state_fn
;
sctp_disposition_t
status
;
int
error
=
0
;
typedef
const
char
*
(
printfn_t
)(
sctp_subtype_t
);
static
printfn_t
*
table
[]
=
{
/* Our previously transmitted packet ran into some congestion
NULL
,
sctp_cname
,
sctp_tname
,
sctp_oname
,
sctp_pname
,
* so we should take action by reducing cwnd and ssthresh
};
* and then ACK our peer that we we've done so by
printfn_t
*
debug_fn
__attribute__
((
unused
))
=
table
[
event_type
];
* sending a CWR.
*/
/* Look up the state function, run it, and then process the
/* First, try to determine if we want to actually lower
* side effects. These three steps are the heart of lksctp.
* our cwnd variables. Only lower them if the ECNE looks more
* recent than the last response.
*/
*/
state_fn
=
sctp_sm_lookup_event
(
event_type
,
state
,
subtype
);
if
(
TSN_lt
(
asoc
->
last_cwr_tsn
,
lowest_tsn
))
{
struct
sctp_transport
*
transport
;
sctp_init_cmd_seq
(
&
commands
);
/* Find which transport's congestion variables
* need to be adjusted.
*/
transport
=
sctp_assoc_lookup_tsn
(
asoc
,
lowest_tsn
);
DEBUG_PRE
;
/* Update the congestion variables. */
status
=
(
*
state_fn
->
fn
)(
ep
,
asoc
,
subtype
,
event_arg
,
&
commands
);
if
(
transport
)
DEBUG_POST
;
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_ECNE
);
asoc
->
last_cwr_tsn
=
lowest_tsn
;
}
error
=
sctp_side_effects
(
event_type
,
subtype
,
state
,
/* Always try to quiet the other end. In case of lost CWR,
ep
,
asoc
,
event_arg
,
* resend last_cwr_tsn.
status
,
&
commands
,
*/
priority
);
repl
=
sctp_make_cwr
(
asoc
,
asoc
->
last_cwr_tsn
,
chunk
);
DEBUG_POST_SFX
;
return
error
;
/* If we run out of memory, it will look like a lost CWR. We'll
* get back in sync eventually.
*/
return
repl
;
}
}
#undef DEBUG_PRE
/* Helper function to do delayed processing of ECN CWR chunk. */
#undef DEBUG_POST
static
void
sctp_do_ecn_cwr_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
)
/*****************************************************************
* This the master state function side effect processing function.
*****************************************************************/
int
sctp_side_effects
(
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
sctp_state_t
state
,
sctp_endpoint_t
*
ep
,
sctp_association_t
*
asoc
,
void
*
event_arg
,
sctp_disposition_t
status
,
sctp_cmd_seq_t
*
commands
,
int
priority
)
{
{
int
error
;
/* Turn off ECNE getting auto-prepended to every outgoing
* packet
/* FIXME - Most of the dispositions left today would be categorized
* as "exceptional" dispositions. For those dispositions, it
* may not be proper to run through any of the commands at all.
* For example, the command interpreter might be run only with
* disposition SCTP_DISPOSITION_CONSUME.
*/
*/
if
(
0
!=
(
error
=
sctp_cmd_interpreter
(
event_type
,
subtype
,
state
,
asoc
->
need_ecne
=
0
;
ep
,
asoc
,
}
event_arg
,
status
,
commands
,
priority
)))
goto
bail
;
switch
(
status
)
{
/* Generate SACK if necessary. We call this at the end of a packet. */
case
SCTP_DISPOSITION_DISCARD
:
int
sctp_gen_sack
(
struct
sctp_association
*
asoc
,
int
force
,
SCTP_DEBUG_PRINTK
(
"Ignored sctp protocol event - state %d, "
sctp_cmd_seq_t
*
commands
)
"event_type %d, event_id %d
\n
"
,
{
state
,
event_type
,
subtype
.
chunk
);
__u32
ctsn
,
max_tsn_seen
;
break
;
struct
sctp_chunk
*
sack
;
int
error
=
0
;
case
SCTP_DISPOSITION_NOMEM
:
if
(
force
)
/* We ran out of memory, so we need to discard this
asoc
->
peer
.
sack_needed
=
1
;
* packet.
*/
/* BUG--we should now recover some memory, probably by
* reneging...
*/
error
=
-
ENOMEM
;
break
;
case
SCTP_DISPOSITION_DELETE_TCB
:
ctsn
=
sctp_tsnmap_get_ctsn
(
&
asoc
->
peer
.
tsn_map
);
/* This should now be a command. */
max_tsn_seen
=
sctp_tsnmap_get_max_tsn_seen
(
&
asoc
->
peer
.
tsn_map
);
break
;
case
SCTP_DISPOSITION_CONSUME
:
/* From 12.2 Parameters necessary per association (i.e. the TCB):
case
SCTP_DISPOSITION_ABORT
:
*
/*
* Ack State : This flag indicates if the next received packet
* We should no longer have much work to do here as the
* : is to be responded to with a SACK. ...
* real work has been done as explicit commands above.
* : When DATA chunks are out of order, SACK's
* : are not delayed (see Section 6).
*
* [This is actually not mentioned in Section 6, but we
* implement it here anyway. --piggy]
*/
*/
break
;
if
(
max_tsn_seen
!=
ctsn
)
asoc
->
peer
.
sack_needed
=
1
;
case
SCTP_DISPOSITION_VIOLATION
:
printk
(
KERN_ERR
"sctp protocol violation state %d "
"chunkid %d
\n
"
,
state
,
subtype
.
chunk
);
break
;
case
SCTP_DISPOSITION_NOT_IMPL
:
/* From 6.2 Acknowledgement on Reception of DATA Chunks:
printk
(
KERN_WARNING
"sctp unimplemented feature in state %d, "
*
"event_type %d, event_id %d
\n
"
,
* Section 4.2 of [RFC2581] SHOULD be followed. Specifically,
state
,
event_type
,
subtype
.
chunk
);
* an acknowledgement SHOULD be generated for at least every
break
;
* second packet (not every second DATA chunk) received, and
* SHOULD be generated within 200 ms of the arrival of any
* unacknowledged DATA chunk. ...
*/
if
(
!
asoc
->
peer
.
sack_needed
)
{
/* We will need a SACK for the next packet. */
asoc
->
peer
.
sack_needed
=
1
;
goto
out
;
}
else
{
if
(
asoc
->
a_rwnd
>
asoc
->
rwnd
)
asoc
->
a_rwnd
=
asoc
->
rwnd
;
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
goto
nomem
;
case
SCTP_DISPOSITION_BUG
:
asoc
->
peer
.
sack_needed
=
0
;
printk
(
KERN_ERR
"sctp bug in state %d, "
"event_type %d, event_id %d
\n
"
,
state
,
event_type
,
subtype
.
chunk
);
BUG
();
break
;
default:
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
printk
(
KERN_ERR
"sctp impossible disposition %d "
"in state %d, event_type %d, event_id %d
\n
"
,
status
,
state
,
event_type
,
subtype
.
chunk
);
BUG
();
break
;
};
bail:
/* Stop the SACK timer. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_SACK
));
}
out:
return
error
;
nomem:
error
=
-
ENOMEM
;
return
error
;
return
error
;
}
}
/********************************************************************
/* When the T3-RTX timer expires, it calls this function to create the
* 2nd Level Abstractions
* relevant state machine event.
********************************************************************/
*/
void
sctp_generate_t3_rtx_event
(
unsigned
long
peer
)
/* This is the side-effect interpreter. */
int
sctp_cmd_interpreter
(
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
sctp_state_t
state
,
sctp_endpoint_t
*
ep
,
sctp_association_t
*
asoc
,
void
*
event_arg
,
sctp_disposition_t
status
,
sctp_cmd_seq_t
*
commands
,
int
priority
)
{
{
int
error
=
0
;
int
error
;
int
force
;
struct
sctp_transport
*
transport
=
(
struct
sctp_transport
*
)
peer
;
sctp_cmd_t
*
cmd
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
sctp_chunk_t
*
new_obj
;
sctp_chunk_t
*
chunk
=
NULL
;
struct
sctp_packet
*
packet
;
struct
list_head
*
pos
;
struct
timer_list
*
timer
;
unsigned
long
timeout
;
struct
sctp_transport
*
t
;
sctp_sackhdr_t
sackh
;
if
(
SCTP_EVENT_T_TIMEOUT
!=
event_type
)
chunk
=
(
sctp_chunk_t
*
)
event_arg
;
/* Note: This whole file is a huge candidate for rework.
* For example, each command could either have its own handler, so
* the loop would look like:
* while (cmds)
* cmd->handle(x, y, z)
* --jgrimm
*/
while
(
NULL
!=
(
cmd
=
sctp_next_cmd
(
commands
)))
{
switch
(
cmd
->
verb
)
{
case
SCTP_CMD_NOP
:
/* Do nothing. */
break
;
case
SCTP_CMD_NEW_ASOC
:
/* Register a new association. */
asoc
=
cmd
->
obj
.
ptr
;
/* Register with the endpoint. */
sctp_endpoint_add_asoc
(
ep
,
asoc
);
sctp_hash_established
(
asoc
);
break
;
case
SCTP_CMD_UPDATE_ASSOC
:
sctp_assoc_update
(
asoc
,
cmd
->
obj
.
ptr
);
break
;
case
SCTP_CMD_PURGE_OUTQUEUE
:
sctp_outq_teardown
(
&
asoc
->
outqueue
);
break
;
case
SCTP_CMD_DELETE_TCB
:
/* Check whether a task is in the sock. */
/* Delete the current association. */
sctp_unhash_established
(
asoc
);
sctp_association_free
(
asoc
);
asoc
=
NULL
;
break
;
case
SCTP_CMD_NEW_STATE
:
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
/* Enter a new state. */
if
(
sock_owned_by_user
(
asoc
->
base
.
sk
))
{
sctp_cmd_new_state
(
commands
,
asoc
,
cmd
->
obj
.
state
);
SCTP_DEBUG_PRINTK
(
"%s:Sock is busy.
\n
"
,
__FUNCTION__
);
break
;
case
SCTP_CMD_REPORT_TSN
:
/* Try again later. */
/* Record the arrival of a TSN. */
if
(
!
mod_timer
(
&
transport
->
T3_rtx_timer
,
jiffies
+
(
HZ
/
20
)))
sctp_tsnmap_mark
(
&
asoc
->
peer
.
tsn_map
,
cmd
->
obj
.
u32
);
sctp_transport_hold
(
transport
);
break
;
goto
out_unlock
;
}
case
SCTP_CMD_GEN_SACK
:
/* Is this transport really dead and just waiting around for
/* Generate a Selective ACK.
* the timer to let go of the reference?
* The argument tells us whether to just count
* the packet and MAYBE generate a SACK, or
* force a SACK out.
*/
*/
force
=
cmd
->
obj
.
i32
;
if
(
transport
->
dead
)
error
=
sctp_gen_sack
(
asoc
,
force
,
commands
);
goto
out_unlock
;
break
;
case
SCTP_CMD_PROCESS_SACK
:
/* Run through the state machine. */
/* Process an inbound SACK. */
error
=
sctp_do_sm
(
SCTP_EVENT_T_TIMEOUT
,
error
=
sctp_cmd_process_sack
(
commands
,
asoc
,
SCTP_ST_TIMEOUT
(
SCTP_EVENT_TIMEOUT_T3_RTX
),
cmd
->
obj
.
ptr
);
asoc
->
state
,
break
;
asoc
->
ep
,
asoc
,
transport
,
GFP_ATOMIC
);
case
SCTP_CMD_GEN_INIT_ACK
:
if
(
error
)
/* Generate an INIT ACK chunk. */
asoc
->
base
.
sk
->
err
=
-
error
;
new_obj
=
sctp_make_init_ack
(
asoc
,
chunk
,
GFP_ATOMIC
,
0
);
if
(
!
new_obj
)
goto
nomem
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
out_unlock:
SCTP_CHUNK
(
new_obj
));
sctp_bh_unlock_sock
(
asoc
->
base
.
sk
);
break
;
sctp_transport_put
(
transport
);
}
case
SCTP_CMD_PEER_INIT
:
/* This is a sa interface for producing timeout events. It works
/* Process a unified INIT from the peer.
* for timeouts which use the association as their parameter.
* Note: Only used during INIT-ACK processing. If
* there is an error just return to the outter
* layer which will bail.
*/
*/
error
=
sctp_cmd_process_init
(
commands
,
asoc
,
chunk
,
static
void
sctp_generate_timeout_event
(
sctp_association_t
*
asoc
,
cmd
->
obj
.
ptr
,
priority
);
sctp_event_timeout_t
timeout_type
)
break
;
{
int
error
=
0
;
case
SCTP_CMD_GEN_COOKIE_ECHO
:
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
/* Generate a COOKIE ECHO chunk. */
if
(
sock_owned_by_user
(
asoc
->
base
.
sk
))
{
new_obj
=
sctp_make_cookie_echo
(
asoc
,
chunk
);
SCTP_DEBUG_PRINTK
(
"%s:Sock is busy: timer %d
\n
"
,
if
(
!
new_obj
)
{
__FUNCTION__
,
if
(
cmd
->
obj
.
ptr
)
timeout_type
);
sctp_free_chunk
(
cmd
->
obj
.
ptr
);
goto
nomem
;
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
/* If there is an ERROR chunk to be sent along with
/* Try again later. */
* the COOKIE_ECHO, send it, too.
if
(
!
mod_timer
(
&
asoc
->
timers
[
timeout_type
],
jiffies
+
(
HZ
/
20
)))
*/
sctp_association_hold
(
asoc
);
if
(
cmd
->
obj
.
ptr
)
goto
out_unlock
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
}
SCTP_CHUNK
(
cmd
->
obj
.
ptr
));
break
;
case
SCTP_CMD_GEN_SHUTDOWN
:
/* Is this association really dead and just waiting around for
/* Generate SHUTDOWN when in SHUTDOWN_SENT state.
* the timer to let go of the reference?
* Reset error counts.
*/
*/
asoc
->
overall_error_count
=
0
;
if
(
asoc
->
base
.
dead
)
goto
out_unlock
;
/* Generate a SHUTDOWN chunk. */
new_obj
=
sctp_make_shutdown
(
asoc
);
if
(
!
new_obj
)
goto
nomem
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
break
;
case
SCTP_CMD_CHUNK_ULP
:
/* Run through the state machine. */
/* Send a chunk to the sockets layer. */
error
=
sctp_do_sm
(
SCTP_EVENT_T_TIMEOUT
,
SCTP_DEBUG_PRINTK
(
"sm_sideff: %s %p, %s %p.
\n
"
,
SCTP_ST_TIMEOUT
(
timeout_type
),
"chunk_up:"
,
cmd
->
obj
.
ptr
,
asoc
->
state
,
asoc
->
ep
,
asoc
,
"ulpq:"
,
&
asoc
->
ulpq
);
(
void
*
)
timeout_type
,
sctp_ulpq_tail_data
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
,
GFP_ATOMIC
);
GFP_ATOMIC
);
break
;
case
SCTP_CMD_EVENT_ULP
:
if
(
error
)
/* Send a notification to the sockets layer. */
asoc
->
base
.
sk
->
err
=
-
error
;
SCTP_DEBUG_PRINTK
(
"sm_sideff: %s %p, %s %p.
\n
"
,
"event_up:"
,
cmd
->
obj
.
ptr
,
"ulpq:"
,
&
asoc
->
ulpq
);
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
);
break
;
case
SCTP_CMD_REPLY
:
out_unlock:
/* Send a chunk to our peer. */
sctp_bh_unlock_sock
(
asoc
->
base
.
sk
);
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sctp_association_put
(
asoc
);
cmd
->
obj
.
ptr
);
}
break
;
case
SCTP_CMD_SEND_PKT
:
void
sctp_generate_t1_cookie_event
(
unsigned
long
data
)
/* Send a full packet to our peer. */
{
packet
=
cmd
->
obj
.
ptr
;
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
sctp_packet_transmit
(
packet
);
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T1_COOKIE
);
sctp_ootb_pkt_free
(
packet
);
}
break
;
case
SCTP_CMD_RETRAN
:
void
sctp_generate_t1_init_event
(
unsigned
long
data
)
/* Mark a transport for retransmission. */
{
sctp_retransmit
(
&
asoc
->
outqueue
,
cmd
->
obj
.
transport
,
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
SCTP_RETRANSMIT_T3_RTX
);
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T1_INIT
);
break
;
}
case
SCTP_CMD_TRANSMIT
:
void
sctp_generate_t2_shutdown_event
(
unsigned
long
data
)
/* Kick start transmission. */
{
error
=
sctp_outq_flush
(
&
asoc
->
outqueue
,
0
);
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
break
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
);
}
case
SCTP_CMD_ECN_CE
:
void
sctp_generate_t5_shutdown_guard_event
(
unsigned
long
data
)
/* Do delayed CE processing. */
{
sctp_do_ecn_ce_work
(
asoc
,
cmd
->
obj
.
u32
);
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
break
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD
);
case
SCTP_CMD_ECN_ECNE
:
}
/* sctp_generate_t5_shutdown_guard_event() */
/* Do delayed ECNE processing. */
new_obj
=
sctp_do_ecn_ecne_work
(
asoc
,
cmd
->
obj
.
u32
,
chunk
);
if
(
new_obj
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
break
;
case
SCTP_CMD_ECN_CWR
:
void
sctp_generate_autoclose_event
(
unsigned
long
data
)
/* Do delayed CWR processing. */
{
sctp_do_ecn_cwr_work
(
asoc
,
cmd
->
obj
.
u32
);
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
break
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_AUTOCLOSE
);
}
case
SCTP_CMD_SETUP_T2
:
/* Generate a heart beat event. If the sock is busy, reschedule. Make
sctp_cmd_setup_t2
(
commands
,
asoc
,
cmd
->
obj
.
ptr
);
* sure that the transport is still valid.
break
;
*/
void
sctp_generate_heartbeat_event
(
unsigned
long
data
)
{
int
error
=
0
;
struct
sctp_transport
*
transport
=
(
struct
sctp_transport
*
)
data
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
case
SCTP_CMD_TIMER_START
:
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
timer
=
&
asoc
->
timers
[
cmd
->
obj
.
to
];
if
(
sock_owned_by_user
(
asoc
->
base
.
sk
))
{
timeout
=
asoc
->
timeouts
[
cmd
->
obj
.
to
];
SCTP_DEBUG_PRINTK
(
"%s:Sock is busy.
\n
"
,
__FUNCTION__
);
if
(
!
timeout
)
BUG
();
timer
->
expires
=
jiffies
+
timeout
;
/* Try again later. */
sctp_association_hold
(
asoc
);
if
(
!
mod_timer
(
&
transport
->
hb_timer
,
jiffies
+
(
HZ
/
20
)))
add_timer
(
timer
);
sctp_transport_hold
(
transport
);
break
;
goto
out_unlock
;
}
case
SCTP_CMD_TIMER_RESTART
:
/* Is this structure just waiting around for us to actually
timer
=
&
asoc
->
timers
[
cmd
->
obj
.
to
];
* get destroyed?
timeout
=
asoc
->
timeouts
[
cmd
->
obj
.
to
];
*/
if
(
!
mod_timer
(
timer
,
jiffies
+
timeout
))
if
(
transport
->
dead
)
sctp_association_hold
(
asoc
);
goto
out_unlock
;
break
;
case
SCTP_CMD_TIMER_STOP
:
error
=
sctp_do_sm
(
SCTP_EVENT_T_TIMEOUT
,
timer
=
&
asoc
->
timers
[
cmd
->
obj
.
to
];
SCTP_ST_TIMEOUT
(
SCTP_EVENT_TIMEOUT_HEARTBEAT
),
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
asoc
->
state
,
sctp_association_put
(
asoc
);
asoc
->
ep
,
asoc
,
break
;
transport
,
GFP_ATOMIC
)
;
case
SCTP_CMD_INIT_RESTART
:
if
(
error
)
/* Do the needed accounting and updates
asoc
->
base
.
sk
->
err
=
-
error
;
* associated with restarting an initialization
* timer.
*/
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
++
;
asoc
->
timeouts
[
cmd
->
obj
.
to
]
*=
2
;
if
(
asoc
->
timeouts
[
cmd
->
obj
.
to
]
>
asoc
->
max_init_timeo
)
{
asoc
->
timeouts
[
cmd
->
obj
.
to
]
=
asoc
->
max_init_timeo
;
}
/* If we've sent any data bundled with
out_unlock:
* COOKIE-ECHO we need to resend.
sctp_bh_unlock_sock
(
asoc
->
base
.
sk
);
*/
sctp_transport_put
(
transport
);
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
}
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
sctp_retransmit_mark
(
&
asoc
->
outqueue
,
t
,
0
);
}
sctp_add_cmd_sf
(
commands
,
/* Inject a SACK Timeout event into the state machine. */
SCTP_CMD_TIMER_RESTART
,
void
sctp_generate_sack_event
(
unsigned
long
data
)
SCTP_TO
(
cmd
->
obj
.
to
));
{
break
;
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_SACK
);
}
case
SCTP_CMD_INIT_FAILED
:
sctp_timer_event_t
*
sctp_timer_events
[
SCTP_NUM_TIMEOUT_TYPES
]
=
{
sctp_cmd_init_failed
(
commands
,
asoc
);
NULL
,
break
;
sctp_generate_t1_cookie_event
,
sctp_generate_t1_init_event
,
sctp_generate_t2_shutdown_event
,
NULL
,
sctp_generate_t5_shutdown_guard_event
,
sctp_generate_heartbeat_event
,
sctp_generate_sack_event
,
sctp_generate_autoclose_event
,
};
case
SCTP_CMD_ASSOC_FAILED
:
sctp_cmd_assoc_failed
(
commands
,
asoc
,
event_type
,
subtype
,
chunk
);
break
;
case
SCTP_CMD_COUNTER_INC
:
/* RFC 2960 8.2 Path Failure Detection
asoc
->
counters
[
cmd
->
obj
.
counter
]
++
;
*
break
;
* When its peer endpoint is multi-homed, an endpoint should keep a
* error counter for each of the destination transport addresses of the
* peer endpoint.
*
* Each time the T3-rtx timer expires on any address, or when a
* HEARTBEAT sent to an idle address is not acknowledged within a RTO,
* the error counter of that destination address will be incremented.
* When the value in the error counter exceeds the protocol parameter
* 'Path.Max.Retrans' of that destination address, the endpoint should
* mark the destination transport address as inactive, and a
* notification SHOULD be sent to the upper layer.
*
*/
static
void
sctp_do_8_2_transport_strike
(
sctp_association_t
*
asoc
,
struct
sctp_transport
*
transport
)
{
/* The check for association's overall error counter exceeding the
* threshold is done in the state function.
*/
asoc
->
overall_error_count
++
;
case
SCTP_CMD_COUNTER_RESET
:
if
(
transport
->
active
&&
asoc
->
counters
[
cmd
->
obj
.
counter
]
=
0
;
(
transport
->
error_count
++
>=
transport
->
error_threshold
))
{
break
;
SCTP_DEBUG_PRINTK
(
"transport_strike: transport "
"IP:%d.%d.%d.%d failed.
\n
"
,
NIPQUAD
(
transport
->
ipaddr
.
v4
.
sin_addr
));
sctp_assoc_control_transport
(
asoc
,
transport
,
SCTP_TRANSPORT_DOWN
,
SCTP_FAILED_THRESHOLD
);
}
case
SCTP_CMD_REPORT_DUP
:
/* E2) For the destination address for which the timer
sctp_tsnmap_mark_dup
(
&
asoc
->
peer
.
tsn_map
,
* expires, set RTO <- RTO * 2 ("back off the timer"). The
cmd
->
obj
.
u32
);
* maximum value discussed in rule C7 above (RTO.max) may be
break
;
* used to provide an upper bound to this doubling operation.
*/
transport
->
rto
=
min
((
transport
->
rto
*
2
),
transport
->
asoc
->
rto_max
);
}
case
SCTP_CMD_REPORT_BAD_TAG
:
/* Worker routine to handle INIT command failure. */
SCTP_DEBUG_PRINTK
(
"vtag mismatch!
\n
"
);
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
commands
,
break
;
sctp_association_t
*
asoc
,
unsigned
error
)
{
struct
sctp_ulpevent
*
event
;
case
SCTP_CMD_STRIKE
:
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_CANT_STR_ASSOC
,
/* Mark one strike against a transport. */
0
,
0
,
0
,
GFP_ATOMIC
);
sctp_do_8_2_transport_strike
(
asoc
,
cmd
->
obj
.
transport
);
break
;
case
SCTP_CMD_TRANSPORT_RESET
:
if
(
event
)
t
=
cmd
->
obj
.
transport
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
sctp_cmd_transport_reset
(
commands
,
asoc
,
t
);
SCTP_ULPEVENT
(
event
));
break
;
case
SCTP_CMD_TRANSPORT_ON
:
/* SEND_FAILED sent later when cleaning up the association. */
t
=
cmd
->
obj
.
transport
;
asoc
->
outqueue
.
error
=
error
;
sctp_cmd_transport_on
(
commands
,
asoc
,
t
,
chunk
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
()
);
break
;
}
case
SCTP_CMD_HB_TIMERS_START
:
/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */
sctp_cmd_hb_timers_start
(
commands
,
asoc
);
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
commands
,
break
;
struct
sctp_association
*
asoc
,
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
struct
sctp_chunk
*
chunk
,
unsigned
error
)
{
struct
sctp_ulpevent
*
event
;
case
SCTP_CMD_HB_TIMER_UPDATE
:
/* Cancel any partial delivery in progress. */
t
=
cmd
->
obj
.
transport
;
sctp_ulpq_abort_pd
(
&
asoc
->
ulpq
,
GFP_ATOMIC
);
sctp_cmd_hb_timer_update
(
commands
,
asoc
,
t
);
break
;
case
SCTP_CMD_HB_TIMERS_STOP
:
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_COMM_LOST
,
sctp_cmd_hb_timers_stop
(
commands
,
asoc
);
(
__u16
)
error
,
0
,
0
,
break
;
GFP_ATOMIC
);
if
(
event
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
SCTP_ULPEVENT
(
event
));
case
SCTP_CMD_REPORT_ERROR
:
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
error
=
cmd
->
obj
.
error
;
SCTP_STATE
(
SCTP_STATE_CLOSED
));
break
;
case
SCTP_CMD_PROCESS_CTSN
:
/* SEND_FAILED sent later when cleaning up the association. */
/* Dummy up a SACK for processing. */
asoc
->
outqueue
.
error
=
error
;
sackh
.
cum_tsn_ack
=
cmd
->
obj
.
u32
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
sackh
.
a_rwnd
=
0
;
}
sackh
.
num_gap_ack_blocks
=
0
;
sackh
.
num_dup_tsns
=
0
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_PROCESS_SACK
,
SCTP_SACKH
(
&
sackh
));
break
;
case
SCTP_CMD_DISCARD_PACKET
:
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
/* We need to discard the whole packet. */
* inside the cookie. In reality, this is only used for INIT-ACK processing
chunk
->
pdiscard
=
1
;
* since all other cases use "temporary" associations and can do all
break
;
* their work in statefuns directly.
*/
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
commands
,
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
int
gfp
)
{
int
error
;
case
SCTP_CMD_RTO_PENDING
:
/* We only process the init as a sideeffect in a single
t
=
cmd
->
obj
.
transport
;
* case. This is when we process the INIT-ACK. If we
t
->
rto_pending
=
1
;
* fail during INIT processing (due to malloc problems),
break
;
* just return the error and stop processing the stack.
*/
if
(
!
sctp_process_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
gfp
))
error
=
-
ENOMEM
;
else
error
=
0
;
case
SCTP_CMD_PART_DELIVER
:
return
error
;
sctp_ulpq_partial_delivery
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
,
}
GFP_ATOMIC
);
break
;
case
SCTP_CMD_RENEGE
:
/* Helper function to break out starting up of heartbeat timers. */
sctp_ulpq_renege
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
,
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
cmds
,
GFP_ATOMIC
);
sctp_association_t
*
asoc
)
break
;
{
struct
sctp_transport
*
t
;
struct
list_head
*
pos
;
/* Start a heartbeat timer for each transport on the association.
* hold a reference on the transport to make sure none of
* the needed data structures go away.
*/
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
default:
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)))
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
sctp_transport_hold
(
t
);
cmd
->
verb
,
cmd
->
obj
.
ptr
);
break
;
};
if
(
error
)
return
error
;
}
}
}
return
error
;
static
void
sctp_cmd_hb_timers_stop
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
)
{
struct
sctp_transport
*
t
;
struct
list_head
*
pos
;
nomem:
/* Stop all heartbeat timers. */
error
=
-
ENOMEM
;
return
error
;
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
del_timer
(
&
t
->
hb_timer
))
sctp_transport_put
(
t
);
}
}
}
/* A helper function for delayed processing of INET ECN CE bit. */
/* Helper function to update the heartbeat timer. */
static
void
sctp_do_ecn_ce_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
)
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
struct
sctp_transport
*
t
)
{
{
/* Save the TSN away for comparison when we receive CWR */
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)))
asoc
->
last_ecne_tsn
=
lowest_tsn
;
sctp_transport_hold
(
t
);
asoc
->
need_ecne
=
1
;
}
}
/* Helper function for delayed processing of SCTP ECNE chunk. */
/* Helper function to handle the reception of an HEARTBEAT ACK. */
/* RFC 2960 Appendix A
static
void
sctp_cmd_transport_on
(
sctp_cmd_seq_t
*
cmds
,
*
sctp_association_t
*
asoc
,
* RFC 2481 details a specific bit for a sender to send in
struct
sctp_transport
*
t
,
* the header of its next outbound TCP segment to indicate to
* its peer that it has reduced its congestion window. This
* is termed the CWR bit. For SCTP the same indication is made
* by including the CWR chunk. This chunk contains one data
* element, i.e. the TSN number that was sent in the ECNE chunk.
* This element represents the lowest TSN number in the datagram
* that was originally marked with the CE bit.
*/
static
sctp_chunk_t
*
sctp_do_ecn_ecne_work
(
sctp_association_t
*
asoc
,
__u32
lowest_tsn
,
sctp_chunk_t
*
chunk
)
sctp_chunk_t
*
chunk
)
{
{
sctp_
chunk_t
*
repl
;
sctp_
sender_hb_info_t
*
hbinfo
;
/*
Our previously transmitted packet ran into some congestion
/*
8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
*
so we should take action by reducing cwnd and ssthresh
*
HEARTBEAT should clear the error counter of the destination
*
and then ACK our peer that we we've done so by
*
transport address to which the HEARTBEAT was sent.
*
sending a CWR
.
*
The association's overall error count is also cleared
.
*/
*/
t
->
error_count
=
0
;
t
->
asoc
->
overall_error_count
=
0
;
/* First, try to determine if we want to actually lower
/* Mark the destination transport address as active if it is not so
* our cwnd variables. Only lower them if the ECNE looks more
* marked.
* recent than the last response.
*/
*/
if
(
TSN_lt
(
asoc
->
last_cwr_tsn
,
lowest_tsn
))
{
if
(
!
t
->
active
)
struct
sctp_transport
*
transport
;
sctp_assoc_control_transport
(
asoc
,
t
,
SCTP_TRANSPORT_UP
,
SCTP_HEARTBEAT_SUCCESS
);
/* Find which transport's congestion variables
/* The receiver of the HEARTBEAT ACK should also perform an
* need to be adjusted.
* RTT measurement for that destination transport address
* using the time value carried in the HEARTBEAT ACK chunk.
*/
*/
transport
=
sctp_assoc_lookup_tsn
(
asoc
,
lowest_tsn
);
hbinfo
=
(
sctp_sender_hb_info_t
*
)
chunk
->
skb
->
data
;
sctp_transport_update_rto
(
t
,
(
jiffies
-
hbinfo
->
sent_at
));
/* Update the congestion variables. */
}
if
(
transport
)
sctp_transport_lower_cwnd
(
transport
,
SCTP_LOWER_CWND_ECNE
);
asoc
->
last_cwr_tsn
=
lowest_tsn
;
}
/* Always try to quiet the other end. In case of lost CWR,
/* Helper function to do a transport reset at the expiry of the hearbeat
* resend last_cwr_tsn
.
* timer
.
*/
*/
repl
=
sctp_make_cwr
(
asoc
,
asoc
->
last_cwr_tsn
,
chunk
);
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
struct
sctp_transport
*
t
)
{
sctp_transport_lower_cwnd
(
t
,
SCTP_LOWER_CWND_INACTIVE
);
/* If we run out of memory, it will look like a lost CWR. We'll
/* Mark one strike against a transport. */
* get back in sync eventually.
sctp_do_8_2_transport_strike
(
asoc
,
t
);
*/
return
repl
;
}
}
/* Helper function to do delayed processing of ECN CWR chunk. */
/* Helper function to process the process SACK command. */
static
void
sctp_do_ecn_cwr_work
(
sctp_association_t
*
asoc
,
static
int
sctp_cmd_process_sack
(
sctp_cmd_seq_t
*
cmds
,
__u32
lowest_tsn
)
sctp_association_t
*
asoc
,
sctp_sackhdr_t
*
sackh
)
{
{
/* Turn off ECNE getting auto-prepended to every outgoing
int
err
;
* packet
if
(
sctp_outq_sack
(
&
asoc
->
outqueue
,
sackh
))
{
/* There are no more TSNs awaiting SACK. */
err
=
sctp_do_sm
(
SCTP_EVENT_T_OTHER
,
SCTP_ST_OTHER
(
SCTP_EVENT_NO_PENDING_TSN
),
asoc
->
state
,
asoc
->
ep
,
asoc
,
NULL
,
GFP_ATOMIC
);
}
else
{
/* Windows may have opened, so we need
* to check if we have DATA to transmit
*/
*/
asoc
->
need_ecne
=
0
;
err
=
sctp_outq_flush
(
&
asoc
->
outqueue
,
0
);
}
return
err
;
}
}
/* This macro is to compress the text a bit... */
/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
#define AP(v) asoc->peer.v
* the transport for a shutdown chunk.
*/
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
)
{
struct
sctp_transport
*
t
;
t
=
sctp_assoc_choose_shutdown_transport
(
asoc
);
asoc
->
shutdown_last_sent_to
=
t
;
asoc
->
timeouts
[
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
]
=
t
->
rto
;
chunk
->
transport
=
t
;
}
/* Generate SACK if necessary. We call this at the end of a packet. */
/* Helper function to change the state of an association. */
int
sctp_gen_sack
(
sctp_association_t
*
asoc
,
int
force
,
sctp_cmd_seq_t
*
commands
)
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_state_t
state
)
{
{
__u32
ctsn
,
max_tsn_seen
;
sctp_chunk_t
*
sack
;
int
error
=
0
;
if
(
force
)
struct
sock
*
sk
=
asoc
->
base
.
sk
;
asoc
->
peer
.
sack_needed
=
1
;
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
)
;
ctsn
=
sctp_tsnmap_get_ctsn
(
&
asoc
->
peer
.
tsn_map
)
;
asoc
->
state
=
state
;
max_tsn_seen
=
sctp_tsnmap_get_max_tsn_seen
(
&
asoc
->
peer
.
tsn_map
)
;
asoc
->
state_timestamp
=
jiffies
;
/* From 12.2 Parameters necessary per association (i.e. the TCB):
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
||
*
(
SCTP_STATE_CLOSED
==
asoc
->
state
))
{
* Ack State : This flag indicates if the next received packet
/* Wake up any processes waiting in the asoc's wait queue in
* : is to be responded to with a SACK. ...
* sctp_wait_for_connect() or sctp_wait_for_sndbuf().
* : When DATA chunks are out of order, SACK's
* : are not delayed (see Section 6).
*
* [This is actually not mentioned in Section 6, but we
* implement it here anyway. --piggy]
*/
*/
if
(
max_tsn_seen
!=
ctsn
)
if
(
waitqueue_active
(
&
asoc
->
wait
)
)
asoc
->
peer
.
sack_needed
=
1
;
wake_up_interruptible
(
&
asoc
->
wait
)
;
/* From 6.2 Acknowledgement on Reception of DATA Chunks:
/* 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
;
}
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* functionality there.
*/
#define DEBUG_PRE \
SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \
"ep %p, %s, %s, asoc %p[%s], %s\n", \
ep, sctp_evttype_tbl[event_type], \
(*debug_fn)(subtype), asoc, \
sctp_state_tbl[state], state_fn->name)
#define DEBUG_POST \
SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \
"asoc %p, status: %s\n", \
asoc, sctp_status_tbl[status])
#define DEBUG_POST_SFX \
SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \
error, asoc, \
sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \
sctp_assoc2id(asoc)))?asoc->state:SCTP_STATE_CLOSED])
/*
* This is the master state machine processing function.
*
*
* Section 4.2 of [RFC2581] SHOULD be followed. Specifically,
* If you want to understand all of lksctp, this is a
* an acknowledgement SHOULD be generated for at least every
* good place to start.
* second packet (not every second DATA chunk) received, and
* SHOULD be generated within 200 ms of the arrival of any
* unacknowledged DATA chunk. ...
*/
*/
if
(
!
asoc
->
peer
.
sack_needed
)
{
int
sctp_do_sm
(
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
/* We will need a SACK for the next packet. */
sctp_state_t
state
,
asoc
->
peer
.
sack_needed
=
1
;
sctp_endpoint_t
*
ep
,
goto
out
;
sctp_association_t
*
asoc
,
}
else
{
void
*
event_arg
,
if
(
asoc
->
a_rwnd
>
asoc
->
rwnd
)
int
priority
)
asoc
->
a_rwnd
=
asoc
->
rwnd
;
{
sack
=
sctp_make_sack
(
asoc
);
sctp_cmd_seq_t
commands
;
if
(
!
sack
)
sctp_sm_table_entry_t
*
state_fn
;
goto
nomem
;
sctp_disposition_t
status
;
int
error
=
0
;
typedef
const
char
*
(
printfn_t
)(
sctp_subtype_t
);
static
printfn_t
*
table
[]
=
{
NULL
,
sctp_cname
,
sctp_tname
,
sctp_oname
,
sctp_pname
,
};
printfn_t
*
debug_fn
__attribute__
((
unused
))
=
table
[
event_type
];
asoc
->
peer
.
sack_needed
=
0
;
/* Look up the state function, run it, and then process the
* side effects. These three steps are the heart of lksctp.
*/
state_fn
=
sctp_sm_lookup_event
(
event_type
,
state
,
subtype
);
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sack
);
sctp_init_cmd_seq
(
&
commands
);
/* Stop the SACK timer. */
DEBUG_PRE
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
status
=
(
*
state_fn
->
fn
)(
ep
,
asoc
,
subtype
,
event_arg
,
&
commands
);
SCTP_TO
(
SCTP_EVENT_TIMEOUT_SACK
));
DEBUG_POST
;
}
out:
error
=
sctp_side_effects
(
event_type
,
subtype
,
state
,
return
error
;
ep
,
asoc
,
event_arg
,
status
,
&
commands
,
priority
);
DEBUG_POST_SFX
;
nomem:
error
=
-
ENOMEM
;
return
error
;
return
error
;
}
}
/* Handle a duplicate TSN. */
#undef DEBUG_PRE
void
sctp_do_TSNdup
(
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
long
gap
)
#undef DEBUG_POST
{
#if 0
sctp_chunk_t *sack;
/* Caution: gap < 2 * SCTP_TSN_MAP_SIZE
* so gap can be negative.
*
* --xguo
*/
/* Count this TSN. */
if (gap < SCTP_TSN_MAP_SIZE) {
asoc->peer.tsn_map[gap]++;
} else {
asoc->peer.tsn_map_overflow[gap - SCTP_TSN_MAP_SIZE]++;
}
/* From 6.2 Acknowledgement on Reception of DATA Chunks
*
* When a packet arrives with duplicate DATA chunk(s)
* and with no new DATA chunk(s), the endpoint MUST
* immediately send a SACK with no delay. If a packet
* arrives with duplicate DATA chunk(s) bundled with
* new DATA chunks, the endpoint MAY immediately send a
* SACK. Normally receipt of duplicate DATA chunks
* will occur when the original SACK chunk was lost and
* the peer's RTO has expired. The duplicate TSN
* number(s) SHOULD be reported in the SACK as
* duplicate.
*/
asoc->counters[SctpCounterAckState] = 2;
#endif /* 0 */
}
/* sctp_do_TSNdup() */
#undef AP
/* When the T3-RTX timer expires, it calls this function to create the
/*****************************************************************
* relevant state machine event.
* This the master state function side effect processing function.
*/
*****************************************************************/
void
sctp_generate_t3_rtx_event
(
unsigned
long
peer
)
int
sctp_side_effects
(
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
sctp_state_t
state
,
sctp_endpoint_t
*
ep
,
sctp_association_t
*
asoc
,
void
*
event_arg
,
sctp_disposition_t
status
,
sctp_cmd_seq_t
*
commands
,
int
priority
)
{
{
int
error
;
int
error
;
struct
sctp_transport
*
transport
=
(
struct
sctp_transport
*
)
peer
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
/* Check whether a task is in the sock. */
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
if
(
sock_owned_by_user
(
asoc
->
base
.
sk
))
{
SCTP_DEBUG_PRINTK
(
"%s:Sock is busy.
\n
"
,
__FUNCTION__
);
/* Try again later. */
if
(
!
mod_timer
(
&
transport
->
T3_rtx_timer
,
jiffies
+
(
HZ
/
20
)))
sctp_transport_hold
(
transport
);
goto
out_unlock
;
}
/* Is this transport really dead and just waiting around for
/* FIXME - Most of the dispositions left today would be categorized
* the timer to let go of the reference?
* as "exceptional" dispositions. For those dispositions, it
* may not be proper to run through any of the commands at all.
* For example, the command interpreter might be run only with
* disposition SCTP_DISPOSITION_CONSUME.
*/
*/
if
(
transport
->
dead
)
if
(
0
!=
(
error
=
sctp_cmd_interpreter
(
event_type
,
subtype
,
state
,
goto
out_unlock
;
ep
,
asoc
,
event_arg
,
status
,
/* Run through the state machine. */
commands
,
priority
)))
error
=
sctp_do_sm
(
SCTP_EVENT_T_TIMEOUT
,
goto
bail
;
SCTP_ST_TIMEOUT
(
SCTP_EVENT_TIMEOUT_T3_RTX
),
asoc
->
state
,
asoc
->
ep
,
asoc
,
transport
,
GFP_ATOMIC
);
if
(
error
)
asoc
->
base
.
sk
->
err
=
-
error
;
out_unlock:
switch
(
status
)
{
sctp_bh_unlock_sock
(
asoc
->
base
.
sk
);
case
SCTP_DISPOSITION_DISCARD
:
sctp_transport_put
(
transport
);
SCTP_DEBUG_PRINTK
(
"Ignored sctp protocol event - state %d, "
}
"event_type %d, event_id %d
\n
"
,
state
,
event_type
,
subtype
.
chunk
);
break
;
/* This is a sa interface for producing timeout events. It works
case
SCTP_DISPOSITION_NOMEM
:
* for timeouts which use the association as their parameter.
/* We ran out of memory, so we need to discard this
* packet.
*/
*/
static
void
sctp_generate_timeout_event
(
sctp_association_t
*
asoc
,
/* BUG--we should now recover some memory, probably by
sctp_event_timeout_t
timeout_type
)
* reneging...
{
*/
int
error
=
0
;
error
=
-
ENOMEM
;
break
;
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
if
(
sock_owned_by_user
(
asoc
->
base
.
sk
))
{
SCTP_DEBUG_PRINTK
(
"%s:Sock is busy: timer %d
\n
"
,
__FUNCTION__
,
timeout_type
);
/* Try again later. */
case
SCTP_DISPOSITION_DELETE_TCB
:
if
(
!
mod_timer
(
&
asoc
->
timers
[
timeout_type
],
jiffies
+
(
HZ
/
20
)))
/* This should now be a command. */
sctp_association_hold
(
asoc
);
break
;
goto
out_unlock
;
}
/* Is this association really dead and just waiting around for
case
SCTP_DISPOSITION_CONSUME
:
* the timer to let go of the reference?
case
SCTP_DISPOSITION_ABORT
:
/*
* We should no longer have much work to do here as the
* real work has been done as explicit commands above.
*/
*/
if
(
asoc
->
base
.
dead
)
break
;
goto
out_unlock
;
/* Run through the state machine. */
case
SCTP_DISPOSITION_VIOLATION
:
error
=
sctp_do_sm
(
SCTP_EVENT_T_TIMEOUT
,
printk
(
KERN_ERR
"sctp protocol violation state %d "
SCTP_ST_TIMEOUT
(
timeout_type
),
"chunkid %d
\n
"
,
state
,
subtype
.
chunk
);
asoc
->
state
,
asoc
->
ep
,
asoc
,
break
;
(
void
*
)
timeout_type
,
GFP_ATOMIC
);
if
(
error
)
case
SCTP_DISPOSITION_NOT_IMPL
:
asoc
->
base
.
sk
->
err
=
-
error
;
printk
(
KERN_WARNING
"sctp unimplemented feature in state %d, "
"event_type %d, event_id %d
\n
"
,
state
,
event_type
,
subtype
.
chunk
);
break
;
out_unlock:
case
SCTP_DISPOSITION_BUG
:
sctp_bh_unlock_sock
(
asoc
->
base
.
sk
);
printk
(
KERN_ERR
"sctp bug in state %d, "
sctp_association_put
(
asoc
);
"event_type %d, event_id %d
\n
"
,
}
state
,
event_type
,
subtype
.
chunk
);
BUG
();
break
;
void
sctp_generate_t1_cookie_event
(
unsigned
long
data
)
default:
{
printk
(
KERN_ERR
"sctp impossible disposition %d "
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
"in state %d, event_type %d, event_id %d
\n
"
,
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T1_COOKIE
);
status
,
state
,
event_type
,
subtype
.
chunk
);
}
BUG
();
break
;
};
void
sctp_generate_t1_init_event
(
unsigned
long
data
)
bail:
{
return
error
;
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T1_INIT
);
}
}
void
sctp_generate_t2_shutdown_event
(
unsigned
long
data
)
/********************************************************************
{
* 2nd Level Abstractions
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
********************************************************************/
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
);
}
void
sctp_generate_t5_shutdown_guard_event
(
unsigned
long
data
)
/* This is the side-effect interpreter. */
int
sctp_cmd_interpreter
(
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
sctp_state_t
state
,
sctp_endpoint_t
*
ep
,
sctp_association_t
*
asoc
,
void
*
event_arg
,
sctp_disposition_t
status
,
sctp_cmd_seq_t
*
commands
,
int
priority
)
{
{
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
int
error
=
0
;
sctp_generate_timeout_event
(
asoc
,
int
force
;
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD
);
sctp_cmd_t
*
cmd
;
sctp_chunk_t
*
new_obj
;
}
/* sctp_generate_t5_shutdown_guard_event() */
sctp_chunk_t
*
chunk
=
NULL
;
struct
sctp_packet
*
packet
;
struct
list_head
*
pos
;
struct
timer_list
*
timer
;
unsigned
long
timeout
;
struct
sctp_transport
*
t
;
sctp_sackhdr_t
sackh
;
void
sctp_generate_autoclose_event
(
unsigned
long
data
)
if
(
SCTP_EVENT_T_TIMEOUT
!=
event_type
)
{
chunk
=
(
sctp_chunk_t
*
)
event_arg
;
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_AUTOCLOSE
);
}
/* Generate a heart beat event. If the sock is busy, reschedule. Make
/* Note: This whole file is a huge candidate for rework.
* sure that the transport is still valid.
* For example, each command could either have its own handler, so
* the loop would look like:
* while (cmds)
* cmd->handle(x, y, z)
* --jgrimm
*/
*/
void
sctp_generate_heartbeat_event
(
unsigned
long
data
)
while
(
NULL
!=
(
cmd
=
sctp_next_cmd
(
commands
)))
{
{
switch
(
cmd
->
verb
)
{
int
error
=
0
;
case
SCTP_CMD_NOP
:
struct
sctp_transport
*
transport
=
(
struct
sctp_transport
*
)
data
;
/* Do nothing. */
sctp_association_t
*
asoc
=
transport
->
asoc
;
break
;
sctp_bh_lock_sock
(
asoc
->
base
.
sk
);
case
SCTP_CMD_NEW_ASOC
:
if
(
sock_owned_by_user
(
asoc
->
base
.
sk
))
{
/* Register a new association. */
SCTP_DEBUG_PRINTK
(
"%s:Sock is busy.
\n
"
,
__FUNCTION__
);
asoc
=
cmd
->
obj
.
ptr
;
/* Register with the endpoint. */
sctp_endpoint_add_asoc
(
ep
,
asoc
);
sctp_hash_established
(
asoc
);
break
;
/* Try again later. */
case
SCTP_CMD_UPDATE_ASSOC
:
if
(
!
mod_timer
(
&
transport
->
hb_timer
,
jiffies
+
(
HZ
/
20
)))
sctp_assoc_update
(
asoc
,
cmd
->
obj
.
ptr
);
sctp_transport_hold
(
transport
);
break
;
goto
out_unlock
;
}
/* Is this structure just waiting around for us to actually
case
SCTP_CMD_PURGE_OUTQUEUE
:
* get destroyed?
sctp_outq_teardown
(
&
asoc
->
outqueue
);
*/
break
;
if
(
transport
->
dead
)
goto
out_unlock
;
error
=
sctp_do_sm
(
SCTP_EVENT_T_TIMEOUT
,
case
SCTP_CMD_DELETE_TCB
:
SCTP_ST_TIMEOUT
(
SCTP_EVENT_TIMEOUT_HEARTBEAT
),
/* Delete the current association. */
asoc
->
state
,
sctp_unhash_established
(
asoc
);
asoc
->
ep
,
asoc
,
sctp_association_free
(
asoc
);
transport
,
GFP_ATOMIC
);
asoc
=
NULL
;
break
;
if
(
error
)
case
SCTP_CMD_NEW_STATE
:
asoc
->
base
.
sk
->
err
=
-
error
;
/* Enter a new state. */
sctp_cmd_new_state
(
commands
,
asoc
,
cmd
->
obj
.
state
);
break
;
out_unlock
:
case
SCTP_CMD_REPORT_TSN
:
sctp_bh_unlock_sock
(
asoc
->
base
.
sk
);
/* Record the arrival of a TSN. */
sctp_transport_put
(
transport
);
sctp_tsnmap_mark
(
&
asoc
->
peer
.
tsn_map
,
cmd
->
obj
.
u32
);
}
break
;
/* Inject a SACK Timeout event into the state machine. */
case
SCTP_CMD_GEN_SACK
:
void
sctp_generate_sack_event
(
unsigned
long
data
)
/* Generate a Selective ACK.
{
* The argument tells us whether to just count
sctp_association_t
*
asoc
=
(
sctp_association_t
*
)
data
;
* the packet and MAYBE generate a SACK, or
sctp_generate_timeout_event
(
asoc
,
SCTP_EVENT_TIMEOUT_SACK
);
* force a SACK out.
}
*/
force
=
cmd
->
obj
.
i32
;
error
=
sctp_gen_sack
(
asoc
,
force
,
commands
);
break
;
sctp_timer_event_t
*
sctp_timer_events
[
SCTP_NUM_TIMEOUT_TYPES
]
=
{
case
SCTP_CMD_PROCESS_SACK
:
NULL
,
/* Process an inbound SACK. */
sctp_generate_t1_cookie_event
,
error
=
sctp_cmd_process_sack
(
commands
,
asoc
,
sctp_generate_t1_init_event
,
cmd
->
obj
.
ptr
);
sctp_generate_t2_shutdown_event
,
break
;
NULL
,
sctp_generate_t5_shutdown_guard_event
,
sctp_generate_heartbeat_event
,
sctp_generate_sack_event
,
sctp_generate_autoclose_event
,
};
/********************************************************************
case
SCTP_CMD_GEN_INIT_ACK
:
* 3rd Level Abstractions
/* Generate an INIT ACK chunk. */
********************************************************************/
new_obj
=
sctp_make_init_ack
(
asoc
,
chunk
,
GFP_ATOMIC
,
0
);
if
(
!
new_obj
)
goto
nomem
;
/* RFC 2960 8.2 Path Failure Detection
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
*
SCTP_CHUNK
(
new_obj
));
* When its peer endpoint is multi-homed, an endpoint should keep a
break
;
* error counter for each of the destination transport addresses of the
* peer endpoint.
case
SCTP_CMD_PEER_INIT
:
*
/* Process a unified INIT from the peer.
* Each time the T3-rtx timer expires on any address, or when a
* Note: Only used during INIT-ACK processing. If
* HEARTBEAT sent to an idle address is not acknowledged within a RTO,
* there is an error just return to the outter
* the error counter of that destination address will be incremented.
* layer which will bail.
* When the value in the error counter exceeds the protocol parameter
* 'Path.Max.Retrans' of that destination address, the endpoint should
* mark the destination transport address as inactive, and a
* notification SHOULD be sent to the upper layer.
*
*/
static
void
sctp_do_8_2_transport_strike
(
sctp_association_t
*
asoc
,
struct
sctp_transport
*
transport
)
{
/* The check for association's overall error counter exceeding the
* threshold is done in the state function.
*/
*/
asoc
->
overall_error_count
++
;
error
=
sctp_cmd_process_init
(
commands
,
asoc
,
chunk
,
cmd
->
obj
.
ptr
,
priority
);
break
;
if
(
transport
->
active
&&
case
SCTP_CMD_GEN_COOKIE_ECHO
:
(
transport
->
error_count
++
>=
transport
->
error_threshold
))
{
/* Generate a COOKIE ECHO chunk. */
SCTP_DEBUG_PRINTK
(
"transport_strike: transport "
new_obj
=
sctp_make_cookie_echo
(
asoc
,
chunk
);
"IP:%d.%d.%d.%d failed.
\n
"
,
if
(
!
new_obj
)
{
NIPQUAD
(
transport
->
ipaddr
.
v4
.
sin_addr
));
if
(
cmd
->
obj
.
ptr
)
sctp_assoc_control_transport
(
asoc
,
transport
,
sctp_free_chunk
(
cmd
->
obj
.
ptr
);
SCTP_TRANSPORT_DOWN
,
goto
nomem
;
SCTP_FAILED_THRESHOLD
);
}
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
/* E2) For the destination address for which the timer
/* If there is an ERROR chunk to be sent along with
* expires, set RTO <- RTO * 2 ("back off the timer"). The
* the COOKIE_ECHO, send it, too.
* maximum value discussed in rule C7 above (RTO.max) may be
* used to provide an upper bound to this doubling operation.
*/
*/
transport
->
rto
=
min
((
transport
->
rto
*
2
),
transport
->
asoc
->
rto_max
);
if
(
cmd
->
obj
.
ptr
)
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
cmd
->
obj
.
ptr
));
break
;
/* Worker routine to handle INIT command failure. */
case
SCTP_CMD_GEN_SHUTDOWN
:
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
commands
,
/* Generate SHUTDOWN when in SHUTDOWN_SENT state.
sctp_association_t
*
asoc
)
* Reset error counts.
{
*/
struct
sctp_ulpevent
*
event
;
asoc
->
overall_error_count
=
0
;
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
/* Generate a SHUTDOWN chunk. */
0
,
new_obj
=
sctp_make_shutdown
(
asoc
);
SCTP_CANT_STR_ASSOC
,
if
(
!
new_obj
)
0
,
0
,
0
,
goto
nomem
;
GFP_ATOMIC
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
break
;
if
(
event
)
case
SCTP_CMD_CHUNK_ULP
:
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
/* Send a chunk to the sockets layer. */
SCTP_ULPEVENT
(
event
));
SCTP_DEBUG_PRINTK
(
"sm_sideff: %s %p, %s %p.
\n
"
,
"chunk_up:"
,
cmd
->
obj
.
ptr
,
"ulpq:"
,
&
asoc
->
ulpq
);
sctp_ulpq_tail_data
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
,
GFP_ATOMIC
);
break
;
/* FIXME: We need to handle data possibly either
case
SCTP_CMD_EVENT_ULP
:
* sent via COOKIE-ECHO bundling or just waiting in
/* Send a notification to the sockets layer. */
* the transmit queue, if the user has enabled
SCTP_DEBUG_PRINTK
(
"sm_sideff: %s %p, %s %p.
\n
"
,
* SEND_FAILED notifications.
"event_up:"
,
cmd
->
obj
.
ptr
,
*/
"ulpq:"
,
&
asoc
->
ulpq
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
()
);
sctp_ulpq_tail_event
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
);
}
break
;
/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */
case
SCTP_CMD_REPLY
:
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
commands
,
/* Send a chunk to our peer. */
sctp_association_t
*
asoc
,
error
=
sctp_outq_tail
(
&
asoc
->
outqueue
,
sctp_event_t
event_type
,
cmd
->
obj
.
ptr
);
sctp_subtype_t
subtype
,
break
;
sctp_chunk_t
*
chunk
)
{
struct
sctp_ulpevent
*
event
;
__u16
error
=
0
;
switch
(
event_type
)
{
case
SCTP_CMD_SEND_PKT
:
case
SCTP_EVENT_T_PRIMITIVE
:
/* Send a full packet to our peer. */
if
(
SCTP_PRIMITIVE_ABORT
==
subtype
.
primitive
)
packet
=
cmd
->
obj
.
ptr
;
error
=
SCTP_ERROR_USER_ABORT
;
sctp_packet_transmit
(
packet
);
sctp_ootb_pkt_free
(
packet
);
break
;
break
;
case
SCTP_EVENT_T_CHUNK
:
if
(
chunk
&&
(
SCTP_CID_ABORT
==
chunk
->
chunk_hdr
->
type
)
&&
case
SCTP_CMD_RETRAN
:
(
ntohs
(
chunk
->
chunk_hdr
->
length
)
>=
/* Mark a transport for retransmission. */
(
sizeof
(
struct
sctp_chunkhdr
)
+
sctp_retransmit
(
&
asoc
->
outqueue
,
cmd
->
obj
.
transport
,
sizeof
(
struct
sctp_errhdr
))))
{
SCTP_RTXR_T3_RTX
);
error
=
((
sctp_errhdr_t
*
)
chunk
->
skb
->
data
)
->
cause
;
}
break
;
break
;
default:
case
SCTP_CMD_TRANSMIT
:
/* Kick start transmission. */
error
=
sctp_outq_flush
(
&
asoc
->
outqueue
,
0
);
break
;
break
;
}
/* Cancel any partial delivery in progress. */
case
SCTP_CMD_ECN_CE
:
sctp_ulpq_abort_pd
(
&
asoc
->
ulpq
,
GFP_ATOMIC
);
/* Do delayed CE processing. */
sctp_do_ecn_ce_work
(
asoc
,
cmd
->
obj
.
u32
);
break
;
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_COMM_LOST
,
case
SCTP_CMD_ECN_ECNE
:
error
,
0
,
0
,
GFP_ATOMIC
);
/* Do delayed ECNE processing. */
if
(
event
)
new_obj
=
sctp_do_ecn_ecne_work
(
asoc
,
cmd
->
obj
.
u32
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
chunk
);
SCTP_ULPEVENT
(
event
));
if
(
new_obj
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
break
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
case
SCTP_CMD_ECN_CWR
:
SCTP_STATE
(
SCTP_STATE_CLOSED
));
/* Do delayed CWR processing. */
sctp_do_ecn_cwr_work
(
asoc
,
cmd
->
obj
.
u32
);
break
;
/* FIXME: We need to handle data that could not be sent or was not
case
SCTP_CMD_SETUP_T2
:
* acked, if the user has enabled SEND_FAILED notifications.
sctp_cmd_setup_t2
(
commands
,
asoc
,
cmd
->
obj
.
ptr
);
*/
break
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
}
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
case
SCTP_CMD_TIMER_START
:
* inside the cookie. In reality, this is only used for INIT-ACK processing
timer
=
&
asoc
->
timers
[
cmd
->
obj
.
to
];
* since all other cases use "temporary" associations and can do all
timeout
=
asoc
->
timeouts
[
cmd
->
obj
.
to
];
* their work in statefuns directly.
if
(
!
timeout
)
*/
BUG
();
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
int
priority
)
{
int
error
;
/* We only process the init as a sideeffect in a single
timer
->
expires
=
jiffies
+
timeout
;
* case. This is when we process the INIT-ACK. If we
sctp_association_hold
(
asoc
);
* fail during INIT processing (due to malloc problems),
add_timer
(
timer
);
* just return the error and stop processing the stack.
break
;
*/
if
(
!
sctp_process_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
case
SCTP_CMD_TIMER_RESTART
:
sctp_source
(
chunk
),
peer_init
,
timer
=
&
asoc
->
timers
[
cmd
->
obj
.
to
];
priority
))
timeout
=
asoc
->
timeouts
[
cmd
->
obj
.
to
];
error
=
-
ENOMEM
;
if
(
!
mod_timer
(
timer
,
jiffies
+
timeout
))
else
sctp_association_hold
(
asoc
);
error
=
0
;
break
;
return
error
;
case
SCTP_CMD_TIMER_STOP
:
}
timer
=
&
asoc
->
timers
[
cmd
->
obj
.
to
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
break
;
/* Helper function to break out starting up of heartbeat timers. */
case
SCTP_CMD_INIT_RESTART
:
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
cmds
,
/* Do the needed accounting and updates
sctp_association_t
*
asoc
)
* associated with restarting an initialization
{
* timer.
struct
sctp_transport
*
t
;
*/
struct
list_head
*
pos
;
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
++
;
asoc
->
timeouts
[
cmd
->
obj
.
to
]
*=
2
;
if
(
asoc
->
timeouts
[
cmd
->
obj
.
to
]
>
asoc
->
max_init_timeo
)
{
asoc
->
timeouts
[
cmd
->
obj
.
to
]
=
asoc
->
max_init_timeo
;
}
/* Start a heartbeat timer for each transport on the association.
/* If we've sent any data bundled with
* hold a reference on the transport to make sure none of
* COOKIE-ECHO we need to resend.
* the needed data structures go away.
*/
*/
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)))
sctp_retransmit_mark
(
&
asoc
->
outqueue
,
t
,
0
);
sctp_transport_hold
(
t
);
}
}
}
static
void
sctp_cmd_hb_timers_stop
(
sctp_cmd_seq_t
*
cmds
,
sctp_add_cmd_sf
(
commands
,
sctp_association_t
*
asoc
)
SCTP_CMD_TIMER_RESTART
,
{
SCTP_TO
(
cmd
->
obj
.
to
));
struct
sctp_transport
*
t
;
break
;
struct
list_head
*
pos
;
/* Stop all heartbeat timers. */
case
SCTP_CMD_INIT_FAILED
:
sctp_cmd_init_failed
(
commands
,
asoc
,
cmd
->
obj
.
u32
);
break
;
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
case
SCTP_CMD_ASSOC_FAILED
:
t
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
sctp_cmd_assoc_failed
(
commands
,
asoc
,
event_type
,
if
(
del_timer
(
&
t
->
hb_timer
))
subtype
,
chunk
,
cmd
->
obj
.
u32
);
sctp_transport_put
(
t
);
break
;
}
}
/* Helper function to update the heartbeat timer. */
case
SCTP_CMD_COUNTER_INC
:
static
void
sctp_cmd_hb_timer_update
(
sctp_cmd_seq_t
*
cmds
,
asoc
->
counters
[
cmd
->
obj
.
counter
]
++
;
sctp_association_t
*
asoc
,
break
;
struct
sctp_transport
*
t
)
{
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
sctp_transport_timeout
(
t
)))
sctp_transport_hold
(
t
);
}
/* Helper function to handle the reception of an HEARTBEAT ACK. */
case
SCTP_CMD_COUNTER_RESET
:
static
void
sctp_cmd_transport_on
(
sctp_cmd_seq_t
*
cmds
,
asoc
->
counters
[
cmd
->
obj
.
counter
]
=
0
;
sctp_association_t
*
asoc
,
break
;
struct
sctp_transport
*
t
,
sctp_chunk_t
*
chunk
)
{
sctp_sender_hb_info_t
*
hbinfo
;
/* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
case
SCTP_CMD_REPORT_DUP
:
* HEARTBEAT should clear the error counter of the destination
sctp_tsnmap_mark_dup
(
&
asoc
->
peer
.
tsn_map
,
* transport address to which the HEARTBEAT was sent.
cmd
->
obj
.
u32
);
* The association's overall error count is also cleared.
break
;
*/
t
->
error_count
=
0
;
t
->
asoc
->
overall_error_count
=
0
;
/* Mark the destination transport address as active if it is not so
case
SCTP_CMD_REPORT_BAD_TAG
:
* marked.
SCTP_DEBUG_PRINTK
(
"vtag mismatch!
\n
"
);
*/
break
;
if
(
!
t
->
active
)
sctp_assoc_control_transport
(
asoc
,
t
,
SCTP_TRANSPORT_UP
,
SCTP_HEARTBEAT_SUCCESS
);
/* The receiver of the HEARTBEAT ACK should also perform an
case
SCTP_CMD_STRIKE
:
* RTT measurement for that destination transport address
/* Mark one strike against a transport. */
* using the time value carried in the HEARTBEAT ACK chunk.
sctp_do_8_2_transport_strike
(
asoc
,
cmd
->
obj
.
transport
);
*/
break
;
hbinfo
=
(
sctp_sender_hb_info_t
*
)
chunk
->
skb
->
data
;
sctp_transport_update_rto
(
t
,
(
jiffies
-
hbinfo
->
sent_at
));
}
/* Helper function to do a transport reset at the expiry of the hearbeat
case
SCTP_CMD_TRANSPORT_RESET
:
* timer.
t
=
cmd
->
obj
.
transport
;
*/
sctp_cmd_transport_reset
(
commands
,
asoc
,
t
);
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
cmds
,
break
;
sctp_association_t
*
asoc
,
struct
sctp_transport
*
t
)
{
sctp_transport_lower_cwnd
(
t
,
SCTP_LOWER_CWND_INACTIVE
);
/* Mark one strike against a transport. */
case
SCTP_CMD_TRANSPORT_ON
:
sctp_do_8_2_transport_strike
(
asoc
,
t
);
t
=
cmd
->
obj
.
transport
;
}
sctp_cmd_transport_on
(
commands
,
asoc
,
t
,
chunk
);
break
;
/* Helper function to process the process SACK command. */
case
SCTP_CMD_HB_TIMERS_START
:
static
int
sctp_cmd_process_sack
(
sctp_cmd_seq_t
*
cmds
,
sctp_cmd_hb_timers_start
(
commands
,
asoc
);
sctp_association_t
*
asoc
,
break
;
sctp_sackhdr_t
*
sackh
)
{
int
err
;
if
(
sctp_outq_sack
(
&
asoc
->
outqueue
,
sackh
))
{
case
SCTP_CMD_HB_TIMER_UPDATE
:
/* There are no more TSNs awaiting SACK. */
t
=
cmd
->
obj
.
transport
;
err
=
sctp_do_sm
(
SCTP_EVENT_T_OTHER
,
sctp_cmd_hb_timer_update
(
commands
,
asoc
,
t
);
SCTP_ST_OTHER
(
SCTP_EVENT_NO_PENDING_TSN
),
break
;
asoc
->
state
,
asoc
->
ep
,
asoc
,
NULL
,
GFP_ATOMIC
);
}
else
{
/* Windows may have opened, so we need
* to check if we have DATA to transmit
*/
err
=
sctp_outq_flush
(
&
asoc
->
outqueue
,
0
);
}
return
err
;
case
SCTP_CMD_HB_TIMERS_STOP
:
}
sctp_cmd_hb_timers_stop
(
commands
,
asoc
);
break
;
/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
case
SCTP_CMD_REPORT_ERROR
:
* the transport for a shutdown chunk.
error
=
cmd
->
obj
.
error
;
*/
break
;
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
)
{
struct
sctp_transport
*
t
;
t
=
sctp_assoc_choose_shutdown_transport
(
asoc
);
case
SCTP_CMD_PROCESS_CTSN
:
asoc
->
shutdown_last_sent_to
=
t
;
/* Dummy up a SACK for processing. */
asoc
->
timeouts
[
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
]
=
t
->
rto
;
sackh
.
cum_tsn_ack
=
cmd
->
obj
.
u32
;
chunk
->
transport
=
t
;
sackh
.
a_rwnd
=
0
;
}
sackh
.
num_gap_ack_blocks
=
0
;
sackh
.
num_dup_tsns
=
0
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_PROCESS_SACK
,
SCTP_SACKH
(
&
sackh
));
break
;
/* Helper function to change the state of an association. */
case
SCTP_CMD_DISCARD_PACKET
:
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
/* We need to discard the whole packet. */
sctp_state_t
state
)
chunk
->
pdiscard
=
1
;
{
break
;
struct
sock
*
sk
=
asoc
->
base
.
sk
;
case
SCTP_CMD_RTO_PENDING
:
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
t
=
cmd
->
obj
.
transport
;
t
->
rto_pending
=
1
;
break
;
asoc
->
state
=
state
;
case
SCTP_CMD_PART_DELIVER
:
asoc
->
state_timestamp
=
jiffies
;
sctp_ulpq_partial_delivery
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
,
GFP_ATOMIC
);
break
;
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
||
case
SCTP_CMD_RENEGE
:
(
SCTP_STATE_CLOSED
==
asoc
->
state
))
{
sctp_ulpq_renege
(
&
asoc
->
ulpq
,
cmd
->
obj
.
ptr
,
/* Wake up any processes waiting in the asoc's wait queue in
GFP_ATOMIC
);
* sctp_wait_for_connect() or sctp_wait_for_sndbuf().
break
;
*/
if
(
waitqueue_active
(
&
asoc
->
wait
))
wake_up_interruptible
(
&
asoc
->
wait
);
/* Wake up any processes waiting in the sk's sleep queue of
default:
* a TCP-style or UDP-style peeled-off socket in
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
* sctp_wait_for_accept() or sctp_wait_for_packet().
cmd
->
verb
,
cmd
->
obj
.
ptr
);
* For a UDP-style socket, the waiters are woken up by the
break
;
* notifications.
};
*/
if
(
error
)
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
return
error
;
sk
->
state_change
(
sk
);
}
}
/* Change the sk->state of a TCP-style socket that has sucessfully
return
error
;
* completed a connect() call.
*/
nomem:
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
&&
error
=
-
ENOMEM
;
(
SCTP_SOCKET_TCP
==
sp
->
type
)
&&
(
SCTP_SS_CLOSED
==
sk
->
state
))
return
error
;
sk
->
state
=
SCTP_SS_ESTABLISHED
;
}
}
net/sctp/sm_statefuns.c
View file @
381a2af8
...
@@ -191,14 +191,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -191,14 +191,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
sctp_chunk_t
*
err_chunk
;
sctp_chunk_t
*
err_chunk
;
struct
sctp_packet
*
packet
;
struct
sctp_packet
*
packet
;
sctp_unrecognized_param_t
*
unk_param
;
sctp_unrecognized_param_t
*
unk_param
;
struct
sock
*
sk
;
int
len
;
int
len
;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
if
(
ep
==
sctp_sk
((
sctp_get_ctl_sock
()))
->
ep
)
return
sctp_sf_ootb
(
ep
,
asoc
,
type
,
arg
,
commands
);
/* 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.
...
@@ -206,6 +201,22 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -206,6 +201,22 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if
(
!
chunk
->
singleton
)
if
(
!
chunk
->
singleton
)
return
SCTP_DISPOSITION_VIOLATION
;
return
SCTP_DISPOSITION_VIOLATION
;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
if
(
ep
==
sctp_sk
((
sctp_get_ctl_sock
()))
->
ep
)
return
sctp_sf_tabort_8_4_8
(
ep
,
asoc
,
type
,
arg
,
commands
);
sk
=
ep
->
base
.
sk
;
/* If the endpoint is not listening or if the number of associations
* on the TCP-style socket exceed the max backlog, respond with an
* ABORT.
*/
if
((
SCTP_SS_LISTENING
!=
sk
->
state
)
||
((
SCTP_SOCKET_TCP
==
sctp_sk
(
sk
)
->
type
)
&&
(
sk
->
ack_backlog
>=
sk
->
max_ack_backlog
)))
return
sctp_sf_tabort_8_4_8
(
ep
,
asoc
,
type
,
arg
,
commands
);
/* Verify the INIT chunk before processing it. */
/* Verify the INIT chunk before processing it. */
err_chunk
=
NULL
;
err_chunk
=
NULL
;
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
...
@@ -729,7 +740,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
...
@@ -729,7 +740,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
...
@@ -1379,7 +1391,8 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
...
@@ -1379,7 +1391,8 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
))
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
))
goto
nomem
;
goto
nomem
;
/* Make sure no new addresses are being added during the
/* Make sure no new addresses are being added during the
...
@@ -1444,7 +1457,8 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
...
@@ -1444,7 +1457,8 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
*/
*/
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
))
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
))
goto
nomem
;
goto
nomem
;
/* Update the content of current association. */
/* Update the content of current association. */
...
@@ -1772,14 +1786,16 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
...
@@ -1772,14 +1786,16 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_errhdr_t
*
err
;
sctp_errhdr_t
*
err
;
err
=
(
sctp_errhdr_t
*
)(
chunk
->
skb
->
data
);
/* If we have gotten too many failures, give up. */
/* If we have gotten too many failures, give up. */
if
(
1
+
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
>
if
(
1
+
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
>
asoc
->
max_init_attempts
)
{
asoc
->
max_init_attempts
)
{
/* INIT_FAILED will issue an ulpevent. */
/* INIT_FAILED will issue an ulpevent. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_U32
(
err
->
cause
));
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
err
=
(
sctp_errhdr_t
*
)(
chunk
->
skb
->
data
);
/* Process the error here */
/* Process the error here */
switch
(
err
->
cause
)
{
switch
(
err
->
cause
)
{
...
@@ -1834,7 +1850,8 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
...
@@ -1834,7 +1850,8 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
attempts
=
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
+
1
;
attempts
=
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
+
1
;
if
(
attempts
>=
asoc
->
max_init_attempts
)
{
if
(
attempts
>=
asoc
->
max_init_attempts
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_U32
(
SCTP_ERROR_STALE_COOKIE
));
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
...
@@ -1936,12 +1953,18 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
...
@@ -1936,12 +1953,18 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
__u16
error
=
SCTP_ERROR_NO_ERROR
;
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
if
(
chunk
&&
(
ntohs
(
chunk
->
chunk_hdr
->
length
)
>=
(
sizeof
(
struct
sctp_chunkhdr
)
+
sizeof
(
struct
sctp_errhdr
))))
error
=
((
sctp_errhdr_t
*
)
chunk
->
skb
->
data
)
->
cause
;
/* ASSOC_FAILED will DELETE_TCB. */
/* ASSOC_FAILED will DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_
NULL
(
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_
U32
(
error
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
...
@@ -1961,6 +1984,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
...
@@ -1961,6 +1984,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
__u16
error
=
SCTP_ERROR_NO_ERROR
;
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
if
(
!
sctp_vtag_verify_either
(
chunk
,
asoc
))
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
@@ -1971,10 +1995,14 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
...
@@ -1971,10 +1995,14 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_INIT
));
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_INIT
));
if
(
chunk
&&
(
ntohs
(
chunk
->
chunk_hdr
->
length
)
>=
(
sizeof
(
struct
sctp_chunkhdr
)
+
sizeof
(
struct
sctp_errhdr
))))
error
=
((
sctp_errhdr_t
*
)
chunk
->
skb
->
data
)
->
cause
;
/* CMD_INIT_FAILED will DELETE_TCB. */
/* CMD_INIT_FAILED will DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_
NULL
(
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_
U32
(
error
));
/* BUG? This does not look complete... */
return
SCTP_DISPOSITION_ABORT
;
return
SCTP_DISPOSITION_ABORT
;
}
}
...
@@ -2381,7 +2409,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
...
@@ -2381,7 +2409,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet.
* processing the rest of the chunks in the packet.
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_DATA
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
...
@@ -2596,7 +2625,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
...
@@ -2596,7 +2625,8 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet.
* processing the rest of the chunks in the packet.
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DISCARD_PACKET
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_DATA
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
...
@@ -3547,7 +3577,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
...
@@ -3547,7 +3577,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
*/
*/
/* Delete the established association. */
/* Delete the established association. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_USER_ABORT
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
...
@@ -3686,7 +3717,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
...
@@ -3686,7 +3717,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
*/
*/
/* Delete the established association. */
/* Delete the established association. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_U32
(
SCTP_ERROR_USER_ABORT
));
return
retval
;
return
retval
;
}
}
...
@@ -4012,7 +4044,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
...
@@ -4012,7 +4044,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
...
@@ -4147,7 +4180,8 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
...
@@ -4147,7 +4180,8 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
SCTP_TO
(
timer
));
SCTP_TO
(
timer
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
}
else
{
}
else
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
}
}
...
@@ -4181,7 +4215,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
...
@@ -4181,7 +4215,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
SCTP_DEBUG_PRINTK
(
"Timer T2 expired.
\n
"
);
SCTP_DEBUG_PRINTK
(
"Timer T2 expired.
\n
"
);
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
if
(
asoc
->
overall_error_count
>=
asoc
->
overall_error_threshold
)
{
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_INC_STATS
(
SctpAborteds
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
SCTP_DEC_STATS
(
SctpCurrEstab
);
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
...
@@ -4244,7 +4279,8 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
...
@@ -4244,7 +4279,8 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
goto
nomem
;
goto
nomem
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
nomem:
nomem:
...
...
net/sctp/socket.c
View file @
381a2af8
...
@@ -244,9 +244,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
...
@@ -244,9 +244,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
if
(
!
snum
)
if
(
!
snum
)
snum
=
inet_sk
(
sk
)
->
num
;
snum
=
inet_sk
(
sk
)
->
num
;
/* Add the address to the bind address list. */
/* Add the address to the bind address list. */
sctp_local_bh_disable
();
sctp_local_bh_disable
();
sctp_write_lock
(
&
ep
->
base
.
addr_lock
);
sctp_write_lock
(
&
ep
->
base
.
addr_lock
);
...
@@ -257,7 +254,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
...
@@ -257,7 +254,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
addr
->
v4
.
sin_port
=
htons
(
addr
->
v4
.
sin_port
);
addr
->
v4
.
sin_port
=
htons
(
addr
->
v4
.
sin_port
);
if
(
!
ret
&&
!
bp
->
port
)
if
(
!
ret
&&
!
bp
->
port
)
bp
->
port
=
snum
;
bp
->
port
=
snum
;
sctp_write_unlock
(
&
ep
->
base
.
addr_lock
);
sctp_write_unlock
(
&
ep
->
base
.
addr_lock
);
sctp_local_bh_enable
();
sctp_local_bh_enable
();
...
@@ -2750,6 +2746,9 @@ int sctp_inet_listen(struct socket *sock, int backlog)
...
@@ -2750,6 +2746,9 @@ int sctp_inet_listen(struct socket *sock, int backlog)
err
=
-
EINVAL
;
err
=
-
EINVAL
;
if
(
sock
->
state
!=
SS_UNCONNECTED
)
if
(
sock
->
state
!=
SS_UNCONNECTED
)
goto
out
;
goto
out
;
if
(
unlikely
(
backlog
<
0
))
goto
out
;
switch
(
sock
->
type
)
{
switch
(
sock
->
type
)
{
case
SOCK_SEQPACKET
:
case
SOCK_SEQPACKET
:
err
=
sctp_seqpacket_listen
(
sk
,
backlog
);
err
=
sctp_seqpacket_listen
(
sk
,
backlog
);
...
@@ -3152,7 +3151,10 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
...
@@ -3152,7 +3151,10 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
return
-
EINVAL
;
return
-
EINVAL
;
/* Is this a valid SCTP address? */
/* Is this a valid SCTP address? */
if
(
!
af
->
addr_valid
((
union
sctp_addr
*
)
addr
))
if
(
!
af
->
addr_valid
(
addr
))
return
-
EINVAL
;
if
(
!
sctp_sk
(
sk
)
->
pf
->
send_verify
(
sctp_sk
(
sk
),
(
addr
)))
return
-
EINVAL
;
return
-
EINVAL
;
return
0
;
return
0
;
...
...
net/sctp/ulpevent.c
View file @
381a2af8
...
@@ -628,6 +628,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
...
@@ -628,6 +628,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
if
(
!
event
)
if
(
!
event
)
goto
fail_init
;
goto
fail_init
;
event
->
iif
=
sctp_chunk_iif
(
chunk
);
/* Note: Not clearing the entire event struct as
/* Note: Not clearing the entire event struct as
* this is just a fragment of the real event. However,
* this is just a fragment of the real event. However,
* we still need to do rwnd accounting.
* we still need to do rwnd accounting.
...
...
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