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
54bf5a09
Commit
54bf5a09
authored
Dec 22, 2002
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/sctp-2.5
parents
5e163a89
6ebf07d1
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
650 additions
and
435 deletions
+650
-435
include/linux/sysctl.h
include/linux/sysctl.h
+2
-1
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+2
-2
include/net/sctp/sm.h
include/net/sctp/sm.h
+10
-3
include/net/sctp/structs.h
include/net/sctp/structs.h
+21
-8
net/sctp/associola.c
net/sctp/associola.c
+6
-3
net/sctp/bind_addr.c
net/sctp/bind_addr.c
+2
-2
net/sctp/input.c
net/sctp/input.c
+6
-3
net/sctp/ipv6.c
net/sctp/ipv6.c
+110
-78
net/sctp/protocol.c
net/sctp/protocol.c
+106
-44
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+50
-10
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+22
-9
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+137
-57
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+1
-1
net/sctp/socket.c
net/sctp/socket.c
+135
-211
net/sctp/sysctl.c
net/sctp/sysctl.c
+5
-0
net/sctp/transport.c
net/sctp/transport.c
+1
-1
net/sctp/ulpevent.c
net/sctp/ulpevent.c
+34
-2
No files found.
include/linux/sysctl.h
View file @
54bf5a09
...
...
@@ -544,7 +544,8 @@ enum {
NET_SCTP_PATH_MAX_RETRANS
=
8
,
NET_SCTP_MAX_INIT_RETRANSMITS
=
9
,
NET_SCTP_HB_INTERVAL
=
10
,
NET_SCTP_MAX_BURST
=
11
,
NET_SCTP_PRESERVE_ENABLE
=
11
,
NET_SCTP_MAX_BURST
=
12
,
};
/* CTL_PROC names: */
...
...
include/net/sctp/sctp.h
View file @
54bf5a09
...
...
@@ -123,8 +123,8 @@ extern sctp_protocol_t sctp_proto;
extern
struct
sock
*
sctp_get_ctl_sock
(
void
);
extern
int
sctp_copy_local_addr_list
(
sctp_protocol_t
*
,
sctp_bind_addr_t
*
,
sctp_scope_t
,
int
priority
,
int
flags
);
extern
s
ctp_pf_t
*
sctp_get_pf_specific
(
in
t
family
);
extern
void
sctp_set_pf_specific
(
int
family
,
sctp_pf_t
*
);
extern
s
truct
sctp_pf
*
sctp_get_pf_specific
(
sa_family_
t
family
);
extern
int
sctp_register_pf
(
struct
sctp_pf
*
,
sa_family_t
);
/*
* sctp_socket.c
...
...
include/net/sctp/sm.h
View file @
54bf5a09
...
...
@@ -140,6 +140,8 @@ sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
sctp_state_fn_t
sctp_sf_do_5_2_4_dupcook
;
sctp_state_fn_t
sctp_sf_unk_chunk
;
sctp_state_fn_t
sctp_sf_do_8_5_1_E_sa
;
sctp_state_fn_t
sctp_sf_cookie_echoed_err
;
sctp_state_fn_t
sctp_sf_do_5_2_6_stale
;
/* Prototypes for primitive event state functions. */
sctp_state_fn_t
sctp_sf_do_prm_asoc
;
...
...
@@ -175,7 +177,6 @@ sctp_state_fn_t sctp_sf_autoclose_timer_expire;
*/
/* Prototypes for chunk state functions. Not in use. */
sctp_state_fn_t
sctp_sf_do_5_2_6_stale
;
sctp_state_fn_t
sctp_sf_do_9_2_reshutack
;
sctp_state_fn_t
sctp_sf_do_9_2_reshut
;
sctp_state_fn_t
sctp_sf_do_9_2_shutack
;
...
...
@@ -211,7 +212,7 @@ void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag);
/* Prototypes for chunk-building functions. */
sctp_chunk_t
*
sctp_make_init
(
const
sctp_association_t
*
,
const
sctp_bind_addr_t
*
,
int
priority
);
int
priority
,
int
vparam_len
);
sctp_chunk_t
*
sctp_make_init_ack
(
const
sctp_association_t
*
,
const
sctp_chunk_t
*
,
const
int
priority
,
...
...
@@ -322,9 +323,15 @@ sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *,
const
__u8
*
,
int
addrs_len
);
sctp_association_t
*
sctp_unpack_cookie
(
const
sctp_endpoint_t
*
,
const
sctp_association_t
*
,
sctp_chunk_t
*
,
int
priority
,
int
*
err
);
sctp_chunk_t
*
,
int
priority
,
int
*
err
,
sctp_chunk_t
**
err_chk_p
);
int
sctp_addip_addr_config
(
sctp_association_t
*
,
sctp_param_t
,
struct
sockaddr_storage
*
,
int
);
void
sctp_send_stale_cookie_err
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
,
sctp_cmd_seq_t
*
commands
,
sctp_chunk_t
*
err_chunk
);
/* 3rd level prototypes */
__u32
sctp_generate_tag
(
const
sctp_endpoint_t
*
);
...
...
include/net/sctp/structs.h
View file @
54bf5a09
...
...
@@ -42,6 +42,7 @@
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -182,6 +183,9 @@ struct SCTP_protocol {
/* Valid.Cookie.Life - 60 seconds */
int
valid_cookie_life
;
/* Whether Cookie Preservative is enabled(1) or not(0) */
int
cookie_preserve_enable
;
/* Association.Max.Retrans - 10 attempts
* Path.Max.Retrans - 5 attempts (per destination address)
...
...
@@ -234,7 +238,7 @@ struct SCTP_protocol {
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
*/
typedef
struct
sctp_func
{
struct
sctp_af
{
int
(
*
queue_xmit
)
(
struct
sk_buff
*
skb
);
int
(
*
setsockopt
)
(
struct
sock
*
sk
,
int
level
,
...
...
@@ -259,27 +263,34 @@ typedef struct sctp_func {
void
(
*
from_skb
)
(
union
sctp_addr
*
,
struct
sk_buff
*
skb
,
int
saddr
);
void
(
*
from_sk
)
(
union
sctp_addr
*
,
struct
sock
*
sk
);
void
(
*
to_sk
)
(
union
sctp_addr
*
,
struct
sock
*
sk
);
int
(
*
addr_valid
)
(
union
sctp_addr
*
);
sctp_scope_t
(
*
scope
)
(
union
sctp_addr
*
);
void
(
*
inaddr_any
)
(
union
sctp_addr
*
,
unsigned
short
);
int
(
*
is_any
)
(
const
union
sctp_addr
*
);
int
(
*
available
)
(
const
union
sctp_addr
*
);
__u16
net_header_len
;
int
sockaddr_len
;
sa_family_t
sa_family
;
struct
list_head
list
;
}
sctp_func_t
;
};
sctp_func_t
*
sctp_get_af_specific
(
sa_family_t
);
struct
sctp_af
*
sctp_get_af_specific
(
sa_family_t
);
int
sctp_register_af
(
struct
sctp_af
*
);
/* Protocol family functions. */
typedef
struct
sctp_pf
{
void
(
*
event_msgname
)(
sctp_ulpevent_t
*
,
char
*
,
int
*
);
void
(
*
skb_msgname
)(
struct
sk_buff
*
,
char
*
,
int
*
);
int
(
*
af_supported
)(
sa_family_t
);
void
(
*
skb_msgname
)
(
struct
sk_buff
*
,
char
*
,
int
*
);
int
(
*
af_supported
)
(
sa_family_t
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
struct
sctp_opt
*
);
struct
sctp_func
*
af
;
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
struct
sctp_af
*
af
;
}
sctp_pf_t
;
/* SCTP Socket type: UDP or TCP style. */
...
...
@@ -623,7 +634,7 @@ struct SCTP_transport {
union
sctp_addr
ipaddr
;
/* These are the functions we call to handle LLP stuff. */
s
ctp_func_t
*
af_specific
;
s
truct
sctp_af
*
af_specific
;
/* Which association do we belong to? */
sctp_association_t
*
asoc
;
...
...
@@ -1271,7 +1282,6 @@ struct SCTP_association {
/* The cookie life I award for any cookie. */
struct
timeval
cookie_life
;
__u32
cookie_preserve
;
/* Overall : The overall association error count.
* Error Count : [Clear this any time I get something.]
...
...
@@ -1350,6 +1360,9 @@ struct SCTP_association {
*/
__u32
rwnd
;
/* This is the last advertised value of rwnd over a SACK chunk. */
__u32
a_rwnd
;
/* Number of bytes by which the rwnd has slopped. The rwnd is allowed
* to slop over a maximum of the association's frag_point.
*/
...
...
net/sctp/associola.c
View file @
54bf5a09
...
...
@@ -128,8 +128,9 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc
->
state_timestamp
=
jiffies
;
/* Set things that have constant value. */
asoc
->
cookie_life
.
tv_sec
=
SCTP_DEFAULT_COOKIE_LIFE_SEC
;
asoc
->
cookie_life
.
tv_usec
=
SCTP_DEFAULT_COOKIE_LIFE_USEC
;
asoc
->
cookie_life
.
tv_sec
=
sctp_proto
.
valid_cookie_life
/
HZ
;
asoc
->
cookie_life
.
tv_usec
=
(
sctp_proto
.
valid_cookie_life
%
HZ
)
*
1000000L
/
HZ
;
asoc
->
pmtu
=
0
;
asoc
->
frag_point
=
0
;
...
...
@@ -185,6 +186,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
else
asoc
->
rwnd
=
sk
->
rcvbuf
;
asoc
->
a_rwnd
=
0
;
asoc
->
rwnd_over
=
0
;
/* Use my own max window until I learn something better. */
...
...
@@ -642,7 +645,7 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
const
union
sctp_addr
*
ss2
)
{
struct
sctp_
func
*
af
;
struct
sctp_
af
*
af
;
af
=
sctp_get_af_specific
(
ss1
->
sa
.
sa_family
);
if
(
!
af
)
...
...
net/sctp/bind_addr.c
View file @
54bf5a09
...
...
@@ -327,7 +327,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
/* Is this a wildcard address? */
int
sctp_is_any
(
const
union
sctp_addr
*
addr
)
{
struct
sctp_
func
*
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
struct
sctp_
af
*
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
if
(
!
af
)
return
0
;
return
af
->
is_any
(
addr
);
...
...
@@ -362,7 +362,7 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
/* What is the scope of 'addr'? */
sctp_scope_t
sctp_scope
(
const
union
sctp_addr
*
addr
)
{
struct
sctp_
func
*
af
;
struct
sctp_
af
*
af
;
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
if
(
!
af
)
...
...
net/sctp/input.c
View file @
54bf5a09
...
...
@@ -42,6 +42,7 @@
* Hui Huang <hui.huang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -96,7 +97,7 @@ int sctp_rcv(struct sk_buff *skb)
struct
sctphdr
*
sh
;
union
sctp_addr
src
;
union
sctp_addr
dest
;
struct
sctp_
func
*
af
;
struct
sctp_
af
*
af
;
int
ret
=
0
;
if
(
skb
->
pkt_type
!=
PACKET_HOST
)
...
...
@@ -279,6 +280,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
{
sctp_chunkhdr_t
*
ch
;
__u8
*
ch_end
;
sctp_errhdr_t
*
err
;
ch
=
(
sctp_chunkhdr_t
*
)
skb
->
data
;
...
...
@@ -308,8 +310,9 @@ int sctp_rcv_ootb(struct sk_buff *skb)
goto
discard
;
if
(
ch
->
type
==
SCTP_CID_ERROR
)
{
/* FIXME - Need to check the "Stale cookie" ERROR. */
goto
discard
;
err
=
(
sctp_errhdr_t
*
)(
ch
+
sizeof
(
sctp_chunkhdr_t
));
if
(
SCTP_ERROR_STALE_COOKIE
==
err
->
cause
)
goto
discard
;
}
ch
=
(
sctp_chunkhdr_t
*
)
ch_end
;
...
...
net/sctp/ipv6.c
View file @
54bf5a09
...
...
@@ -76,8 +76,19 @@
#include <asm/uaccess.h>
/* FIXME: Cleanup so we don't need TEST_FRAME here. */
#ifndef TEST_FRAME
extern
struct
notifier_block
sctp_inetaddr_notifier
;
/* FIXME: This macro needs to be moved to a common header file. */
#define NIP6(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
/* FIXME: Comments. */
static
inline
void
sctp_v6_err
(
struct
sk_buff
*
skb
,
struct
inet6_skb_parm
*
opt
,
...
...
@@ -92,13 +103,38 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
struct
sock
*
sk
=
skb
->
sk
;
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
flowi
fl
;
struct
dst_entry
*
dst
;
struct
dst_entry
*
dst
=
skb
->
dst
;
struct
rt6_info
*
rt6
=
(
struct
rt6_info
*
)
dst
;
struct
in6_addr
saddr
;
int
err
=
0
;
int
err
;
fl
.
proto
=
sk
->
protocol
;
fl
.
fl6_dst
=
&
np
->
daddr
;
fl
.
fl6_src
=
NULL
;
fl
.
fl6_dst
=
&
rt6
->
rt6i_dst
.
addr
;
/* FIXME: Currently, ip6_route_output() doesn't fill in the source
* address in the returned route entry. So we call ipv6_get_saddr()
* to get an appropriate source address. It is possible that this address
* may not be part of the bind address list of the association.
* Once ip6_route_ouput() is fixed so that it returns a route entry
* with an appropriate source address, the following if condition can
* be removed. With ip6_route_output() returning a source address filled
* route entry, sctp_transport_route() can do real source address
* selection for v6.
*/
if
(
ipv6_addr_any
(
&
rt6
->
rt6i_src
.
addr
))
{
err
=
ipv6_get_saddr
(
dst
,
fl
.
fl6_dst
,
&
saddr
);
if
(
err
)
{
printk
(
KERN_ERR
"%s: No saddr available for "
"DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x
\n
"
,
__FUNCTION__
,
NIP6
(
fl
.
fl6_src
));
return
err
;
}
fl
.
fl6_src
=
&
saddr
;
}
else
{
fl
.
fl6_src
=
&
rt6
->
rt6i_src
.
addr
;
}
fl
.
fl6_flowlabel
=
np
->
flow_label
;
IP6_ECN_flow_xmit
(
sk
,
fl
.
fl6_flowlabel
);
...
...
@@ -111,63 +147,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
fl
.
nl_u
.
ip6_u
.
daddr
=
rt0
->
addr
;
}
dst
=
__sk_dst_check
(
sk
,
np
->
dst_cookie
);
if
(
dst
==
NULL
)
{
dst
=
ip6_route_output
(
sk
,
&
fl
);
if
(
dst
->
error
)
{
sk
->
err_soft
=
-
dst
->
error
;
dst_release
(
dst
);
return
-
sk
->
err_soft
;
}
ip6_dst_store
(
sk
,
dst
,
NULL
);
}
skb
->
dst
=
dst_clone
(
dst
);
/* FIXME: This is all temporary until real source address
* selection is done.
*/
if
(
ipv6_addr_any
(
&
np
->
saddr
))
{
err
=
ipv6_get_saddr
(
dst
,
fl
.
fl6_dst
,
&
saddr
);
if
(
err
)
printk
(
KERN_ERR
"sctp_v6_xmit: no saddr available
\n
"
);
/* FIXME: This is a workaround until we get
* real source address selection done. This is here
* to disallow loopback when the scoping rules have
* not bound loopback to the endpoint.
*/
if
(
sctp_ipv6_addr_type
(
&
saddr
)
&
IPV6_ADDR_LOOPBACK
)
{
if
(
!
(
sctp_ipv6_addr_type
(
&
np
->
daddr
)
&
IPV6_ADDR_LOOPBACK
))
{
ipv6_addr_copy
(
&
saddr
,
&
np
->
daddr
);
}
}
fl
.
fl6_src
=
&
saddr
;
}
else
{
fl
.
fl6_src
=
&
np
->
saddr
;
}
/* Restore final destination back after routing done */
fl
.
nl_u
.
ip6_u
.
daddr
=
&
np
->
daddr
;
return
ip6_xmit
(
sk
,
skb
,
&
fl
,
np
->
opt
);
}
#endif
/* TEST_FRAME */
/* FIXME: This macro needs to be moved to a common header file. */
#define NIP6(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
/* Returns the dst cache entry for the given source and destination ip
* addresses.
...
...
@@ -176,7 +157,7 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr,
union
sctp_addr
*
saddr
)
{
struct
dst_entry
*
dst
;
struct
flowi
fl
=
{
struct
flowi
fl
=
{
.
nl_u
=
{
.
ip6_u
=
{
.
daddr
=
&
daddr
->
v6
.
sin6_addr
,
}
}
};
...
...
@@ -261,6 +242,20 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
ipv6_addr_copy
(
&
addr
->
v6
.
sin6_addr
,
from
);
}
/* Initialize an sctp_addr from a socket. */
static
void
sctp_v6_from_sk
(
union
sctp_addr
*
addr
,
struct
sock
*
sk
)
{
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_port
=
inet_sk
(
sk
)
->
num
;
addr
->
v6
.
sin6_addr
=
inet6_sk
(
sk
)
->
rcv_saddr
;
}
/* Initialize sk->rcv_saddr from sctp_addr. */
static
void
sctp_v6_to_sk
(
union
sctp_addr
*
addr
,
struct
sock
*
sk
)
{
inet6_sk
(
sk
)
->
rcv_saddr
=
addr
->
v6
.
sin6_addr
;
}
/* Initialize a sctp_addr from a dst_entry. */
static
void
sctp_v6_dst_saddr
(
union
sctp_addr
*
addr
,
struct
dst_entry
*
dst
)
{
...
...
@@ -270,15 +265,15 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst)
}
/* Compare addresses exactly. Well.. almost exactly; ignore scope_id
* for now. FIXME.
* for now. 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
)
{
int
match
;
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
match
=
!
ipv6_addr_cmp
((
struct
in6_addr
*
)
&
addr1
->
v6
.
sin6_addr
,
match
=
!
ipv6_addr_cmp
((
struct
in6_addr
*
)
&
addr1
->
v6
.
sin6_addr
,
(
struct
in6_addr
*
)
&
addr2
->
v6
.
sin6_addr
);
return
match
;
...
...
@@ -300,6 +295,22 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
return
IPV6_ADDR_ANY
==
type
;
}
/* Should this be available for binding? */
static
int
sctp_v6_available
(
const
union
sctp_addr
*
addr
)
{
int
type
;
struct
in6_addr
*
in6
=
(
struct
in6_addr
*
)
&
addr
->
v6
.
sin6_addr
;
type
=
ipv6_addr_type
(
in6
);
if
(
IPV6_ADDR_ANY
==
type
)
return
1
;
if
(
!
(
type
&
IPV6_ADDR_UNICAST
))
return
0
;
return
ipv6_chk_addr
(
in6
,
NULL
);
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
...
...
@@ -309,7 +320,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
*/
static
int
sctp_v6_addr_valid
(
union
sctp_addr
*
addr
)
{
int
ret
=
sctp_
ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
);
int
ret
=
ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
);
/* FIXME: v4-mapped-v6 address support. */
...
...
@@ -442,14 +453,14 @@ static int sctp_inet6_af_supported(sa_family_t family)
/* Address matching with wildcards allowed. This extra level
* of indirection lets us choose whether a PF_INET6 should
* disallow any v4 addresses if we so choose.
* disallow any v4 addresses if we so choose.
*/
static
int
sctp_inet6_cmp_addr
(
const
union
sctp_addr
*
addr1
,
static
int
sctp_inet6_cmp_addr
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
,
struct
sctp_opt
*
opt
)
{
struct
sctp_
func
*
af1
,
*
af2
;
struct
sctp_
af
*
af1
,
*
af2
;
af1
=
sctp_get_af_specific
(
addr1
->
sa
.
sa_family
);
af2
=
sctp_get_af_specific
(
addr2
->
sa
.
sa_family
);
...
...
@@ -461,11 +472,25 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
return
af1
->
cmp_addr
(
addr1
,
addr2
);
}
/* Verify that the provided sockaddr looks bindable. Common verification,
* has already been taken care of.
*/
static
int
sctp_inet6_bind_verify
(
struct
sctp_opt
*
opt
,
union
sctp_addr
*
addr
)
{
struct
sctp_af
*
af
;
/* ASSERT: address family has already been verified. */
if
(
addr
->
sa
.
sa_family
!=
AF_INET6
)
{
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
}
else
af
=
opt
->
pf
->
af
;
return
af
->
available
(
addr
);
}
static
struct
proto_ops
inet6_seqpacket_ops
=
{
.
family
=
PF_INET6
,
...
...
@@ -501,29 +526,33 @@ static struct inet6_protocol sctpv6_protocol = {
.
err_handler
=
sctp_v6_err
,
};
static
s
ctp_func_t
sctp_ipv6_specific
=
{
static
s
truct
sctp_af
sctp_ipv6_specific
=
{
.
queue_xmit
=
sctp_v6_xmit
,
.
setsockopt
=
ipv6_setsockopt
,
.
setsockopt
=
ipv6_setsockopt
,
.
getsockopt
=
ipv6_getsockopt
,
.
get_dst
=
sctp_v6_get_dst
,
.
copy_addrlist
=
sctp_v6_copy_addrlist
,
.
from_skb
=
sctp_v6_from_skb
,
.
from_sk
=
sctp_v6_from_sk
,
.
to_sk
=
sctp_v6_to_sk
,
.
dst_saddr
=
sctp_v6_dst_saddr
,
.
cmp_addr
=
sctp_v6_cmp_addr
,
.
scope
=
sctp_v6_scope
,
.
addr_valid
=
sctp_v6_addr_valid
,
.
inaddr_any
=
sctp_v6_inaddr_any
,
.
is_any
=
sctp_v6_is_any
,
.
available
=
sctp_v6_available
,
.
net_header_len
=
sizeof
(
struct
ipv6hdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in6
),
.
sa_family
=
AF_INET6
,
};
static
s
ctp_pf_t
sctp_pf_inet6_specific
=
{
static
s
truct
sctp_pf
sctp_pf_inet6_specific
=
{
.
event_msgname
=
sctp_inet6_event_msgname
,
.
skb_msgname
=
sctp_inet6_skb_msgname
,
.
af_supported
=
sctp_inet6_af_supported
,
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
bind_verify
=
sctp_inet6_bind_verify
,
.
af
=
&
sctp_ipv6_specific
,
};
...
...
@@ -538,11 +567,13 @@ int sctp_v6_init(void)
inet6_register_protosw
(
&
sctpv6_protosw
);
/* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific
(
PF_INET6
,
&
sctp_pf_inet6_specific
);
sctp_register_pf
(
&
sctp_pf_inet6_specific
,
PF_INET6
);
/* Register the SCTP specfic AF_INET6 functions. */
sctp_register_af
(
&
sctp_ipv6_specific
);
/* Fill in address family info. */
INIT_LIST_HEAD
(
&
sctp_ipv6_specific
.
list
);
list_add_tail
(
&
sctp_ipv6_specific
.
list
,
&
sctp_proto
.
address_families
);
/* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
return
0
;
}
...
...
@@ -553,4 +584,5 @@ void sctp_v6_exit(void)
list_del
(
&
sctp_ipv6_specific
.
list
);
inet6_del_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
);
inet6_unregister_protosw
(
&
sctpv6_protosw
);
unregister_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
}
net/sctp/protocol.c
View file @
54bf5a09
...
...
@@ -40,6 +40,7 @@
* Jon Grimm <jgrimm@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -67,8 +68,10 @@ struct sctp_mib sctp_statistics[NR_CPUS * 2];
*/
static
struct
socket
*
sctp_ctl_socket
;
static
sctp_pf_t
*
sctp_pf_inet6_specific
;
static
sctp_pf_t
*
sctp_pf_inet_specific
;
static
struct
sctp_pf
*
sctp_pf_inet6_specific
;
static
struct
sctp_pf
*
sctp_pf_inet_specific
;
static
struct
sctp_af
*
sctp_af_v4_specific
;
static
struct
sctp_af
*
sctp_af_v6_specific
;
extern
struct
net_proto_family
inet_family_ops
;
...
...
@@ -140,12 +143,12 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
{
struct
net_device
*
dev
;
struct
list_head
*
pos
;
struct
sctp_
func
*
af
;
struct
sctp_
af
*
af
;
read_lock
(
&
dev_base_lock
);
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
list_for_each
(
pos
,
&
proto
->
address_families
)
{
af
=
list_entry
(
pos
,
s
ctp_func_t
,
list
);
af
=
list_entry
(
pos
,
s
truct
sctp_af
,
list
);
af
->
copy_addrlist
(
&
proto
->
local_addr_list
,
dev
);
}
}
...
...
@@ -251,7 +254,6 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr,
return
&
rt
->
u
.
dst
;
}
/* Initialize a sctp_addr from in incoming skb. */
static
void
sctp_v4_from_skb
(
union
sctp_addr
*
addr
,
struct
sk_buff
*
skb
,
int
is_saddr
)
...
...
@@ -274,6 +276,21 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
memcpy
(
&
addr
->
v4
.
sin_addr
.
s_addr
,
from
,
sizeof
(
struct
in_addr
));
}
/* Initialize an sctp_addr from a socket. */
static
void
sctp_v4_from_sk
(
union
sctp_addr
*
addr
,
struct
sock
*
sk
)
{
addr
->
v4
.
sin_family
=
AF_INET
;
addr
->
v4
.
sin_port
=
inet_sk
(
sk
)
->
num
;
addr
->
v4
.
sin_addr
.
s_addr
=
inet_sk
(
sk
)
->
rcv_saddr
;
}
/* Initialize sk->rcv_saddr from sctp_addr. */
static
void
sctp_v4_to_sk
(
union
sctp_addr
*
addr
,
struct
sock
*
sk
)
{
inet_sk
(
sk
)
->
rcv_saddr
=
addr
->
v4
.
sin_addr
.
s_addr
;
}
/* Initialize a sctp_addr from a dst_entry. */
static
void
sctp_v4_dst_saddr
(
union
sctp_addr
*
saddr
,
struct
dst_entry
*
dst
)
{
...
...
@@ -311,7 +328,7 @@ static int sctp_v4_is_any(const union sctp_addr *addr)
}
/* This function checks if the address is a valid address to be used for
* SCTP.
* SCTP
binding
.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
...
...
@@ -326,6 +343,18 @@ static int sctp_v4_addr_valid(union sctp_addr *addr)
return
1
;
}
/* Should this be available for binding? */
static
int
sctp_v4_available
(
const
union
sctp_addr
*
addr
)
{
int
ret
=
inet_addr_type
(
addr
->
v4
.
sin_addr
.
s_addr
);
/* FIXME: ip_nonlocal_bind sysctl support. */
if
(
addr
->
v4
.
sin_addr
.
s_addr
!=
INADDR_ANY
&&
ret
!=
RTN_LOCAL
)
return
0
;
return
1
;
}
/* Checking the loopback, private and other address scopes as defined in
* RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
...
...
@@ -365,11 +394,11 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
return
retval
;
}
/* Event handler for inet
device
events.
/* Event handler for inet
address addition/deletion
events.
* Basically, whenever there is an event, we re-build our local address list.
*/
static
int
sctp_
netdev
_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
static
int
sctp_
inetaddr
_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
{
long
flags
__attribute__
((
unused
));
...
...
@@ -405,29 +434,42 @@ int sctp_ctl_sock_init(void)
return
0
;
}
/* Register address family specific functions. */
int
sctp_register_af
(
struct
sctp_af
*
af
)
{
switch
(
af
->
sa_family
)
{
case
AF_INET
:
if
(
sctp_af_v4_specific
)
return
0
;
sctp_af_v4_specific
=
af
;
break
;
case
AF_INET6
:
if
(
sctp_af_v6_specific
)
return
0
;
sctp_af_v6_specific
=
af
;
break
;
default:
return
0
;
}
INIT_LIST_HEAD
(
&
af
->
list
);
list_add_tail
(
&
af
->
list
,
&
sctp_proto
.
address_families
);
return
1
;
}
/* Get the table of functions for manipulating a particular address
* family.
*/
s
ctp_func_t
*
sctp_get_af_specific
(
sa_family_t
family
)
s
truct
sctp_af
*
sctp_get_af_specific
(
sa_family_t
family
)
{
struct
list_head
*
pos
;
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
struct
sctp_func
*
retval
,
*
af
;
retval
=
NULL
;
/* Cycle through all AF specific functions looking for a
* match.
*/
list_for_each
(
pos
,
&
proto
->
address_families
)
{
af
=
list_entry
(
pos
,
sctp_func_t
,
list
);
if
(
family
==
af
->
sa_family
)
{
retval
=
af
;
break
;
}
switch
(
family
)
{
case
AF_INET
:
return
sctp_af_v4_specific
;
case
AF_INET6
:
return
sctp_af_v6_specific
;
default:
return
NULL
;
}
return
retval
;
}
/* Common code to initialize a AF_INET msg_name. */
...
...
@@ -495,21 +537,28 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1,
return
0
;
}
/* Verify that provided sockaddr looks bindable. Common verification has
* already been taken care of.
*/
static
int
sctp_inet_bind_verify
(
struct
sctp_opt
*
opt
,
union
sctp_addr
*
addr
)
{
return
sctp_v4_available
(
addr
);
}
struct
sctp_
func
sctp_ipv4_specific
;
struct
sctp_
af
sctp_ipv4_specific
;
static
s
ctp_pf_t
sctp_pf_inet
=
{
static
s
truct
sctp_pf
sctp_pf_inet
=
{
.
event_msgname
=
sctp_inet_event_msgname
,
.
skb_msgname
=
sctp_inet_skb_msgname
,
.
af_supported
=
sctp_inet_af_supported
,
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
bind_verify
=
sctp_inet_bind_verify
,
.
af
=
&
sctp_ipv4_specific
,
};
/* Registration for netdev events. */
struct
notifier_block
sctp_netdev_notifier
=
{
.
notifier_call
=
sctp_netdev_event
,
/* Notifier for inetaddr addition/deletion events. */
struct
notifier_block
sctp_inetaddr_notifier
=
{
.
notifier_call
=
sctp_inetaddr_event
,
};
/* Socket operations. */
...
...
@@ -551,25 +600,28 @@ static struct inet_protocol sctp_protocol = {
};
/* IPv4 address related functions. */
struct
sctp_
func
sctp_ipv4_specific
=
{
struct
sctp_
af
sctp_ipv4_specific
=
{
.
queue_xmit
=
ip_queue_xmit
,
.
setsockopt
=
ip_setsockopt
,
.
getsockopt
=
ip_getsockopt
,
.
get_dst
=
sctp_v4_get_dst
,
.
copy_addrlist
=
sctp_v4_copy_addrlist
,
.
from_skb
=
sctp_v4_from_skb
,
.
from_sk
=
sctp_v4_from_sk
,
.
to_sk
=
sctp_v4_to_sk
,
.
dst_saddr
=
sctp_v4_dst_saddr
,
.
cmp_addr
=
sctp_v4_cmp_addr
,
.
addr_valid
=
sctp_v4_addr_valid
,
.
inaddr_any
=
sctp_v4_inaddr_any
,
.
is_any
=
sctp_v4_is_any
,
.
available
=
sctp_v4_available
,
.
scope
=
sctp_v4_scope
,
.
net_header_len
=
sizeof
(
struct
iphdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in
),
.
sa_family
=
AF_INET
,
};
s
ctp_pf_t
*
sctp_get_pf_specific
(
in
t
family
)
{
s
truct
sctp_pf
*
sctp_get_pf_specific
(
sa_family_
t
family
)
{
switch
(
family
)
{
case
PF_INET
:
...
...
@@ -581,20 +633,24 @@ sctp_pf_t *sctp_get_pf_specific(int family) {
}
}
/*
Set
the PF specific function table. */
void
sctp_set_pf_specific
(
int
family
,
sctp_pf_t
*
pf
)
/*
Register
the PF specific function table. */
int
sctp_register_pf
(
struct
sctp_pf
*
pf
,
sa_family_t
family
)
{
switch
(
family
)
{
case
PF_INET
:
if
(
sctp_pf_inet_specific
)
return
0
;
sctp_pf_inet_specific
=
pf
;
break
;
case
PF_INET6
:
if
(
sctp_pf_inet6_specific
)
return
0
;
sctp_pf_inet6_specific
=
pf
;
break
;
default:
BUG
();
break
;
return
0
;
}
return
1
;
}
/* Initialize the universe into something sensible. */
...
...
@@ -617,7 +673,7 @@ int sctp_init(void)
sctp_dbg_objcnt_init
();
/* Initialize the SCTP specific PF functions. */
sctp_
set_pf_specific
(
PF_INET
,
&
sctp_pf_inet
);
sctp_
register_pf
(
&
sctp_pf_inet
,
PF_INET
);
/*
* 14. Suggested SCTP Protocol Parameter Values
*/
...
...
@@ -636,6 +692,9 @@ int sctp_init(void)
/* Valid.Cookie.Life - 60 seconds */
sctp_proto
.
valid_cookie_life
=
60
*
HZ
;
/* Whether Cookie Preservative is enabled(1) or not(0) */
sctp_proto
.
cookie_preserve_enable
=
1
;
/* Max.Burst - 4 */
sctp_proto
.
max_burst
=
SCTP_MAX_BURST
;
...
...
@@ -709,8 +768,7 @@ int sctp_init(void)
sctp_sysctl_register
();
INIT_LIST_HEAD
(
&
sctp_proto
.
address_families
);
INIT_LIST_HEAD
(
&
sctp_ipv4_specific
.
list
);
list_add_tail
(
&
sctp_ipv4_specific
.
list
,
&
sctp_proto
.
address_families
);
sctp_register_af
(
&
sctp_ipv4_specific
);
status
=
sctp_v6_init
();
if
(
status
)
...
...
@@ -727,7 +785,9 @@ int sctp_init(void)
INIT_LIST_HEAD
(
&
sctp_proto
.
local_addr_list
);
sctp_proto
.
local_addr_lock
=
SPIN_LOCK_UNLOCKED
;
register_inetaddr_notifier
(
&
sctp_netdev_notifier
);
/* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier
(
&
sctp_inetaddr_notifier
);
sctp_get_local_addr_list
(
&
sctp_proto
);
return
0
;
...
...
@@ -757,8 +817,10 @@ void sctp_exit(void)
* up all the remaining associations and all that memory.
*/
/* Unregister notifier for inet address additions/deletions. */
unregister_inetaddr_notifier
(
&
sctp_inetaddr_notifier
);
/* Free the local address list. */
unregister_inetaddr_notifier
(
&
sctp_netdev_notifier
);
sctp_free_local_addr_list
(
&
sctp_proto
);
/* Free the control endpoint. */
...
...
net/sctp/sm_make_chunk.c
View file @
54bf5a09
...
...
@@ -77,13 +77,18 @@ static const sctp_supported_addrs_param_t sat_param = {
{
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES
,
__constant_htons
(
SCTP_SAT_LEN
),
},
{
/* types[] */
SCTP_PARAM_IPV4_ADDRESS
,
SCTP_V6
(
SCTP_PARAM_IPV6_ADDRESS
,)
}
};
/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above
* structure is split and the address types array is initialized using a
* fixed length array.
*/
static
const
__u16
sat_addr_types
[
2
]
=
{
SCTP_PARAM_IPV4_ADDRESS
,
SCTP_V6
(
SCTP_PARAM_IPV6_ADDRESS
,)
};
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
* Note 2: The ECN capable field is reserved for future use of
...
...
@@ -163,7 +168,7 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
*/
sctp_chunk_t
*
sctp_make_init
(
const
sctp_association_t
*
asoc
,
const
sctp_bind_addr_t
*
bp
,
int
priority
)
int
priority
,
int
vparam_len
)
{
sctp_inithdr_t
init
;
union
sctp_params
addrs
;
...
...
@@ -192,6 +197,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
chunksize
=
sizeof
(
init
)
+
addrs_len
+
SCTP_SAT_LEN
;
chunksize
+=
sizeof
(
ecap_param
);
chunksize
+=
vparam_len
;
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
...
...
@@ -213,7 +219,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
sctp_addto_chunk
(
retval
,
sizeof
(
init
),
&
init
);
retval
->
param_hdr
.
v
=
sctp_addto_chunk
(
retval
,
addrs_len
,
addrs
.
v
);
sctp_addto_chunk
(
retval
,
SCTP_SAT_LEN
,
&
sat_param
);
sctp_addto_chunk
(
retval
,
sizeof
(
sctp_paramhdr_t
),
&
sat_param
);
sctp_addto_chunk
(
retval
,
sizeof
(
sat_addr_types
),
sat_addr_types
);
sctp_addto_chunk
(
retval
,
sizeof
(
ecap_param
),
&
ecap_param
);
nodata:
...
...
@@ -1337,7 +1346,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep,
sctp_association_t
*
sctp_unpack_cookie
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
int
priority
,
int
*
error
)
int
*
error
,
sctp_chunk_t
**
err_chk_p
)
{
sctp_association_t
*
retval
=
NULL
;
sctp_signed_cookie_t
*
cookie
;
...
...
@@ -1394,7 +1403,29 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* for init collision case of lost COOKIE ACK.
*/
if
(
!
asoc
&&
tv_lt
(
bear_cookie
->
expiration
,
chunk
->
skb
->
stamp
))
{
*
error
=
-
SCTP_IERROR_STALE_COOKIE
;
/*
* Section 3.3.10.3 Stale Cookie Error (3)
*
* Cause of error
* ---------------
* Stale Cookie Error: Indicates the receipt of a valid State
* Cookie that has expired.
*/
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
ntohs
(
chunk
->
chunk_hdr
->
length
));
if
(
*
err_chk_p
)
{
suseconds_t
usecs
=
(
chunk
->
skb
->
stamp
.
tv_sec
-
bear_cookie
->
expiration
.
tv_sec
)
*
1000000L
+
chunk
->
skb
->
stamp
.
tv_usec
-
bear_cookie
->
expiration
.
tv_usec
;
usecs
=
htonl
(
usecs
);
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_STALE_COOKIE
,
&
usecs
,
sizeof
(
usecs
));
*
error
=
-
SCTP_IERROR_STALE_COOKIE
;
}
else
*
error
=
-
SCTP_IERROR_NOMEM
;
goto
fail
;
}
...
...
@@ -1751,6 +1782,7 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
__u16
sat
;
int
retval
=
1
;
sctp_scope_t
scope
;
time_t
stale
;
/* We maintain all INIT parameters in network byte order all the
* time. This allows us to not worry about whether the parameters
...
...
@@ -1770,8 +1802,16 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
break
;
case
SCTP_PARAM_COOKIE_PRESERVATIVE
:
asoc
->
cookie_preserve
=
ntohl
(
param
.
life
->
lifespan_increment
);
if
(
!
sctp_proto
.
cookie_preserve_enable
)
break
;
stale
=
ntohl
(
param
.
life
->
lifespan_increment
);
/* Suggested Cookie Life span increment's unit is msec,
* (1/1000sec).
*/
asoc
->
cookie_life
.
tv_sec
+=
stale
/
1000
;
asoc
->
cookie_life
.
tv_usec
+=
(
stale
%
1000
)
*
1000
;
break
;
case
SCTP_PARAM_HOST_NAME_ADDRESS
:
...
...
net/sctp/sm_sideeffect.c
View file @
54bf5a09
...
...
@@ -68,7 +68,8 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
sctp_transport_t
*
transport
);
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
);
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
sctp_event_t
event_type
,
sctp_chunk_t
*
chunk
);
sctp_event_t
event_type
,
sctp_subtype_t
stype
,
sctp_chunk_t
*
chunk
);
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
...
...
@@ -517,7 +518,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case
SCTP_CMD_ASSOC_FAILED
:
sctp_cmd_assoc_failed
(
commands
,
asoc
,
event_type
,
chunk
);
subtype
,
chunk
);
break
;
case
SCTP_CMD_COUNTER_INC
:
...
...
@@ -736,6 +737,9 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
if
(
!
sack
)
goto
nomem
;
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
...
...
@@ -1046,18 +1050,27 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
asoc
,
sctp_event_t
event_type
,
sctp_subtype_t
subtype
,
sctp_chunk_t
*
chunk
)
{
sctp_ulpevent_t
*
event
;
__u16
error
=
0
;
if
(
event_type
==
SCTP_EVENT_T_PRIMITIVE
)
error
=
SCTP_ERROR_USER_ABORT
;
if
(
chunk
&&
(
SCTP_CID_ABORT
==
chunk
->
chunk_hdr
->
type
)
&&
(
ntohs
(
chunk
->
chunk_hdr
->
length
)
>=
(
sizeof
(
struct
sctp_chunkhdr
)
+
sizeof
(
struct
sctp_errhdr
))))
{
error
=
((
sctp_errhdr_t
*
)
chunk
->
skb
->
data
)
->
cause
;
switch
(
event_type
)
{
case
SCTP_EVENT_T_PRIMITIVE
:
if
(
SCTP_PRIMITIVE_ABORT
==
subtype
.
primitive
)
error
=
SCTP_ERROR_USER_ABORT
;
break
;
case
SCTP_EVENT_T_CHUNK
:
if
(
chunk
&&
(
SCTP_CID_ABORT
==
chunk
->
chunk_hdr
->
type
)
&&
(
ntohs
(
chunk
->
chunk_hdr
->
length
)
>=
(
sizeof
(
struct
sctp_chunkhdr
)
+
sizeof
(
struct
sctp_errhdr
))))
{
error
=
((
sctp_errhdr_t
*
)
chunk
->
skb
->
data
)
->
cause
;
}
break
;
default:
break
;
}
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
...
...
net/sctp/sm_statefuns.c
View file @
54bf5a09
...
...
@@ -2,6 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2002 Nokia Corp.
*
* This file is part of the SCTP kernel reference Implementation
...
...
@@ -502,6 +503,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_chunk_t
*
repl
;
sctp_ulpevent_t
*
ev
;
int
error
=
0
;
sctp_chunk_t
*
err_chk_p
;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, responding with an ABORT.
...
...
@@ -521,7 +523,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
* "Z" will reply with a COOKIE ACK chunk after building a TCB
* and moving to the ESTABLISHED state.
*/
new_asoc
=
sctp_unpack_cookie
(
ep
,
asoc
,
chunk
,
GFP_ATOMIC
,
&
error
);
new_asoc
=
sctp_unpack_cookie
(
ep
,
asoc
,
chunk
,
GFP_ATOMIC
,
&
error
,
&
err_chk_p
);
/* FIXME:
* If the re-build failed, what is the proper error path
...
...
@@ -537,6 +540,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
case
-
SCTP_IERROR_NOMEM
:
goto
nomem
;
case
-
SCTP_IERROR_STALE_COOKIE
:
sctp_send_stale_cookie_err
(
ep
,
asoc
,
chunk
,
commands
,
err_chk_p
);
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
case
-
SCTP_IERROR_BAD_SIG
:
default:
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
...
@@ -862,8 +870,8 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
/* Check if the timestamp looks valid. */
if
(
time_after
(
hbinfo
->
sent_at
,
jiffies
)
||
time_after
(
jiffies
,
hbinfo
->
sent_at
+
max_interval
))
{
SCTP_DEBUG_PRINTK
(
"%s: HEARTBEAT ACK with invalid timestamp
received for transport: %p
\n
"
,
SCTP_DEBUG_PRINTK
(
"%s: HEARTBEAT ACK with invalid timestamp
"
"
received for transport: %p
\n
"
,
__FUNCTION__
,
link
);
return
SCTP_DISPOSITION_DISCARD
;
}
...
...
@@ -1562,6 +1570,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
sctp_association_t
*
new_asoc
;
int
error
=
0
;
char
action
;
sctp_chunk_t
*
err_chk_p
;
/* "Decode" the chunk. We have no optional parameters so we
* are in good shape.
...
...
@@ -1575,7 +1584,8 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
* current association, consider the State Cookie valid even if
* the lifespan is exceeded.
*/
new_asoc
=
sctp_unpack_cookie
(
ep
,
asoc
,
chunk
,
GFP_ATOMIC
,
&
error
);
new_asoc
=
sctp_unpack_cookie
(
ep
,
asoc
,
chunk
,
GFP_ATOMIC
,
&
error
,
&
err_chk_p
);
/* FIXME:
* If the re-build failed, what is the proper error path
...
...
@@ -1591,6 +1601,12 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
case
-
SCTP_IERROR_NOMEM
:
goto
nomem
;
case
-
SCTP_IERROR_STALE_COOKIE
:
sctp_send_stale_cookie_err
(
ep
,
asoc
,
chunk
,
commands
,
err_chk_p
);
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
break
;
case
-
SCTP_IERROR_BAD_SIG
:
default:
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
...
...
@@ -1706,7 +1722,47 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep,
return
sctp_sf_shutdown_sent_abort
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
#if 0
/*
* Handle an Error received in COOKIE_ECHOED state.
*
* Only handle the error type of stale COOKIE Error, the other errors will
* be ignored.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t
sctp_sf_cookie_echoed_err
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_errhdr_t
*
err
;
/* If we have gotten too many failures, give up. */
if
(
1
+
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
>
asoc
->
max_init_attempts
)
{
/* INIT_FAILED will issue an ulpevent. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
}
err
=
(
sctp_errhdr_t
*
)(
chunk
->
skb
->
data
);
/* Process the error here */
switch
(
err
->
cause
)
{
case
SCTP_ERROR_STALE_COOKIE
:
return
sctp_sf_do_5_2_6_stale
(
ep
,
asoc
,
type
,
arg
,
commands
);
default:
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
}
/*
* Handle a Stale COOKIE Error
*
...
...
@@ -1732,47 +1788,30 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep,
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
sctp_disposition_t
sctp_sf_
do_5_2_6_stale
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_chunk_t
*
chunk
=
arg
;
time_t
stale
;
sctp_cookie_preserve_param_t
bht
;
sctp_errhdr_t
*
err
;
struct
list_head
*
pos
;
sctp_transport_t
*
t
;
sctp_chunk_t
*
reply
;
sctp_bind_addr_t
*
bp
;
int
attempts
;
/* This is not a real chunk type. It is a subtype of the
* ERROR chunk type. The ERROR chunk processing will bring us
* here.
*/
sctp_chunk_t *in_packet;
stp_chunk_t *reply;
sctp_inithdr_t initack;
__u8 *addrs;
int addrs_len;
time_t rtt;
struct sctpCookiePreserve bht;
attempts
=
asoc
->
counters
[
SCTP_COUNTER_INIT_ERROR
]
+
1
;
/* If we have gotten too many failures, give up. */
if (1 + asoc->counters[SctpCounterInits] > asoc->max_init_attempts) {
/* FIXME: Move to new ulpevent. */
retval->event_up = sctp_make_ulp_init_timeout(asoc);
if (!retval->event_up)
goto nomem;
sctp_add_cmd_sf(retval->commands, SCTP_CMD_DELETE_TCB,
SCTP_NULL());
if
(
attempts
>=
asoc
->
max_init_attempts
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_INIT_FAILED
,
SCTP_NULL
());
return
SCTP_DISPOSITION_DELETE_TCB
;
}
retval->counters[0] = SCTP_COUNTER_INCR;
retval->counters[0] = SctpCounterInits;
retval->counters[1] = 0;
retval->counters[1] = 0;
/* Calculate the RTT in ms. */
/* BUG--we should get the send time of the HEARTBEAT REQUEST. */
in_packet = chunk;
rtt = 1000 * timeval_sub(in_packet->skb->stamp,
asoc->c.state_timestamp);
err
=
(
sctp_errhdr_t
*
)(
chunk
->
skb
->
data
);
/* When calculating the time extension, an implementation
* SHOULD use the RTT information measured based on the
...
...
@@ -1780,28 +1819,48 @@ sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep,
* more than 1 second beyond the measured RTT, due to long
* State Cookie lifetimes making the endpoint more subject to
* a replay attack.
* Measure of Staleness's unit is usec. (1/1000000 sec)
* Suggested Cookie Life-span Increment's unit is msec.
* (1/1000 sec)
* In general, if you use the suggested cookie life, the value
* found in the field of measure of staleness should be doubled
* to give ample time to retransmit the new cookie and thus
* yield a higher probability of success on the reattempt.
*/
bht.p = {SCTP_COOKIE_PRESERVE, 8}
;
bht.extraTime = htonl(rtt + 1000)
;
stale
=
ntohl
(
*
(
suseconds_t
*
)((
u8
*
)
err
+
sizeof
(
sctp_errhdr_t
)))
;
stale
=
stale
<<
1
/
1000
;
initack.init_tag = htonl(asoc->c.my_vtag);
initack.a_rwnd = htonl(atomic_read(&asoc->rnwd));
initack.num_outbound_streams = htons(asoc->streamoutcnt);
initack.num_inbound_streams = htons(asoc->streamincnt);
initack.initial_tsn = htonl(asoc->c.initSeqNumber);
sctp_get_my_addrs(asoc, &addrs, &addrs_len);
bht
.
param_hdr
.
type
=
SCTP_PARAM_COOKIE_PRESERVATIVE
;
bht
.
param_hdr
.
length
=
htons
(
sizeof
(
bht
));
bht
.
lifespan_increment
=
htonl
(
stale
);
/* Build that new INIT chunk. */
reply = sctp_make_chunk(SCTP_INITIATION, 0,
sizeof(initack)
+ sizeof(bht)
+ addrs_len);
bp
=
(
sctp_bind_addr_t
*
)
&
asoc
->
base
.
bind_addr
;
reply
=
sctp_make_init
(
asoc
,
bp
,
GFP_ATOMIC
,
sizeof
(
bht
));
if
(
!
reply
)
goto
nomem
;
sctp_addto_chunk(reply, sizeof(initack), &initack);
sctp_addto_chunk
(
reply
,
sizeof
(
bht
),
&
bht
);
sctp_addto_chunk(reply, addrs_len, addrs);
/* Cast away the const modifier, as we want to just
* rerun it through as a sideffect.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_COUNTER_INC
,
SCTP_COUNTER
(
SCTP_COUNTER_INIT_ERROR
));
/* If we've sent any data bundled with COOKIE-ECHO we need to resend. */
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_RETRAN
,
SCTP_TRANSPORT
(
t
));
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_STOP
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_COOKIE
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_COOKIE_WAIT
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TIMER_START
,
SCTP_TO
(
SCTP_EVENT_TIMEOUT_T1_INIT
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
return
SCTP_DISPOSITION_CONSUME
;
...
...
@@ -1809,7 +1868,6 @@ sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep,
nomem:
return
SCTP_DISPOSITION_NOMEM
;
}
#endif /* 0 */
/*
* Process an ABORT.
...
...
@@ -3220,7 +3278,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
* 1 to 4294967295 (see 5.3.1 for Tag value selection). ...
*/
repl
=
sctp_make_init
(
asoc
,
bp
,
GFP_ATOMIC
);
repl
=
sctp_make_init
(
asoc
,
bp
,
GFP_ATOMIC
,
0
);
if
(
!
repl
)
goto
nomem
;
...
...
@@ -3992,7 +4050,7 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
switch
(
timer
)
{
case
SCTP_EVENT_TIMEOUT_T1_INIT
:
bp
=
(
sctp_bind_addr_t
*
)
&
asoc
->
base
.
bind_addr
;
repl
=
sctp_make_init
(
asoc
,
bp
,
GFP_ATOMIC
);
repl
=
sctp_make_init
(
asoc
,
bp
,
GFP_ATOMIC
,
0
);
break
;
case
SCTP_EVENT_TIMEOUT_T1_COOKIE
:
...
...
@@ -4334,3 +4392,25 @@ void sctp_ootb_pkt_free(sctp_packet_t *packet)
sctp_transport_free
(
packet
->
transport
);
sctp_packet_free
(
packet
);
}
/* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */
void
sctp_send_stale_cookie_err
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
,
sctp_cmd_seq_t
*
commands
,
sctp_chunk_t
*
err_chunk
)
{
sctp_packet_t
*
packet
;
if
(
err_chunk
)
{
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
if
(
packet
)
{
/* Set the skb to the belonging sock for accounting. */
err_chunk
->
skb
->
sk
=
ep
->
base
.
sk
;
sctp_packet_append_chunk
(
packet
,
err_chunk
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
}
else
sctp_free_chunk
(
err_chunk
);
}
}
net/sctp/sm_statetable.c
View file @
54bf5a09
...
...
@@ -295,7 +295,7 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
cookie_echoed_err, .name = "sctp_sf_cookie_echoed_err
"}, \
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_operr_notify, .name = "sctp_sf_operr_notify"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
...
...
net/sctp/socket.c
View file @
54bf5a09
...
...
@@ -87,12 +87,7 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
int
msg_len
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
sctp_association_t
*
asoc
,
long
*
timeo_p
);
static
inline
void
sctp_sk_addr_set
(
struct
sock
*
,
const
union
sctp_addr
*
newaddr
,
union
sctp_addr
*
saveaddr
);
static
inline
void
sctp_sk_addr_restore
(
struct
sock
*
,
const
union
sctp_addr
*
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
struct
sockaddr
*
,
int
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
...
...
@@ -133,101 +128,75 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return
retval
;
}
static
long
sctp_get_port_local
(
struct
sock
*
,
un
signed
short
);
static
long
sctp_get_port_local
(
struct
sock
*
,
un
ion
sctp_addr
*
);
/*
Bind a local address either to an endpoint or to an association.
*/
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
newaddr
,
int
addr_
len
)
/*
Verify this is a valid sockaddr.
*/
static
struct
sctp_af
*
sctp_sockaddr_af
(
struct
sctp_opt
*
opt
,
union
sctp_addr
*
addr
,
int
len
)
{
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
unsigned
short
sa_family
=
newaddr
->
sa
.
sa_family
;
union
sctp_addr
tmpaddr
,
saveaddr
;
unsigned
short
*
snum
;
int
ret
=
0
;
struct
sctp_af
*
af
;
SCTP_DEBUG_PRINTK
(
"sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)
\n
"
,
sk
,
newaddr
,
addr_len
);
/* FIXME: This function needs to handle v4-mapped-on-v6
* addresses!
*/
if
(
PF_INET
==
sk
->
family
)
{
if
(
sa_family
!=
AF_INET
)
return
-
EINVAL
;
}
/* Check minimum size. */
if
(
len
<
sizeof
(
struct
sockaddr
))
return
NULL
;
/* Make a local copy of the new address. */
tmpaddr
=
*
newaddr
;
/* Does this PF support this AF? */
if
(
!
opt
->
pf
->
af_supported
(
addr
->
sa
.
sa_family
))
return
NULL
;
switch
(
sa_family
)
{
case
AF_INET
:
if
(
addr_len
<
sizeof
(
struct
sockaddr_in
))
return
-
EINVAL
;
/* If we get this far, af is valid. */
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
ret
=
inet_addr_type
(
newaddr
->
v4
.
sin_addr
.
s_addr
);
if
(
len
<
af
->
sockaddr_len
)
return
NULL
;
/* FIXME:
* Should we allow apps to bind to non-local addresses by
* checking the IP sysctl parameter "ip_nonlocal_bind"?
*/
if
(
newaddr
->
v4
.
sin_addr
.
s_addr
!=
INADDR_ANY
&&
ret
!=
RTN_LOCAL
)
return
-
EADDRNOTAVAIL
;
return
af
;
}
tmpaddr
.
v4
.
sin_port
=
htons
(
tmpaddr
.
v4
.
sin_port
);
snum
=
&
tmpaddr
.
v4
.
sin_port
;
break
;
case
AF_INET6
:
SCTP_V6
(
/* FIXME: Hui, please verify this. Looking at
* the ipv6 code I see a SIN6_LEN_RFC2133 check.
* I'm guessing that scope_id is a newer addition.
*/
if
(
addr_len
<
sizeof
(
struct
sockaddr_in6
))
return
-
EINVAL
;
/* Bind a local address either to an endpoint or to an association. */
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
,
int
len
)
{
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
struct
sctp_af
*
af
;
unsigned
short
snum
;
int
ret
=
0
;
/* FIXME - The support for IPv6 multiple types
* of addresses need to be added later.
*/
ret
=
sctp_ipv6_addr_type
(
&
newaddr
->
v6
.
sin6_addr
);
tmpaddr
.
v6
.
sin6_port
=
htons
(
tmpaddr
.
v6
.
sin6_port
);
snum
=
&
tmpaddr
.
v6
.
sin6_port
;
break
;
)
SCTP_DEBUG_PRINTK
(
"sctp_do_bind(sk: %p, newaddr: %p, len: %d)
\n
"
,
sk
,
addr
,
len
);
default:
/* Common sockaddr verification. */
af
=
sctp_sockaddr_af
(
sp
,
addr
,
len
);
if
(
!
af
)
return
-
EINVAL
;
};
/* PF specific bind() address verification. */
if
(
!
sp
->
pf
->
bind_verify
(
sp
,
addr
))
return
-
EADDRNOTAVAIL
;
snum
=
ntohs
(
addr
->
v4
.
sin_port
);
SCTP_DEBUG_PRINTK
(
"sctp_do_bind: port: %d, new port: %d
\n
"
,
bp
->
port
,
*
snum
);
bp
->
port
,
snum
);
/* We must either be unbound, or bind to the same port. */
if
(
bp
->
port
&&
(
*
snum
!=
bp
->
port
))
{
if
(
bp
->
port
&&
(
snum
!=
bp
->
port
))
{
SCTP_DEBUG_PRINTK
(
"sctp_do_bind:"
" New port %d does not match existing port "
"%d.
\n
"
,
*
snum
,
bp
->
port
);
"%d.
\n
"
,
snum
,
bp
->
port
);
return
-
EINVAL
;
}
if
(
*
snum
&&
*
snum
<
PROT_SOCK
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
if
(
snum
&&
snum
<
PROT_SOCK
&&
!
capable
(
CAP_NET_BIND_SERVICE
))
return
-
EACCES
;
/* FIXME - Make socket understand that there might be multiple bind
* addresses and there will be multiple source addresses involved in
* routing and failover decisions.
*/
sctp_sk_addr_set
(
sk
,
&
tmpaddr
,
&
saveaddr
);
/* Make sure we are allowed to bind here.
* The function sctp_get_port_local() does duplicate address
* detection.
*/
if
((
ret
=
sctp_get_port_local
(
sk
,
*
snum
)))
{
sctp_sk_addr_restore
(
sk
,
&
saveaddr
);
if
((
ret
=
sctp_get_port_local
(
sk
,
addr
)))
{
if
(
ret
==
(
long
)
sk
)
{
/* This endpoint has a conflicting address. */
return
-
EINVAL
;
...
...
@@ -237,25 +206,32 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr,
}
/* Refresh ephemeral port. */
if
(
!*
snum
)
*
snum
=
inet_sk
(
sk
)
->
num
;
if
(
!
snum
)
snum
=
inet_sk
(
sk
)
->
num
;
/* The getsockname() API depends on 'sport' being set. */
inet_sk
(
sk
)
->
sport
=
htons
(
inet_sk
(
sk
)
->
num
);
/* Add the address to the bind address list. */
sctp_local_bh_disable
();
sctp_write_lock
(
&
ep
->
base
.
addr_lock
);
/* Use GFP_ATOMIC since BHs are disabled. */
if
((
ret
=
sctp_add_bind_addr
(
bp
,
&
tmpaddr
,
GFP_ATOMIC
)))
{
sctp_sk_addr_restore
(
sk
,
&
saveaddr
);
}
else
if
(
!
bp
->
port
)
{
bp
->
port
=
*
snum
;
}
addr
->
v4
.
sin_port
=
ntohs
(
addr
->
v4
.
sin_port
);
ret
=
sctp_add_bind_addr
(
bp
,
addr
,
GFP_ATOMIC
);
addr
->
v4
.
sin_port
=
htons
(
addr
->
v4
.
sin_port
);
if
(
!
ret
&&
!
bp
->
port
)
bp
->
port
=
snum
;
sctp_write_unlock
(
&
ep
->
base
.
addr_lock
);
sctp_local_bh_enable
();
/* Copy back into socket for getsockname() use. */
if
(
!
ret
)
{
inet_sk
(
sk
)
->
sport
=
htons
(
inet_sk
(
sk
)
->
num
);
af
->
to_sk
(
addr
,
sk
);
}
return
ret
;
}
...
...
@@ -735,7 +711,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
SCTP_STATIC
int
sctp_msghdr_parse
(
const
struct
msghdr
*
,
sctp_cmsgs_t
*
);
SCTP_STATIC
int
sctp_sendmsg
(
struct
kiocb
*
iocb
,
struct
sock
*
sk
,
struct
msghdr
*
msg
,
int
size
)
struct
msghdr
*
msg
,
int
msg_len
)
{
sctp_opt_t
*
sp
;
sctp_endpoint_t
*
ep
;
...
...
@@ -750,13 +726,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_assoc_t
associd
=
NULL
;
sctp_cmsgs_t
cmsgs
=
{
0
};
int
err
;
size_t
msg_len
;
sctp_scope_t
scope
;
long
timeo
;
__u16
sinfo_flags
=
0
;
SCTP_DEBUG_PRINTK
(
"sctp_sendmsg(sk: %p, msg: %p,
"
"size: %d)
\n
"
,
sk
,
msg
,
size
);
SCTP_DEBUG_PRINTK
(
"sctp_sendmsg(sk: %p, msg: %p,
msg_len: %d)
\n
"
,
sk
,
msg
,
msg_len
);
err
=
0
;
sp
=
sctp_sk
(
sk
);
...
...
@@ -778,12 +753,16 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
* For a peeled-off socket, msg_name is ignored.
*/
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sp
->
type
)
&&
msg
->
msg_name
)
{
err
=
sctp_verify_addr
(
sk
,
(
struct
sockaddr
*
)
msg
->
msg_name
,
msg
->
msg_namelen
);
int
msg_namelen
=
msg
->
msg_namelen
;
err
=
sctp_verify_addr
(
sk
,
(
union
sctp_addr
*
)
msg
->
msg_name
,
msg_namelen
);
if
(
err
)
return
err
;
memcpy
(
&
to
,
msg
->
msg_name
,
msg
->
msg_namelen
);
if
(
msg_namelen
>
sizeof
(
to
))
msg_namelen
=
sizeof
(
to
);
memcpy
(
&
to
,
msg
->
msg_name
,
msg_namelen
);
SCTP_DEBUG_PRINTK
(
"Just memcpy'd. msg_name is "
"0x%x:%u.
\n
"
,
to
.
v4
.
sin_addr
.
s_addr
,
to
.
v4
.
sin_port
);
...
...
@@ -792,8 +771,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
msg_name
=
msg
->
msg_name
;
}
msg_len
=
get_user_iov_size
(
msg
->
msg_iov
,
msg
->
msg_iovlen
);
sinfo
=
cmsgs
.
info
;
sinit
=
cmsgs
.
init
;
...
...
@@ -1216,9 +1193,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
* Otherwise, set MSG_EOR indicating the end of a message.
*/
if
(
skb_len
>
copied
)
{
msg
->
msg_flags
&=
~
MSG_EOR
;
if
(
flags
&
MSG_PEEK
)
goto
out_free
;
sctp_skb_pull
(
skb
,
copied
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
msg
->
msg_flags
&=
~
MSG_EOR
;
goto
out
;
}
else
{
msg
->
msg_flags
|=
MSG_EOR
;
...
...
@@ -1335,6 +1314,16 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
return
0
;
}
static
inline
int
sctp_setsockopt_initmsg
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
if
(
optlen
!=
sizeof
(
struct
sctp_initmsg
))
return
-
EINVAL
;
if
(
copy_from_user
(
&
sctp_sk
(
sk
)
->
initmsg
,
optval
,
optlen
))
return
-
EFAULT
;
return
0
;
}
/* API 6.2 setsockopt(), getsockopt()
*
* Applications use setsockopt() and getsockopt() to set or retrieve
...
...
@@ -1355,13 +1344,10 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
* optlen - the size of the buffer.
*/
SCTP_STATIC
int
sctp_setsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
optlen
)
char
*
optval
,
int
optlen
)
{
int
retval
=
0
;
char
*
tmp
;
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
struct
list_head
*
pos
;
sctp_func_t
*
af
;
SCTP_DEBUG_PRINTK
(
"sctp_setsockopt(sk: %p... optname: %d)
\n
"
,
sk
,
optname
);
...
...
@@ -1373,14 +1359,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
* are at all well-founded.
*/
if
(
level
!=
SOL_SCTP
)
{
list_for_each
(
pos
,
&
proto
->
address_families
)
{
af
=
list_entry
(
pos
,
sctp_func_t
,
list
);
retval
=
af
->
setsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
if
(
retval
<
0
)
goto
out_nounlock
;
}
struct
sctp_af
*
af
=
sctp_sk
(
sk
)
->
pf
->
af
;
retval
=
af
->
setsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
goto
out_nounlock
;
}
sctp_lock_sock
(
sk
);
...
...
@@ -1430,6 +1411,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
optlen
);
break
;
case
SCTP_INITMSG
:
retval
=
sctp_setsockopt_initmsg
(
sk
,
optval
,
optlen
);
break
;
default:
retval
=
-
ENOPROTOOPT
;
break
;
...
...
@@ -1484,7 +1469,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
goto
out_unlock
;
}
err
=
sctp_verify_addr
(
sk
,
uaddr
,
addr_len
);
err
=
sctp_verify_addr
(
sk
,
(
union
sctp_addr
*
)
uaddr
,
addr_len
);
if
(
err
)
goto
out_unlock
;
...
...
@@ -1938,13 +1923,19 @@ static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
return
0
;
}
static
inline
int
sctp_getsockopt_initmsg
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
if
(
len
!=
sizeof
(
struct
sctp_initmsg
))
return
-
EINVAL
;
if
(
copy_to_user
(
optval
,
&
sctp_sk
(
sk
)
->
initmsg
,
len
))
return
-
EFAULT
;
return
0
;
}
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
{
int
retval
=
0
;
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
sctp_func_t
*
af
;
struct
list_head
*
pos
;
int
len
;
SCTP_DEBUG_PRINTK
(
"sctp_getsockopt(sk: %p, ...)
\n
"
,
sk
);
...
...
@@ -1956,13 +1947,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
* are at all well-founded.
*/
if
(
level
!=
SOL_SCTP
)
{
list_for_each
(
pos
,
&
proto
->
address_families
)
{
af
=
list_entry
(
pos
,
sctp_func_t
,
list
);
retval
=
af
->
getsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
if
(
retval
<
0
)
return
retval
;
}
struct
sctp_af
*
af
=
sctp_sk
(
sk
)
->
pf
->
af
;
retval
=
af
->
getsockopt
(
sk
,
level
,
optname
,
optval
,
optlen
);
return
retval
;
}
if
(
get_user
(
len
,
optlen
))
...
...
@@ -1997,6 +1985,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
optlen
);
break
;
case
SCTP_INITMSG
:
retval
=
sctp_getsockopt_initmsg
(
sk
,
len
,
optval
,
optlen
);
break
;
default:
retval
=
-
ENOPROTOOPT
;
break
;
...
...
@@ -2030,12 +2022,17 @@ static void sctp_unhash(struct sock *sk)
*/
static
sctp_bind_bucket_t
*
sctp_bucket_create
(
sctp_bind_hashbucket_t
*
head
,
unsigned
short
snum
);
static
long
sctp_get_port_local
(
struct
sock
*
sk
,
un
signed
short
snum
)
static
long
sctp_get_port_local
(
struct
sock
*
sk
,
un
ion
sctp_addr
*
addr
)
{
sctp_bind_hashbucket_t
*
head
;
/* hash list */
sctp_bind_bucket_t
*
pp
;
/* hash list port iterator */
sctp_protocol_t
*
sctp
=
sctp_get_protocol
();
unsigned
short
snum
;
int
ret
;
/* NOTE: Remember to put this back to net order. */
addr
->
v4
.
sin_port
=
ntohs
(
addr
->
v4
.
sin_port
);
snum
=
addr
->
v4
.
sin_port
;
SCTP_DEBUG_PRINTK
(
"sctp_get_port() begins, snum=%d
\n
"
,
snum
);
...
...
@@ -2101,6 +2098,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
}
}
if
(
pp
!=
NULL
&&
pp
->
sk
!=
NULL
)
{
/* We had a port hash table hit - there is an
* available port (pp != NULL) and it is being
...
...
@@ -2108,7 +2106,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* socket is going to be sk2.
*/
int
sk_reuse
=
sk
->
reuse
;
union
sctp_addr
tmpaddr
;
struct
sock
*
sk2
=
pp
->
sk
;
SCTP_DEBUG_PRINTK
(
"sctp_get_port() found a "
...
...
@@ -2116,27 +2113,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
if
(
pp
->
fastreuse
!=
0
&&
sk
->
reuse
!=
0
)
goto
success
;
/* FIXME - multiple addresses need to be supported
* later.
*/
switch
(
sk
->
family
)
{
case
PF_INET
:
tmpaddr
.
v4
.
sin_family
=
AF_INET
;
tmpaddr
.
v4
.
sin_port
=
snum
;
tmpaddr
.
v4
.
sin_addr
.
s_addr
=
inet_sk
(
sk
)
->
rcv_saddr
;
break
;
case
PF_INET6
:
SCTP_V6
(
tmpaddr
.
v6
.
sin6_family
=
AF_INET6
;
tmpaddr
.
v6
.
sin6_port
=
snum
;
tmpaddr
.
v6
.
sin6_addr
=
inet6_sk
(
sk
)
->
rcv_saddr
;
)
break
;
default:
break
;
};
/* Run through the list of sockets bound to the port
* (pp->port) [via the pointers bind_next and
* bind_pprev in the struct sock *sk2 (pp->sk)]. On each one,
...
...
@@ -2154,8 +2130,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
if
(
sk_reuse
&&
sk2
->
reuse
)
continue
;
if
(
sctp_bind_addr_match
(
&
ep2
->
base
.
bind_addr
,
&
tmpaddr
,
if
(
sctp_bind_addr_match
(
&
ep2
->
base
.
bind_addr
,
addr
,
sctp_sk
(
sk
)))
goto
found
;
}
...
...
@@ -2207,12 +2182,25 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
sctp_local_bh_enable
();
SCTP_DEBUG_PRINTK
(
"sctp_get_port() ends, ret=%d
\n
"
,
ret
);
addr
->
v4
.
sin_port
=
htons
(
addr
->
v4
.
sin_port
);
return
ret
;
}
/* Assign a 'snum' port to the socket. If snum == 0, an ephemeral
* port is requested.
*/
static
int
sctp_get_port
(
struct
sock
*
sk
,
unsigned
short
snum
)
{
long
ret
=
sctp_get_port_local
(
sk
,
snum
);
long
ret
;
union
sctp_addr
addr
;
struct
sctp_af
*
af
=
sctp_sk
(
sk
)
->
pf
->
af
;
/* Set up a dummy address struct from the sk. */
af
->
from_sk
(
&
addr
,
sk
);
addr
.
v4
.
sin_port
=
htons
(
snum
);
/* Note: sk->num gets filled in if ephemeral port request. */
ret
=
sctp_get_port_local
(
sk
,
&
addr
);
return
(
ret
?
1
:
0
);
}
...
...
@@ -2413,7 +2401,7 @@ void sctp_put_port(struct sock *sk)
static
int
sctp_autobind
(
struct
sock
*
sk
)
{
union
sctp_addr
autoaddr
;
struct
sctp_
func
*
af
;
struct
sctp_
af
*
af
;
unsigned
short
port
;
/* Initialize a local sockaddr structure to INADDR_ANY. */
...
...
@@ -2537,58 +2525,6 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
return
0
;
}
/* Setup sk->rcv_saddr before calling get_port(). */
static
inline
void
sctp_sk_addr_set
(
struct
sock
*
sk
,
const
union
sctp_addr
*
newaddr
,
union
sctp_addr
*
saveaddr
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
saveaddr
->
sa
.
sa_family
=
newaddr
->
sa
.
sa_family
;
switch
(
newaddr
->
sa
.
sa_family
)
{
case
AF_INET
:
saveaddr
->
v4
.
sin_addr
.
s_addr
=
inet
->
rcv_saddr
;
inet
->
rcv_saddr
=
inet
->
saddr
=
newaddr
->
v4
.
sin_addr
.
s_addr
;
break
;
case
AF_INET6
:
SCTP_V6
({
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
saveaddr
->
v6
.
sin6_addr
=
np
->
rcv_saddr
;
np
->
rcv_saddr
=
np
->
saddr
=
newaddr
->
v6
.
sin6_addr
;
break
;
})
default:
break
;
};
}
/* Restore sk->rcv_saddr after failing get_port(). */
static
inline
void
sctp_sk_addr_restore
(
struct
sock
*
sk
,
const
union
sctp_addr
*
addr
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
switch
(
addr
->
sa
.
sa_family
)
{
case
AF_INET
:
inet
->
rcv_saddr
=
inet
->
saddr
=
addr
->
v4
.
sin_addr
.
s_addr
;
break
;
case
AF_INET6
:
SCTP_V6
({
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
np
->
rcv_saddr
=
np
->
saddr
=
addr
->
v6
.
sin6_addr
;
break
;
})
default:
break
;
};
}
/*
* Wait for a packet..
* Note: This function is the same function as in core/datagram.c
...
...
@@ -2711,27 +2647,15 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
}
/* Verify that this is a valid address. */
static
int
sctp_verify_addr
(
struct
sock
*
sk
,
struct
sock
addr
*
addr
,
int
len
)
static
int
sctp_verify_addr
(
struct
sock
*
sk
,
union
sctp_
addr
*
addr
,
int
len
)
{
struct
sctp_func
*
af
;
/* Check minimum size. */
if
(
len
<
sizeof
(
struct
sockaddr
))
return
-
EINVAL
;
struct
sctp_af
*
af
;
/*
Do we support this address family in general?
*/
af
=
sctp_
get_af_specific
(
addr
->
sa_family
);
/*
Verify basic sockaddr.
*/
af
=
sctp_
sockaddr_af
(
sctp_sk
(
sk
),
addr
,
len
);
if
(
!
af
)
return
-
EINVAL
;
/* Does this PF support this AF? */
if
(
!
sctp_sk
(
sk
)
->
pf
->
af_supported
(
addr
->
sa_family
))
return
-
EINVAL
;
/* Verify the minimum for this AF sockaddr. */
if
(
len
<
af
->
sockaddr_len
)
return
-
EINVAL
;
/* Is this a valid SCTP address? */
if
(
!
af
->
addr_valid
((
union
sctp_addr
*
)
addr
))
return
-
EINVAL
;
...
...
net/sctp/sysctl.c
View file @
54bf5a09
/* SCTP kernel reference Implementation
* Copyright (c) 2002 International Business Machines Corp.
* Copyright (c) 2002 Intel Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -32,6 +33,7 @@
* Written or modified by:
* Mingqin Liu <liuming@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
...
...
@@ -70,6 +72,9 @@ static ctl_table sctp_table[] = {
{
NET_SCTP_HB_INTERVAL
,
"hb_interval"
,
&
sctp_proto
.
hb_interval
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
,
&
sysctl_jiffies
},
{
NET_SCTP_PRESERVE_ENABLE
,
"cookie_preserve_enable"
,
&
sctp_proto
.
cookie_preserve_enable
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
,
&
sysctl_jiffies
},
{
NET_SCTP_RTO_ALPHA
,
"rto_alpha_exp_divisor"
,
&
sctp_proto
.
rto_alpha
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
...
...
net/sctp/transport.c
View file @
54bf5a09
...
...
@@ -207,7 +207,7 @@ void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr,
struct
sctp_opt
*
opt
)
{
sctp_association_t
*
asoc
=
transport
->
asoc
;
struct
sctp_
func
*
af
=
transport
->
af_specific
;
struct
sctp_
af
*
af
=
transport
->
af_specific
;
union
sctp_addr
*
daddr
=
&
transport
->
ipaddr
;
sctp_bind_addr_t
*
bp
;
rwlock_t
*
addr_lock
;
...
...
net/sctp/ulpevent.c
View file @
54bf5a09
...
...
@@ -762,6 +762,8 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
{
sctp_association_t
*
asoc
;
sctp_ulpevent_t
*
event
;
sctp_chunk_t
*
sack
;
struct
timer_list
*
timer
;
/* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as
...
...
@@ -782,9 +784,39 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
asoc
->
rwnd
+=
skb
->
len
;
}
SCTP_DEBUG_PRINTK
(
"rwnd increased by %d to (%u, %u)
\n
"
,
skb
->
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
);
SCTP_DEBUG_PRINTK
(
"rwnd increased by %d to (%u, %u) - %u
\n
"
,
skb
->
len
,
asoc
->
rwnd
,
asoc
->
rwnd_over
,
asoc
->
a_rwnd
);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in Section 4.2.3.3
* of RFC 1122.
*/
if
((
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
&&
(
asoc
->
rwnd
>
asoc
->
a_rwnd
)
&&
((
asoc
->
rwnd
-
asoc
->
a_rwnd
)
>=
min_t
(
__u32
,
(
asoc
->
base
.
sk
->
rcvbuf
>>
1
),
asoc
->
pmtu
)))
{
SCTP_DEBUG_PRINTK
(
"Sending window update SACK- rwnd: %u "
"a_rwnd: %u
\n
"
,
asoc
->
rwnd
,
asoc
->
a_rwnd
);
sack
=
sctp_make_sack
(
asoc
);
if
(
!
sack
)
goto
out
;
/* Update the last advertised rwnd value. */
asoc
->
a_rwnd
=
asoc
->
rwnd
;
asoc
->
peer
.
sack_needed
=
0
;
asoc
->
peer
.
next_dup_tsn
=
0
;
sctp_push_outqueue
(
&
asoc
->
outqueue
,
sack
);
/* Stop the SACK timer. */
timer
=
&
asoc
->
timers
[
SCTP_EVENT_TIMEOUT_SACK
];
if
(
timer_pending
(
timer
)
&&
del_timer
(
timer
))
sctp_association_put
(
asoc
);
}
out:
sctp_association_put
(
asoc
);
}
...
...
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