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
d9441eda
Commit
d9441eda
authored
May 26, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Plain Diff
Merge us.ibm.com:/home/sridhar/BK/linux-2.5.70
into us.ibm.com:/home/sridhar/BK/lksctp-2.5.70
parents
6e9445e6
d1cd8a96
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
600 additions
and
312 deletions
+600
-312
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+19
-18
include/net/sctp/structs.h
include/net/sctp/structs.h
+51
-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/endpointola.c
net/sctp/endpointola.c
+1
-1
net/sctp/input.c
net/sctp/input.c
+16
-15
net/sctp/objcnt.c
net/sctp/objcnt.c
+2
-0
net/sctp/protocol.c
net/sctp/protocol.c
+102
-75
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+10
-8
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+2
-1
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+44
-26
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 @
d9441eda
...
...
@@ -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
;
...
...
@@ -456,6 +455,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 +502,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 +529,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 +552,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 @
d9441eda
...
...
@@ -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.
...
...
@@ -289,6 +314,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
;
...
...
@@ -1492,13 +1521,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 @
d9441eda
...
...
@@ -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 @
d9441eda
...
...
@@ -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 @
d9441eda
...
...
@@ -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/endpointola.c
View file @
d9441eda
...
...
@@ -209,7 +209,7 @@ void sctp_endpoint_destroy(struct sctp_endpoint *ep)
sctp_bind_addr_free
(
&
ep
->
base
.
bind_addr
);
/* Remove and free the port */
if
(
ep
->
base
.
sk
->
prev
!=
NULL
)
if
(
ep
->
base
.
sk
->
prev
)
sctp_put_port
(
ep
->
base
.
sk
);
/* Give up our hold on the sock. */
...
...
net/sctp/input.c
View file @
d9441eda
...
...
@@ -503,10 +503,11 @@ 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
));
sctp_walk_errors
(
err
,
ch
)
{
if
(
SCTP_ERROR_STALE_COOKIE
==
err
->
cause
)
goto
discard
;
}
}
ch
=
(
sctp_chunkhdr_t
*
)
ch_end
;
}
while
(
ch_end
<
skb
->
tail
);
...
...
@@ -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
);
...
...
net/sctp/objcnt.c
View file @
d9441eda
...
...
@@ -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/protocol.c
View file @
d9441eda
/* 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
...
...
@@ -59,7 +59,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,6 +74,9 @@ 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
);
...
...
@@ -106,10 +109,12 @@ __init int sctp_proc_init(void)
return
rc
;
}
/* 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
();
if
(
proc_net_sctp
)
{
...
...
@@ -153,7 +158,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 +166,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 +197,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 +215,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 +237,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
;
}
...
...
@@ -572,10 +576,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 +630,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
;
}
...
...
@@ -928,6 +932,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
)
...
...
@@ -946,91 +966,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
();
...
...
@@ -1045,13 +1065,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
;
...
...
@@ -1061,16 +1081,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
);
...
...
@@ -1088,7 +1112,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
);
...
...
@@ -1097,9 +1121,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 @
d9441eda
...
...
@@ -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
)
{
...
...
@@ -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
;
...
...
@@ -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. */
...
...
@@ -1907,7 +1909,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 @
d9441eda
...
...
@@ -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 @
d9441eda
...
...
@@ -737,7 +737,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
));
...
...
@@ -1787,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
);
}
/*
...
...
@@ -2066,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
;
...
...
@@ -2096,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
;
}
...
...
@@ -2739,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
);
...
...
@@ -4405,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/socket.c
View file @
d9441eda
...
...
@@ -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
->
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
->
prev
;
pp
=
(
s
truct
sctp_bind_bucke
t
*
)
sk
->
prev
;
if
(
sk
->
bind_next
)
sk
->
bind_next
->
bind_pprev
=
sk
->
bind_pprev
;
*
(
sk
->
bind_pprev
)
=
sk
->
bind_next
;
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 @
d9441eda
...
...
@@ -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 @
d9441eda
...
...
@@ -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