Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
1ee0db3c
Commit
1ee0db3c
authored
Jun 12, 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/sctp-2.5
parents
afab4c80
ccdf98ff
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
808 additions
and
376 deletions
+808
-376
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+24
-19
include/net/sctp/structs.h
include/net/sctp/structs.h
+53
-23
include/net/sctp/user.h
include/net/sctp/user.h
+5
-0
net/sctp/associola.c
net/sctp/associola.c
+16
-19
net/sctp/bind_addr.c
net/sctp/bind_addr.c
+1
-3
net/sctp/input.c
net/sctp/input.c
+18
-16
net/sctp/ipv6.c
net/sctp/ipv6.c
+9
-0
net/sctp/objcnt.c
net/sctp/objcnt.c
+2
-0
net/sctp/proc.c
net/sctp/proc.c
+159
-0
net/sctp/protocol.c
net/sctp/protocol.c
+126
-80
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+16
-10
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+2
-1
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+44
-27
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+2
-55
net/sctp/socket.c
net/sctp/socket.c
+312
-98
net/sctp/sysctl.c
net/sctp/sysctl.c
+12
-14
net/sctp/transport.c
net/sctp/transport.c
+7
-11
No files found.
include/net/sctp/sctp.h
View file @
1ee0db3c
...
...
@@ -119,12 +119,10 @@
*/
/*
* sctp
_
protocol.c
* sctp
/
protocol.c
*/
extern
struct
sctp_protocol
sctp_proto
;
extern
struct
sock
*
sctp_get_ctl_sock
(
void
);
extern
int
sctp_copy_local_addr_list
(
struct
sctp_protocol
*
,
struct
sctp_bind_addr
*
,
extern
int
sctp_copy_local_addr_list
(
struct
sctp_bind_addr
*
,
sctp_scope_t
,
int
gfp
,
int
flags
);
extern
struct
sctp_pf
*
sctp_get_pf_specific
(
sa_family_t
family
);
extern
int
sctp_register_pf
(
struct
sctp_pf
*
,
sa_family_t
);
...
...
@@ -275,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_assoc;
extern
atomic_t
sctp_dbg_objcnt_transport
;
extern
atomic_t
sctp_dbg_objcnt_chunk
;
extern
atomic_t
sctp_dbg_objcnt_bind_addr
;
extern
atomic_t
sctp_dbg_objcnt_bind_bucket
;
extern
atomic_t
sctp_dbg_objcnt_addr
;
extern
atomic_t
sctp_dbg_objcnt_ssnmap
;
extern
atomic_t
sctp_dbg_objcnt_datamsg
;
...
...
@@ -418,6 +417,10 @@ static inline __s32 sctp_jitter(__u32 rto)
static
__u32
sctp_rand
;
__s32
ret
;
/* Avoid divide by zero. */
if
(
!
rto
)
rto
=
1
;
sctp_rand
+=
jiffies
;
sctp_rand
^=
(
sctp_rand
<<
12
);
sctp_rand
^=
(
sctp_rand
>>
20
);
...
...
@@ -448,7 +451,7 @@ static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu)
* there is room for a param header too.
*/
#define sctp_walk_params(pos, chunk, member)\
_sctp_walk_params((pos), (chunk),
ntohs((chunk)->chunk_hdr.length
), member)
_sctp_walk_params((pos), (chunk),
WORD_ROUND(ntohs((chunk)->chunk_hdr.length)
), member)
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
...
...
@@ -456,6 +459,18 @@ for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += WORD_ROUND(ntohs(pos.p->length)))
#define sctp_walk_errors(err, chunk_hdr)\
_sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length))
#define _sctp_walk_errors(err, chunk_hdr, end)\
for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
sizeof(sctp_chunkhdr_t));\
(void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
(void *)err <= (void *)chunk_hdr + end - \
WORD_ROUND(ntohs(err->length));\
err = (sctp_errhdr_t *)((void *)err + \
WORD_ROUND(ntohs(err->length))))
/* Round an int up to the next multiple of 4. */
#define WORD_ROUND(s) (((s)+3)&~3)
...
...
@@ -491,12 +506,6 @@ void sctp_put_port(struct sock *sk);
/* Static inline functions. */
/* Return the SCTP protocol structure. */
static
inline
struct
sctp_protocol
*
sctp_get_protocol
(
void
)
{
return
&
sctp_proto
;
}
/* Convert from an IP version number to an Address Family symbol. */
static
inline
int
ipver2af
(
__u8
ipver
)
{
...
...
@@ -524,24 +533,21 @@ static inline int sctp_sanity_check(void)
/* This is the hash function for the SCTP port hash table. */
static
inline
int
sctp_phashfn
(
__u16
lport
)
{
struct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
return
(
lport
&
(
sctp_proto
->
port_hashsize
-
1
));
return
(
lport
&
(
sctp_port_hashsize
-
1
));
}
/* This is the hash function for the endpoint hash table. */
static
inline
int
sctp_ep_hashfn
(
__u16
lport
)
{
struct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
return
(
lport
&
(
sctp_proto
->
ep_hashsize
-
1
));
return
(
lport
&
(
sctp_ep_hashsize
-
1
));
}
/* This is the hash function for the association hash table. */
static
inline
int
sctp_assoc_hashfn
(
__u16
lport
,
__u16
rport
)
{
struct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
int
h
=
(
lport
<<
16
)
+
rport
;
h
^=
h
>>
8
;
return
(
h
&
(
sctp_
proto
->
assoc_hashsize
-
1
));
return
(
h
&
(
sctp_assoc_hashsize
-
1
));
}
/* This is the hash function for the association hash table. This is
...
...
@@ -550,10 +556,9 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
*/
static
inline
int
sctp_vtag_hashfn
(
__u16
lport
,
__u16
rport
,
__u32
vtag
)
{
struct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
int
h
=
(
lport
<<
16
)
+
rport
;
h
^=
vtag
;
return
(
h
&
(
sctp_
proto
->
assoc_hashsize
-
1
));
return
(
h
&
(
sctp_assoc_hashsize
-
1
));
}
/* WARNING: Do not change the layout of the members in sctp_sock! */
...
...
include/net/sctp/structs.h
View file @
1ee0db3c
...
...
@@ -71,7 +71,7 @@ union sctp_addr {
};
/* Forward declarations for data structures. */
struct
sctp_
protocol
;
struct
sctp_
globals
;
struct
sctp_endpoint
;
struct
sctp_association
;
struct
sctp_transport
;
...
...
@@ -92,28 +92,28 @@ struct sctp_ssnmap;
/* Structures useful for managing bind/connect. */
typedef
struct
sctp_bind_bucket
{
struct
sctp_bind_bucket
{
unsigned
short
port
;
unsigned
short
fastreuse
;
struct
sctp_bind_bucket
*
next
;
struct
sctp_bind_bucket
**
pprev
;
struct
sock
*
sk
;
}
sctp_bind_bucket_t
;
};
typedef
struct
sctp_bind_hashbucket
{
struct
sctp_bind_hashbucket
{
spinlock_t
lock
;
struct
sctp_bind_bucket
*
chain
;
}
sctp_bind_hashbucket_t
;
};
/* Used for hashing all associations. */
typedef
struct
sctp_hashbucket
{
struct
sctp_hashbucket
{
rwlock_t
lock
;
struct
sctp_ep_common
*
chain
;
}
sctp_hashbucket_t
__attribute__
((
__aligned__
(
8
)));
}
__attribute__
((
__aligned__
(
8
)));
/* The SCTP
protocol
structure. */
struct
sctp_protocol
{
/* The SCTP
globals
structure. */
extern
struct
sctp_globals
{
/* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
*
* The following protocol parameters are RECOMMENDED:
...
...
@@ -167,17 +167,17 @@ struct sctp_protocol {
/* This is the hash of all endpoints. */
int
ep_hashsize
;
s
ctp_hashbucket_
t
*
ep_hashbucket
;
s
truct
sctp_hashbucke
t
*
ep_hashbucket
;
/* This is the hash of all associations. */
int
assoc_hashsize
;
s
ctp_hashbucket_
t
*
assoc_hashbucket
;
s
truct
sctp_hashbucke
t
*
assoc_hashbucket
;
/* This is the sctp port control hash. */
int
port_hashsize
;
int
port_rover
;
spinlock_t
port_alloc_lock
;
/* Protects port_rover. */
s
ctp_bind_hashbucket_
t
*
port_hashtable
;
s
truct
sctp_bind_hashbucke
t
*
port_hashtable
;
/* This is the global local address list.
* We actively maintain this complete list of interfaces on
...
...
@@ -187,8 +187,33 @@ struct sctp_protocol {
*/
struct
list_head
local_addr_list
;
spinlock_t
local_addr_lock
;
};
}
sctp_globals
;
#define sctp_rto_initial (sctp_globals.rto_initial)
#define sctp_rto_min (sctp_globals.rto_min)
#define sctp_rto_max (sctp_globals.rto_max)
#define sctp_rto_alpha (sctp_globals.rto_alpha)
#define sctp_rto_beta (sctp_globals.rto_beta)
#define sctp_max_burst (sctp_globals.max_burst)
#define sctp_valid_cookie_life (sctp_globals.valid_cookie_life)
#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable)
#define sctp_max_retrans_association (sctp_globals.max_retrans_association)
#define sctp_max_retrans_path (sctp_globals.max_retrans_path)
#define sctp_max_retrans_init (sctp_globals.max_retrans_init)
#define sctp_hb_interval (sctp_globals.hb_interval)
#define sctp_max_instreams (sctp_globals.max_instreams)
#define sctp_max_outstreams (sctp_globals.max_outstreams)
#define sctp_address_families (sctp_globals.address_families)
#define sctp_ep_hashsize (sctp_globals.ep_hashsize)
#define sctp_ep_hashbucket (sctp_globals.ep_hashbucket)
#define sctp_assoc_hashsize (sctp_globals.assoc_hashsize)
#define sctp_assoc_hashbucket (sctp_globals.assoc_hashbucket)
#define sctp_port_hashsize (sctp_globals.port_hashsize)
#define sctp_port_rover (sctp_globals.port_rover)
#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock)
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.local_addr_lock)
/*
* Pointers to address related SCTP functions.
...
...
@@ -239,7 +264,9 @@ struct sctp_af {
int
(
*
is_any
)
(
const
union
sctp_addr
*
);
int
(
*
available
)
(
const
union
sctp_addr
*
);
int
(
*
skb_iif
)
(
const
struct
sk_buff
*
sk
);
int
(
*
is_ce
)
(
const
struct
sk_buff
*
sk
);
int
(
*
is_ce
)
(
const
struct
sk_buff
*
sk
);
void
(
*
seq_dump_addr
)(
struct
seq_file
*
seq
,
union
sctp_addr
*
addr
);
__u16
net_header_len
;
int
sockaddr_len
;
sa_family_t
sa_family
;
...
...
@@ -289,6 +316,10 @@ struct sctp_opt {
/* Various Socket Options. */
__u16
default_stream
;
__u32
default_ppid
;
__u16
default_flags
;
__u32
default_context
;
__u32
default_timetolive
;
struct
sctp_initmsg
initmsg
;
struct
sctp_rtoinfo
rtoinfo
;
struct
sctp_paddrparams
paddrparam
;
...
...
@@ -461,7 +492,7 @@ struct sctp_datamsg {
/* Reference counting. */
atomic_t
refcnt
;
/* When is this message no longer interesting to the peer? */
unsigned
long
expires_at
;
unsigned
long
expires_at
;
/* Did the messenge fail to send? */
int
send_error
;
char
send_failed
;
...
...
@@ -1492,13 +1523,12 @@ struct sctp_association {
*/
int
counters
[
SCTP_NUMBER_COUNTERS
];
struct
{
__u16
stream
;
__u16
flags
;
__u32
ppid
;
__u32
context
;
__u32
timetolive
;
}
defaults
;
/* Default send parameters. */
__u16
default_stream
;
__u16
default_flags
;
__u32
default_ppid
;
__u32
default_context
;
__u32
default_timetolive
;
/* This tracks outbound ssn for a given stream. */
struct
sctp_ssnmap
*
ssnmap
;
...
...
include/net/sctp/user.h
View file @
1ee0db3c
...
...
@@ -485,6 +485,11 @@ struct sctp_paddrinfo {
__u32
spinfo_mtu
;
};
/* Peer addresses's state. */
enum
sctp_spinfo_state
{
SCTP_INACTIVE
,
SCTP_ACTIVE
,
};
/*
* 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO)
...
...
net/sctp/associola.c
View file @
1ee0db3c
...
...
@@ -96,7 +96,6 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
int
gfp
)
{
struct
sctp_opt
*
sp
;
struct
sctp_protocol
*
proto
=
sctp_get_protocol
();
int
i
;
/* Retrieve the SCTP per socket area. */
...
...
@@ -129,26 +128,26 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc
->
state_timestamp
=
jiffies
;
/* Set things that have constant value. */
asoc
->
cookie_life
.
tv_sec
=
sctp_
proto
.
valid_cookie_life
/
HZ
;
asoc
->
cookie_life
.
tv_usec
=
(
sctp_
proto
.
valid_cookie_life
%
HZ
)
*
asoc
->
cookie_life
.
tv_sec
=
sctp_valid_cookie_life
/
HZ
;
asoc
->
cookie_life
.
tv_usec
=
(
sctp_valid_cookie_life
%
HZ
)
*
1000000L
/
HZ
;
asoc
->
pmtu
=
0
;
asoc
->
frag_point
=
0
;
/* Initialize the default association max_retrans and RTO values. */
asoc
->
max_retrans
=
proto
->
max_retrans_association
;
asoc
->
rto_initial
=
proto
->
rto_initial
;
asoc
->
rto_max
=
proto
->
rto_max
;
asoc
->
rto_min
=
proto
->
rto_min
;
asoc
->
max_retrans
=
sctp_
max_retrans_association
;
asoc
->
rto_initial
=
sctp_
rto_initial
;
asoc
->
rto_max
=
sctp_
rto_max
;
asoc
->
rto_min
=
sctp_
rto_min
;
asoc
->
overall_error_threshold
=
0
;
asoc
->
overall_error_threshold
=
asoc
->
max_retrans
;
asoc
->
overall_error_count
=
0
;
/* Initialize the maximum mumber of new data packets that can be sent
* in a burst.
*/
asoc
->
max_burst
=
proto
->
max_burst
;
asoc
->
max_burst
=
sctp_
max_burst
;
/* Copy things from the endpoint. */
for
(
i
=
SCTP_EVENT_TIMEOUT_NONE
;
i
<
SCTP_NUM_TIMEOUT_TYPES
;
++
i
)
{
...
...
@@ -277,6 +276,12 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc
->
autoclose
=
sp
->
autoclose
;
asoc
->
default_stream
=
sp
->
default_stream
;
asoc
->
default_ppid
=
sp
->
default_ppid
;
asoc
->
default_flags
=
sp
->
default_flags
;
asoc
->
default_context
=
sp
->
default_context
;
asoc
->
default_timetolive
=
sp
->
default_timetolive
;
return
asoc
;
fail_init:
...
...
@@ -478,16 +483,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer
->
partial_bytes_acked
=
0
;
peer
->
flight_size
=
0
;
peer
->
error_threshold
=
peer
->
max_retrans
;
/* Update the overall error threshold value of the association
* taking the new peer's error threshold into account.
*/
asoc
->
overall_error_threshold
=
min
(
asoc
->
overall_error_threshold
+
peer
->
error_threshold
,
asoc
->
max_retrans
);
/* By default, enable heartbeat for peer address. */
peer
->
hb_allowed
=
1
;
...
...
@@ -550,12 +547,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
/* Record the transition on the transport. */
switch
(
command
)
{
case
SCTP_TRANSPORT_UP
:
transport
->
active
=
1
;
transport
->
active
=
SCTP_ACTIVE
;
spc_state
=
ADDRESS_AVAILABLE
;
break
;
case
SCTP_TRANSPORT_DOWN
:
transport
->
active
=
0
;
transport
->
active
=
SCTP_INACTIVE
;
spc_state
=
ADDRESS_UNREACHABLE
;
break
;
...
...
net/sctp/bind_addr.c
View file @
1ee0db3c
...
...
@@ -329,12 +329,10 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
union
sctp_addr
*
addr
,
sctp_scope_t
scope
,
int
gfp
,
int
flags
)
{
struct
sctp_protocol
*
proto
=
sctp_get_protocol
();
int
error
=
0
;
if
(
sctp_is_any
(
addr
))
{
error
=
sctp_copy_local_addr_list
(
proto
,
dest
,
scope
,
gfp
,
flags
);
error
=
sctp_copy_local_addr_list
(
dest
,
scope
,
gfp
,
flags
);
}
else
if
(
sctp_in_scope
(
addr
,
scope
))
{
/* Now that the address is in scope, check to see if
* the address type is supported by local sock as
...
...
net/sctp/input.c
View file @
1ee0db3c
...
...
@@ -503,9 +503,10 @@ int sctp_rcv_ootb(struct sk_buff *skb)
goto
discard
;
if
(
SCTP_CID_ERROR
==
ch
->
type
)
{
err
=
(
sctp_errhdr_t
*
)(
ch
+
sizeof
(
sctp_chunkhdr_t
));
if
(
SCTP_ERROR_STALE_COOKIE
==
err
->
cause
)
goto
discard
;
sctp_walk_errors
(
err
,
ch
)
{
if
(
SCTP_ERROR_STALE_COOKIE
==
err
->
cause
)
goto
discard
;
}
}
ch
=
(
sctp_chunkhdr_t
*
)
ch_end
;
...
...
@@ -522,12 +523,12 @@ void __sctp_hash_endpoint(struct sctp_endpoint *ep)
{
struct
sctp_ep_common
**
epp
;
struct
sctp_ep_common
*
epb
;
s
ctp_hashbucket_
t
*
head
;
s
truct
sctp_hashbucke
t
*
head
;
epb
=
&
ep
->
base
;
epb
->
hashent
=
sctp_ep_hashfn
(
epb
->
bind_addr
.
port
);
head
=
&
sctp_
proto
.
ep_hashbucket
[
epb
->
hashent
];
head
=
&
sctp_ep_hashbucket
[
epb
->
hashent
];
sctp_write_lock
(
&
head
->
lock
);
epp
=
&
head
->
chain
;
...
...
@@ -550,14 +551,14 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep)
/* Remove endpoint from the hash table. */
void
__sctp_unhash_endpoint
(
struct
sctp_endpoint
*
ep
)
{
s
ctp_hashbucket_
t
*
head
;
s
truct
sctp_hashbucke
t
*
head
;
struct
sctp_ep_common
*
epb
;
epb
=
&
ep
->
base
;
epb
->
hashent
=
sctp_ep_hashfn
(
epb
->
bind_addr
.
port
);
head
=
&
sctp_
proto
.
ep_hashbucket
[
epb
->
hashent
];
head
=
&
sctp_ep_hashbucket
[
epb
->
hashent
];
sctp_write_lock
(
&
head
->
lock
);
...
...
@@ -582,13 +583,13 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep)
/* Look up an endpoint. */
struct
sctp_endpoint
*
__sctp_rcv_lookup_endpoint
(
const
union
sctp_addr
*
laddr
)
{
s
ctp_hashbucket_
t
*
head
;
s
truct
sctp_hashbucke
t
*
head
;
struct
sctp_ep_common
*
epb
;
struct
sctp_endpoint
*
ep
;
int
hash
;
hash
=
sctp_ep_hashfn
(
laddr
->
v4
.
sin_port
);
head
=
&
sctp_
proto
.
ep_hashbucket
[
hash
];
head
=
&
sctp_ep_hashbucket
[
hash
];
read_lock
(
&
head
->
lock
);
for
(
epb
=
head
->
chain
;
epb
;
epb
=
epb
->
next
)
{
ep
=
sctp_ep
(
epb
);
...
...
@@ -619,14 +620,14 @@ void __sctp_hash_established(struct sctp_association *asoc)
{
struct
sctp_ep_common
**
epp
;
struct
sctp_ep_common
*
epb
;
s
ctp_hashbucket_
t
*
head
;
s
truct
sctp_hashbucke
t
*
head
;
epb
=
&
asoc
->
base
;
/* Calculate which chain this entry will belong to. */
epb
->
hashent
=
sctp_assoc_hashfn
(
epb
->
bind_addr
.
port
,
asoc
->
peer
.
port
);
head
=
&
sctp_
proto
.
assoc_hashbucket
[
epb
->
hashent
];
head
=
&
sctp_assoc_hashbucket
[
epb
->
hashent
];
sctp_write_lock
(
&
head
->
lock
);
epp
=
&
head
->
chain
;
...
...
@@ -649,7 +650,7 @@ void sctp_unhash_established(struct sctp_association *asoc)
/* Remove association from the hash table. */
void
__sctp_unhash_established
(
struct
sctp_association
*
asoc
)
{
s
ctp_hashbucket_
t
*
head
;
s
truct
sctp_hashbucke
t
*
head
;
struct
sctp_ep_common
*
epb
;
epb
=
&
asoc
->
base
;
...
...
@@ -657,7 +658,7 @@ void __sctp_unhash_established(struct sctp_association *asoc)
epb
->
hashent
=
sctp_assoc_hashfn
(
epb
->
bind_addr
.
port
,
asoc
->
peer
.
port
);
head
=
&
sctp_
proto
.
assoc_hashbucket
[
epb
->
hashent
];
head
=
&
sctp_assoc_hashbucket
[
epb
->
hashent
];
sctp_write_lock
(
&
head
->
lock
);
...
...
@@ -677,7 +678,7 @@ struct sctp_association *__sctp_lookup_association(
const
union
sctp_addr
*
peer
,
struct
sctp_transport
**
pt
)
{
s
ctp_hashbucket_
t
*
head
;
s
truct
sctp_hashbucke
t
*
head
;
struct
sctp_ep_common
*
epb
;
struct
sctp_association
*
asoc
;
struct
sctp_transport
*
transport
;
...
...
@@ -687,7 +688,7 @@ struct sctp_association *__sctp_lookup_association(
* have wildcards anyways.
*/
hash
=
sctp_assoc_hashfn
(
local
->
v4
.
sin_port
,
peer
->
v4
.
sin_port
);
head
=
&
sctp_
proto
.
assoc_hashbucket
[
hash
];
head
=
&
sctp_assoc_hashbucket
[
hash
];
read_lock
(
&
head
->
lock
);
for
(
epb
=
head
->
chain
;
epb
;
epb
=
epb
->
next
)
{
asoc
=
sctp_assoc
(
epb
);
...
...
@@ -766,6 +767,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
sctp_chunkhdr_t
*
ch
;
union
sctp_params
params
;
sctp_init_chunk_t
*
init
;
struct
sctp_transport
*
transport
;
ch
=
(
sctp_chunkhdr_t
*
)
skb
->
data
;
...
...
@@ -805,7 +807,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
continue
;
sctp_param2sockaddr
(
paddr
,
params
.
addr
,
ntohs
(
sh
->
source
),
0
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
&
transport
);
if
(
asoc
)
return
asoc
;
}
...
...
net/sctp/ipv6.c
View file @
1ee0db3c
...
...
@@ -61,6 +61,7 @@
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include <net/protocol.h>
#include <net/tcp.h>
...
...
@@ -578,6 +579,13 @@ static int sctp_v6_is_ce(const struct sk_buff *skb)
return
*
((
__u32
*
)(
skb
->
nh
.
ipv6h
))
&
htonl
(
1
<<
20
);
}
/* Dump the v6 addr to the seq file. */
static
void
sctp_v6_seq_dump_addr
(
struct
seq_file
*
seq
,
union
sctp_addr
*
addr
)
{
seq_printf
(
seq
,
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
,
NIP6
(
addr
->
v6
.
sin6_addr
));
}
/* Initialize a PF_INET6 socket msg_name. */
static
void
sctp_inet6_msgname
(
char
*
msgname
,
int
*
addr_len
)
{
...
...
@@ -840,6 +848,7 @@ static struct sctp_af sctp_ipv6_specific = {
.
available
=
sctp_v6_available
,
.
skb_iif
=
sctp_v6_skb_iif
,
.
is_ce
=
sctp_v6_is_ce
,
.
seq_dump_addr
=
sctp_v6_seq_dump_addr
,
.
net_header_len
=
sizeof
(
struct
ipv6hdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in6
),
.
sa_family
=
AF_INET6
,
...
...
net/sctp/objcnt.c
View file @
1ee0db3c
...
...
@@ -53,6 +53,7 @@ SCTP_DBG_OBJCNT(ep);
SCTP_DBG_OBJCNT
(
transport
);
SCTP_DBG_OBJCNT
(
assoc
);
SCTP_DBG_OBJCNT
(
bind_addr
);
SCTP_DBG_OBJCNT
(
bind_bucket
);
SCTP_DBG_OBJCNT
(
chunk
);
SCTP_DBG_OBJCNT
(
addr
);
SCTP_DBG_OBJCNT
(
ssnmap
);
...
...
@@ -68,6 +69,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY
(
transport
),
SCTP_DBG_OBJCNT_ENTRY
(
chunk
),
SCTP_DBG_OBJCNT_ENTRY
(
bind_addr
),
SCTP_DBG_OBJCNT_ENTRY
(
bind_bucket
),
SCTP_DBG_OBJCNT_ENTRY
(
addr
),
SCTP_DBG_OBJCNT_ENTRY
(
ssnmap
),
SCTP_DBG_OBJCNT_ENTRY
(
datamsg
),
...
...
net/sctp/proc.c
View file @
1ee0db3c
...
...
@@ -128,3 +128,162 @@ void sctp_snmp_proc_exit(void)
{
remove_proc_entry
(
"snmp"
,
proc_net_sctp
);
}
/* Dump local addresses of an association/endpoint. */
static
void
sctp_seq_dump_local_addrs
(
struct
seq_file
*
seq
,
struct
sctp_ep_common
*
epb
)
{
struct
list_head
*
pos
;
struct
sockaddr_storage_list
*
laddr
;
union
sctp_addr
*
addr
;
struct
sctp_af
*
af
;
list_for_each
(
pos
,
&
epb
->
bind_addr
.
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
addr
=
(
union
sctp_addr
*
)
&
laddr
->
a
;
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
af
->
seq_dump_addr
(
seq
,
addr
);
}
}
/* Dump remote addresses of an association. */
static
void
sctp_seq_dump_remote_addrs
(
struct
seq_file
*
seq
,
struct
sctp_association
*
assoc
)
{
struct
list_head
*
pos
;
struct
sctp_transport
*
transport
;
union
sctp_addr
*
addr
;
struct
sctp_af
*
af
;
list_for_each
(
pos
,
&
assoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
addr
=
(
union
sctp_addr
*
)
&
transport
->
ipaddr
;
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
af
->
seq_dump_addr
(
seq
,
addr
);
}
}
/* Display sctp endpoints (/proc/net/sctp/eps). */
static
int
sctp_eps_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
struct
sctp_hashbucket
*
head
;
struct
sctp_ep_common
*
epb
;
struct
sctp_endpoint
*
ep
;
struct
sock
*
sk
;
int
hash
;
seq_printf
(
seq
,
" ENDPT SOCK STY SST HBKT LPORT LADDRS
\n
"
);
for
(
hash
=
0
;
hash
<
sctp_ep_hashsize
;
hash
++
)
{
head
=
&
sctp_ep_hashbucket
[
hash
];
read_lock
(
&
head
->
lock
);
for
(
epb
=
head
->
chain
;
epb
;
epb
=
epb
->
next
)
{
ep
=
sctp_ep
(
epb
);
sk
=
epb
->
sk
;
seq_printf
(
seq
,
"%8p %8p %-3d %-3d %-4d %-5d "
,
ep
,
sk
,
sctp_sk
(
sk
)
->
type
,
sk
->
sk_state
,
hash
,
epb
->
bind_addr
.
port
);
sctp_seq_dump_local_addrs
(
seq
,
epb
);
seq_printf
(
seq
,
"
\n
"
);
}
read_unlock
(
&
head
->
lock
);
}
return
0
;
}
/* Initialize the seq file operations for 'eps' object. */
static
int
sctp_eps_seq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
sctp_eps_seq_show
,
NULL
);
}
static
struct
file_operations
sctp_eps_seq_fops
=
{
.
open
=
sctp_eps_seq_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
/* Set up the proc fs entry for 'eps' object. */
int
__init
sctp_eps_proc_init
(
void
)
{
struct
proc_dir_entry
*
p
;
p
=
create_proc_entry
(
"eps"
,
S_IRUGO
,
proc_net_sctp
);
if
(
!
p
)
return
-
ENOMEM
;
p
->
proc_fops
=
&
sctp_eps_seq_fops
;
return
0
;
}
/* Cleanup the proc fs entry for 'eps' object. */
void
sctp_eps_proc_exit
(
void
)
{
remove_proc_entry
(
"eps"
,
proc_net_sctp
);
}
/* Display sctp associations (/proc/net/sctp/assocs). */
static
int
sctp_assocs_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
struct
sctp_hashbucket
*
head
;
struct
sctp_ep_common
*
epb
;
struct
sctp_association
*
assoc
;
struct
sock
*
sk
;
int
hash
;
seq_printf
(
seq
,
" ASSOC SOCK STY SST ST HBKT LPORT RPORT "
"LADDRS <-> RADDRS
\n
"
);
for
(
hash
=
0
;
hash
<
sctp_assoc_hashsize
;
hash
++
)
{
head
=
&
sctp_assoc_hashbucket
[
hash
];
read_lock
(
&
head
->
lock
);
for
(
epb
=
head
->
chain
;
epb
;
epb
=
epb
->
next
)
{
assoc
=
sctp_assoc
(
epb
);
sk
=
epb
->
sk
;
seq_printf
(
seq
,
"%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d "
,
assoc
,
sk
,
sctp_sk
(
sk
)
->
type
,
sk
->
sk_state
,
assoc
->
state
,
hash
,
epb
->
bind_addr
.
port
,
assoc
->
peer
.
port
);
sctp_seq_dump_local_addrs
(
seq
,
epb
);
seq_printf
(
seq
,
"<-> "
);
sctp_seq_dump_remote_addrs
(
seq
,
assoc
);
seq_printf
(
seq
,
"
\n
"
);
}
read_unlock
(
&
head
->
lock
);
}
return
0
;
}
/* Initialize the seq file operations for 'assocs' object. */
static
int
sctp_assocs_seq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
sctp_assocs_seq_show
,
NULL
);
}
static
struct
file_operations
sctp_assocs_seq_fops
=
{
.
open
=
sctp_assocs_seq_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
/* Set up the proc fs entry for 'assocs' object. */
int
__init
sctp_assocs_proc_init
(
void
)
{
struct
proc_dir_entry
*
p
;
p
=
create_proc_entry
(
"assocs"
,
S_IRUGO
,
proc_net_sctp
);
if
(
!
p
)
return
-
ENOMEM
;
p
->
proc_fops
=
&
sctp_assocs_seq_fops
;
return
0
;
}
/* Cleanup the proc fs entry for 'assocs' object. */
void
sctp_assocs_proc_exit
(
void
)
{
remove_proc_entry
(
"assocs"
,
proc_net_sctp
);
}
net/sctp/protocol.c
View file @
1ee0db3c
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-200
2
International Business Machines, Corp.
* Copyright (c) 2001-200
3
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
...
...
@@ -50,6 +50,7 @@
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/seq_file.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/ipv6.h>
...
...
@@ -59,7 +60,7 @@
#include <net/inet_ecn.h>
/* Global data structures. */
struct
sctp_
protocol
sctp_proto
;
struct
sctp_
globals
sctp_globals
;
struct
proc_dir_entry
*
proc_net_sctp
;
DEFINE_SNMP_STAT
(
struct
sctp_mib
,
sctp_statistics
);
...
...
@@ -74,10 +75,17 @@ static struct sctp_pf *sctp_pf_inet_specific;
static
struct
sctp_af
*
sctp_af_v4_specific
;
static
struct
sctp_af
*
sctp_af_v6_specific
;
kmem_cache_t
*
sctp_chunk_cachep
;
kmem_cache_t
*
sctp_bucket_cachep
;
extern
struct
net_proto_family
inet_family_ops
;
extern
int
sctp_snmp_proc_init
(
void
);
extern
int
sctp_snmp_proc_exit
(
void
);
extern
int
sctp_eps_proc_init
(
void
);
extern
int
sctp_eps_proc_exit
(
void
);
extern
int
sctp_assocs_proc_init
(
void
);
extern
int
sctp_assocs_proc_exit
(
void
);
/* Return the address of the control sock. */
struct
sock
*
sctp_get_ctl_sock
(
void
)
...
...
@@ -88,8 +96,6 @@ struct sock *sctp_get_ctl_sock(void)
/* Set up the proc fs entry for the SCTP protocol. */
__init
int
sctp_proc_init
(
void
)
{
int
rc
=
0
;
if
(
!
proc_net_sctp
)
{
struct
proc_dir_entry
*
ent
;
ent
=
proc_mkdir
(
"net/sctp"
,
0
);
...
...
@@ -97,20 +103,31 @@ __init int sctp_proc_init(void)
ent
->
owner
=
THIS_MODULE
;
proc_net_sctp
=
ent
;
}
else
rc
=
-
ENOMEM
;
goto
out_nomem
;
}
if
(
sctp_snmp_proc_init
())
rc
=
-
ENOMEM
;
goto
out_nomem
;
if
(
sctp_eps_proc_init
())
goto
out_nomem
;
if
(
sctp_assocs_proc_init
())
goto
out_nomem
;
return
0
;
return
rc
;
out_nomem:
return
-
ENOMEM
;
}
/* Clean up the proc fs entry for the SCTP protocol. */
/* Clean up the proc fs entry for the SCTP protocol.
* Note: Do not make this __exit as it is used in the init error
* path.
*/
void
sctp_proc_exit
(
void
)
{
sctp_snmp_proc_exit
();
sctp_eps_proc_exit
();
sctp_assocs_proc_exit
();
if
(
proc_net_sctp
)
{
proc_net_sctp
=
NULL
;
...
...
@@ -153,7 +170,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Extract our IP addresses from the system and stash them in the
* protocol structure.
*/
static
void
__sctp_get_local_addr_list
(
struct
sctp_protocol
*
proto
)
static
void
__sctp_get_local_addr_list
(
void
)
{
struct
net_device
*
dev
;
struct
list_head
*
pos
;
...
...
@@ -161,30 +178,30 @@ static void __sctp_get_local_addr_list(struct sctp_protocol *proto)
read_lock
(
&
dev_base_lock
);
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
list_for_each
(
pos
,
&
proto
->
address_families
)
{
__list_for_each
(
pos
,
&
sctp_
address_families
)
{
af
=
list_entry
(
pos
,
struct
sctp_af
,
list
);
af
->
copy_addrlist
(
&
proto
->
local_addr_list
,
dev
);
af
->
copy_addrlist
(
&
sctp_
local_addr_list
,
dev
);
}
}
read_unlock
(
&
dev_base_lock
);
}
static
void
sctp_get_local_addr_list
(
struct
sctp_protocol
*
proto
)
static
void
sctp_get_local_addr_list
(
void
)
{
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
sctp_
proto
.
local_addr_lock
,
flags
);
__sctp_get_local_addr_list
(
&
sctp_proto
);
sctp_spin_unlock_irqrestore
(
&
sctp_
proto
.
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
sctp_local_addr_lock
,
flags
);
__sctp_get_local_addr_list
();
sctp_spin_unlock_irqrestore
(
&
sctp_local_addr_lock
,
flags
);
}
/* Free the existing local addresses. */
static
void
__sctp_free_local_addr_list
(
struct
sctp_protocol
*
proto
)
static
void
__sctp_free_local_addr_list
(
void
)
{
struct
sockaddr_storage_list
*
addr
;
struct
list_head
*
pos
,
*
temp
;
list_for_each_safe
(
pos
,
temp
,
&
proto
->
local_addr_list
)
{
list_for_each_safe
(
pos
,
temp
,
&
sctp_
local_addr_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
list_del
(
pos
);
kfree
(
addr
);
...
...
@@ -192,18 +209,17 @@ static void __sctp_free_local_addr_list(struct sctp_protocol *proto)
}
/* Free the existing local addresses. */
static
void
sctp_free_local_addr_list
(
struct
sctp_protocol
*
proto
)
static
void
sctp_free_local_addr_list
(
void
)
{
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
proto
->
local_addr_lock
,
flags
);
__sctp_free_local_addr_list
(
proto
);
sctp_spin_unlock_irqrestore
(
&
proto
->
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
sctp_
local_addr_lock
,
flags
);
__sctp_free_local_addr_list
();
sctp_spin_unlock_irqrestore
(
&
sctp_
local_addr_lock
,
flags
);
}
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
int
sctp_copy_local_addr_list
(
struct
sctp_protocol
*
proto
,
struct
sctp_bind_addr
*
bp
,
sctp_scope_t
scope
,
int
sctp_copy_local_addr_list
(
struct
sctp_bind_addr
*
bp
,
sctp_scope_t
scope
,
int
gfp
,
int
copy_flags
)
{
struct
sockaddr_storage_list
*
addr
;
...
...
@@ -211,8 +227,8 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
struct
list_head
*
pos
;
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
proto
->
local_addr_lock
,
flags
);
list_for_each
(
pos
,
&
proto
->
local_addr_list
)
{
sctp_spin_lock_irqsave
(
&
sctp_
local_addr_lock
,
flags
);
list_for_each
(
pos
,
&
sctp_
local_addr_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
(
sctp_in_scope
(
&
addr
->
a
,
scope
))
{
/* Now that the address is in scope, check to see if
...
...
@@ -233,7 +249,7 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
}
end_copy:
sctp_spin_unlock_irqrestore
(
&
proto
->
local_addr_lock
,
flags
);
sctp_spin_unlock_irqrestore
(
&
sctp_
local_addr_lock
,
flags
);
return
error
;
}
...
...
@@ -564,6 +580,12 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk,
return
newsk
;
}
/* Dump the v4 addr to the seq file. */
static
void
sctp_v4_seq_dump_addr
(
struct
seq_file
*
seq
,
union
sctp_addr
*
addr
)
{
seq_printf
(
seq
,
"%d.%d.%d.%d "
,
NIPQUAD
(
addr
->
v4
.
sin_addr
));
}
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
*/
...
...
@@ -572,10 +594,10 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
{
unsigned
long
flags
;
sctp_spin_lock_irqsave
(
&
sctp_
proto
.
local_addr_lock
,
flags
);
__sctp_free_local_addr_list
(
&
sctp_proto
);
__sctp_get_local_addr_list
(
&
sctp_proto
);
sctp_spin_unlock_irqrestore
(
&
sctp_
proto
.
local_addr_lock
,
flags
);
sctp_spin_lock_irqsave
(
&
sctp_local_addr_lock
,
flags
);
__sctp_free_local_addr_list
();
__sctp_get_local_addr_list
();
sctp_spin_unlock_irqrestore
(
&
sctp_local_addr_lock
,
flags
);
return
NOTIFY_DONE
;
}
...
...
@@ -626,7 +648,7 @@ int sctp_register_af(struct sctp_af *af)
}
INIT_LIST_HEAD
(
&
af
->
list
);
list_add_tail
(
&
af
->
list
,
&
sctp_
proto
.
address_families
);
list_add_tail
(
&
af
->
list
,
&
sctp_address_families
);
return
1
;
}
...
...
@@ -839,6 +861,7 @@ struct sctp_af sctp_ipv4_specific = {
.
scope
=
sctp_v4_scope
,
.
skb_iif
=
sctp_v4_skb_iif
,
.
is_ce
=
sctp_v4_is_ce
,
.
seq_dump_addr
=
sctp_v4_seq_dump_addr
,
.
net_header_len
=
sizeof
(
struct
iphdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in
),
.
sa_family
=
AF_INET
,
...
...
@@ -914,6 +937,22 @@ __init int sctp_init(void)
inet_register_protosw
(
&
sctp_seqpacket_protosw
);
inet_register_protosw
(
&
sctp_stream_protosw
);
/* Allocate a cache pools. */
sctp_bucket_cachep
=
kmem_cache_create
(
"sctp_bind_bucket"
,
sizeof
(
struct
sctp_bind_bucket
),
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
if
(
!
sctp_bucket_cachep
)
goto
err_bucket_cachep
;
sctp_chunk_cachep
=
kmem_cache_create
(
"sctp_chunk"
,
sizeof
(
struct
sctp_chunk
),
0
,
SLAB_HWCACHE_ALIGN
,
NULL
,
NULL
);
if
(
!
sctp_chunk_cachep
)
goto
err_chunk_cachep
;
/* Allocate and initialise sctp mibs. */
status
=
init_sctp_mibs
();
if
(
status
)
...
...
@@ -932,91 +971,91 @@ __init int sctp_init(void)
*/
/* The following protocol parameters are RECOMMENDED: */
/* RTO.Initial - 3 seconds */
sctp_
proto
.
rto_initial
=
SCTP_RTO_INITIAL
;
sctp_rto_initial
=
SCTP_RTO_INITIAL
;
/* RTO.Min - 1 second */
sctp_
proto
.
rto_min
=
SCTP_RTO_MIN
;
sctp_
rto_min
=
SCTP_RTO_MIN
;
/* RTO.Max - 60 seconds */
sctp_
proto
.
rto_max
=
SCTP_RTO_MAX
;
sctp_
rto_max
=
SCTP_RTO_MAX
;
/* RTO.Alpha - 1/8 */
sctp_
proto
.
rto_alpha
=
SCTP_RTO_ALPHA
;
sctp_
rto_alpha
=
SCTP_RTO_ALPHA
;
/* RTO.Beta - 1/4 */
sctp_
proto
.
rto_beta
=
SCTP_RTO_BETA
;
sctp_
rto_beta
=
SCTP_RTO_BETA
;
/* Valid.Cookie.Life - 60 seconds */
sctp_
proto
.
valid_cookie_life
=
60
*
HZ
;
sctp_
valid_cookie_life
=
60
*
HZ
;
/* Whether Cookie Preservative is enabled(1) or not(0) */
sctp_
proto
.
cookie_preserve_enable
=
1
;
sctp_
cookie_preserve_enable
=
1
;
/* Max.Burst - 4 */
sctp_
proto
.
max_burst
=
SCTP_MAX_BURST
;
sctp_
max_burst
=
SCTP_MAX_BURST
;
/* Association.Max.Retrans - 10 attempts
* Path.Max.Retrans - 5 attempts (per destination address)
* Max.Init.Retransmits - 8 attempts
*/
sctp_
proto
.
max_retrans_association
=
10
;
sctp_
proto
.
max_retrans_path
=
5
;
sctp_
proto
.
max_retrans_init
=
8
;
sctp_
max_retrans_association
=
10
;
sctp_
max_retrans_path
=
5
;
sctp_
max_retrans_init
=
8
;
/* HB.interval - 30 seconds */
sctp_
proto
.
hb_interval
=
30
*
HZ
;
sctp_hb_interval
=
30
*
HZ
;
/* Implementation specific variables. */
/* Initialize default stream count setup information. */
sctp_
proto
.
max_instreams
=
SCTP_DEFAULT_INSTREAMS
;
sctp_
proto
.
max_outstreams
=
SCTP_DEFAULT_OUTSTREAMS
;
sctp_
max_instreams
=
SCTP_DEFAULT_INSTREAMS
;
sctp_
max_outstreams
=
SCTP_DEFAULT_OUTSTREAMS
;
/* Allocate and initialize the association hash table. */
sctp_
proto
.
assoc_hashsize
=
4096
;
sctp_
proto
.
assoc_hashbucket
=
(
sctp_hashbucket_
t
*
)
kmalloc
(
4096
*
sizeof
(
s
ctp_hashbucket_
t
),
GFP_KERNEL
);
if
(
!
sctp_
proto
.
assoc_hashbucket
)
{
sctp_assoc_hashsize
=
4096
;
sctp_
assoc_hashbucket
=
(
struct
sctp_hashbucke
t
*
)
kmalloc
(
4096
*
sizeof
(
s
truct
sctp_hashbucke
t
),
GFP_KERNEL
);
if
(
!
sctp_assoc_hashbucket
)
{
printk
(
KERN_ERR
"SCTP: Failed association hash alloc.
\n
"
);
status
=
-
ENOMEM
;
goto
err_ahash_alloc
;
}
for
(
i
=
0
;
i
<
sctp_
proto
.
assoc_hashsize
;
i
++
)
{
sctp_
proto
.
assoc_hashbucket
[
i
].
lock
=
RW_LOCK_UNLOCKED
;
sctp_
proto
.
assoc_hashbucket
[
i
].
chain
=
NULL
;
for
(
i
=
0
;
i
<
sctp_assoc_hashsize
;
i
++
)
{
sctp_assoc_hashbucket
[
i
].
lock
=
RW_LOCK_UNLOCKED
;
sctp_assoc_hashbucket
[
i
].
chain
=
NULL
;
}
/* Allocate and initialize the endpoint hash table. */
sctp_
proto
.
ep_hashsize
=
64
;
sctp_
proto
.
ep_hashbucket
=
(
sctp_hashbucket_
t
*
)
kmalloc
(
64
*
sizeof
(
s
ctp_hashbucket_
t
),
GFP_KERNEL
);
if
(
!
sctp_
proto
.
ep_hashbucket
)
{
sctp_ep_hashsize
=
64
;
sctp_
ep_hashbucket
=
(
struct
sctp_hashbucke
t
*
)
kmalloc
(
64
*
sizeof
(
s
truct
sctp_hashbucke
t
),
GFP_KERNEL
);
if
(
!
sctp_ep_hashbucket
)
{
printk
(
KERN_ERR
"SCTP: Failed endpoint_hash alloc.
\n
"
);
status
=
-
ENOMEM
;
goto
err_ehash_alloc
;
}
for
(
i
=
0
;
i
<
sctp_
proto
.
ep_hashsize
;
i
++
)
{
sctp_
proto
.
ep_hashbucket
[
i
].
lock
=
RW_LOCK_UNLOCKED
;
sctp_
proto
.
ep_hashbucket
[
i
].
chain
=
NULL
;
for
(
i
=
0
;
i
<
sctp_ep_hashsize
;
i
++
)
{
sctp_ep_hashbucket
[
i
].
lock
=
RW_LOCK_UNLOCKED
;
sctp_ep_hashbucket
[
i
].
chain
=
NULL
;
}
/* Allocate and initialize the SCTP port hash table. */
sctp_p
roto
.
p
ort_hashsize
=
4096
;
sctp_p
roto
.
port_hashtable
=
(
sctp_bind_hashbucket_
t
*
)
kmalloc
(
4096
*
sizeof
(
s
ctp_bind_hashbucket_t
),
GFP_KERNEL
);
if
(
!
sctp_p
roto
.
p
ort_hashtable
)
{
sctp_port_hashsize
=
4096
;
sctp_p
ort_hashtable
=
(
struct
sctp_bind_hashbucke
t
*
)
kmalloc
(
4096
*
sizeof
(
s
truct
sctp_bind_hashbucket
),
GFP_KERNEL
);
if
(
!
sctp_port_hashtable
)
{
printk
(
KERN_ERR
"SCTP: Failed bind hash alloc."
);
status
=
-
ENOMEM
;
goto
err_bhash_alloc
;
}
sctp_p
roto
.
p
ort_alloc_lock
=
SPIN_LOCK_UNLOCKED
;
sctp_p
roto
.
p
ort_rover
=
sysctl_local_port_range
[
0
]
-
1
;
for
(
i
=
0
;
i
<
sctp_p
roto
.
p
ort_hashsize
;
i
++
)
{
sctp_p
roto
.
p
ort_hashtable
[
i
].
lock
=
SPIN_LOCK_UNLOCKED
;
sctp_p
roto
.
p
ort_hashtable
[
i
].
chain
=
NULL
;
sctp_port_alloc_lock
=
SPIN_LOCK_UNLOCKED
;
sctp_port_rover
=
sysctl_local_port_range
[
0
]
-
1
;
for
(
i
=
0
;
i
<
sctp_port_hashsize
;
i
++
)
{
sctp_port_hashtable
[
i
].
lock
=
SPIN_LOCK_UNLOCKED
;
sctp_port_hashtable
[
i
].
chain
=
NULL
;
}
sctp_sysctl_register
();
INIT_LIST_HEAD
(
&
sctp_
proto
.
address_families
);
INIT_LIST_HEAD
(
&
sctp_address_families
);
sctp_register_af
(
&
sctp_ipv4_specific
);
status
=
sctp_v6_init
();
...
...
@@ -1031,13 +1070,13 @@ __init int sctp_init(void)
}
/* Initialize the local address list. */
INIT_LIST_HEAD
(
&
sctp_
proto
.
local_addr_list
);
sctp_
proto
.
local_addr_lock
=
SPIN_LOCK_UNLOCKED
;
INIT_LIST_HEAD
(
&
sctp_local_addr_list
);
sctp_local_addr_lock
=
SPIN_LOCK_UNLOCKED
;
/* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier
(
&
sctp_inetaddr_notifier
);
sctp_get_local_addr_list
(
&
sctp_proto
);
sctp_get_local_addr_list
();
__unsafe
(
THIS_MODULE
);
return
0
;
...
...
@@ -1047,16 +1086,20 @@ __init int sctp_init(void)
err_v6_init:
sctp_sysctl_unregister
();
list_del
(
&
sctp_ipv4_specific
.
list
);
kfree
(
sctp_p
roto
.
p
ort_hashtable
);
kfree
(
sctp_port_hashtable
);
err_bhash_alloc:
kfree
(
sctp_
proto
.
ep_hashbucket
);
kfree
(
sctp_ep_hashbucket
);
err_ehash_alloc:
kfree
(
sctp_
proto
.
assoc_hashbucket
);
kfree
(
sctp_assoc_hashbucket
);
err_ahash_alloc:
sctp_dbg_objcnt_exit
();
sctp_proc_exit
();
cleanup_sctp_mibs
();
err_init_mibs:
kmem_cache_destroy
(
sctp_chunk_cachep
);
err_chunk_cachep:
kmem_cache_destroy
(
sctp_bucket_cachep
);
err_bucket_cachep:
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_unregister_protosw
(
&
sctp_seqpacket_protosw
);
inet_unregister_protosw
(
&
sctp_stream_protosw
);
...
...
@@ -1074,7 +1117,7 @@ __exit void sctp_exit(void)
unregister_inetaddr_notifier
(
&
sctp_inetaddr_notifier
);
/* Free the local address list. */
sctp_free_local_addr_list
(
&
sctp_proto
);
sctp_free_local_addr_list
();
/* Free the control endpoint. */
sock_release
(
sctp_ctl_socket
);
...
...
@@ -1083,9 +1126,12 @@ __exit void sctp_exit(void)
sctp_sysctl_unregister
();
list_del
(
&
sctp_ipv4_specific
.
list
);
kfree
(
sctp_proto
.
assoc_hashbucket
);
kfree
(
sctp_proto
.
ep_hashbucket
);
kfree
(
sctp_proto
.
port_hashtable
);
kfree
(
sctp_assoc_hashbucket
);
kfree
(
sctp_ep_hashbucket
);
kfree
(
sctp_port_hashtable
);
kmem_cache_destroy
(
sctp_chunk_cachep
);
kmem_cache_destroy
(
sctp_bucket_cachep
);
sctp_dbg_objcnt_exit
();
sctp_proc_exit
();
...
...
net/sctp/sm_make_chunk.c
View file @
1ee0db3c
...
...
@@ -68,6 +68,8 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
extern
kmem_cache_t
*
sctp_chunk_cachep
;
/* What was the inbound interface for this chunk? */
int
sctp_chunk_iif
(
const
struct
sctp_chunk
*
chunk
)
{
...
...
@@ -874,7 +876,7 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const
void
*
payload
,
const
size_t
paylen
)
{
struct
sctp_chunk
*
retval
=
sctp_make_chunk
(
asoc
,
SCTP_CID_HEARTBEAT
,
0
,
paylen
);
0
,
paylen
);
if
(
!
retval
)
goto
nodata
;
...
...
@@ -976,7 +978,9 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
const
struct
sctp_association
*
asoc
,
struct
sock
*
sk
)
{
struct
sctp_chunk
*
retval
=
t_new
(
struct
sctp_chunk
,
GFP_ATOMIC
);
struct
sctp_chunk
*
retval
;
retval
=
kmem_cache_alloc
(
sctp_chunk_cachep
,
SLAB_ATOMIC
);
if
(
!
retval
)
goto
nodata
;
...
...
@@ -1048,7 +1052,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
* arguments, reserving enough space for a 'paylen' byte payload.
*/
struct
sctp_chunk
*
sctp_make_chunk
(
const
struct
sctp_association
*
asoc
,
__u8
type
,
__u8
flags
,
int
paylen
)
__u8
type
,
__u8
flags
,
int
paylen
)
{
struct
sctp_chunk
*
retval
;
sctp_chunkhdr_t
*
chunk_hdr
;
...
...
@@ -1075,13 +1079,12 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
}
retval
->
chunk_hdr
=
chunk_hdr
;
retval
->
chunk_end
=
((
__u8
*
)
chunk_hdr
)
+
sizeof
(
s
ctp_chunkhdr_t
);
retval
->
chunk_end
=
((
__u8
*
)
chunk_hdr
)
+
sizeof
(
s
truct
sctp_chunkhdr
);
/* Set the skb to the belonging sock for accounting. */
skb
->
sk
=
sk
;
return
retval
;
nodata:
return
NULL
;
}
...
...
@@ -1090,12 +1093,11 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
/* Release the memory occupied by a chunk. */
static
void
sctp_chunk_destroy
(
struct
sctp_chunk
*
chunk
)
{
/* Free the chunk skb data and the SCTP_chunk stub itself. */
dev_kfree_skb
(
chunk
->
skb
);
kfree
(
chunk
);
SCTP_DBG_OBJCNT_DEC
(
chunk
);
kmem_cache_free
(
sctp_chunk_cachep
,
chunk
);
}
/* Possibly, free the chunk. */
...
...
@@ -1728,8 +1730,12 @@ int sctp_verify_init(const struct sctp_association *asoc,
sctp_walk_params
(
param
,
peer_init
,
init_hdr
.
params
)
{
if
(
!
sctp_verify_param
(
asoc
,
param
,
cid
,
chunk
,
errp
))
return
0
;
if
(
!
sctp_verify_param
(
asoc
,
param
,
cid
,
chunk
,
errp
))
{
if
(
SCTP_PARAM_HOST_NAME_ADDRESS
==
param
.
p
->
type
)
return
0
;
else
return
1
;
}
}
/* for (loop through all parameters) */
...
...
@@ -1907,7 +1913,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
break
;
case
SCTP_PARAM_COOKIE_PRESERVATIVE
:
if
(
!
sctp_
proto
.
cookie_preserve_enable
)
if
(
!
sctp_cookie_preserve_enable
)
break
;
stale
=
ntohl
(
param
.
life
->
lifespan_increment
);
...
...
net/sctp/sm_sideeffect.c
View file @
1ee0db3c
...
...
@@ -415,7 +415,8 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
struct
sctp_ulpevent
*
event
;
event
=
sctp_ulpevent_make_assoc_change
(
asoc
,
0
,
SCTP_CANT_STR_ASSOC
,
0
,
0
,
0
,
GFP_ATOMIC
);
(
__u16
)
error
,
0
,
0
,
GFP_ATOMIC
);
if
(
event
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
...
...
net/sctp/sm_statefuns.c
View file @
1ee0db3c
...
...
@@ -738,7 +738,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
{
struct
sctp_transport
*
transport
=
(
struct
sctp_transport
*
)
arg
;
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. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_U32
(
SCTP_ERROR_NO_ERROR
));
...
...
@@ -1238,7 +1238,6 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* parameter type.
*/
sctp_addto_chunk
(
repl
,
len
,
unk_param
);
sctp_chunk_free
(
err_chunk
);
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
...
...
@@ -1788,24 +1787,17 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
struct
sctp_chunk
*
chunk
=
arg
;
sctp_errhdr_t
*
err
;
err
=
(
sctp_errhdr_t
*
)(
chunk
->
skb
->
data
);
/* 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_U32
(
err
->
cause
));
return
SCTP_DISPOSITION_DELETE_TCB
;
}
/* 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
);
/* FUTURE FIXME: When PR-SCTP related and other optional
* parms are emitted, this will have to change to handle multiple
* errors.
*/
sctp_walk_errors
(
err
,
chunk
->
chunk_hdr
)
{
if
(
SCTP_ERROR_STALE_COOKIE
==
err
->
cause
)
return
sctp_sf_do_5_2_6_stale
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
/*
...
...
@@ -2067,6 +2059,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
struct
sctp_chunk
*
chunk
=
arg
;
sctp_shutdownhdr_t
*
sdh
;
sctp_disposition_t
disposition
;
struct
sctp_ulpevent
*
ev
;
/* Convert the elaborate header. */
sdh
=
(
sctp_shutdownhdr_t
*
)
chunk
->
skb
->
data
;
...
...
@@ -2097,12 +2090,28 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
arg
,
commands
);
}
if
(
SCTP_DISPOSITION_NOMEM
==
disposition
)
goto
out
;
/* - verify, by checking the Cumulative TSN Ack field of the
* chunk, that all its outstanding DATA chunks have been
* received by the SHUTDOWN sender.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_PROCESS_CTSN
,
SCTP_U32
(
chunk
->
subh
.
shutdown_hdr
->
cum_tsn_ack
));
/* API 5.3.1.5 SCTP_SHUTDOWN_EVENT
* When a peer sends a SHUTDOWN, SCTP delivers this notification to
* inform the application that it should cease sending data.
*/
ev
=
sctp_ulpevent_make_shutdown_event
(
asoc
,
0
,
GFP_ATOMIC
);
if
(
!
ev
)
{
disposition
=
SCTP_DISPOSITION_NOMEM
;
goto
out
;
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_EVENT_ULP
,
SCTP_ULPEVENT
(
ev
));
out:
return
disposition
;
}
...
...
@@ -2334,7 +2343,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
if
(
af
&&
af
->
is_ce
(
chunk
->
skb
)
&&
asoc
->
peer
.
ecn_capable
)
{
/* Do real work as sideffect. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ECN_CE
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ECN_CE
,
SCTP_U32
(
tsn
));
}
}
...
...
@@ -2375,7 +2384,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
* PMTU. In cases, such as loopback, this might be a rather
* large spill over.
*/
if
(
!
asoc
->
rwnd
||
asoc
->
rwnd_over
||
if
(
!
asoc
->
rwnd
||
asoc
->
rwnd_over
||
(
datalen
>
asoc
->
rwnd
+
asoc
->
frag_point
))
{
/* If this is the next TSN, consider reneging to make
...
...
@@ -2594,7 +2603,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
if
(
af
&&
af
->
is_ce
(
chunk
->
skb
)
&&
asoc
->
peer
.
ecn_capable
)
{
/* Do real work as sideffect. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ECN_CE
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ECN_CE
,
SCTP_U32
(
tsn
));
}
}
...
...
@@ -2740,6 +2749,9 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
/* Pull the SACK chunk from the data buffer */
sackh
=
sctp_sm_pull_sack
(
chunk
);
/* Was this a bogus SACK? */
if
(
!
sackh
)
return
sctp_sf_pdiscard
(
ep
,
asoc
,
type
,
arg
,
commands
);
chunk
->
subh
.
sack_hdr
=
sackh
;
ctsn
=
ntohl
(
sackh
->
cum_tsn_ack
);
...
...
@@ -4406,22 +4418,27 @@ sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
********************************************************************/
/* Pull the SACK chunk based on the SACK header. */
s
ctp_sackhdr_t
*
sctp_sm_pull_sack
(
struct
sctp_chunk
*
chunk
)
s
truct
sctp_sackhdr
*
sctp_sm_pull_sack
(
struct
sctp_chunk
*
chunk
)
{
sctp_sackhdr_t
*
sack
;
struct
sctp_sackhdr
*
sack
;
unsigned
int
len
;
__u16
num_blocks
;
__u16
num_dup_tsns
;
/*
FIXME:
Protect ourselves from reading too far into
/* Protect ourselves from reading too far into
* the skb from a bogus sender.
*/
sack
=
(
sctp_sackhdr_t
*
)
chunk
->
skb
->
data
;
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_sackhdr_t
));
sack
=
(
struct
sctp_sackhdr
*
)
chunk
->
skb
->
data
;
num_blocks
=
ntohs
(
sack
->
num_gap_ack_blocks
);
num_dup_tsns
=
ntohs
(
sack
->
num_dup_tsns
);
len
=
sizeof
(
struct
sctp_sackhdr
);
len
=
(
num_blocks
+
num_dup_tsns
)
*
sizeof
(
__u32
);
if
(
len
>
chunk
->
skb
->
len
)
return
NULL
;
skb_pull
(
chunk
->
skb
,
len
);
skb_pull
(
chunk
->
skb
,
(
num_blocks
+
num_dup_tsns
)
*
sizeof
(
__u32
));
return
sack
;
}
...
...
net/sctp/sm_statetable.c
View file @
1ee0db3c
...
...
@@ -436,51 +436,6 @@ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NU
TYPE_SCTP_SHUTDOWN_COMPLETE
,
};
/* state_fn_t chunk_event_table[][] */
static
sctp_sm_table_entry_t
chunk_event_table_asconf
[
SCTP_STATE_NUM_STATES
]
=
{
/* SCTP_STATE_EMPTY */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_CLOSED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_COOKIE_WAIT */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_COOKIE_ECHOED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_ESTABLISHED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"
},
/* SCTP_STATE_SHUTDOWN_PENDING */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_SHUTDOWN_SENT */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_SHUTDOWN_RECEIVED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
};
/* chunk asconf */
static
sctp_sm_table_entry_t
chunk_event_table_asconf_ack
[
SCTP_STATE_NUM_STATES
]
=
{
/* SCTP_STATE_EMPTY */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_CLOSED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_COOKIE_WAIT */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_COOKIE_ECHOED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_ESTABLISHED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"
},
/* SCTP_STATE_SHUTDOWN_PENDING */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_SHUTDOWN_SENT */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_SHUTDOWN_RECEIVED */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
{.
fn
=
sctp_sf_discard_chunk
,
.
name
=
"sctp_sf_discard_chunk"
},
};
/* chunk asconf_ack */
static
sctp_sm_table_entry_t
chunk_event_table_unknown
[
SCTP_STATE_NUM_STATES
]
=
{
...
...
@@ -783,7 +738,7 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_t
imer_ignore, .name = "sctp_sf_timer_igno
re"}, \
{.fn = sctp_sf_t
5_timer_expire, .name = "sctp_sf_t5_timer_expi
re"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_t5_timer_expire, .name = "sctp_sf_t5_timer_expire"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
...
...
@@ -877,13 +832,5 @@ sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t stat
return
&
chunk_event_table
[
cid
][
state
];
}
switch
(
cid
)
{
case
SCTP_CID_ASCONF
:
return
&
chunk_event_table_asconf
[
state
];
case
SCTP_CID_ASCONF_ACK
:
return
&
chunk_event_table_asconf_ack
[
state
];
default:
return
&
chunk_event_table_unknown
[
state
];
}
return
&
chunk_event_table_unknown
[
state
];
}
net/sctp/socket.c
View file @
1ee0db3c
...
...
@@ -99,6 +99,8 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
struct
sctp_association
*
,
sctp_socket_type_t
);
static
char
*
sctp_hmac_alg
=
SCTP_COOKIE_HMAC_ALG
;
extern
kmem_cache_t
*
sctp_bucket_cachep
;
/* Look up the association by its id. If this is not a UDP-style
* socket, the ID field is always ignored.
*/
...
...
@@ -106,10 +108,16 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
{
struct
sctp_association
*
asoc
=
NULL
;
/* If this is not a UDP-style socket, assoc id should be
* ignored.
*/
/* If this is not a UDP-style socket, assoc id should be ignored. */
if
(
!
sctp_style
(
sk
,
UDP
))
{
/* Return NULL if the socket state is not ESTABLISHED. It
* could be a TCP-style listening socket or a socket which
* hasn't yet called connect() to establish an association.
*/
if
(
!
sctp_sstate
(
sk
,
ESTABLISHED
))
return
NULL
;
/* Get the first and the only association from the list. */
if
(
!
list_empty
(
&
sctp_sk
(
sk
)
->
ep
->
asocs
))
asoc
=
list_entry
(
sctp_sk
(
sk
)
->
ep
->
asocs
.
next
,
struct
sctp_association
,
asocs
);
...
...
@@ -132,6 +140,30 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
return
asoc
;
}
/* Look up the transport from an address and an assoc id. If both address and
* id are specified, the associations matching the address and the id should be
* the same.
*/
struct
sctp_transport
*
sctp_addr_id2transport
(
struct
sock
*
sk
,
struct
sockaddr_storage
*
addr
,
sctp_assoc_t
id
)
{
struct
sctp_association
*
addr_asoc
=
NULL
,
*
id_asoc
=
NULL
;
struct
sctp_transport
*
transport
;
addr_asoc
=
sctp_endpoint_lookup_assoc
(
sctp_sk
(
sk
)
->
ep
,
(
union
sctp_addr
*
)
addr
,
&
transport
);
if
(
!
addr_asoc
)
return
NULL
;
id_asoc
=
sctp_id2assoc
(
sk
,
id
);
if
(
id_asoc
&&
(
id_asoc
!=
addr_asoc
))
return
NULL
;
return
transport
;
}
/* API 3.1.2 bind() - UDP Style Syntax
* The syntax of bind() is,
*
...
...
@@ -710,7 +742,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
struct
sctp_association
*
asoc
;
struct
list_head
*
pos
,
*
temp
;
printk
(
"sctp_close(sk: 0x%p, timeout:%ld)
\n
"
,
sk
,
timeout
);
SCTP_DEBUG_PRINTK
(
"sctp_close(sk: 0x%p, timeout:%ld)
\n
"
,
sk
,
timeout
);
sctp_lock_sock
(
sk
);
sk
->
sk_shutdown
=
SHUTDOWN_MASK
;
...
...
@@ -1061,11 +1093,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo
.
sinfo_stream
=
asoc
->
default
s
.
stream
;
default_sinfo
.
sinfo_flags
=
asoc
->
default
s
.
flags
;
default_sinfo
.
sinfo_ppid
=
asoc
->
default
s
.
ppid
;
default_sinfo
.
sinfo_context
=
asoc
->
default
s
.
context
;
default_sinfo
.
sinfo_timetolive
=
asoc
->
default
s
.
timetolive
;
default_sinfo
.
sinfo_stream
=
asoc
->
default
_
stream
;
default_sinfo
.
sinfo_flags
=
asoc
->
default
_
flags
;
default_sinfo
.
sinfo_ppid
=
asoc
->
default
_
ppid
;
default_sinfo
.
sinfo_context
=
asoc
->
default
_
context
;
default_sinfo
.
sinfo_timetolive
=
asoc
->
default
_
timetolive
;
default_sinfo
.
sinfo_assoc_id
=
sctp_assoc2id
(
asoc
);
sinfo
=
&
default_sinfo
;
}
...
...
@@ -1333,6 +1365,13 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
return
err
;
}
/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
*
* This option is a on/off flag. If enabled no SCTP message
* fragmentation will be performed. Instead if a message being sent
* exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user.
*/
static
int
sctp_setsockopt_disable_fragments
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
...
...
@@ -1359,6 +1398,17 @@ static int sctp_setsockopt_events(struct sock *sk, char *optval,
return
0
;
}
/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
*
* This socket option is applicable to the UDP-style socket only. When
* set it will cause associations that are idle for more than the
* specified number of seconds to automatically close. An association
* being idle is defined an association that has NOT sent or received
* user data. The special value of '0' indicates that no automatic
* close of any associations should be performed. The option expects an
* integer defining the number of seconds of idle time before an
* association is closed.
*/
static
int
sctp_setsockopt_autoclose
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
...
...
@@ -1376,12 +1426,41 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return
0
;
}
/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS)
*
* Applications can enable or disable heartbeats for any peer address of
* an association, modify an address's heartbeat interval, force a
* heartbeat to be sent immediately, and adjust the address's maximum
* number of retransmissions sent before an address is considered
* unreachable. The following structure is used to access and modify an
* address's parameters:
*
* struct sctp_paddrparams {
* sctp_assoc_t spp_assoc_id;
* struct sockaddr_storage spp_address;
* uint32_t spp_hbinterval;
* uint16_t spp_pathmaxrxt;
* };
*
* spp_assoc_id - (UDP style socket) This is filled in the application,
* and identifies the association for this query.
* spp_address - This specifies which address is of interest.
* spp_hbinterval - This contains the value of the heartbeat interval,
* in milliseconds. A value of 0, when modifying the
* parameter, specifies that the heartbeat on this
* address should be disabled. A value of UINT32_MAX
* (4294967295), when modifying the parameter,
* specifies that a heartbeat should be sent
* immediately to the peer address, and the current
* interval should remain unchanged.
* spp_pathmaxrxt - This contains the maximum number of
* retransmissions before this address shall be
* considered unreachable.
*/
static
int
sctp_setsockopt_peer_addr_params
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
struct
sctp_paddrparams
params
;
struct
sctp_association
*
asoc
;
union
sctp_addr
*
addr
;
struct
sctp_transport
*
trans
;
int
error
;
...
...
@@ -1390,15 +1469,10 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
if
(
copy_from_user
(
&
params
,
optval
,
optlen
))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
params
.
spp_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
addr
=
(
union
sctp_addr
*
)
&
(
params
.
spp_address
);
trans
=
sctp_assoc_lookup_paddr
(
asoc
,
addr
);
trans
=
sctp_addr_id2transport
(
sk
,
&
params
.
spp_address
,
params
.
spp_assoc_id
);
if
(
!
trans
)
return
-
E
NOENT
;
return
-
E
INVAL
;
/* Applications can enable or disable heartbeats for any peer address
* of an association, modify an address's heartbeat interval, force a
...
...
@@ -1412,7 +1486,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
* and the current interval should remain unchanged.
*/
if
(
0xffffffff
==
params
.
spp_hbinterval
)
{
error
=
sctp_primitive_REQUESTHEARTBEAT
(
asoc
,
trans
);
error
=
sctp_primitive_REQUESTHEARTBEAT
(
trans
->
asoc
,
trans
);
if
(
error
)
return
error
;
}
else
{
...
...
@@ -1435,6 +1509,17 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
return
0
;
}
/* 7.1.3 Initialization Parameters (SCTP_INITMSG)
*
* Applications can specify protocol parameters for the default association
* initialization. The option name argument to setsockopt() and getsockopt()
* is SCTP_INITMSG.
*
* Setting initialization parameters is effective only on an unconnected
* socket (for UDP-style sockets only future associations are effected
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
static
int
sctp_setsockopt_initmsg
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
if
(
optlen
!=
sizeof
(
struct
sctp_initmsg
))
...
...
@@ -1445,7 +1530,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
}
/*
* 7.1.1
5
Set default send parameters (SET_DEFAULT_SEND_PARAM)
* 7.1.1
4
Set default send parameters (SET_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied
...
...
@@ -1463,6 +1548,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
{
struct
sctp_sndrcvinfo
info
;
struct
sctp_association
*
asoc
;
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
if
(
optlen
!=
sizeof
(
struct
sctp_sndrcvinfo
))
return
-
EINVAL
;
...
...
@@ -1470,14 +1556,23 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
info
.
sinfo_assoc_id
);
if
(
!
asoc
)
if
(
!
asoc
&&
info
.
sinfo_assoc_id
&&
sctp_style
(
sk
,
UDP
)
)
return
-
EINVAL
;
asoc
->
defaults
.
stream
=
info
.
sinfo_stream
;
asoc
->
defaults
.
flags
=
info
.
sinfo_flags
;
asoc
->
defaults
.
ppid
=
info
.
sinfo_ppid
;
asoc
->
defaults
.
context
=
info
.
sinfo_context
;
asoc
->
defaults
.
timetolive
=
info
.
sinfo_timetolive
;
if
(
asoc
)
{
asoc
->
default_stream
=
info
.
sinfo_stream
;
asoc
->
default_flags
=
info
.
sinfo_flags
;
asoc
->
default_ppid
=
info
.
sinfo_ppid
;
asoc
->
default_context
=
info
.
sinfo_context
;
asoc
->
default_timetolive
=
info
.
sinfo_timetolive
;
}
else
{
sp
->
default_stream
=
info
.
sinfo_stream
;
sp
->
default_flags
=
info
.
sinfo_flags
;
sp
->
default_ppid
=
info
.
sinfo_ppid
;
sp
->
default_context
=
info
.
sinfo_context
;
sp
->
default_timetolive
=
info
.
sinfo_timetolive
;
}
return
0
;
}
...
...
@@ -1490,8 +1585,6 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
static
int
sctp_setsockopt_peer_prim
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
struct
sctp_setpeerprim
prim
;
struct
sctp_association
*
asoc
;
union
sctp_addr
*
addr
;
struct
sctp_transport
*
trans
;
if
(
optlen
!=
sizeof
(
struct
sctp_setpeerprim
))
...
...
@@ -1500,18 +1593,11 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
if
(
copy_from_user
(
&
prim
,
optval
,
sizeof
(
struct
sctp_setpeerprim
)))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
prim
.
sspp_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
/* Find the requested address. */
addr
=
(
union
sctp_addr
*
)
&
(
prim
.
sspp_addr
);
trans
=
sctp_assoc_lookup_paddr
(
asoc
,
addr
);
trans
=
sctp_addr_id2transport
(
sk
,
&
prim
.
sspp_addr
,
prim
.
sspp_assoc_id
);
if
(
!
trans
)
return
-
E
NOENT
;
return
-
E
INVAL
;
sctp_assoc_set_primary
(
asoc
,
trans
);
sctp_assoc_set_primary
(
trans
->
asoc
,
trans
);
return
0
;
}
...
...
@@ -1906,13 +1992,10 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
SCTP_STATIC
int
sctp_init_sock
(
struct
sock
*
sk
)
{
struct
sctp_endpoint
*
ep
;
struct
sctp_protocol
*
proto
;
struct
sctp_opt
*
sp
;
SCTP_DEBUG_PRINTK
(
"sctp_init_sock(sk: %p)
\n
"
,
sk
);
proto
=
sctp_get_protocol
();
sp
=
sctp_sk
(
sk
);
/* Initialize the SCTP per socket area. */
...
...
@@ -1933,23 +2016,26 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/
sp
->
default_stream
=
0
;
sp
->
default_ppid
=
0
;
sp
->
default_flags
=
0
;
sp
->
default_context
=
0
;
sp
->
default_timetolive
=
0
;
/* Initialize default setup parameters. These parameters
* can be modified with the SCTP_INITMSG socket option or
* overridden by the SCTP_INIT CMSG.
*/
sp
->
initmsg
.
sinit_num_ostreams
=
proto
->
max_outstreams
;
sp
->
initmsg
.
sinit_max_instreams
=
proto
->
max_instreams
;
sp
->
initmsg
.
sinit_max_attempts
=
proto
->
max_retrans_init
;
sp
->
initmsg
.
sinit_max_init_timeo
=
proto
->
rto_max
/
HZ
;
sp
->
initmsg
.
sinit_num_ostreams
=
sctp_
max_outstreams
;
sp
->
initmsg
.
sinit_max_instreams
=
sctp_
max_instreams
;
sp
->
initmsg
.
sinit_max_attempts
=
sctp_
max_retrans_init
;
sp
->
initmsg
.
sinit_max_init_timeo
=
sctp_
rto_max
/
HZ
;
/* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option.
* FIXME: These are not used yet.
*/
sp
->
rtoinfo
.
srto_initial
=
proto
->
rto_initial
;
sp
->
rtoinfo
.
srto_max
=
proto
->
rto_max
;
sp
->
rtoinfo
.
srto_min
=
proto
->
rto_min
;
sp
->
rtoinfo
.
srto_initial
=
sctp_
rto_initial
;
sp
->
rtoinfo
.
srto_max
=
sctp_
rto_max
;
sp
->
rtoinfo
.
srto_min
=
sctp_
rto_min
;
/* Initialize default event subscriptions.
* the struct sock is initialized to zero, so only
...
...
@@ -1964,8 +2050,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Default Peer Address Parameters. These defaults can
* be modified via SCTP_SET_PEER_ADDR_PARAMS
*/
sp
->
paddrparam
.
spp_hbinterval
=
proto
->
hb_interval
/
HZ
;
sp
->
paddrparam
.
spp_pathmaxrxt
=
proto
->
max_retrans_path
;
sp
->
paddrparam
.
spp_hbinterval
=
sctp_
hb_interval
/
HZ
;
sp
->
paddrparam
.
spp_pathmaxrxt
=
sctp_
max_retrans_path
;
/* If enabled no SCTP message fragmentation will be performed.
* Configure through SCTP_DISABLE_FRAGMENTS socket option.
...
...
@@ -2131,6 +2217,64 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
return
(
retval
);
}
/* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO)
*
* Applications can retrieve information about a specific peer address
* of an association, including its reachability state, congestion
* window, and retransmission timer values. This information is
* read-only.
*/
static
int
sctp_getsockopt_peer_addr_info
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
struct
sctp_paddrinfo
pinfo
;
struct
sctp_transport
*
transport
;
int
retval
=
0
;
if
(
len
!=
sizeof
(
pinfo
))
{
retval
=
-
EINVAL
;
goto
out
;
}
if
(
copy_from_user
(
&
pinfo
,
optval
,
sizeof
(
pinfo
)))
{
retval
=
-
EFAULT
;
goto
out
;
}
transport
=
sctp_addr_id2transport
(
sk
,
&
pinfo
.
spinfo_address
,
pinfo
.
spinfo_assoc_id
);
if
(
!
transport
)
return
-
EINVAL
;
pinfo
.
spinfo_assoc_id
=
sctp_assoc2id
(
transport
->
asoc
);
pinfo
.
spinfo_state
=
transport
->
active
;
pinfo
.
spinfo_cwnd
=
transport
->
cwnd
;
pinfo
.
spinfo_srtt
=
transport
->
srtt
;
pinfo
.
spinfo_rto
=
transport
->
rto
;
pinfo
.
spinfo_mtu
=
transport
->
pmtu
;
if
(
put_user
(
len
,
optlen
))
{
retval
=
-
EFAULT
;
goto
out
;
}
if
(
copy_to_user
(
optval
,
&
pinfo
,
len
))
{
retval
=
-
EFAULT
;
goto
out
;
}
out:
return
(
retval
);
}
/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
*
* This option is a on/off flag. If enabled no SCTP message
* fragmentation will be performed. Instead if a message being sent
* exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user.
*/
static
int
sctp_getsockopt_disable_fragments
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
...
...
@@ -2148,6 +2292,11 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
return
0
;
}
/* 7.1.15 Set notification and ancillary events (SCTP_SET_EVENTS)
*
* This socket option is used to specify various notifications and
* ancillary data the user wishes to receive.
*/
static
int
sctp_getsockopt_set_events
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
if
(
len
!=
sizeof
(
struct
sctp_event_subscribe
))
...
...
@@ -2157,6 +2306,17 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in
return
0
;
}
/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
*
* This socket option is applicable to the UDP-style socket only. When
* set it will cause associations that are idle for more than the
* specified number of seconds to automatically close. An association
* being idle is defined an association that has NOT sent or received
* user data. The special value of '0' indicates that no automatic
* close of any associations should be performed. The option expects an
* integer defining the number of seconds of idle time before an
* association is closed.
*/
static
int
sctp_getsockopt_autoclose
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
/* Applicable to UDP-style socket only */
...
...
@@ -2240,12 +2400,41 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
return
retval
;
}
/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS)
*
* Applications can enable or disable heartbeats for any peer address of
* an association, modify an address's heartbeat interval, force a
* heartbeat to be sent immediately, and adjust the address's maximum
* number of retransmissions sent before an address is considered
* unreachable. The following structure is used to access and modify an
* address's parameters:
*
* struct sctp_paddrparams {
* sctp_assoc_t spp_assoc_id;
* struct sockaddr_storage spp_address;
* uint32_t spp_hbinterval;
* uint16_t spp_pathmaxrxt;
* };
*
* spp_assoc_id - (UDP style socket) This is filled in the application,
* and identifies the association for this query.
* spp_address - This specifies which address is of interest.
* spp_hbinterval - This contains the value of the heartbeat interval,
* in milliseconds. A value of 0, when modifying the
* parameter, specifies that the heartbeat on this
* address should be disabled. A value of UINT32_MAX
* (4294967295), when modifying the parameter,
* specifies that a heartbeat should be sent
* immediately to the peer address, and the current
* interval should remain unchanged.
* spp_pathmaxrxt - This contains the maximum number of
* retransmissions before this address shall be
* considered unreachable.
*/
static
int
sctp_getsockopt_peer_addr_params
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
struct
sctp_paddrparams
params
;
struct
sctp_association
*
asoc
;
union
sctp_addr
*
addr
;
struct
sctp_transport
*
trans
;
if
(
len
!=
sizeof
(
struct
sctp_paddrparams
))
...
...
@@ -2253,15 +2442,10 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
if
(
copy_from_user
(
&
params
,
optval
,
*
optlen
))
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
params
.
spp_assoc_id
);
if
(
!
asoc
)
return
-
EINVAL
;
addr
=
(
union
sctp_addr
*
)
&
(
params
.
spp_address
);
trans
=
sctp_assoc_lookup_paddr
(
asoc
,
addr
);
trans
=
sctp_addr_id2transport
(
sk
,
&
params
.
spp_address
,
params
.
spp_assoc_id
);
if
(
!
trans
)
return
-
E
NOENT
;
return
-
E
INVAL
;
/* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this
...
...
@@ -2286,6 +2470,17 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
return
0
;
}
/* 7.1.3 Initialization Parameters (SCTP_INITMSG)
*
* Applications can specify protocol parameters for the default association
* initialization. The option name argument to setsockopt() and getsockopt()
* is SCTP_INITMSG.
*
* Setting initialization parameters is effective only on an unconnected
* socket (for UDP-style sockets only future associations are effected
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
static
int
sctp_getsockopt_initmsg
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
if
(
len
!=
sizeof
(
struct
sctp_initmsg
))
...
...
@@ -2491,7 +2686,7 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len,
/*
*
* 7.1.1
5
Set default send parameters (SET_DEFAULT_SEND_PARAM)
* 7.1.1
4
Set default send parameters (SET_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied
...
...
@@ -2511,6 +2706,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
{
struct
sctp_sndrcvinfo
info
;
struct
sctp_association
*
asoc
;
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
if
(
len
!=
sizeof
(
struct
sctp_sndrcvinfo
))
return
-
EINVAL
;
...
...
@@ -2518,14 +2714,22 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
return
-
EFAULT
;
asoc
=
sctp_id2assoc
(
sk
,
info
.
sinfo_assoc_id
);
if
(
!
asoc
)
if
(
!
asoc
&&
info
.
sinfo_assoc_id
&&
sctp_style
(
sk
,
UDP
)
)
return
-
EINVAL
;
info
.
sinfo_stream
=
asoc
->
defaults
.
stream
;
info
.
sinfo_flags
=
asoc
->
defaults
.
flags
;
info
.
sinfo_ppid
=
asoc
->
defaults
.
ppid
;
info
.
sinfo_context
=
asoc
->
defaults
.
context
;
info
.
sinfo_timetolive
=
asoc
->
defaults
.
timetolive
;
if
(
asoc
)
{
info
.
sinfo_stream
=
asoc
->
default_stream
;
info
.
sinfo_flags
=
asoc
->
default_flags
;
info
.
sinfo_ppid
=
asoc
->
default_ppid
;
info
.
sinfo_context
=
asoc
->
default_context
;
info
.
sinfo_timetolive
=
asoc
->
default_timetolive
;
}
else
{
info
.
sinfo_stream
=
sp
->
default_stream
;
info
.
sinfo_flags
=
sp
->
default_flags
;
info
.
sinfo_ppid
=
sp
->
default_ppid
;
info
.
sinfo_context
=
sp
->
default_context
;
info
.
sinfo_timetolive
=
sp
->
default_timetolive
;
}
if
(
copy_to_user
(
optval
,
&
info
,
sizeof
(
struct
sctp_sndrcvinfo
)))
return
-
EFAULT
;
...
...
@@ -2698,6 +2902,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case
SCTP_MAXSEG
:
retval
=
sctp_getsockopt_maxseg
(
sk
,
len
,
optval
,
optlen
);
break
;
case
SCTP_GET_PEER_ADDR_INFO
:
retval
=
sctp_getsockopt_peer_addr_info
(
sk
,
len
,
optval
,
optlen
);
break
;
default:
retval
=
-
ENOPROTOOPT
;
break
;
...
...
@@ -2721,7 +2929,7 @@ static void sctp_unhash(struct sock *sk)
*
* The port hash table (contained in the 'global' SCTP protocol storage
* returned by struct sctp_protocol *sctp_get_protocol()). The hash
* table is an array of 4096 lists (sctp_bind_hashbucket
_t
). Each
* table is an array of 4096 lists (sctp_bind_hashbucket). Each
* list (the list number is the port number hashed out, so as you
* would expect from a hash function, all the ports in a given list have
* such a number that hashes out to the same list number; you were
...
...
@@ -2729,13 +2937,13 @@ static void sctp_unhash(struct sock *sk)
* link to the socket (struct sock) that uses it, the port number and
* a fastreuse flag (FIXME: NPI ipg).
*/
static
sctp_bind_bucket_t
*
sctp_bucket_create
(
sctp_bind_hashbucket_t
*
head
,
unsigned
short
snum
);
static
struct
sctp_bind_bucket
*
sctp_bucket_create
(
struct
sctp_bind_hashbucket
*
head
,
unsigned
short
snum
);
static
long
sctp_get_port_local
(
struct
sock
*
sk
,
union
sctp_addr
*
addr
)
{
sctp_bind_hashbucket_t
*
head
;
/* hash list */
sctp_bind_bucket_t
*
pp
;
/* hash list port iterator */
struct
sctp_protocol
*
sctp
=
sctp_get_protocol
();
struct
sctp_bind_hashbucket
*
head
;
/* hash list */
struct
sctp_bind_bucket
*
pp
;
/* hash list port iterator */
unsigned
short
snum
;
int
ret
;
...
...
@@ -2750,8 +2958,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
if
(
snum
==
0
)
{
/* Search for an available port.
*
* 'sctp
->
port_rover' was the last port assigned, so
* we start to search from 'sctp
->
port_rover +
* 'sctp
_
port_rover' was the last port assigned, so
* we start to search from 'sctp
_
port_rover +
* 1'. What we do is first check if port 'rover' is
* already in the hash table; if not, we use that; if
* it is, we try next.
...
...
@@ -2762,14 +2970,14 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
int
rover
;
int
index
;
sctp_spin_lock
(
&
sctp
->
port_alloc_lock
);
rover
=
sctp
->
port_rover
;
sctp_spin_lock
(
&
sctp
_
port_alloc_lock
);
rover
=
sctp
_
port_rover
;
do
{
rover
++
;
if
((
rover
<
low
)
||
(
rover
>
high
))
rover
=
low
;
index
=
sctp_phashfn
(
rover
);
head
=
&
sctp
->
port_hashtable
[
index
];
head
=
&
sctp
_
port_hashtable
[
index
];
sctp_spin_lock
(
&
head
->
lock
);
for
(
pp
=
head
->
chain
;
pp
;
pp
=
pp
->
next
)
if
(
pp
->
port
==
rover
)
...
...
@@ -2778,8 +2986,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
next:
sctp_spin_unlock
(
&
head
->
lock
);
}
while
(
--
remaining
>
0
);
sctp
->
port_rover
=
rover
;
sctp_spin_unlock
(
&
sctp
->
port_alloc_lock
);
sctp
_
port_rover
=
rover
;
sctp_spin_unlock
(
&
sctp
_
port_alloc_lock
);
/* Exhausted local port range during search? */
ret
=
1
;
...
...
@@ -2799,7 +3007,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* to the port number (snum) - we detect that with the
* port iterator, pp being NULL.
*/
head
=
&
sctp
->
port_hashtable
[
sctp_phashfn
(
snum
)];
head
=
&
sctp
_
port_hashtable
[
sctp_phashfn
(
snum
)];
sctp_spin_lock
(
&
head
->
lock
);
for
(
pp
=
head
->
chain
;
pp
;
pp
=
pp
->
next
)
{
if
(
pp
->
port
==
snum
)
...
...
@@ -3105,12 +3313,13 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
* 2nd Level Abstractions
********************************************************************/
static
sctp_bind_bucket_t
*
sctp_bucket_create
(
sctp_bind_hashbucket_t
*
head
,
unsigned
short
snum
)
static
struct
sctp_bind_bucket
*
sctp_bucket_create
(
struct
sctp_bind_hashbucket
*
head
,
unsigned
short
snum
)
{
s
ctp_bind_bucket_
t
*
pp
;
s
truct
sctp_bind_bucke
t
*
pp
;
SCTP_DEBUG_PRINTK
(
"sctp_bucket_create() begins, snum=%d
\n
"
,
snum
);
pp
=
kmalloc
(
sizeof
(
sctp_bind_bucket_t
),
GFP_ATOMIC
);
pp
=
kmem_cache_alloc
(
sctp_bucket_cachep
,
SLAB_ATOMIC
);
SCTP_DBG_OBJCNT_INC
(
bind_bucket
);
if
(
pp
)
{
pp
->
port
=
snum
;
pp
->
fastreuse
=
0
;
...
...
@@ -3120,31 +3329,36 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi
head
->
chain
=
pp
;
pp
->
pprev
=
&
head
->
chain
;
}
SCTP_DEBUG_PRINTK
(
"sctp_bucket_create() ends, pp=%p
\n
"
,
pp
);
return
pp
;
}
/* Caller must hold hashbucket lock for this tb with local BH disabled */
static
void
sctp_bucket_destroy
(
struct
sctp_bind_bucket
*
pp
)
{
if
(
!
pp
->
sk
)
{
if
(
pp
->
next
)
pp
->
next
->
pprev
=
pp
->
pprev
;
*
(
pp
->
pprev
)
=
pp
->
next
;
kmem_cache_free
(
sctp_bucket_cachep
,
pp
);
SCTP_DBG_OBJCNT_DEC
(
bind_bucket
);
}
}
/* FIXME: Comments! */
static
__inline__
void
__sctp_put_port
(
struct
sock
*
sk
)
{
struct
sctp_protocol
*
sctp_proto
=
sctp_get_protocol
();
sctp_bind_hashbucket_t
*
head
=
&
sctp_proto
->
port_hashtable
[
sctp_phashfn
(
inet_sk
(
sk
)
->
num
)];
sctp_bind_bucket_t
*
pp
;
struct
sctp_bind_hashbucket
*
head
=
&
sctp_port_hashtable
[
sctp_phashfn
(
inet_sk
(
sk
)
->
num
)];
struct
sctp_bind_bucket
*
pp
;
sctp_spin_lock
(
&
head
->
lock
);
pp
=
(
s
ctp_bind_bucket_
t
*
)
sk
->
sk_prev
;
pp
=
(
s
truct
sctp_bind_bucke
t
*
)
sk
->
sk_prev
;
if
(
sk
->
sk_bind_next
)
sk
->
sk_bind_next
->
sk_bind_pprev
=
sk
->
sk_bind_pprev
;
*
(
sk
->
sk_bind_pprev
)
=
sk
->
sk_bind_next
;
sk
->
sk_prev
=
NULL
;
inet_sk
(
sk
)
->
num
=
0
;
if
(
pp
->
sk
)
{
if
(
pp
->
next
)
pp
->
next
->
pprev
=
pp
->
pprev
;
*
(
pp
->
pprev
)
=
pp
->
next
;
kfree
(
pp
);
}
sctp_bucket_destroy
(
pp
);
sctp_spin_unlock
(
&
head
->
lock
);
}
...
...
net/sctp/sysctl.c
View file @
1ee0db3c
...
...
@@ -42,13 +42,11 @@
#include <net/sctp/structs.h>
#include <linux/sysctl.h>
extern
struct
sctp_protocol
sctp_proto
;
static
ctl_table
sctp_table
[]
=
{
{
.
ctl_name
=
NET_SCTP_RTO_INITIAL
,
.
procname
=
"rto_initial"
,
.
data
=
&
sctp_
proto
.
rto_initial
,
.
data
=
&
sctp_rto_initial
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec_jiffies
,
...
...
@@ -57,7 +55,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_RTO_MIN
,
.
procname
=
"rto_min"
,
.
data
=
&
sctp_
proto
.
rto_min
,
.
data
=
&
sctp_rto_min
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec_jiffies
,
...
...
@@ -66,7 +64,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_RTO_MAX
,
.
procname
=
"rto_max"
,
.
data
=
&
sctp_
proto
.
rto_max
,
.
data
=
&
sctp_rto_max
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec_jiffies
,
...
...
@@ -75,7 +73,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_VALID_COOKIE_LIFE
,
.
procname
=
"valid_cookie_life"
,
.
data
=
&
sctp_
proto
.
valid_cookie_life
,
.
data
=
&
sctp_valid_cookie_life
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec_jiffies
,
...
...
@@ -84,7 +82,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_MAX_BURST
,
.
procname
=
"max_burst"
,
.
data
=
&
sctp_
proto
.
max_burst
,
.
data
=
&
sctp_max_burst
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
...
...
@@ -92,7 +90,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_ASSOCIATION_MAX_RETRANS
,
.
procname
=
"association_max_retrans"
,
.
data
=
&
sctp_
proto
.
max_retrans_association
,
.
data
=
&
sctp_max_retrans_association
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
...
...
@@ -100,7 +98,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_PATH_MAX_RETRANS
,
.
procname
=
"path_max_retrans"
,
.
data
=
&
sctp_
proto
.
max_retrans_path
,
.
data
=
&
sctp_max_retrans_path
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
...
...
@@ -108,7 +106,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_MAX_INIT_RETRANSMITS
,
.
procname
=
"max_init_retransmits"
,
.
data
=
&
sctp_
proto
.
max_retrans_init
,
.
data
=
&
sctp_max_retrans_init
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
...
...
@@ -116,7 +114,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_HB_INTERVAL
,
.
procname
=
"hb_interval"
,
.
data
=
&
sctp_
proto
.
hb_interval
,
.
data
=
&
sctp_hb_interval
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec_jiffies
,
...
...
@@ -125,7 +123,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_PRESERVE_ENABLE
,
.
procname
=
"cookie_preserve_enable"
,
.
data
=
&
sctp_
proto
.
cookie_preserve_enable
,
.
data
=
&
sctp_cookie_preserve_enable
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec_jiffies
,
...
...
@@ -134,7 +132,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_RTO_ALPHA
,
.
procname
=
"rto_alpha_exp_divisor"
,
.
data
=
&
sctp_
proto
.
rto_alpha
,
.
data
=
&
sctp_rto_alpha
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
...
...
@@ -142,7 +140,7 @@ static ctl_table sctp_table[] = {
{
.
ctl_name
=
NET_SCTP_RTO_BETA
,
.
procname
=
"rto_beta_exp_divisor"
,
.
data
=
&
sctp_
proto
.
rto_beta
,
.
data
=
&
sctp_rto_beta
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
&
proc_dointvec
...
...
net/sctp/transport.c
View file @
1ee0db3c
...
...
@@ -82,8 +82,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const
union
sctp_addr
*
addr
,
int
gfp
)
{
struct
sctp_protocol
*
proto
=
sctp_get_protocol
();
/* Copy in the address. */
peer
->
ipaddr
=
*
addr
;
peer
->
af_specific
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
...
...
@@ -99,7 +97,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
* parameter 'RTO.Initial'.
*/
peer
->
rtt
=
0
;
peer
->
rto
=
proto
->
rto_initial
;
peer
->
rto
=
sctp_
rto_initial
;
peer
->
rttvar
=
0
;
peer
->
srtt
=
0
;
peer
->
rto_pending
=
0
;
...
...
@@ -108,11 +106,11 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer
->
last_time_used
=
jiffies
;
peer
->
last_time_ecne_reduced
=
jiffies
;
peer
->
active
=
1
;
peer
->
active
=
SCTP_ACTIVE
;
peer
->
hb_allowed
=
0
;
/* Initialize the default path max_retrans. */
peer
->
max_retrans
=
proto
->
max_retrans_path
;
peer
->
max_retrans
=
sctp_
max_retrans_path
;
peer
->
error_threshold
=
0
;
peer
->
error_count
=
0
;
...
...
@@ -272,8 +270,6 @@ void sctp_transport_put(struct sctp_transport *transport)
/* Update transport's RTO based on the newly calculated RTT. */
void
sctp_transport_update_rto
(
struct
sctp_transport
*
tp
,
__u32
rtt
)
{
struct
sctp_protocol
*
proto
=
sctp_get_protocol
();
/* Check for valid transport. */
SCTP_ASSERT
(
tp
,
"NULL transport"
,
return
);
...
...
@@ -292,10 +288,10 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
* For example, assuming the default value of RTO.Alpha of
* 1/8, rto_alpha would be expressed as 3.
*/
tp
->
rttvar
=
tp
->
rttvar
-
(
tp
->
rttvar
>>
proto
->
rto_beta
)
+
((
abs
(
tp
->
srtt
-
rtt
))
>>
proto
->
rto_beta
);
tp
->
srtt
=
tp
->
srtt
-
(
tp
->
srtt
>>
proto
->
rto_alpha
)
+
(
rtt
>>
proto
->
rto_alpha
);
tp
->
rttvar
=
tp
->
rttvar
-
(
tp
->
rttvar
>>
sctp_
rto_beta
)
+
((
abs
(
tp
->
srtt
-
rtt
))
>>
sctp_
rto_beta
);
tp
->
srtt
=
tp
->
srtt
-
(
tp
->
srtt
>>
sctp_
rto_alpha
)
+
(
rtt
>>
sctp_
rto_alpha
);
}
else
{
/* 6.3.1 C2) When the first RTT measurement R is made, set
* SRTT <- R, RTTVAR <- R/2.
...
...
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