Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
28b9daad
Commit
28b9daad
authored
Nov 14, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge nuts.ninka.net:/home/davem/src/BK/sctp-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
f7efec4a
89de669a
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1541 additions
and
1128 deletions
+1541
-1128
include/net/sctp/command.h
include/net/sctp/command.h
+3
-0
include/net/sctp/sctp.h
include/net/sctp/sctp.h
+57
-24
include/net/sctp/sm.h
include/net/sctp/sm.h
+4
-6
include/net/sctp/structs.h
include/net/sctp/structs.h
+114
-104
net/sctp/associola.c
net/sctp/associola.c
+48
-143
net/sctp/bind_addr.c
net/sctp/bind_addr.c
+43
-204
net/sctp/endpointola.c
net/sctp/endpointola.c
+35
-19
net/sctp/input.c
net/sctp/input.c
+40
-96
net/sctp/ipv6.c
net/sctp/ipv6.c
+200
-11
net/sctp/output.c
net/sctp/output.c
+11
-9
net/sctp/outqueue.c
net/sctp/outqueue.c
+3
-3
net/sctp/primitive.c
net/sctp/primitive.c
+23
-0
net/sctp/protocol.c
net/sctp/protocol.c
+192
-82
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+142
-193
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+82
-29
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+112
-54
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+16
-8
net/sctp/socket.c
net/sctp/socket.c
+403
-132
net/sctp/transport.c
net/sctp/transport.c
+13
-11
No files found.
include/net/sctp/command.h
View file @
28b9daad
...
@@ -27,6 +27,7 @@
...
@@ -27,6 +27,7 @@
*
*
* La Monte H.P. Yarroll <piggy@acm.org>
* La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
...
@@ -72,6 +73,7 @@ typedef enum {
...
@@ -72,6 +73,7 @@ typedef enum {
SCTP_CMD_STRIKE
,
/* Mark a strike against a transport. */
SCTP_CMD_STRIKE
,
/* Mark a strike against a transport. */
SCTP_CMD_TRANSMIT
,
/* Transmit the outqueue. */
SCTP_CMD_TRANSMIT
,
/* Transmit the outqueue. */
SCTP_CMD_HB_TIMERS_START
,
/* Start the heartbeat timers. */
SCTP_CMD_HB_TIMERS_START
,
/* Start the heartbeat timers. */
SCTP_CMD_HB_TIMERS_UPDATE
,
/* Update the heartbeat timers. */
SCTP_CMD_TRANSPORT_RESET
,
/* Reset the status of a transport. */
SCTP_CMD_TRANSPORT_RESET
,
/* Reset the status of a transport. */
SCTP_CMD_TRANSPORT_ON
,
/* Mark the transport as active. */
SCTP_CMD_TRANSPORT_ON
,
/* Mark the transport as active. */
SCTP_CMD_REPORT_ERROR
,
/* Pass this error back out of the sm. */
SCTP_CMD_REPORT_ERROR
,
/* Pass this error back out of the sm. */
...
@@ -83,6 +85,7 @@ typedef enum {
...
@@ -83,6 +85,7 @@ typedef enum {
SCTP_CMD_UPDATE_ASSOC
,
/* Update association information. */
SCTP_CMD_UPDATE_ASSOC
,
/* Update association information. */
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_PURGE_OUTQUEUE
,
/* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_SETUP_T2
,
/* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING
,
/* Set transport's rto_pending. */
SCTP_CMD_LAST
SCTP_CMD_LAST
}
sctp_verb_t
;
}
sctp_verb_t
;
...
...
include/net/sctp/sctp.h
View file @
28b9daad
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2002
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
* This file is part of the SCTP kernel reference Implementation
...
@@ -142,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg);
...
@@ -142,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg);
extern
int
sctp_primitive_SHUTDOWN
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_SHUTDOWN
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_ABORT
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_ABORT
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_SEND
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_SEND
(
sctp_association_t
*
,
void
*
arg
);
extern
int
sctp_primitive_REQUESTHEARTBEAT
(
sctp_association_t
*
,
void
*
arg
);
/*
/*
* sctp_crc32c.c
* sctp_crc32c.c
...
@@ -418,6 +418,19 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
...
@@ -418,6 +418,19 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
return
retval
;
return
retval
;
}
}
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
* 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)
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += WORD_ROUND(ntohs(pos.p->length)))
/* Round an int up to the next multiple of 4. */
/* Round an int up to the next multiple of 4. */
#define WORD_ROUND(s) (((s)+3)&~3)
#define WORD_ROUND(s) (((s)+3)&~3)
...
@@ -460,6 +473,26 @@ static inline sctp_protocol_t *sctp_get_protocol(void)
...
@@ -460,6 +473,26 @@ static inline sctp_protocol_t *sctp_get_protocol(void)
return
&
sctp_proto
;
return
&
sctp_proto
;
}
}
/* Convert from an IP version number to an Address Family symbol. */
static
inline
int
ipver2af
(
__u8
ipver
)
{
int
family
;
switch
(
ipver
)
{
case
4
:
family
=
AF_INET
;
break
;
case
6
:
family
=
AF_INET6
;
break
;
default:
family
=
0
;
break
;
};
return
family
;
}
/* Warning: The following hash functions assume a power of two 'size'. */
/* Warning: The following hash functions assume a power of two 'size'. */
/* This is the hash function for the SCTP port hash table. */
/* This is the hash function for the SCTP port hash table. */
static
inline
int
sctp_phashfn
(
__u16
lport
)
static
inline
int
sctp_phashfn
(
__u16
lport
)
...
...
include/net/sctp/sm.h
View file @
28b9daad
...
@@ -157,6 +157,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort;
...
@@ -157,6 +157,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort;
sctp_state_fn_t
sctp_sf_error_closed
;
sctp_state_fn_t
sctp_sf_error_closed
;
sctp_state_fn_t
sctp_sf_error_shutdown
;
sctp_state_fn_t
sctp_sf_error_shutdown
;
sctp_state_fn_t
sctp_sf_ignore_primitive
;
sctp_state_fn_t
sctp_sf_ignore_primitive
;
sctp_state_fn_t
sctp_sf_do_prm_requestheartbeat
;
/* Prototypes for other event state functions. */
/* Prototypes for other event state functions. */
sctp_state_fn_t
sctp_sf_do_9_2_start_shutdown
;
sctp_state_fn_t
sctp_sf_do_9_2_start_shutdown
;
...
@@ -206,9 +207,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *,
...
@@ -206,9 +207,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *,
sctp_chunk_t
*
,
sctp_chunk_t
*
,
const
int
priority
);
const
int
priority
);
__u32
sctp_generate_verification_tag
(
void
);
__u32
sctp_generate_verification_tag
(
void
);
sctpParam_t
sctp_get_my_addrs_raw
(
const
sctp_association_t
*
,
const
int
priority
,
int
*
addrs_len
);
void
sctp_populate_tie_tags
(
__u8
*
cookie
,
__u32
curTag
,
__u32
hisTag
);
void
sctp_populate_tie_tags
(
__u8
*
cookie
,
__u32
curTag
,
__u32
hisTag
);
/* Prototypes for chunk-building functions. */
/* Prototypes for chunk-building functions. */
...
@@ -334,10 +332,10 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *);
...
@@ -334,10 +332,10 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
);
/* 4th level prototypes */
/* 4th level prototypes */
void
sctp_param2sockaddr
(
sockaddr_storage_t
*
addr
,
sctp_addr_param_t
*
,
void
sctp_param2sockaddr
(
union
sctp_addr
*
addr
,
sctp_addr_param_t
*
,
__u16
port
);
__u16
port
);
int
sctp_addr2sockaddr
(
const
sctpParam_t
,
sockaddr_storage_t
*
);
int
sctp_addr2sockaddr
(
const
union
sctp_params
,
union
sctp_addr
*
);
int
sockaddr2sctp_addr
(
const
sockaddr_storage_t
*
,
sctp_addr_param_t
*
);
int
sockaddr2sctp_addr
(
const
union
sctp_addr
*
,
sctp_addr_param_t
*
);
/* Extern declarations for major data structures. */
/* Extern declarations for major data structures. */
sctp_sm_table_entry_t
*
sctp_chunk_event_lookup
(
sctp_cid_t
,
sctp_state_t
);
sctp_sm_table_entry_t
*
sctp_chunk_event_lookup
(
sctp_cid_t
,
sctp_state_t
);
...
...
include/net/sctp/structs.h
View file @
28b9daad
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 International Business Machines Corp.
* Copyright (c) 2001
-2002
International Business Machines Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
* This file is part of the SCTP kernel reference Implementation
*
*
...
@@ -95,11 +95,11 @@ struct sockaddr_storage {
...
@@ -95,11 +95,11 @@ struct sockaddr_storage {
/* A convenience structure for handling sockaddr structures.
/* A convenience structure for handling sockaddr structures.
* We should wean ourselves off this.
* We should wean ourselves off this.
*/
*/
typedef
union
{
union
sctp_addr
{
struct
sockaddr_in
v4
;
struct
sockaddr_in
v4
;
struct
sockaddr_in6
v6
;
struct
sockaddr_in6
v6
;
struct
sockaddr
sa
;
struct
sockaddr
sa
;
}
sockaddr_storage_t
;
};
/* Forward declarations for data structures. */
/* Forward declarations for data structures. */
...
@@ -246,22 +246,40 @@ typedef struct sctp_func {
...
@@ -246,22 +246,40 @@ typedef struct sctp_func {
int
optname
,
int
optname
,
char
*
optval
,
char
*
optval
,
int
*
optlen
);
int
*
optlen
);
struct
dst_entry
*
(
*
get_dst
)
(
sockaddr_storage_t
*
daddr
,
struct
dst_entry
*
(
*
get_dst
)
(
union
sctp_addr
*
daddr
,
sockaddr_storage_t
*
saddr
);
union
sctp_addr
*
saddr
);
int
(
*
cmp_saddr
)
(
struct
dst_entry
*
dst
,
void
(
*
copy_addrlist
)
(
struct
list_head
*
,
sockaddr_storage_t
*
saddr
);
struct
net_device
*
);
void
(
*
dst_saddr
)
(
union
sctp_addr
*
saddr
,
struct
dst_entry
*
dst
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
);
void
(
*
addr_copy
)
(
union
sctp_addr
*
dst
,
union
sctp_addr
*
src
);
void
(
*
from_skb
)
(
union
sctp_addr
*
,
struct
sk_buff
*
skb
,
int
saddr
);
int
(
*
addr_valid
)
(
union
sctp_addr
*
);
sctp_scope_t
(
*
scope
)
(
union
sctp_addr
*
);
void
(
*
inaddr_any
)
(
union
sctp_addr
*
,
unsigned
short
);
int
(
*
is_any
)
(
const
union
sctp_addr
*
);
__u16
net_header_len
;
__u16
net_header_len
;
int
sockaddr_len
;
int
sockaddr_len
;
sa_family_t
sa_family
;
sa_family_t
sa_family
;
struct
list_head
list
;
struct
list_head
list
;
}
sctp_func_t
;
}
sctp_func_t
;
sctp_func_t
*
sctp_get_af_specific
(
const
sockaddr_storage_t
*
address
);
sctp_func_t
*
sctp_get_af_specific
(
sa_family_t
);
/* Protocol family functions. */
/* Protocol family functions. */
typedef
struct
sctp_pf
{
typedef
struct
sctp_pf
{
void
(
*
event_msgname
)(
sctp_ulpevent_t
*
,
char
*
,
int
*
);
void
(
*
event_msgname
)(
sctp_ulpevent_t
*
,
char
*
,
int
*
);
void
(
*
skb_msgname
)(
struct
sk_buff
*
,
char
*
,
int
*
);
void
(
*
skb_msgname
)(
struct
sk_buff
*
,
char
*
,
int
*
);
int
(
*
af_supported
)(
sa_family_t
);
int
(
*
cmp_addr
)
(
const
union
sctp_addr
*
,
const
union
sctp_addr
*
,
struct
sctp_opt
*
);
struct
sctp_func
*
af
;
}
sctp_pf_t
;
}
sctp_pf_t
;
/* SCTP Socket type: UDP or TCP style. */
/* SCTP Socket type: UDP or TCP style. */
...
@@ -339,7 +357,7 @@ typedef struct sctp_cookie {
...
@@ -339,7 +357,7 @@ typedef struct sctp_cookie {
__u32
initial_tsn
;
__u32
initial_tsn
;
/* This holds the originating address of the INIT packet. */
/* This holds the originating address of the INIT packet. */
sockaddr_storage_t
peer_addr
;
union
sctp_addr
peer_addr
;
/* This is a shim for my peer's INIT packet, followed by
/* This is a shim for my peer's INIT packet, followed by
* a copy of the raw address list of the association.
* a copy of the raw address list of the association.
...
@@ -359,20 +377,6 @@ typedef struct sctp_signed_cookie {
...
@@ -359,20 +377,6 @@ typedef struct sctp_signed_cookie {
}
sctp_signed_cookie_t
;
}
sctp_signed_cookie_t
;
/* This convenience type allows us to avoid casting when walking
* through a parameter list.
*/
typedef
union
{
__u8
*
v
;
sctp_paramhdr_t
*
p
;
sctp_cookie_preserve_param_t
*
bht
;
sctp_hostname_param_t
*
dns
;
sctp_cookie_param_t
*
cookie
;
sctp_supported_addrs_param_t
*
sat
;
sctp_ipv4addr_param_t
*
v4
;
sctp_ipv6addr_param_t
*
v6
;
}
sctpParam_t
;
/* This is another convenience type to allocate memory for address
/* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around
* params for the maximum size and pass such structures around
...
@@ -383,6 +387,21 @@ typedef union {
...
@@ -383,6 +387,21 @@ typedef union {
sctp_ipv6addr_param_t
v6
;
sctp_ipv6addr_param_t
v6
;
}
sctp_addr_param_t
;
}
sctp_addr_param_t
;
/* A convenience type to allow walking through the various
* parameters and avoid casting all over the place.
*/
union
sctp_params
{
void
*
v
;
sctp_paramhdr_t
*
p
;
sctp_cookie_preserve_param_t
*
life
;
sctp_hostname_param_t
*
dns
;
sctp_cookie_param_t
*
cookie
;
sctp_supported_addrs_param_t
*
sat
;
sctp_ipv4addr_param_t
*
v4
;
sctp_ipv6addr_param_t
*
v6
;
sctp_addr_param_t
*
addr
;
};
/* RFC 2960. Section 3.3.5 Heartbeat.
/* RFC 2960. Section 3.3.5 Heartbeat.
* Heartbeat Information: variable length
* Heartbeat Information: variable length
* The Sender-specific Heartbeat Info field should normally include
* The Sender-specific Heartbeat Info field should normally include
...
@@ -392,7 +411,7 @@ typedef union {
...
@@ -392,7 +411,7 @@ typedef union {
*/
*/
typedef
struct
sctp_sender_hb_info
{
typedef
struct
sctp_sender_hb_info
{
sctp_paramhdr_t
param_hdr
;
sctp_paramhdr_t
param_hdr
;
sockaddr_storage_t
daddr
;
union
sctp_addr
daddr
;
unsigned
long
sent_at
;
unsigned
long
sent_at
;
}
sctp_sender_hb_info_t
__attribute__
((
packed
));
}
sctp_sender_hb_info_t
__attribute__
((
packed
));
...
@@ -433,7 +452,7 @@ struct SCTP_chunk {
...
@@ -433,7 +452,7 @@ struct SCTP_chunk {
*/
*/
/* We point this at the FIRST TLV parameter to chunk_hdr. */
/* We point this at the FIRST TLV parameter to chunk_hdr. */
sctpParam_t
param_hdr
;
union
sctp_params
param_hdr
;
union
{
union
{
__u8
*
v
;
__u8
*
v
;
sctp_datahdr_t
*
data_hdr
;
sctp_datahdr_t
*
data_hdr
;
...
@@ -478,9 +497,9 @@ struct SCTP_chunk {
...
@@ -478,9 +497,9 @@ struct SCTP_chunk {
__u8
tsn_missing_report
;
/* Data chunk missing counter. */
__u8
tsn_missing_report
;
/* Data chunk missing counter. */
/* What is the origin IP address for this chunk? */
/* What is the origin IP address for this chunk? */
sockaddr_storage_t
source
;
union
sctp_addr
source
;
/* Destination address for this chunk. */
/* Destination address for this chunk. */
sockaddr_storage_t
dest
;
union
sctp_addr
dest
;
/* For an inbound chunk, this tells us where it came from.
/* For an inbound chunk, this tells us where it came from.
* For an outbound chunk, it tells us where we'd like it to
* For an outbound chunk, it tells us where we'd like it to
...
@@ -497,8 +516,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
...
@@ -497,8 +516,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
int
sctp_user_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
struct
iovec
*
data
);
int
sctp_user_addto_chunk
(
sctp_chunk_t
*
chunk
,
int
len
,
struct
iovec
*
data
);
sctp_chunk_t
*
sctp_chunkify
(
struct
sk_buff
*
,
const
sctp_association_t
*
,
sctp_chunk_t
*
sctp_chunkify
(
struct
sk_buff
*
,
const
sctp_association_t
*
,
struct
sock
*
);
struct
sock
*
);
void
sctp_init_addrs
(
sctp_chunk_t
*
chunk
);
void
sctp_init_addrs
(
sctp_chunk_t
*
,
union
sctp_addr
*
,
union
sctp_addr
*
);
const
sockaddr_storage_t
*
sctp_source
(
const
sctp_chunk_t
*
chunk
);
const
union
sctp_addr
*
sctp_source
(
const
sctp_chunk_t
*
chunk
);
/* This is a structure for holding either an IPv6 or an IPv4 address. */
/* This is a structure for holding either an IPv6 or an IPv4 address. */
/* sin_family -- AF_INET or AF_INET6
/* sin_family -- AF_INET or AF_INET6
...
@@ -507,7 +526,7 @@ const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk);
...
@@ -507,7 +526,7 @@ const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk);
*/
*/
struct
sockaddr_storage_list
{
struct
sockaddr_storage_list
{
struct
list_head
list
;
struct
list_head
list
;
sockaddr_storage_t
a
;
union
sctp_addr
a
;
};
};
typedef
sctp_chunk_t
*
(
sctp_packet_phandler_t
)(
sctp_association_t
*
);
typedef
sctp_chunk_t
*
(
sctp_packet_phandler_t
)(
sctp_association_t
*
);
...
@@ -573,7 +592,7 @@ void sctp_packet_free(sctp_packet_t *);
...
@@ -573,7 +592,7 @@ void sctp_packet_free(sctp_packet_t *);
/* This represents a remote transport address.
/* This represents a remote transport address.
* For local transport addresses, we just use
sockaddr_storage_t
.
* For local transport addresses, we just use
union sctp_addr
.
*
*
* RFC2960 Section 1.4 Key Terms
* RFC2960 Section 1.4 Key Terms
*
*
...
@@ -601,7 +620,7 @@ struct SCTP_transport {
...
@@ -601,7 +620,7 @@ struct SCTP_transport {
int
dead
;
int
dead
;
/* This is the peer's IP address and port. */
/* This is the peer's IP address and port. */
sockaddr_storage_t
ipaddr
;
union
sctp_addr
ipaddr
;
/* These are the functions we call to handle LLP stuff. */
/* These are the functions we call to handle LLP stuff. */
sctp_func_t
*
af_specific
;
sctp_func_t
*
af_specific
;
...
@@ -684,13 +703,15 @@ struct SCTP_transport {
...
@@ -684,13 +703,15 @@ struct SCTP_transport {
*/
*/
unsigned
long
last_time_ecne_reduced
;
unsigned
long
last_time_ecne_reduced
;
/*
state : The current
state of this destination,
/*
active : The current active
state of this destination,
* : i.e. DOWN, UP,
ALLOW-HB, NO-HEARTBEAT,
etc.
* : i.e. DOWN, UP, etc.
*/
*/
struct
{
int
active
;
int
active
;
/* hb_allowed : The current heartbeat state of this destination,
* : i.e. ALLOW-HB, NO-HEARTBEAT, etc.
*/
int
hb_allowed
;
int
hb_allowed
;
}
state
;
/* These are the error stats for this destination. */
/* These are the error stats for this destination. */
...
@@ -739,11 +760,12 @@ struct SCTP_transport {
...
@@ -739,11 +760,12 @@ struct SCTP_transport {
int
malloced
;
/* Is this structure kfree()able? */
int
malloced
;
/* Is this structure kfree()able? */
};
};
extern
sctp_transport_t
*
sctp_transport_new
(
const
sockaddr_storage_t
*
,
int
);
extern
sctp_transport_t
*
sctp_transport_new
(
const
union
sctp_addr
*
,
int
);
extern
sctp_transport_t
*
sctp_transport_init
(
sctp_transport_t
*
,
extern
sctp_transport_t
*
sctp_transport_init
(
sctp_transport_t
*
,
const
sockaddr_storage_t
*
,
int
);
const
union
sctp_addr
*
,
int
);
extern
void
sctp_transport_set_owner
(
sctp_transport_t
*
,
sctp_association_t
*
);
extern
void
sctp_transport_set_owner
(
sctp_transport_t
*
,
sctp_association_t
*
);
extern
void
sctp_transport_route
(
sctp_transport_t
*
,
sockaddr_storage_t
*
);
extern
void
sctp_transport_route
(
sctp_transport_t
*
,
union
sctp_addr
*
,
struct
sctp_opt
*
);
extern
void
sctp_transport_free
(
sctp_transport_t
*
);
extern
void
sctp_transport_free
(
sctp_transport_t
*
);
extern
void
sctp_transport_destroy
(
sctp_transport_t
*
);
extern
void
sctp_transport_destroy
(
sctp_transport_t
*
);
extern
void
sctp_transport_reset_timers
(
sctp_transport_t
*
);
extern
void
sctp_transport_reset_timers
(
sctp_transport_t
*
);
...
@@ -890,11 +912,12 @@ void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port);
...
@@ -890,11 +912,12 @@ void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port);
void
sctp_bind_addr_free
(
sctp_bind_addr_t
*
);
void
sctp_bind_addr_free
(
sctp_bind_addr_t
*
);
int
sctp_bind_addr_copy
(
sctp_bind_addr_t
*
dest
,
const
sctp_bind_addr_t
*
src
,
int
sctp_bind_addr_copy
(
sctp_bind_addr_t
*
dest
,
const
sctp_bind_addr_t
*
src
,
sctp_scope_t
scope
,
int
priority
,
int
flags
);
sctp_scope_t
scope
,
int
priority
,
int
flags
);
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
,
sockaddr_storage_t
*
,
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
,
int
priority
);
int
priority
);
int
sctp_del_bind_addr
(
sctp_bind_addr_t
*
,
sockaddr_storage_t
*
);
int
sctp_del_bind_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
);
int
sctp_bind_addr_has_addr
(
sctp_bind_addr_t
*
,
const
sockaddr_storage_t
*
);
int
sctp_bind_addr_match
(
sctp_bind_addr_t
*
,
const
union
sctp_addr
*
,
sctpParam_t
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
struct
sctp_opt
*
);
union
sctp_params
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
int
*
addrs_len
,
int
*
addrs_len
,
int
priority
);
int
priority
);
int
sctp_raw_to_bind_addrs
(
sctp_bind_addr_t
*
bp
,
int
sctp_raw_to_bind_addrs
(
sctp_bind_addr_t
*
bp
,
...
@@ -903,10 +926,10 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp,
...
@@ -903,10 +926,10 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp,
unsigned
short
port
,
unsigned
short
port
,
int
priority
);
int
priority
);
sctp_scope_t
sctp_scope
(
const
sockaddr_storage_t
*
);
sctp_scope_t
sctp_scope
(
const
union
sctp_addr
*
);
int
sctp_in_scope
(
const
sockaddr_storage_t
*
addr
,
const
sctp_scope_t
scope
);
int
sctp_in_scope
(
const
union
sctp_addr
*
addr
,
const
sctp_scope_t
scope
);
int
sctp_is_any
(
const
sockaddr_storage_t
*
addr
);
int
sctp_is_any
(
const
union
sctp_addr
*
addr
);
int
sctp_addr_is_valid
(
const
sockaddr_storage_t
*
addr
);
int
sctp_addr_is_valid
(
const
union
sctp_addr
*
addr
);
/* What type of sctp_endpoint_common? */
/* What type of sctp_endpoint_common? */
...
@@ -1048,35 +1071,25 @@ void sctp_endpoint_put(sctp_endpoint_t *);
...
@@ -1048,35 +1071,25 @@ void sctp_endpoint_put(sctp_endpoint_t *);
void
sctp_endpoint_hold
(
sctp_endpoint_t
*
);
void
sctp_endpoint_hold
(
sctp_endpoint_t
*
);
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
,
sctp_association_t
*
asoc
);
void
sctp_endpoint_add_asoc
(
sctp_endpoint_t
*
,
sctp_association_t
*
asoc
);
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
);
sctp_transport_t
**
);
int
sctp_endpoint_is_peeled_off
(
sctp_endpoint_t
*
,
const
union
sctp_addr
*
);
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
const
sockaddr_storage_t
*
);
const
union
sctp_addr
*
);
int
sctp_has_association
(
const
sockaddr_storage_t
*
laddr
,
int
sctp_has_association
(
const
union
sctp_addr
*
laddr
,
const
sockaddr_storage_t
*
paddr
);
const
union
sctp_addr
*
paddr
);
int
sctp_verify_init
(
const
sctp_association_t
*
asoc
,
int
sctp_verify_init
(
const
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
sctp_cid_t
cid
,
sctp_init_chunk_t
*
peer_init
,
sctp_init_chunk_t
*
peer_init
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chunk
);
sctp_chunk_t
**
err_chunk
);
int
sctp_verify_param
(
const
sctp_association_t
*
asoc
,
int
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
sctpParam_t
param
,
const
union
sctp_addr
*
peer_addr
,
sctp_cid_t
cid
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chunk
);
int
sctp_process_unk_param
(
const
sctp_association_t
*
asoc
,
sctpParam_t
param
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chunk
);
void
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
const
sockaddr_storage_t
*
peer_addr
,
sctp_init_chunk_t
*
peer_init
,
int
priority
);
sctp_init_chunk_t
*
peer_init
,
int
priority
);
int
sctp_process_param
(
sctp_association_t
*
asoc
,
int
sctp_process_param
(
sctp_association_t
*
asoc
,
union
sctp_params
param
,
sctpParam_t
param
,
const
union
sctp_addr
*
peer_addr
,
int
priority
);
const
sockaddr_storage_t
*
peer_addr
,
sctp_cid_t
cid
,
int
priority
);
__u32
sctp_generate_tag
(
const
sctp_endpoint_t
*
ep
);
__u32
sctp_generate_tag
(
const
sctp_endpoint_t
*
ep
);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
ep
);
__u32
sctp_generate_tsn
(
const
sctp_endpoint_t
*
ep
);
...
@@ -1165,7 +1178,7 @@ struct SCTP_association {
...
@@ -1165,7 +1178,7 @@ struct SCTP_association {
/* Cache the primary path address here, when we
/* Cache the primary path address here, when we
* need a an address for msg_name.
* need a an address for msg_name.
*/
*/
sockaddr_storage_t
primary_addr
;
union
sctp_addr
primary_addr
;
/* active_path
/* active_path
* The path that we are currently using to
* The path that we are currently using to
...
@@ -1543,16 +1556,16 @@ void sctp_association_hold(sctp_association_t *);
...
@@ -1543,16 +1556,16 @@ void sctp_association_hold(sctp_association_t *);
sctp_transport_t
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
sctp_transport_t
*
sctp_assoc_choose_shutdown_transport
(
sctp_association_t
*
);
sctp_transport_t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
sctp_transport_t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
,
const
sockaddr_storage_t
*
);
const
union
sctp_addr
*
);
sctp_transport_t
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
sctp_transport_t
*
sctp_assoc_add_peer
(
sctp_association_t
*
,
const
sockaddr_storage_t
*
address
,
const
union
sctp_addr
*
address
,
const
int
priority
);
const
int
priority
);
void
sctp_assoc_control_transport
(
sctp_association_t
*
,
sctp_transport_t
*
,
void
sctp_assoc_control_transport
(
sctp_association_t
*
,
sctp_transport_t
*
,
sctp_transport_cmd_t
,
sctp_sn_error_t
);
sctp_transport_cmd_t
,
sctp_sn_error_t
);
sctp_transport_t
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
,
__u32
);
sctp_transport_t
*
sctp_assoc_lookup_tsn
(
sctp_association_t
*
,
__u32
);
sctp_transport_t
*
sctp_assoc_is_match
(
sctp_association_t
*
,
sctp_transport_t
*
sctp_assoc_is_match
(
sctp_association_t
*
,
const
sockaddr_storage_t
*
,
const
union
sctp_addr
*
,
const
sockaddr_storage_t
*
);
const
union
sctp_addr
*
);
void
sctp_assoc_migrate
(
sctp_association_t
*
,
struct
sock
*
);
void
sctp_assoc_migrate
(
sctp_association_t
*
,
struct
sock
*
);
void
sctp_assoc_update
(
sctp_association_t
*
dst
,
sctp_association_t
*
src
);
void
sctp_assoc_update
(
sctp_association_t
*
dst
,
sctp_association_t
*
src
);
...
@@ -1560,14 +1573,11 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *);
...
@@ -1560,14 +1573,11 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *);
__u32
__sctp_association_get_tsn_block
(
sctp_association_t
*
,
int
);
__u32
__sctp_association_get_tsn_block
(
sctp_association_t
*
,
int
);
__u16
__sctp_association_get_next_ssn
(
sctp_association_t
*
,
__u16
sid
);
__u16
__sctp_association_get_next_ssn
(
sctp_association_t
*
,
__u16
sid
);
int
sctp_cmp_addr
(
const
sockaddr_storage_t
*
ss1
,
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
const
sockaddr_storage_t
*
ss2
);
const
union
sctp_addr
*
ss2
);
int
sctp_cmp_addr_exact
(
const
sockaddr_storage_t
*
ss1
,
const
sockaddr_storage_t
*
ss2
);
sctp_chunk_t
*
sctp_get_ecne_prepend
(
sctp_association_t
*
asoc
);
sctp_chunk_t
*
sctp_get_ecne_prepend
(
sctp_association_t
*
asoc
);
sctp_chunk_t
*
sctp_get_no_prepend
(
sctp_association_t
*
asoc
);
sctp_chunk_t
*
sctp_get_no_prepend
(
sctp_association_t
*
asoc
);
/* A convenience structure to parse out SCTP specific CMSGs. */
/* A convenience structure to parse out SCTP specific CMSGs. */
typedef
struct
sctp_cmsgs
{
typedef
struct
sctp_cmsgs
{
struct
sctp_initmsg
*
init
;
struct
sctp_initmsg
*
init
;
...
...
net/sctp/associola.c
View file @
28b9daad
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines Corp.
* Copyright (c) 2001
-2002
International Business Machines Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2001 La Monte H.P. Yarroll
*
*
...
@@ -363,48 +363,34 @@ static void sctp_association_destroy(sctp_association_t *asoc)
...
@@ -363,48 +363,34 @@ static void sctp_association_destroy(sctp_association_t *asoc)
/* Add a transport address to an association. */
/* Add a transport address to an association. */
sctp_transport_t
*
sctp_assoc_add_peer
(
sctp_association_t
*
asoc
,
sctp_transport_t
*
sctp_assoc_add_peer
(
sctp_association_t
*
asoc
,
const
sockaddr_storage_t
*
addr
,
const
union
sctp_addr
*
addr
,
int
priority
)
int
priority
)
{
{
sctp_transport_t
*
peer
;
sctp_transport_t
*
peer
;
sctp_opt_t
*
sp
;
sctp_opt_t
*
sp
;
const
__u16
*
port
;
unsigned
short
port
;
switch
(
addr
->
sa
.
sa_family
)
{
/* AF_INET and AF_INET6 share common port field. */
case
AF_INET
:
port
=
addr
->
v4
.
sin_port
;
port
=
&
addr
->
v4
.
sin_port
;
break
;
case
AF_INET6
:
SCTP_V6
(
port
=
&
addr
->
v6
.
sin6_port
;
break
;
);
default:
return
NULL
;
};
/* Set the port if it has not been set yet. */
/* Set the port if it has not been set yet. */
if
(
0
==
asoc
->
peer
.
port
)
{
if
(
0
==
asoc
->
peer
.
port
)
{
asoc
->
peer
.
port
=
*
port
;
asoc
->
peer
.
port
=
port
;
}
}
SCTP_ASSERT
(
*
port
==
asoc
->
peer
.
port
,
":Invalid port
\n
"
,
return
NULL
);
/* Check to see if this is a duplicate. */
/* Check to see if this is a duplicate. */
peer
=
sctp_assoc_lookup_paddr
(
asoc
,
addr
);
peer
=
sctp_assoc_lookup_paddr
(
asoc
,
addr
);
if
(
peer
)
if
(
peer
)
return
peer
;
return
peer
;
peer
=
sctp_transport_new
(
addr
,
priority
);
peer
=
sctp_transport_new
(
addr
,
priority
);
if
(
NULL
==
peer
)
if
(
!
peer
)
return
NULL
;
return
NULL
;
sctp_transport_set_owner
(
peer
,
asoc
);
sctp_transport_set_owner
(
peer
,
asoc
);
/* Cache a route for the transport. */
/* Cache a route for the transport. */
sctp_transport_route
(
peer
,
NULL
);
sctp_transport_route
(
peer
,
NULL
,
sctp_sk
(
asoc
->
base
.
sk
)
);
/* If this is the first transport addr on this association,
/* If this is the first transport addr on this association,
* initialize the association PMTU to the peer's PMTU.
* initialize the association PMTU to the peer's PMTU.
...
@@ -423,7 +409,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -423,7 +409,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc
->
frag_point
=
asoc
->
pmtu
-
asoc
->
frag_point
=
asoc
->
pmtu
-
(
SCTP_IP_OVERHEAD
+
sizeof
(
sctp_data_chunk_t
));
(
SCTP_IP_OVERHEAD
+
sizeof
(
sctp_data_chunk_t
));
/* The asoc->peer.port might not be meaningful
as of now
, but
/* The asoc->peer.port might not be meaningful
yet
, but
* initialize the packet structure anyway.
* initialize the packet structure anyway.
*/
*/
(
asoc
->
outqueue
.
init_output
)(
&
peer
->
packet
,
(
asoc
->
outqueue
.
init_output
)(
&
peer
->
packet
,
...
@@ -460,6 +446,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -460,6 +446,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
min
(
asoc
->
overall_error_threshold
+
peer
->
error_threshold
,
min
(
asoc
->
overall_error_threshold
+
peer
->
error_threshold
,
asoc
->
max_retrans
);
asoc
->
max_retrans
);
/* By default, enable heartbeat for peer address. */
peer
->
hb_allowed
=
1
;
/* Initialize the peer's heartbeat interval based on the
/* Initialize the peer's heartbeat interval based on the
* sock configured value.
* sock configured value.
*/
*/
...
@@ -474,7 +463,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -474,7 +463,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc
->
peer
.
primary_path
=
peer
;
asoc
->
peer
.
primary_path
=
peer
;
/* Set a default msg_name for events. */
/* Set a default msg_name for events. */
memcpy
(
&
asoc
->
peer
.
primary_addr
,
&
peer
->
ipaddr
,
memcpy
(
&
asoc
->
peer
.
primary_addr
,
&
peer
->
ipaddr
,
sizeof
(
sockaddr_storage_t
));
sizeof
(
union
sctp_addr
));
asoc
->
peer
.
active_path
=
peer
;
asoc
->
peer
.
active_path
=
peer
;
asoc
->
peer
.
retran_path
=
peer
;
asoc
->
peer
.
retran_path
=
peer
;
}
}
...
@@ -487,7 +476,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
...
@@ -487,7 +476,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
/* Lookup a transport by address. */
/* Lookup a transport by address. */
sctp_transport_t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
asoc
,
sctp_transport_t
*
sctp_assoc_lookup_paddr
(
const
sctp_association_t
*
asoc
,
const
sockaddr_storage_t
*
address
)
const
union
sctp_addr
*
address
)
{
{
sctp_transport_t
*
t
;
sctp_transport_t
*
t
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
...
@@ -522,12 +511,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
...
@@ -522,12 +511,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
/* Record the transition on the transport. */
/* Record the transition on the transport. */
switch
(
command
)
{
switch
(
command
)
{
case
SCTP_TRANSPORT_UP
:
case
SCTP_TRANSPORT_UP
:
transport
->
state
.
active
=
1
;
transport
->
active
=
1
;
spc_state
=
ADDRESS_AVAILABLE
;
spc_state
=
ADDRESS_AVAILABLE
;
break
;
break
;
case
SCTP_TRANSPORT_DOWN
:
case
SCTP_TRANSPORT_DOWN
:
transport
->
state
.
active
=
0
;
transport
->
active
=
0
;
spc_state
=
ADDRESS_UNREACHABLE
;
spc_state
=
ADDRESS_UNREACHABLE
;
break
;
break
;
...
@@ -557,7 +546,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
...
@@ -557,7 +546,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
list_for_each
(
pos
,
&
asoc
->
peer
.
transport_addr_list
)
{
t
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
t
=
list_entry
(
pos
,
sctp_transport_t
,
transports
);
if
(
!
t
->
state
.
active
)
if
(
!
t
->
active
)
continue
;
continue
;
if
(
!
first
||
t
->
last_time_heard
>
first
->
last_time_heard
)
{
if
(
!
first
||
t
->
last_time_heard
>
first
->
last_time_heard
)
{
second
=
first
;
second
=
first
;
...
@@ -577,7 +566,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
...
@@ -577,7 +566,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
* [If the primary is active but not most recent, bump the most
* [If the primary is active but not most recent, bump the most
* recently used transport.]
* recently used transport.]
*/
*/
if
(
asoc
->
peer
.
primary_path
->
state
.
active
&&
if
(
asoc
->
peer
.
primary_path
->
active
&&
first
!=
asoc
->
peer
.
primary_path
)
{
first
!=
asoc
->
peer
.
primary_path
)
{
second
=
first
;
second
=
first
;
first
=
asoc
->
peer
.
primary_path
;
first
=
asoc
->
peer
.
primary_path
;
...
@@ -645,102 +634,21 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
...
@@ -645,102 +634,21 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
return
asoc
->
ssn
[
sid
]
++
;
return
asoc
->
ssn
[
sid
]
++
;
}
}
/* Compare two addresses to see if they match. Wildcard addresses
* always match within their address family.
*
* FIXME: We do not match address scopes correctly.
*/
int
sctp_cmp_addr
(
const
sockaddr_storage_t
*
ss1
,
const
sockaddr_storage_t
*
ss2
)
{
int
len
;
const
void
*
base1
;
const
void
*
base2
;
if
(
ss1
->
sa
.
sa_family
!=
ss2
->
sa
.
sa_family
)
return
0
;
if
(
ss1
->
v4
.
sin_port
!=
ss2
->
v4
.
sin_port
)
return
0
;
switch
(
ss1
->
sa
.
sa_family
)
{
case
AF_INET
:
if
(
INADDR_ANY
==
ss1
->
v4
.
sin_addr
.
s_addr
||
INADDR_ANY
==
ss2
->
v4
.
sin_addr
.
s_addr
)
goto
match
;
len
=
sizeof
(
struct
in_addr
);
base1
=
&
ss1
->
v4
.
sin_addr
;
base2
=
&
ss2
->
v4
.
sin_addr
;
break
;
case
AF_INET6
:
SCTP_V6
(
if
(
IPV6_ADDR_ANY
==
sctp_ipv6_addr_type
(
&
ss1
->
v6
.
sin6_addr
))
goto
match
;
if
(
IPV6_ADDR_ANY
==
sctp_ipv6_addr_type
(
&
ss2
->
v6
.
sin6_addr
))
goto
match
;
len
=
sizeof
(
struct
in6_addr
);
base1
=
&
ss1
->
v6
.
sin6_addr
;
base2
=
&
ss2
->
v6
.
sin6_addr
;
break
;
)
default:
printk
(
KERN_WARNING
"WARNING, bogus socket address family %d
\n
"
,
ss1
->
sa
.
sa_family
);
return
0
;
};
return
(
0
==
memcmp
(
base1
,
base2
,
len
));
match:
return
1
;
}
/* Compare two addresses to see if they match. Wildcard addresses
/* Compare two addresses to see if they match. Wildcard addresses
* only match themselves.
* only match themselves.
*
*
* FIXME: We do not match address scopes correctly.
* FIXME: We do not match address scopes correctly.
*/
*/
int
sctp_cmp_addr_exact
(
const
sockaddr_storage_t
*
ss1
,
int
sctp_cmp_addr_exact
(
const
union
sctp_addr
*
ss1
,
const
sockaddr_storage_t
*
ss2
)
const
union
sctp_addr
*
ss2
)
{
{
int
len
;
struct
sctp_func
*
af
;
const
void
*
base1
;
const
void
*
base2
;
if
(
ss1
->
sa
.
sa_family
!=
ss2
->
sa
.
sa_family
)
return
0
;
if
(
ss1
->
v4
.
sin_port
!=
ss2
->
v4
.
sin_port
)
return
0
;
switch
(
ss1
->
sa
.
sa_family
)
{
case
AF_INET
:
len
=
sizeof
(
struct
in_addr
);
base1
=
&
ss1
->
v4
.
sin_addr
;
base2
=
&
ss2
->
v4
.
sin_addr
;
break
;
case
AF_INET6
:
SCTP_V6
(
len
=
sizeof
(
struct
in6_addr
);
base1
=
&
ss1
->
v6
.
sin6_addr
;
base2
=
&
ss2
->
v6
.
sin6_addr
;
break
;
)
default:
af
=
sctp_get_af_specific
(
ss1
->
sa
.
sa_family
);
printk
(
KERN_WARNING
if
(
!
af
)
"WARNING, bogus socket address family %d
\n
"
,
ss1
->
sa
.
sa_family
);
return
0
;
return
0
;
};
return
(
0
==
memcmp
(
base1
,
base2
,
len
)
);
return
af
->
cmp_addr
(
ss1
,
ss2
);
}
}
/* Return an ecne chunk to get prepended to a packet.
/* Return an ecne chunk to get prepended to a packet.
...
@@ -842,8 +750,8 @@ sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn)
...
@@ -842,8 +750,8 @@ sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn)
/* Is this the association we are looking for? */
/* Is this the association we are looking for? */
sctp_transport_t
*
sctp_assoc_is_match
(
sctp_association_t
*
asoc
,
sctp_transport_t
*
sctp_assoc_is_match
(
sctp_association_t
*
asoc
,
const
sockaddr_storage_t
*
laddr
,
const
union
sctp_addr
*
laddr
,
const
sockaddr_storage_t
*
paddr
)
const
union
sctp_addr
*
paddr
)
{
{
sctp_transport_t
*
transport
;
sctp_transport_t
*
transport
;
...
@@ -855,7 +763,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc,
...
@@ -855,7 +763,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc,
if
(
!
transport
)
if
(
!
transport
)
goto
out
;
goto
out
;
if
(
sctp_bind_addr_has_addr
(
&
asoc
->
base
.
bind_addr
,
laddr
))
if
(
sctp_bind_addr_match
(
&
asoc
->
base
.
bind_addr
,
laddr
,
sctp_sk
(
asoc
->
base
.
sk
)))
goto
out
;
goto
out
;
}
}
transport
=
NULL
;
transport
=
NULL
;
...
@@ -902,17 +811,13 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
...
@@ -902,17 +811,13 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
* the incoming chunk. If so, get out of the while loop.
* the incoming chunk. If so, get out of the while loop.
*/
*/
if
(
!
sctp_id2assoc
(
sk
,
associd
))
if
(
!
sctp_id2assoc
(
sk
,
associd
))
goto
out
;
break
;
if
(
error
!=
0
)
/* If there is an error on chunk, discard this packet. */
goto
err_out
;
if
(
error
&&
chunk
)
chunk
->
pdiscard
=
1
;
}
}
err_out:
/* Is this the right way to pass errors up to the ULP? */
if
(
error
)
sk
->
err
=
-
error
;
out:
}
}
/* This routine moves an association from its old sk to a new sk. */
/* This routine moves an association from its old sk to a new sk. */
...
@@ -1017,7 +922,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
...
@@ -1017,7 +922,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
/* Try to find an active transport. */
/* Try to find an active transport. */
if
(
t
->
state
.
active
)
{
if
(
t
->
active
)
{
break
;
break
;
}
else
{
}
else
{
/* Keep track of the next transport in case
/* Keep track of the next transport in case
...
...
net/sctp/bind_addr.c
View file @
28b9daad
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) Cisco 1999,2000
* Copyright (c) Cisco 1999,2000
* Copyright (c) Motorola 1999,2000,2001
* Copyright (c) Motorola 1999,2000,2001
* Copyright (c) International Business Machines Corp., 2001
* Copyright (c) International Business Machines Corp., 2001
,2002
* Copyright (c) La Monte H.P. Yarroll 2001
* Copyright (c) La Monte H.P. Yarroll 2001
*
*
* This file is part of the SCTP kernel reference implementation.
* This file is part of the SCTP kernel reference implementation.
...
@@ -52,7 +52,7 @@
...
@@ -52,7 +52,7 @@
#include <net/sctp/sm.h>
#include <net/sctp/sm.h>
/* Forward declarations for internal helpers. */
/* Forward declarations for internal helpers. */
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
,
sockaddr_storage_t
*
,
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
,
union
sctp_addr
*
,
sctp_scope_t
scope
,
int
priority
,
int
flags
);
sctp_scope_t
scope
,
int
priority
,
int
flags
);
static
void
sctp_bind_addr_clean
(
sctp_bind_addr_t
*
);
static
void
sctp_bind_addr_clean
(
sctp_bind_addr_t
*
);
...
@@ -143,7 +143,7 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp)
...
@@ -143,7 +143,7 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp)
}
}
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
bp
,
sockaddr_storage_t
*
new
,
int
sctp_add_bind_addr
(
sctp_bind_addr_t
*
bp
,
union
sctp_addr
*
new
,
int
priority
)
int
priority
)
{
{
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
...
@@ -171,7 +171,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new,
...
@@ -171,7 +171,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new,
/* Delete an address from the bind address list in the SCTP_bind_addr
/* Delete an address from the bind address list in the SCTP_bind_addr
* structure.
* structure.
*/
*/
int
sctp_del_bind_addr
(
sctp_bind_addr_t
*
bp
,
sockaddr_storage_t
*
del_addr
)
int
sctp_del_bind_addr
(
sctp_bind_addr_t
*
bp
,
union
sctp_addr
*
del_addr
)
{
{
struct
list_head
*
pos
,
*
temp
;
struct
list_head
*
pos
,
*
temp
;
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
...
@@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr)
...
@@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr)
*
*
* The second argument is the return value for the length.
* The second argument is the return value for the length.
*/
*/
sctpParam_t
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
int
*
addrs_len
,
union
sctp_params
sctp_bind_addrs_to_raw
(
const
sctp_bind_addr_t
*
bp
,
int
priority
)
int
*
addrs_len
,
int
priority
)
{
{
sctpParam_t
addrparms
;
union
sctp_params
addrparms
;
sctpParam_t
retval
;
union
sctp_params
retval
;
int
addrparms_len
;
int
addrparms_len
;
sctp_addr_param_t
rawaddr
;
sctp_addr_param_t
rawaddr
;
int
len
;
int
len
;
struct
sockaddr_storage_list
*
addr
;
struct
sockaddr_storage_list
*
addr
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
retval
.
v
=
NULL
;
addrparms_len
=
0
;
addrparms_len
=
0
;
len
=
0
;
len
=
0
;
...
@@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
...
@@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
len
+=
sizeof
(
sctp_addr_param_t
);
len
+=
sizeof
(
sctp_addr_param_t
);
}
}
addrparms
.
v
=
kmalloc
(
len
,
priority
);
retval
.
v
=
kmalloc
(
len
,
priority
);
if
(
!
addrparms
.
v
)
if
(
!
retval
.
v
)
goto
end_raw
;
goto
end_raw
;
retval
=
addrparms
;
addrparms
=
retval
;
list_for_each
(
pos
,
&
bp
->
address_list
)
{
list_for_each
(
pos
,
&
bp
->
address_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
...
@@ -244,7 +242,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
...
@@ -244,7 +242,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
{
{
sctp_addr_param_t
*
rawaddr
;
sctp_addr_param_t
*
rawaddr
;
sctp_paramhdr_t
*
param
;
sctp_paramhdr_t
*
param
;
sockaddr_storage_t
addr
;
union
sctp_addr
addr
;
int
retval
=
0
;
int
retval
=
0
;
int
len
;
int
len
;
...
@@ -284,15 +282,16 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
...
@@ -284,15 +282,16 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
* 2nd Level Abstractions
* 2nd Level Abstractions
********************************************************************/
********************************************************************/
/* Does this contain a specified address? */
/* Does this contain a specified address? Allow wildcarding. */
int
sctp_bind_addr_has_addr
(
sctp_bind_addr_t
*
bp
,
const
sockaddr_storage_t
*
addr
)
int
sctp_bind_addr_match
(
sctp_bind_addr_t
*
bp
,
const
union
sctp_addr
*
addr
,
struct
sctp_opt
*
opt
)
{
{
struct
sockaddr_storage_list
*
laddr
;
struct
sockaddr_storage_list
*
laddr
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
list_for_each
(
pos
,
&
bp
->
address_list
)
{
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
(
sctp_cmp_addr
(
&
laddr
->
a
,
addr
))
if
(
opt
->
pf
->
cmp_addr
(
&
laddr
->
a
,
addr
,
opt
))
return
1
;
return
1
;
}
}
...
@@ -300,7 +299,7 @@ int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr
...
@@ -300,7 +299,7 @@ int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr
}
}
/* Copy out addresses from the global local address list. */
/* Copy out addresses from the global local address list. */
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
dest
,
sockaddr_storage_t
*
addr
,
static
int
sctp_copy_one_addr
(
sctp_bind_addr_t
*
dest
,
union
sctp_addr
*
addr
,
sctp_scope_t
scope
,
int
priority
,
int
flags
)
sctp_scope_t
scope
,
int
priority
,
int
flags
)
{
{
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
...
@@ -325,94 +324,33 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr,
...
@@ -325,94 +324,33 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr,
return
error
;
return
error
;
}
}
/* Is
addr one of the wildcard
s? */
/* Is
this a wildcard addres
s? */
int
sctp_is_any
(
const
sockaddr_storage_t
*
addr
)
int
sctp_is_any
(
const
union
sctp_addr
*
addr
)
{
{
int
retval
=
0
;
struct
sctp_func
*
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
if
(
!
af
)
switch
(
addr
->
sa
.
sa_family
)
{
return
0
;
case
AF_INET
:
return
af
->
is_any
(
addr
);
if
(
INADDR_ANY
==
addr
->
v4
.
sin_addr
.
s_addr
)
retval
=
1
;
break
;
case
AF_INET6
:
SCTP_V6
(
if
(
IPV6_ADDR_ANY
==
sctp_ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
))
retval
=
1
;
);
break
;
default:
break
;
};
return
retval
;
}
}
/* Is 'addr' valid for 'scope'? */
/* Is 'addr' valid for 'scope'? */
int
sctp_in_scope
(
const
sockaddr_storage_t
*
addr
,
sctp_scope_t
scope
)
int
sctp_in_scope
(
const
union
sctp_addr
*
addr
,
sctp_scope_t
scope
)
{
{
sctp_scope_t
addr_scope
=
sctp_scope
(
addr
);
sctp_scope_t
addr_scope
=
sctp_scope
(
addr
);
switch
(
addr
->
sa
.
sa_family
)
{
case
AF_INET
:
/* According to the SCTP IPv4 address scoping document -
* <draft-stewart-tsvwg-sctp-ipv4-00.txt>, the scope has
* a heirarchy of 5 levels:
* Level 0 - unusable SCTP addresses
* Level 1 - loopback address
* Level 2 - link-local addresses
* Level 3 - private addresses.
* Level 4 - global addresses
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
/* The unusable SCTP addresses will not be considered with
/* The unusable SCTP addresses will not be considered with
* any defined scopes.
* any defined scopes.
*/
*/
if
(
SCTP_SCOPE_UNUSABLE
==
addr_scope
)
if
(
SCTP_SCOPE_UNUSABLE
==
addr_scope
)
return
0
;
return
0
;
/*
/* Note that we are assuming that the scoping are the same
* For INIT and INIT-ACK address list, let L be the level of
* for both IPv4 addresses and IPv6 addresses, i.e., if the
* of requested destination address, sender and receiver
* scope is link local, both IPv4 link local addresses and
* SHOULD include all of its addresses with level greater
* IPv6 link local addresses would be treated as in the
* than or equal to L.
* scope. There is no filtering for IPv4 vs. IPv6 addresses
* based on scoping alone.
*/
if
(
addr_scope
<=
scope
)
return
1
;
break
;
case
AF_INET6
:
/* FIXME:
* This is almost certainly wrong since scopes have an
* heirarchy. I don't know what RFC to look at.
* There may be some guidance in the SCTP implementors
* guide (an Internet Draft as of October 2001).
*
* Further verification on the correctness of the IPv6
* scoping is needed. According to the IPv6 scoping draft,
* the link local and site local address may require
* further scoping.
*
* Is the heirachy of the IPv6 scoping the same as what's
* defined for IPv4?
* If the same heirarchy indeed applies to both famiies,
* this function can be simplified with one set of code.
* (see the comments for IPv4 above)
*/
*/
if
(
addr_scope
<=
scope
)
if
(
addr_scope
<=
scope
)
return
1
;
return
1
;
break
;
default:
return
0
;
};
return
0
;
return
0
;
}
}
...
@@ -422,112 +360,13 @@ int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope)
...
@@ -422,112 +360,13 @@ int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope)
********************************************************************/
********************************************************************/
/* What is the scope of 'addr'? */
/* What is the scope of 'addr'? */
sctp_scope_t
sctp_scope
(
const
sockaddr_storage_t
*
addr
)
sctp_scope_t
sctp_scope
(
const
union
sctp_addr
*
addr
)
{
sctp_scope_t
retval
=
SCTP_SCOPE_GLOBAL
;
switch
(
addr
->
sa
.
sa_family
)
{
case
AF_INET
:
/* We are checking the loopback, private and other address
* scopes as defined in RFC 1918.
* The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
* The set of SCTP address scope hopefully can cover both
* types of addresses.
*/
/* Should IPv4 scoping be a sysctl configurable option
* so users can turn it off (default on) for certain
* unconventional networking environments?
*/
/* Check for unusable SCTP addresses. */
if
(
IS_IPV4_UNUSABLE_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_UNUSABLE
;
}
else
if
(
LOOPBACK
(
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_LOOPBACK
;
}
else
if
(
IS_IPV4_LINK_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_LINK
;
}
else
if
(
IS_IPV4_PRIVATE_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_PRIVATE
;
}
else
{
retval
=
SCTP_SCOPE_GLOBAL
;
}
break
;
case
AF_INET6
:
{
SCTP_V6
(
int
v6scope
;
v6scope
=
ipv6_addr_scope
((
struct
in6_addr
*
)
&
addr
->
v6
.
sin6_addr
);
/* The IPv6 scope is really a set of bit
* fields. See IFA_* in <net/if_inet6.h>.
* Mapping them to the generic SCTP scope
* set is an attempt to have code
* consistencies with the IPv4 scoping.
*/
switch
(
v6scope
)
{
case
IFA_HOST
:
retval
=
SCTP_SCOPE_LOOPBACK
;
break
;
case
IFA_LINK
:
retval
=
SCTP_SCOPE_LINK
;
break
;
case
IFA_SITE
:
retval
=
SCTP_SCOPE_PRIVATE
;
break
;
default:
retval
=
SCTP_SCOPE_GLOBAL
;
break
;
};
);
break
;
}
default:
retval
=
SCTP_SCOPE_GLOBAL
;
break
;
};
return
retval
;
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
int
sctp_addr_is_valid
(
const
sockaddr_storage_t
*
addr
)
{
{
unsigned
short
sa_family
=
addr
->
sa
.
sa_family
;
struct
sctp_func
*
af
;
switch
(
sa_family
)
{
case
AF_INET
:
/* Is this a non-unicast address or a unusable SCTP address? */
if
(
IS_IPV4_UNUSABLE_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
return
0
;
break
;
case
AF_INET6
:
SCTP_V6
(
{
int
ret
=
sctp_ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
);
/* Is this a non-unicast address */
af
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
if
(
!
(
ret
&
IPV6_ADDR_UNICAST
))
if
(
!
af
)
return
0
;
return
SCTP_SCOPE_UNUSABLE
;
break
;
});
default:
return
af
->
scope
((
union
sctp_addr
*
)
addr
);
return
0
;
};
return
1
;
}
}
net/sctp/endpointola.c
View file @
28b9daad
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2002
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2001 La Monte H.P. Yarroll
...
@@ -237,13 +237,14 @@ void sctp_endpoint_put(sctp_endpoint_t *ep)
...
@@ -237,13 +237,14 @@ void sctp_endpoint_put(sctp_endpoint_t *ep)
/* Is this the endpoint we are looking for? */
/* Is this the endpoint we are looking for? */
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
ep
,
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
ep
,
const
sockaddr_storage_t
*
laddr
)
const
union
sctp_addr
*
laddr
)
{
{
sctp_endpoint_t
*
retval
;
sctp_endpoint_t
*
retval
;
sctp_read_lock
(
&
ep
->
base
.
addr_lock
);
sctp_read_lock
(
&
ep
->
base
.
addr_lock
);
if
(
ep
->
base
.
bind_addr
.
port
==
laddr
->
v4
.
sin_port
)
{
if
(
ep
->
base
.
bind_addr
.
port
==
laddr
->
v4
.
sin_port
)
{
if
(
sctp_bind_addr_has_addr
(
&
ep
->
base
.
bind_addr
,
laddr
))
{
if
(
sctp_bind_addr_match
(
&
ep
->
base
.
bind_addr
,
laddr
,
sctp_sk
(
ep
->
base
.
sk
)))
{
retval
=
ep
;
retval
=
ep
;
goto
out
;
goto
out
;
}
}
...
@@ -262,7 +263,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
...
@@ -262,7 +263,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
*/
*/
sctp_association_t
*
__sctp_endpoint_lookup_assoc
(
sctp_association_t
*
__sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
endpoint
,
const
sctp_endpoint_t
*
endpoint
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
transport
)
sctp_transport_t
**
transport
)
{
{
int
rport
;
int
rport
;
...
@@ -289,7 +290,7 @@ sctp_association_t *__sctp_endpoint_lookup_assoc(
...
@@ -289,7 +290,7 @@ sctp_association_t *__sctp_endpoint_lookup_assoc(
/* Lookup association on an endpoint based on a peer address. BH-safe. */
/* Lookup association on an endpoint based on a peer address. BH-safe. */
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
sctp_association_t
*
sctp_endpoint_lookup_assoc
(
const
sctp_endpoint_t
*
ep
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
transport
)
sctp_transport_t
**
transport
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
...
@@ -301,6 +302,30 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
...
@@ -301,6 +302,30 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
return
asoc
;
return
asoc
;
}
}
/* Look for any peeled off association from the endpoint that matches the
* given peer address.
*/
int
sctp_endpoint_is_peeled_off
(
sctp_endpoint_t
*
ep
,
const
union
sctp_addr
*
paddr
)
{
struct
list_head
*
pos
;
struct
sockaddr_storage_list
*
addr
;
sctp_bind_addr_t
*
bp
;
sctp_read_lock
(
&
ep
->
base
.
addr_lock
);
bp
=
&
ep
->
base
.
bind_addr
;
list_for_each
(
pos
,
&
bp
->
address_list
)
{
addr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
if
(
sctp_has_association
(
&
addr
->
a
,
paddr
))
{
sctp_read_unlock
(
&
ep
->
base
.
addr_lock
);
return
1
;
}
}
sctp_read_unlock
(
&
ep
->
base
.
addr_lock
);
return
0
;
}
/* Do delayed input processing. This is scheduled by sctp_rcv().
/* Do delayed input processing. This is scheduled by sctp_rcv().
* This may be called on BH or task time.
* This may be called on BH or task time.
*/
*/
...
@@ -316,7 +341,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -316,7 +341,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
int
error
=
0
;
int
error
=
0
;
if
(
ep
->
base
.
dead
)
if
(
ep
->
base
.
dead
)
goto
out
;
return
;
asoc
=
NULL
;
asoc
=
NULL
;
inqueue
=
&
ep
->
base
.
inqueue
;
inqueue
=
&
ep
->
base
.
inqueue
;
...
@@ -350,25 +375,16 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
...
@@ -350,25 +375,16 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
if
(
chunk
->
transport
)
if
(
chunk
->
transport
)
chunk
->
transport
->
last_time_heard
=
jiffies
;
chunk
->
transport
->
last_time_heard
=
jiffies
;
/* FIX ME We really would rather NOT have to use
* GFP_ATOMIC.
*/
error
=
sctp_do_sm
(
SCTP_EVENT_T_CHUNK
,
subtype
,
state
,
error
=
sctp_do_sm
(
SCTP_EVENT_T_CHUNK
,
subtype
,
state
,
ep
,
asoc
,
chunk
,
GFP_ATOMIC
);
ep
,
asoc
,
chunk
,
GFP_ATOMIC
);
if
(
error
!=
0
)
if
(
error
&&
chunk
)
goto
err_out
;
chunk
->
pdiscard
=
1
;
/* Check to see if the endpoint is freed in response to
/* Check to see if the endpoint is freed in response to
* the incoming chunk. If so, get out of the while loop.
* the incoming chunk. If so, get out of the while loop.
*/
*/
if
(
!
sctp_sk
(
sk
)
->
ep
)
if
(
!
sctp_sk
(
sk
)
->
ep
)
goto
out
;
break
;
}
}
err_out:
/* Is this the right way to pass errors up to the ULP? */
if
(
error
)
ep
->
base
.
sk
->
err
=
-
error
;
out:
}
}
net/sctp/input.c
View file @
28b9daad
...
@@ -60,64 +60,11 @@
...
@@ -60,64 +60,11 @@
/* Forward declarations for internal helpers. */
/* Forward declarations for internal helpers. */
static
int
sctp_rcv_ootb
(
struct
sk_buff
*
);
static
int
sctp_rcv_ootb
(
struct
sk_buff
*
);
sctp_association_t
*
__sctp_rcv_lookup
(
struct
sk_buff
*
skb
,
sctp_association_t
*
__sctp_rcv_lookup
(
struct
sk_buff
*
skb
,
const
sockaddr_storage_t
*
laddr
,
const
union
sctp_addr
*
laddr
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
transportp
);
sctp_transport_t
**
transportp
);
sctp_endpoint_t
*
__sctp_rcv_lookup_endpoint
(
const
sockaddr_storage_t
*
laddr
);
sctp_endpoint_t
*
__sctp_rcv_lookup_endpoint
(
const
union
sctp_addr
*
laddr
);
/* Initialize a sockaddr_storage from in incoming skb.
* FIXME: This belongs with AF specific sctp_func_t. --jgrimm
*/
static
sockaddr_storage_t
*
sctp_sockaddr_storage_init
(
sockaddr_storage_t
*
addr
,
const
struct
sk_buff
*
skb
,
int
is_saddr
)
{
sockaddr_storage_t
*
ret
=
NULL
;
void
*
to
,
*
saddr
,
*
daddr
;
__u16
*
port
;
size_t
len
;
struct
sctphdr
*
sh
;
switch
(
skb
->
nh
.
iph
->
version
)
{
case
4
:
to
=
&
addr
->
v4
.
sin_addr
.
s_addr
;
port
=
&
addr
->
v4
.
sin_port
;
saddr
=
&
skb
->
nh
.
iph
->
saddr
;
daddr
=
&
skb
->
nh
.
iph
->
daddr
;
len
=
sizeof
(
struct
in_addr
);
addr
->
v4
.
sin_family
=
AF_INET
;
break
;
case
6
:
SCTP_V6
(
to
=
&
addr
->
v6
.
sin6_addr
;
port
=
&
addr
->
v6
.
sin6_port
;
saddr
=
&
skb
->
nh
.
ipv6h
->
saddr
;
daddr
=
&
skb
->
nh
.
ipv6h
->
daddr
;
len
=
sizeof
(
struct
in6_addr
);
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_flowinfo
=
0
;
/* FIXME */
addr
->
v6
.
sin6_scope_id
=
0
;
/* FIXME */
break
;
)
default:
goto
out
;
};
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
if
(
is_saddr
)
{
*
port
=
ntohs
(
sh
->
source
);
memcpy
(
to
,
saddr
,
len
);
}
else
{
*
port
=
ntohs
(
sh
->
dest
);
memcpy
(
to
,
daddr
,
len
);
}
ret
=
addr
;
out:
return
ret
;
}
/* Calculate the SCTP checksum of an SCTP packet. */
/* Calculate the SCTP checksum of an SCTP packet. */
static
inline
int
sctp_rcv_checksum
(
struct
sk_buff
*
skb
)
static
inline
int
sctp_rcv_checksum
(
struct
sk_buff
*
skb
)
...
@@ -147,8 +94,9 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -147,8 +94,9 @@ int sctp_rcv(struct sk_buff *skb)
sctp_transport_t
*
transport
=
NULL
;
sctp_transport_t
*
transport
=
NULL
;
sctp_chunk_t
*
chunk
;
sctp_chunk_t
*
chunk
;
struct
sctphdr
*
sh
;
struct
sctphdr
*
sh
;
sockaddr_storage_t
src
;
union
sctp_addr
src
;
sockaddr_storage_t
dest
;
union
sctp_addr
dest
;
struct
sctp_func
*
af
;
int
ret
=
0
;
int
ret
=
0
;
if
(
skb
->
pkt_type
!=
PACKET_HOST
)
if
(
skb
->
pkt_type
!=
PACKET_HOST
)
...
@@ -165,8 +113,13 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -165,8 +113,13 @@ int sctp_rcv(struct sk_buff *skb)
skb_pull
(
skb
,
sizeof
(
struct
sctphdr
));
skb_pull
(
skb
,
sizeof
(
struct
sctphdr
));
sctp_sockaddr_storage_init
(
&
src
,
skb
,
1
);
af
=
sctp_get_af_specific
(
ipver2af
(
skb
->
nh
.
iph
->
version
));
sctp_sockaddr_storage_init
(
&
dest
,
skb
,
0
);
if
(
unlikely
(
!
af
))
goto
bad_packet
;
/* Initialize local addresses for lookups. */
af
->
from_skb
(
&
src
,
skb
,
1
);
af
->
from_skb
(
&
dest
,
skb
,
0
);
/* If the packet is to or from a non-unicast address,
/* If the packet is to or from a non-unicast address,
* silently discard the packet.
* silently discard the packet.
...
@@ -179,7 +132,7 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -179,7 +132,7 @@ int sctp_rcv(struct sk_buff *skb)
* IP broadcast addresses cannot be used in an SCTP transport
* IP broadcast addresses cannot be used in an SCTP transport
* address."
* address."
*/
*/
if
(
!
sctp_addr_is_valid
(
&
src
)
||
!
sctp_addr_is
_valid
(
&
dest
))
if
(
!
af
->
addr_valid
(
&
src
)
||
!
af
->
addr
_valid
(
&
dest
))
goto
discard_it
;
goto
discard_it
;
asoc
=
__sctp_rcv_lookup
(
skb
,
&
src
,
&
dest
,
&
transport
);
asoc
=
__sctp_rcv_lookup
(
skb
,
&
src
,
&
dest
,
&
transport
);
...
@@ -219,7 +172,7 @@ int sctp_rcv(struct sk_buff *skb)
...
@@ -219,7 +172,7 @@ int sctp_rcv(struct sk_buff *skb)
chunk
->
sctp_hdr
=
sh
;
chunk
->
sctp_hdr
=
sh
;
/* Set the source and destination addresses of the incoming chunk. */
/* Set the source and destination addresses of the incoming chunk. */
sctp_init_addrs
(
chunk
);
sctp_init_addrs
(
chunk
,
&
src
,
&
dest
);
/* Remember where we came from. */
/* Remember where we came from. */
chunk
->
transport
=
transport
;
chunk
->
transport
=
transport
;
...
@@ -431,7 +384,7 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep)
...
@@ -431,7 +384,7 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep)
}
}
/* Look up an endpoint. */
/* Look up an endpoint. */
sctp_endpoint_t
*
__sctp_rcv_lookup_endpoint
(
const
sockaddr_storage_t
*
laddr
)
sctp_endpoint_t
*
__sctp_rcv_lookup_endpoint
(
const
union
sctp_addr
*
laddr
)
{
{
sctp_hashbucket_t
*
head
;
sctp_hashbucket_t
*
head
;
sctp_endpoint_common_t
*
epb
;
sctp_endpoint_common_t
*
epb
;
...
@@ -523,8 +476,8 @@ void __sctp_unhash_established(sctp_association_t *asoc)
...
@@ -523,8 +476,8 @@ void __sctp_unhash_established(sctp_association_t *asoc)
}
}
/* Look up an association. */
/* Look up an association. */
sctp_association_t
*
__sctp_lookup_association
(
const
sockaddr_storage_t
*
laddr
,
sctp_association_t
*
__sctp_lookup_association
(
const
union
sctp_addr
*
laddr
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
transportp
)
sctp_transport_t
**
transportp
)
{
{
sctp_hashbucket_t
*
head
;
sctp_hashbucket_t
*
head
;
...
@@ -559,8 +512,8 @@ sctp_association_t *__sctp_lookup_association(const sockaddr_storage_t *laddr,
...
@@ -559,8 +512,8 @@ sctp_association_t *__sctp_lookup_association(const sockaddr_storage_t *laddr,
}
}
/* Look up an association. BH-safe. */
/* Look up an association. BH-safe. */
sctp_association_t
*
sctp_lookup_association
(
const
sockaddr_storage_t
*
laddr
,
sctp_association_t
*
sctp_lookup_association
(
const
union
sctp_addr
*
laddr
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
sctp_transport_t
**
transportp
)
sctp_transport_t
**
transportp
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
...
@@ -573,8 +526,8 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr,
...
@@ -573,8 +526,8 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr,
}
}
/* Is there an association matching the given local and peer addresses? */
/* Is there an association matching the given local and peer addresses? */
int
sctp_has_association
(
const
sockaddr_storage_t
*
laddr
,
int
sctp_has_association
(
const
union
sctp_addr
*
laddr
,
const
sockaddr_storage_t
*
paddr
)
const
union
sctp_addr
*
paddr
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
sctp_transport_t
*
transport
;
sctp_transport_t
*
transport
;
...
@@ -606,21 +559,19 @@ int sctp_has_association(const sockaddr_storage_t *laddr,
...
@@ -606,21 +559,19 @@ int sctp_has_association(const sockaddr_storage_t *laddr,
* in certain circumstances.
* in certain circumstances.
*
*
*/
*/
static
sctp_association_t
*
__sctp_rcv_init
ack
_lookup
(
struct
sk_buff
*
skb
,
static
sctp_association_t
*
__sctp_rcv_init_lookup
(
struct
sk_buff
*
skb
,
const
sockaddr_storage_t
*
laddr
,
sctp_transport_t
**
transportp
)
const
union
sctp_addr
*
laddr
,
sctp_transport_t
**
transportp
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
sockaddr_storage_t
addr
;
union
sctp_addr
addr
;
sockaddr_storage_t
*
paddr
=
&
addr
;
union
sctp_addr
*
paddr
=
&
addr
;
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
struct
sctphdr
*
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
sctp_chunkhdr_t
*
ch
;
sctp_chunkhdr_t
*
ch
;
__u8
*
ch_end
,
*
data
;
union
sctp_params
params
;
sctp_
paramhdr_t
*
parm
;
sctp_
init_chunk_t
*
init
;
ch
=
(
sctp_chunkhdr_t
*
)
skb
->
data
;
ch
=
(
sctp_chunkhdr_t
*
)
skb
->
data
;
ch_end
=
((
__u8
*
)
ch
)
+
WORD_ROUND
(
ntohs
(
ch
->
length
));
/* If this is INIT/INIT-ACK look inside the chunk too. */
/* If this is INIT/INIT-ACK look inside the chunk too. */
switch
(
ch
->
type
)
{
switch
(
ch
->
type
)
{
case
SCTP_CID_INIT
:
case
SCTP_CID_INIT
:
...
@@ -646,24 +597,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
...
@@ -646,24 +597,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Find the start of the TLVs and the end of the chunk. This is
/* Find the start of the TLVs and the end of the chunk. This is
* the region we search for address parameters.
* the region we search for address parameters.
*/
*/
data
=
skb
->
data
+
sizeof
(
sctp_init_chunk_t
);
init
=
(
sctp_init_chunk_t
*
)
skb
->
data
;
/* See sctp_process_init() for how to go thru TLVs. */
while
(
data
<
ch_end
)
{
parm
=
(
sctp_paramhdr_t
*
)
data
;
if
(
!
parm
->
length
)
break
;
data
+=
WORD_ROUND
(
ntohs
(
parm
->
length
));
/* Walk the parameters looking for embedded addresses. */
sctp_walk_params
(
params
,
init
,
init_hdr
.
params
)
{
/* Note: Ignoring hostname addresses. */
/* Note: Ignoring hostname addresses. */
if
((
SCTP_PARAM_IPV4_ADDRESS
!=
par
m
->
type
)
&&
if
((
SCTP_PARAM_IPV4_ADDRESS
!=
par
ams
.
p
->
type
)
&&
(
SCTP_PARAM_IPV6_ADDRESS
!=
par
m
->
type
))
(
SCTP_PARAM_IPV6_ADDRESS
!=
par
ams
.
p
->
type
))
continue
;
continue
;
sctp_param2sockaddr
(
paddr
,
(
sctp_addr_param_t
*
)
parm
,
sctp_param2sockaddr
(
paddr
,
params
.
addr
,
ntohs
(
sh
->
source
));
ntohs
(
sh
->
source
));
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
if
(
asoc
)
if
(
asoc
)
return
asoc
;
return
asoc
;
...
@@ -674,20 +618,20 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
...
@@ -674,20 +618,20 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Lookup an association for an inbound skb. */
/* Lookup an association for an inbound skb. */
sctp_association_t
*
__sctp_rcv_lookup
(
struct
sk_buff
*
skb
,
sctp_association_t
*
__sctp_rcv_lookup
(
struct
sk_buff
*
skb
,
const
sockaddr_storage_t
*
paddr
,
const
union
sctp_addr
*
paddr
,
const
sockaddr_storage_t
*
laddr
,
const
union
sctp_addr
*
laddr
,
sctp_transport_t
**
transportp
)
sctp_transport_t
**
transportp
)
{
{
sctp_association_t
*
asoc
;
sctp_association_t
*
asoc
;
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
asoc
=
__sctp_lookup_association
(
laddr
,
paddr
,
transportp
);
/* Further lookup for INIT
-ACK packet
.
/* Further lookup for INIT
/INIT-ACK packets
.
* SCTP Implementors Guide, 2.18 Handling of address
* SCTP Implementors Guide, 2.18 Handling of address
* parameters within the INIT or INIT-ACK.
* parameters within the INIT or INIT-ACK.
*/
*/
if
(
!
asoc
)
if
(
!
asoc
)
asoc
=
__sctp_rcv_init
ack
_lookup
(
skb
,
laddr
,
transportp
);
asoc
=
__sctp_rcv_init_lookup
(
skb
,
laddr
,
transportp
);
return
asoc
;
return
asoc
;
}
}
...
...
net/sctp/ipv6.c
View file @
28b9daad
...
@@ -172,12 +172,12 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
...
@@ -172,12 +172,12 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
/* Returns the dst cache entry for the given source and destination ip
/* Returns the dst cache entry for the given source and destination ip
* addresses.
* addresses.
*/
*/
struct
dst_entry
*
sctp_v6_get_dst
(
sockaddr_storage_t
*
daddr
,
struct
dst_entry
*
sctp_v6_get_dst
(
union
sctp_addr
*
daddr
,
sockaddr_storage_t
*
saddr
)
union
sctp_addr
*
saddr
)
{
{
struct
dst_entry
*
dst
;
struct
dst_entry
*
dst
;
struct
flowi
fl
=
{
.
nl_u
=
{
.
ip6_u
=
{
.
daddr
=
&
daddr
->
v6
.
sin6_addr
,
struct
flowi
fl
=
{
}
}
};
.
nl_u
=
{
.
ip6_u
=
{
.
daddr
=
&
daddr
->
v6
.
sin6_addr
,
}
}
};
SCTP_DEBUG_PRINTK
(
"%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
,
SCTP_DEBUG_PRINTK
(
"%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
,
...
@@ -206,12 +206,147 @@ struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr,
...
@@ -206,12 +206,147 @@ struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr,
return
dst
;
return
dst
;
}
}
/* Check if the dst entry's source addr matches the given source addr. */
/* Make a copy of all potential local addresses. */
int
sctp_v6_cmp_saddr
(
struct
dst_entry
*
dst
,
sockaddr_storage_t
*
saddr
)
static
void
sctp_v6_copy_addrlist
(
struct
list_head
*
addrlist
,
struct
net_device
*
dev
)
{
struct
inet6_dev
*
in6_dev
;
struct
inet6_ifaddr
*
ifp
;
struct
sockaddr_storage_list
*
addr
;
read_lock
(
&
addrconf_lock
);
if
((
in6_dev
=
__in6_dev_get
(
dev
))
==
NULL
)
{
read_unlock
(
&
addrconf_lock
);
return
;
}
read_lock
(
&
in6_dev
->
lock
);
for
(
ifp
=
in6_dev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
/* Add the address to the local list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
if
(
addr
)
{
addr
->
a
.
v6
.
sin6_family
=
AF_INET6
;
addr
->
a
.
v6
.
sin6_port
=
0
;
addr
->
a
.
v6
.
sin6_addr
=
ifp
->
addr
;
INIT_LIST_HEAD
(
&
addr
->
list
);
list_add_tail
(
&
addr
->
list
,
addrlist
);
}
}
read_unlock
(
&
in6_dev
->
lock
);
read_unlock
(
&
addrconf_lock
);
}
/* Initialize a sockaddr_storage from in incoming skb. */
static
void
sctp_v6_from_skb
(
union
sctp_addr
*
addr
,
struct
sk_buff
*
skb
,
int
is_saddr
)
{
void
*
from
;
__u16
*
port
;
struct
sctphdr
*
sh
;
port
=
&
addr
->
v6
.
sin6_port
;
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_flowinfo
=
0
;
/* FIXME */
addr
->
v6
.
sin6_scope_id
=
0
;
/* FIXME */
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
if
(
is_saddr
)
{
*
port
=
ntohs
(
sh
->
source
);
from
=
&
skb
->
nh
.
ipv6h
->
saddr
;
}
else
{
*
port
=
ntohs
(
sh
->
dest
);
from
=
&
skb
->
nh
.
ipv6h
->
daddr
;
}
ipv6_addr_copy
(
&
addr
->
v6
.
sin6_addr
,
from
);
}
/* Initialize a sctp_addr from a dst_entry. */
static
void
sctp_v6_dst_saddr
(
union
sctp_addr
*
addr
,
struct
dst_entry
*
dst
)
{
{
struct
rt6_info
*
rt
=
(
struct
rt6_info
*
)
dst
;
struct
rt6_info
*
rt
=
(
struct
rt6_info
*
)
dst
;
addr
->
sa
.
sa_family
=
AF_INET6
;
ipv6_addr_copy
(
&
addr
->
v6
.
sin6_addr
,
&
rt
->
rt6i_src
.
addr
);
}
/* Compare addresses exactly. Well.. almost exactly; ignore scope_id
* for now. FIXME.
*/
static
int
sctp_v6_cmp_addr
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
)
{
int
match
;
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
match
=
!
ipv6_addr_cmp
((
struct
in6_addr
*
)
&
addr1
->
v6
.
sin6_addr
,
(
struct
in6_addr
*
)
&
addr2
->
v6
.
sin6_addr
);
return
match
;
}
/* Initialize addr struct to INADDR_ANY. */
static
void
sctp_v6_inaddr_any
(
union
sctp_addr
*
addr
,
unsigned
short
port
)
{
memset
(
addr
,
0x00
,
sizeof
(
union
sctp_addr
));
addr
->
v6
.
sin6_family
=
AF_INET6
;
addr
->
v6
.
sin6_port
=
port
;
}
/* Is this a wildcard address? */
static
int
sctp_v6_is_any
(
const
union
sctp_addr
*
addr
)
{
int
type
;
type
=
ipv6_addr_type
((
struct
in6_addr
*
)
&
addr
->
v6
.
sin6_addr
);
return
IPV6_ADDR_ANY
==
type
;
}
return
ipv6_addr_cmp
(
&
rt
->
rt6i_src
.
addr
,
&
saddr
->
v6
.
sin6_addr
);
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
static
int
sctp_v6_addr_valid
(
union
sctp_addr
*
addr
)
{
int
ret
=
sctp_ipv6_addr_type
(
&
addr
->
v6
.
sin6_addr
);
/* FIXME: v4-mapped-v6 address support. */
/* Is this a non-unicast address */
if
(
!
(
ret
&
IPV6_ADDR_UNICAST
))
return
0
;
return
1
;
}
/* What is the scope of 'addr'? */
static
sctp_scope_t
sctp_v6_scope
(
union
sctp_addr
*
addr
)
{
int
v6scope
;
sctp_scope_t
retval
;
/* The IPv6 scope is really a set of bit fields.
* See IFA_* in <net/if_inet6.h>. Map to a generic SCTP scope.
*/
v6scope
=
ipv6_addr_scope
(
&
addr
->
v6
.
sin6_addr
);
switch
(
v6scope
)
{
case
IFA_HOST
:
retval
=
SCTP_SCOPE_LOOPBACK
;
break
;
case
IFA_LINK
:
retval
=
SCTP_SCOPE_LINK
;
break
;
case
IFA_SITE
:
retval
=
SCTP_SCOPE_PRIVATE
;
break
;
default:
retval
=
SCTP_SCOPE_GLOBAL
;
break
;
};
return
retval
;
}
}
/* Initialize a PF_INET6 socket msg_name. */
/* Initialize a PF_INET6 socket msg_name. */
...
@@ -227,12 +362,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
...
@@ -227,12 +362,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
}
}
/* Initialize a PF_INET msgname from a ulpevent. */
/* Initialize a PF_INET msgname from a ulpevent. */
static
void
sctp_inet6_event_msgname
(
sctp_ulpevent_t
*
event
,
char
*
msgname
,
int
*
addrlen
)
static
void
sctp_inet6_event_msgname
(
sctp_ulpevent_t
*
event
,
char
*
msgname
,
int
*
addrlen
)
{
{
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
struct
sockaddr_in6
*
sin6
,
*
sin6from
;
if
(
msgname
)
{
if
(
msgname
)
{
sockaddr_storage_t
*
addr
;
union
sctp_addr
*
addr
;
sctp_inet6_msgname
(
msgname
,
addrlen
);
sctp_inet6_msgname
(
msgname
,
addrlen
);
sin6
=
(
struct
sockaddr_in6
*
)
msgname
;
sin6
=
(
struct
sockaddr_in6
*
)
msgname
;
...
@@ -288,6 +424,49 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
...
@@ -288,6 +424,49 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
}
}
}
}
/* Do we support this AF? */
static
int
sctp_inet6_af_supported
(
sa_family_t
family
)
{
/* FIXME: v4-mapped-v6 addresses. The I-D is still waffling
* on what to do with sockaddr formats for PF_INET6 sockets.
* For now assume we'll support both.
*/
switch
(
family
)
{
case
AF_INET6
:
case
AF_INET
:
return
1
;
default:
return
0
;
}
}
/* Address matching with wildcards allowed. This extra level
* of indirection lets us choose whether a PF_INET6 should
* disallow any v4 addresses if we so choose.
*/
static
int
sctp_inet6_cmp_addr
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
,
struct
sctp_opt
*
opt
)
{
struct
sctp_func
*
af1
,
*
af2
;
af1
=
sctp_get_af_specific
(
addr1
->
sa
.
sa_family
);
af2
=
sctp_get_af_specific
(
addr2
->
sa
.
sa_family
);
if
(
!
af1
||
!
af2
)
return
0
;
/* Today, wildcard AF_INET/AF_INET6. */
if
(
sctp_is_any
(
addr1
)
||
sctp_is_any
(
addr2
))
return
1
;
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
return
af1
->
cmp_addr
(
addr1
,
addr2
);
}
static
struct
proto_ops
inet6_seqpacket_ops
=
{
static
struct
proto_ops
inet6_seqpacket_ops
=
{
.
family
=
PF_INET6
,
.
family
=
PF_INET6
,
.
release
=
inet6_release
,
.
release
=
inet6_release
,
...
@@ -327,7 +506,14 @@ static sctp_func_t sctp_ipv6_specific = {
...
@@ -327,7 +506,14 @@ static sctp_func_t sctp_ipv6_specific = {
.
setsockopt
=
ipv6_setsockopt
,
.
setsockopt
=
ipv6_setsockopt
,
.
getsockopt
=
ipv6_getsockopt
,
.
getsockopt
=
ipv6_getsockopt
,
.
get_dst
=
sctp_v6_get_dst
,
.
get_dst
=
sctp_v6_get_dst
,
.
cmp_saddr
=
sctp_v6_cmp_saddr
,
.
copy_addrlist
=
sctp_v6_copy_addrlist
,
.
from_skb
=
sctp_v6_from_skb
,
.
dst_saddr
=
sctp_v6_dst_saddr
,
.
cmp_addr
=
sctp_v6_cmp_addr
,
.
scope
=
sctp_v6_scope
,
.
addr_valid
=
sctp_v6_addr_valid
,
.
inaddr_any
=
sctp_v6_inaddr_any
,
.
is_any
=
sctp_v6_is_any
,
.
net_header_len
=
sizeof
(
struct
ipv6hdr
),
.
net_header_len
=
sizeof
(
struct
ipv6hdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in6
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in6
),
.
sa_family
=
AF_INET6
,
.
sa_family
=
AF_INET6
,
...
@@ -336,6 +522,9 @@ static sctp_func_t sctp_ipv6_specific = {
...
@@ -336,6 +522,9 @@ static sctp_func_t sctp_ipv6_specific = {
static
sctp_pf_t
sctp_pf_inet6_specific
=
{
static
sctp_pf_t
sctp_pf_inet6_specific
=
{
.
event_msgname
=
sctp_inet6_event_msgname
,
.
event_msgname
=
sctp_inet6_event_msgname
,
.
skb_msgname
=
sctp_inet6_skb_msgname
,
.
skb_msgname
=
sctp_inet6_skb_msgname
,
.
af_supported
=
sctp_inet6_af_supported
,
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
af
=
&
sctp_ipv6_specific
,
};
};
/* Initialize IPv6 support and register with inet6 stack. */
/* Initialize IPv6 support and register with inet6 stack. */
...
...
net/sctp/output.c
View file @
28b9daad
...
@@ -366,18 +366,13 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -366,18 +366,13 @@ int sctp_packet_transmit(sctp_packet_t *packet)
*/
*/
sh
->
checksum
=
htonl
(
crc32
);
sh
->
checksum
=
htonl
(
crc32
);
/* FIXME: Delete the rest of this switch statement once phase 2
* of address selection (ipv6 support) drops in.
*/
switch
(
transport
->
ipaddr
.
sa
.
sa_family
)
{
switch
(
transport
->
ipaddr
.
sa
.
sa_family
)
{
case
AF_INET
:
inet_sk
(
sk
)
->
daddr
=
transport
->
ipaddr
.
v4
.
sin_addr
.
s_addr
;
break
;
case
AF_INET6
:
case
AF_INET6
:
SCTP_V6
(
inet6_sk
(
sk
)
->
daddr
=
transport
->
ipaddr
.
v6
.
sin6_addr
;)
SCTP_V6
(
inet6_sk
(
sk
)
->
daddr
=
transport
->
ipaddr
.
v6
.
sin6_addr
;)
break
;
break
;
default:
/* This is bogus address type, just bail. */
break
;
};
};
/* IP layer ECN support
/* IP layer ECN support
...
@@ -430,10 +425,12 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -430,10 +425,12 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst
=
transport
->
dst
;
dst
=
transport
->
dst
;
if
(
!
dst
||
dst
->
obsolete
)
{
if
(
!
dst
||
dst
->
obsolete
)
{
sctp_transport_route
(
transport
,
NULL
);
sctp_transport_route
(
transport
,
NULL
,
sctp_sk
(
sk
)
);
}
}
nskb
->
dst
=
dst_clone
(
transport
->
dst
);
nskb
->
dst
=
dst_clone
(
transport
->
dst
);
if
(
!
nskb
->
dst
)
goto
no_route
;
SCTP_DEBUG_PRINTK
(
"***sctp_transmit_packet*** skb length %d
\n
"
,
SCTP_DEBUG_PRINTK
(
"***sctp_transmit_packet*** skb length %d
\n
"
,
nskb
->
len
);
nskb
->
len
);
...
@@ -441,6 +438,11 @@ int sctp_packet_transmit(sctp_packet_t *packet)
...
@@ -441,6 +438,11 @@ int sctp_packet_transmit(sctp_packet_t *packet)
out:
out:
packet
->
size
=
SCTP_IP_OVERHEAD
;
packet
->
size
=
SCTP_IP_OVERHEAD
;
return
err
;
return
err
;
no_route:
kfree_skb
(
nskb
);
IP_INC_STATS_BH
(
IpOutNoRoutes
);
err
=
-
EHOSTUNREACH
;
goto
out
;
}
}
/********************************************************************
/********************************************************************
...
...
net/sctp/outqueue.c
View file @
28b9daad
...
@@ -678,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
...
@@ -678,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
if
(
!
new_transport
)
{
if
(
!
new_transport
)
{
new_transport
=
asoc
->
peer
.
active_path
;
new_transport
=
asoc
->
peer
.
active_path
;
}
else
if
(
!
new_transport
->
state
.
active
)
{
}
else
if
(
!
new_transport
->
active
)
{
/* If the chunk is Heartbeat, send it to
/* If the chunk is Heartbeat, send it to
* chunk->transport, even it's inactive.
* chunk->transport, even it's inactive.
*/
*/
...
@@ -835,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
...
@@ -835,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/
*/
new_transport
=
chunk
->
transport
;
new_transport
=
chunk
->
transport
;
if
(
new_transport
==
NULL
||
if
(
new_transport
==
NULL
||
!
new_transport
->
state
.
active
)
!
new_transport
->
active
)
new_transport
=
asoc
->
peer
.
active_path
;
new_transport
=
asoc
->
peer
.
active_path
;
/* Change packets if necessary. */
/* Change packets if necessary. */
...
@@ -1404,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
...
@@ -1404,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
/* Mark the destination transport address as
/* Mark the destination transport address as
* active if it is not so marked.
* active if it is not so marked.
*/
*/
if
(
!
transport
->
state
.
active
)
{
if
(
!
transport
->
active
)
{
sctp_assoc_control_transport
(
sctp_assoc_control_transport
(
transport
->
asoc
,
transport
->
asoc
,
transport
,
transport
,
...
...
net/sctp/primitive.c
View file @
28b9daad
...
@@ -38,6 +38,7 @@
...
@@ -38,6 +38,7 @@
* La Monte H.P. Yarroll <piggy@acm.org>
* La Monte H.P. Yarroll <piggy@acm.org>
* Narasimha Budihal <narasimha@refcode.org>
* Narasimha Budihal <narasimha@refcode.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
...
@@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT);
...
@@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT);
DECLARE_PRIMITIVE
(
SEND
);
DECLARE_PRIMITIVE
(
SEND
);
/* 10.1 ULP-to-SCTP
* J) Request Heartbeat
*
* Format: REQUESTHEARTBEAT(association id, destination transport address)
*
* -> result
*
* Instructs the local endpoint to perform a HeartBeat on the specified
* destination transport address of the given association. The returned
* result should indicate whether the transmission of the HEARTBEAT
* chunk to the destination address is successful.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o destination transport address - the transport address of the
* asociation on which a heartbeat should be issued.
*/
DECLARE_PRIMITIVE
(
REQUESTHEARTBEAT
);
/* COMMENT BUG. Find out where this is mentioned in the spec. */
/* COMMENT BUG. Find out where this is mentioned in the spec. */
int
sctp_other_icmp_unreachfrag
(
sctp_association_t
*
asoc
,
void
*
arg
)
int
sctp_other_icmp_unreachfrag
(
sctp_association_t
*
asoc
,
void
*
arg
)
{
{
...
...
net/sctp/protocol.c
View file @
28b9daad
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001
-2002
International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2001 La Monte H.P. Yarroll
...
@@ -103,7 +103,7 @@ void sctp_proc_exit(void)
...
@@ -103,7 +103,7 @@ void sctp_proc_exit(void)
/* Private helper to extract ipv4 address and stash them in
/* Private helper to extract ipv4 address and stash them in
* the protocol structure.
* the protocol structure.
*/
*/
static
inline
void
sctp_v4_get_local_addr_list
(
sctp_protocol_t
*
proto
,
static
void
sctp_v4_copy_addrlist
(
struct
list_head
*
addrlist
,
struct
net_device
*
dev
)
struct
net_device
*
dev
)
{
{
struct
in_device
*
in_dev
;
struct
in_device
*
in_dev
;
...
@@ -117,7 +117,6 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
...
@@ -117,7 +117,6 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
}
}
read_lock
(
&
in_dev
->
lock
);
read_lock
(
&
in_dev
->
lock
);
for
(
ifa
=
in_dev
->
ifa_list
;
ifa
;
ifa
=
ifa
->
ifa_next
)
{
for
(
ifa
=
in_dev
->
ifa_list
;
ifa
;
ifa
=
ifa
->
ifa_next
)
{
/* Add the address to the local list. */
/* Add the address to the local list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
...
@@ -126,7 +125,7 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
...
@@ -126,7 +125,7 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_family
=
AF_INET
;
addr
->
a
.
v4
.
sin_port
=
0
;
addr
->
a
.
v4
.
sin_port
=
0
;
addr
->
a
.
v4
.
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
addr
->
a
.
v4
.
sin_addr
.
s_addr
=
ifa
->
ifa_local
;
list_add_tail
(
&
addr
->
list
,
&
proto
->
local_addr_
list
);
list_add_tail
(
&
addr
->
list
,
addr
list
);
}
}
}
}
...
@@ -134,56 +133,21 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
...
@@ -134,56 +133,21 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
read_unlock
(
&
inetdev_lock
);
read_unlock
(
&
inetdev_lock
);
}
}
/* Private helper to extract ipv6 address and stash them in
* the protocol structure.
* FIXME: Make this an address family function.
*/
static
inline
void
sctp_v6_get_local_addr_list
(
sctp_protocol_t
*
proto
,
struct
net_device
*
dev
)
{
#ifdef SCTP_V6_SUPPORT
/* FIXME: The testframe doesn't support this function. */
#ifndef TEST_FRAME
struct
inet6_dev
*
in6_dev
;
struct
inet6_ifaddr
*
ifp
;
struct
sockaddr_storage_list
*
addr
;
read_lock
(
&
addrconf_lock
);
if
((
in6_dev
=
__in6_dev_get
(
dev
))
==
NULL
)
{
read_unlock
(
&
addrconf_lock
);
return
;
}
read_lock_bh
(
&
in6_dev
->
lock
);
for
(
ifp
=
in6_dev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
/* Add the address to the local list. */
addr
=
t_new
(
struct
sockaddr_storage_list
,
GFP_ATOMIC
);
if
(
addr
)
{
addr
->
a
.
v6
.
sin6_family
=
AF_INET6
;
addr
->
a
.
v6
.
sin6_port
=
0
;
addr
->
a
.
v6
.
sin6_addr
=
ifp
->
addr
;
INIT_LIST_HEAD
(
&
addr
->
list
);
list_add_tail
(
&
addr
->
list
,
&
proto
->
local_addr_list
);
}
}
read_unlock_bh
(
&
in6_dev
->
lock
);
read_unlock
(
&
addrconf_lock
);
#endif
/* TEST_FRAME */
#endif
/* SCTP_V6_SUPPORT */
}
/* Extract our IP addresses from the system and stash them in the
/* Extract our IP addresses from the system and stash them in the
* protocol structure.
* protocol structure.
*/
*/
static
void
__sctp_get_local_addr_list
(
sctp_protocol_t
*
proto
)
static
void
__sctp_get_local_addr_list
(
sctp_protocol_t
*
proto
)
{
{
struct
net_device
*
dev
;
struct
net_device
*
dev
;
struct
list_head
*
pos
;
struct
sctp_func
*
af
;
read_lock
(
&
dev_base_lock
);
read_lock
(
&
dev_base_lock
);
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
for
(
dev
=
dev_base
;
dev
;
dev
=
dev
->
next
)
{
sctp_v4_get_local_addr_list
(
proto
,
dev
);
list_for_each
(
pos
,
&
proto
->
address_families
)
{
sctp_v6_get_local_addr_list
(
proto
,
dev
);
af
=
list_entry
(
pos
,
sctp_func_t
,
list
);
af
->
copy_addrlist
(
&
proto
->
local_addr_list
,
dev
);
}
}
}
read_unlock
(
&
dev_base_lock
);
read_unlock
(
&
dev_base_lock
);
}
}
...
@@ -259,13 +223,15 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
...
@@ -259,13 +223,15 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
/* Returns the dst cache entry for the given source and destination ip
/* Returns the dst cache entry for the given source and destination ip
* addresses.
* addresses.
*/
*/
struct
dst_entry
*
sctp_v4_get_dst
(
sockaddr_storage_t
*
daddr
,
struct
dst_entry
*
sctp_v4_get_dst
(
union
sctp_addr
*
daddr
,
sockaddr_storage_t
*
saddr
)
union
sctp_addr
*
saddr
)
{
{
struct
rtable
*
rt
;
struct
rtable
*
rt
;
struct
flowi
fl
=
{
.
nl_u
=
{
.
ip4_u
=
{
.
daddr
=
struct
flowi
fl
;
daddr
->
v4
.
sin_addr
.
s_addr
,
}
}
};
memset
(
&
fl
,
0x0
,
sizeof
(
struct
flowi
));
fl
.
fl4_dst
=
daddr
->
v4
.
sin_addr
.
s_addr
;
fl
.
proto
=
IPPROTO_SCTP
;
if
(
saddr
)
if
(
saddr
)
fl
.
fl4_src
=
saddr
->
v4
.
sin_addr
.
s_addr
;
fl
.
fl4_src
=
saddr
->
v4
.
sin_addr
.
s_addr
;
...
@@ -285,12 +251,118 @@ struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr,
...
@@ -285,12 +251,118 @@ struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr,
return
&
rt
->
u
.
dst
;
return
&
rt
->
u
.
dst
;
}
}
/* Check if the dst entry's source addr matches the given source addr. */
int
sctp_v4_cmp_saddr
(
struct
dst_entry
*
dst
,
sockaddr_storage_t
*
saddr
)
/* Initialize a sctp_addr from in incoming skb. */
static
void
sctp_v4_from_skb
(
union
sctp_addr
*
addr
,
struct
sk_buff
*
skb
,
int
is_saddr
)
{
void
*
from
;
__u16
*
port
;
struct
sctphdr
*
sh
;
port
=
&
addr
->
v4
.
sin_port
;
addr
->
v4
.
sin_family
=
AF_INET
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
if
(
is_saddr
)
{
*
port
=
ntohs
(
sh
->
source
);
from
=
&
skb
->
nh
.
iph
->
saddr
;
}
else
{
*
port
=
ntohs
(
sh
->
dest
);
from
=
&
skb
->
nh
.
iph
->
daddr
;
}
memcpy
(
&
addr
->
v4
.
sin_addr
.
s_addr
,
from
,
sizeof
(
struct
in_addr
));
}
/* Initialize a sctp_addr from a dst_entry. */
static
void
sctp_v4_dst_saddr
(
union
sctp_addr
*
saddr
,
struct
dst_entry
*
dst
)
{
{
struct
rtable
*
rt
=
(
struct
rtable
*
)
dst
;
struct
rtable
*
rt
=
(
struct
rtable
*
)
dst
;
saddr
->
v4
.
sin_family
=
AF_INET
;
saddr
->
v4
.
sin_addr
.
s_addr
=
rt
->
rt_src
;
}
/* Compare two addresses exactly. */
static
int
sctp_v4_cmp_addr
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
)
{
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
if
(
addr1
->
v4
.
sin_port
!=
addr2
->
v4
.
sin_port
)
return
0
;
if
(
addr1
->
v4
.
sin_addr
.
s_addr
!=
addr2
->
v4
.
sin_addr
.
s_addr
)
return
0
;
return
1
;
}
/* Initialize addr struct to INADDR_ANY. */
static
void
sctp_v4_inaddr_any
(
union
sctp_addr
*
addr
,
unsigned
short
port
)
{
addr
->
v4
.
sin_family
=
AF_INET
;
addr
->
v4
.
sin_addr
.
s_addr
=
INADDR_ANY
;
addr
->
v4
.
sin_port
=
port
;
}
return
(
rt
->
rt_src
==
saddr
->
v4
.
sin_addr
.
s_addr
);
/* Is this a wildcard address? */
static
int
sctp_v4_is_any
(
const
union
sctp_addr
*
addr
)
{
return
INADDR_ANY
==
addr
->
v4
.
sin_addr
.
s_addr
;
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
static
int
sctp_v4_addr_valid
(
union
sctp_addr
*
addr
)
{
/* Is this a non-unicast address or a unusable SCTP address? */
if
(
IS_IPV4_UNUSABLE_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
return
0
;
return
1
;
}
/* Checking the loopback, private and other address scopes as defined in
* RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
*
* Level 0 - unusable SCTP addresses
* Level 1 - loopback address
* Level 2 - link-local addresses
* Level 3 - private addresses.
* Level 4 - global addresses
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
static
sctp_scope_t
sctp_v4_scope
(
union
sctp_addr
*
addr
)
{
sctp_scope_t
retval
;
/* Should IPv4 scoping be a sysctl configurable option
* so users can turn it off (default on) for certain
* unconventional networking environments?
*/
/* Check for unusable SCTP addresses. */
if
(
IS_IPV4_UNUSABLE_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_UNUSABLE
;
}
else
if
(
LOOPBACK
(
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_LOOPBACK
;
}
else
if
(
IS_IPV4_LINK_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_LINK
;
}
else
if
(
IS_IPV4_PRIVATE_ADDRESS
(
&
addr
->
v4
.
sin_addr
.
s_addr
))
{
retval
=
SCTP_SCOPE_PRIVATE
;
}
else
{
retval
=
SCTP_SCOPE_GLOBAL
;
}
return
retval
;
}
}
/* Event handler for inet device events.
/* Event handler for inet device events.
...
@@ -336,11 +408,11 @@ int sctp_ctl_sock_init(void)
...
@@ -336,11 +408,11 @@ int sctp_ctl_sock_init(void)
/* Get the table of functions for manipulating a particular address
/* Get the table of functions for manipulating a particular address
* family.
* family.
*/
*/
sctp_func_t
*
sctp_get_af_specific
(
const
sockaddr_storage_t
*
address
)
sctp_func_t
*
sctp_get_af_specific
(
sa_family_t
family
)
{
{
struct
list_head
*
pos
;
struct
list_head
*
pos
;
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
s
ctp_func_t
*
retval
,
*
af
;
s
truct
sctp_func
*
retval
,
*
af
;
retval
=
NULL
;
retval
=
NULL
;
...
@@ -349,7 +421,7 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address)
...
@@ -349,7 +421,7 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address)
*/
*/
list_for_each
(
pos
,
&
proto
->
address_families
)
{
list_for_each
(
pos
,
&
proto
->
address_families
)
{
af
=
list_entry
(
pos
,
sctp_func_t
,
list
);
af
=
list_entry
(
pos
,
sctp_func_t
,
list
);
if
(
address
->
sa
.
sa_
family
==
af
->
sa_family
)
{
if
(
family
==
af
->
sa_family
)
{
retval
=
af
;
retval
=
af
;
break
;
break
;
}
}
...
@@ -370,7 +442,8 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
...
@@ -370,7 +442,8 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
}
}
/* Copy the primary address of the peer primary address as the msg_name. */
/* Copy the primary address of the peer primary address as the msg_name. */
static
void
sctp_inet_event_msgname
(
sctp_ulpevent_t
*
event
,
char
*
msgname
,
int
*
addr_len
)
static
void
sctp_inet_event_msgname
(
sctp_ulpevent_t
*
event
,
char
*
msgname
,
int
*
addr_len
)
{
{
struct
sockaddr_in
*
sin
,
*
sinfrom
;
struct
sockaddr_in
*
sin
,
*
sinfrom
;
...
@@ -384,13 +457,13 @@ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *
...
@@ -384,13 +457,13 @@ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *
}
}
/* Initialize and copy out a msgname from an inbound skb. */
/* Initialize and copy out a msgname from an inbound skb. */
static
void
sctp_inet_skb_msgname
(
struct
sk_buff
*
skb
,
char
*
msgname
,
int
*
addr_
len
)
static
void
sctp_inet_skb_msgname
(
struct
sk_buff
*
skb
,
char
*
msgname
,
int
*
len
)
{
{
struct
sctphdr
*
sh
;
struct
sctphdr
*
sh
;
struct
sockaddr_in
*
sin
;
struct
sockaddr_in
*
sin
;
if
(
msgname
)
{
if
(
msgname
)
{
sctp_inet_msgname
(
msgname
,
addr_
len
);
sctp_inet_msgname
(
msgname
,
len
);
sin
=
(
struct
sockaddr_in
*
)
msgname
;
sin
=
(
struct
sockaddr_in
*
)
msgname
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
sh
=
(
struct
sctphdr
*
)
skb
->
h
.
raw
;
sin
->
sin_port
=
sh
->
source
;
sin
->
sin_port
=
sh
->
source
;
...
@@ -398,9 +471,39 @@ static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_
...
@@ -398,9 +471,39 @@ static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_
}
}
}
}
/* Do we support this AF? */
static
int
sctp_inet_af_supported
(
sa_family_t
family
)
{
/* PF_INET only supports AF_INET addresses. */
return
(
AF_INET
==
family
);
}
/* Address matching with wildcards allowed. */
static
int
sctp_inet_cmp_addr
(
const
union
sctp_addr
*
addr1
,
const
union
sctp_addr
*
addr2
,
struct
sctp_opt
*
opt
)
{
/* PF_INET only supports AF_INET addresses. */
if
(
addr1
->
sa
.
sa_family
!=
addr2
->
sa
.
sa_family
)
return
0
;
if
(
INADDR_ANY
==
addr1
->
v4
.
sin_addr
.
s_addr
||
INADDR_ANY
==
addr2
->
v4
.
sin_addr
.
s_addr
)
return
1
;
if
(
addr1
->
v4
.
sin_addr
.
s_addr
==
addr2
->
v4
.
sin_addr
.
s_addr
)
return
1
;
return
0
;
}
struct
sctp_func
sctp_ipv4_specific
;
static
sctp_pf_t
sctp_pf_inet
=
{
static
sctp_pf_t
sctp_pf_inet
=
{
.
event_msgname
=
sctp_inet_event_msgname
,
.
event_msgname
=
sctp_inet_event_msgname
,
.
skb_msgname
=
sctp_inet_skb_msgname
,
.
skb_msgname
=
sctp_inet_skb_msgname
,
.
af_supported
=
sctp_inet_af_supported
,
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
af
=
&
sctp_ipv4_specific
,
};
};
...
@@ -448,12 +551,19 @@ static struct inet_protocol sctp_protocol = {
...
@@ -448,12 +551,19 @@ static struct inet_protocol sctp_protocol = {
};
};
/* IPv4 address related functions. */
/* IPv4 address related functions. */
s
ctp_func_t
sctp_ipv4_specific
=
{
s
truct
sctp_func
sctp_ipv4_specific
=
{
.
queue_xmit
=
ip_queue_xmit
,
.
queue_xmit
=
ip_queue_xmit
,
.
setsockopt
=
ip_setsockopt
,
.
setsockopt
=
ip_setsockopt
,
.
getsockopt
=
ip_getsockopt
,
.
getsockopt
=
ip_getsockopt
,
.
get_dst
=
sctp_v4_get_dst
,
.
get_dst
=
sctp_v4_get_dst
,
.
cmp_saddr
=
sctp_v4_cmp_saddr
,
.
copy_addrlist
=
sctp_v4_copy_addrlist
,
.
from_skb
=
sctp_v4_from_skb
,
.
dst_saddr
=
sctp_v4_dst_saddr
,
.
cmp_addr
=
sctp_v4_cmp_addr
,
.
addr_valid
=
sctp_v4_addr_valid
,
.
inaddr_any
=
sctp_v4_inaddr_any
,
.
is_any
=
sctp_v4_is_any
,
.
scope
=
sctp_v4_scope
,
.
net_header_len
=
sizeof
(
struct
iphdr
),
.
net_header_len
=
sizeof
(
struct
iphdr
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in
),
.
sockaddr_len
=
sizeof
(
struct
sockaddr_in
),
.
sa_family
=
AF_INET
,
.
sa_family
=
AF_INET
,
...
...
net/sctp/sm_make_chunk.c
View file @
28b9daad
/* SCTP kernel reference Implementation
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001
-2002
Intel Corp.
* Copyright (c) 2001 International Business Machines Corp.
* Copyright (c) 2001
-2002
International Business Machines Corp.
*
*
* This file is part of the SCTP kernel reference Implementation
* This file is part of the SCTP kernel reference Implementation
*
*
...
@@ -166,7 +166,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
...
@@ -166,7 +166,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
int
priority
)
int
priority
)
{
{
sctp_inithdr_t
init
;
sctp_inithdr_t
init
;
sctpParam_t
addrs
;
union
sctp_params
addrs
;
size_t
chunksize
;
size_t
chunksize
;
sctp_chunk_t
*
retval
=
NULL
;
sctp_chunk_t
*
retval
=
NULL
;
int
addrs_len
=
0
;
int
addrs_len
=
0
;
...
@@ -228,7 +228,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
...
@@ -228,7 +228,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
{
{
sctp_inithdr_t
initack
;
sctp_inithdr_t
initack
;
sctp_chunk_t
*
retval
;
sctp_chunk_t
*
retval
;
sctpParam_t
addrs
;
union
sctp_params
addrs
;
int
addrs_len
;
int
addrs_len
;
sctp_cookie_param_t
*
cookie
;
sctp_cookie_param_t
*
cookie
;
int
cookie_len
;
int
cookie_len
;
...
@@ -1031,51 +1031,15 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
...
@@ -1031,51 +1031,15 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
}
}
/* Set chunk->source and dest based on the IP header in chunk->skb. */
/* Set chunk->source and dest based on the IP header in chunk->skb. */
void
sctp_init_addrs
(
sctp_chunk_t
*
chunk
)
void
sctp_init_addrs
(
sctp_chunk_t
*
chunk
,
union
sctp_addr
*
src
,
union
sctp_addr
*
dest
)
{
{
sockaddr_storage_t
*
source
,
*
dest
;
memcpy
(
&
chunk
->
source
,
src
,
sizeof
(
union
sctp_addr
));
struct
sk_buff
*
skb
;
memcpy
(
&
chunk
->
dest
,
dest
,
sizeof
(
union
sctp_addr
));
struct
sctphdr
*
sh
;
struct
iphdr
*
ih4
;
struct
ipv6hdr
*
ih6
;
source
=
&
chunk
->
source
;
dest
=
&
chunk
->
dest
;
skb
=
chunk
->
skb
;
ih4
=
skb
->
nh
.
iph
;
ih6
=
skb
->
nh
.
ipv6h
;
sh
=
chunk
->
sctp_hdr
;
switch
(
ih4
->
version
)
{
case
4
:
source
->
v4
.
sin_family
=
AF_INET
;
source
->
v4
.
sin_port
=
ntohs
(
sh
->
source
);
source
->
v4
.
sin_addr
.
s_addr
=
ih4
->
saddr
;
dest
->
v4
.
sin_family
=
AF_INET
;
dest
->
v4
.
sin_port
=
ntohs
(
sh
->
dest
);
dest
->
v4
.
sin_addr
.
s_addr
=
ih4
->
daddr
;
break
;
case
6
:
SCTP_V6
(
source
->
v6
.
sin6_family
=
AF_INET6
;
source
->
v6
.
sin6_port
=
ntohs
(
sh
->
source
);
source
->
v6
.
sin6_addr
=
ih6
->
saddr
;
dest
->
v6
.
sin6_family
=
AF_INET6
;
dest
->
v6
.
sin6_port
=
ntohs
(
sh
->
dest
);
dest
->
v6
.
sin6_addr
=
ih6
->
daddr
;
/* FIXME: What do we do with scope, etc. ? */
break
;
)
default:
/* This is a bogus address type, just bail. */
break
;
};
}
}
/* Extract the source address from a chunk. */
/* Extract the source address from a chunk. */
const
sockaddr_storage_t
*
sctp_source
(
const
sctp_chunk_t
*
chunk
)
const
union
sctp_addr
*
sctp_source
(
const
sctp_chunk_t
*
chunk
)
{
{
/* If we have a known transport, use that. */
/* If we have a known transport, use that. */
if
(
chunk
->
transport
)
{
if
(
chunk
->
transport
)
{
...
@@ -1482,78 +1446,28 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
...
@@ -1482,78 +1446,28 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions
* 3rd Level Abstractions
********************************************************************/
********************************************************************/
/* Verify the INIT packet before we process it. */
/* Do not attempt to handle the HOST_NAME parm. However, do
int
sctp_verify_init
(
const
sctp_association_t
*
asoc
,
* send back an indicator to the peer.
sctp_cid_t
cid
,
sctp_init_chunk_t
*
peer_init
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
{
sctpParam_t
param
;
uint8_t
*
end
;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify
* the mandatory parameters somewhere here and generate either the
* "Missing mandatory parameter" error or the "Invalid mandatory
* parameter" error. */
/* Find unrecognized parameters. */
end
=
((
uint8_t
*
)
peer_init
+
ntohs
(
peer_init
->
chunk_hdr
.
length
));
for
(
param
.
v
=
peer_init
->
init_hdr
.
params
;
param
.
v
<
end
;
param
.
v
+=
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)))
{
if
(
!
sctp_verify_param
(
asoc
,
param
,
cid
,
chunk
,
err_chk_p
))
return
0
;
}
/* for (loop through all parameters) */
return
1
;
}
/* Find unrecognized parameters in the chunk.
* Return values:
* 0 - discard the chunk
* 1 - continue with the chunk
*/
*/
int
sctp_verify_param
(
const
sctp_association_t
*
asoc
,
static
int
sctp_process_hn_param
(
const
sctp_association_t
*
asoc
,
sctpParam_t
param
,
union
sctp_params
param
,
sctp_cid_t
cid
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
sctp_chunk_t
**
err_chk_p
)
{
{
int
retval
=
1
;
__u16
len
=
ntohs
(
param
.
p
->
length
)
;
/* FIXME - This routine is not looking at each parameter per the
/* Make an ERROR chunk, preparing enough room for
* chunk type, i.e., unrecognized parameters should be further
* returning multiple unknown parameters.
* identified based on the chunk id.
*/
*/
if
(
!*
err_chk_p
)
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
len
);
switch
(
param
.
p
->
type
)
{
if
(
*
err_chk_p
)
case
SCTP_PARAM_IPV4_ADDRESS
:
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_DNS_FAILED
,
case
SCTP_PARAM_IPV6_ADDRESS
:
param
.
v
,
len
);
case
SCTP_PARAM_COOKIE_PRESERVATIVE
:
/* FIXME - If we don't support the host name parameter, we should
* generate an error for this - Unresolvable address.
*/
case
SCTP_PARAM_HOST_NAME_ADDRESS
:
case
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES
:
case
SCTP_PARAM_STATE_COOKIE
:
case
SCTP_PARAM_HEARTBEAT_INFO
:
case
SCTP_PARAM_UNRECOGNIZED_PARAMETERS
:
case
SCTP_PARAM_ECN_CAPABLE
:
break
;
default:
SCTP_DEBUG_PRINTK
(
"Unrecognized param: %d for chunk %d.
\n
"
,
ntohs
(
param
.
p
->
type
),
cid
);
return
sctp_process_unk_param
(
asoc
,
param
,
chunk
,
err_chk_p
);
break
;
/* Stop processing this chunk. */
}
return
0
;
return
retval
;
}
}
/* RFC 3.2.1 & the Implementers Guide 2.2.
/* RFC 3.2.1 & the Implementers Guide 2.2.
...
@@ -1582,8 +1496,8 @@ int sctp_verify_param(const sctp_association_t *asoc,
...
@@ -1582,8 +1496,8 @@ int sctp_verify_param(const sctp_association_t *asoc,
* 0 - discard the chunk
* 0 - discard the chunk
* 1 - continue with the chunk
* 1 - continue with the chunk
*/
*/
int
sctp_process_unk_param
(
const
sctp_association_t
*
asoc
,
static
int
sctp_process_unk_param
(
const
sctp_association_t
*
asoc
,
sctpParam_t
param
,
union
sctp_params
param
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
sctp_chunk_t
**
err_chk_p
)
{
{
...
@@ -1604,7 +1518,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
...
@@ -1604,7 +1518,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
if
(
*
err_chk_p
)
if
(
*
err_chk_p
)
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_UNKNOWN_PARAM
,
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_UNKNOWN_PARAM
,
(
const
void
*
)
param
.
p
,
param
.
v
,
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)));
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)));
break
;
break
;
...
@@ -1620,7 +1534,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
...
@@ -1620,7 +1534,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
if
(
*
err_chk_p
)
{
if
(
*
err_chk_p
)
{
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_UNKNOWN_PARAM
,
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_UNKNOWN_PARAM
,
(
const
void
*
)
param
.
p
,
param
.
v
,
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)));
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)));
}
else
{
}
else
{
/* If there is no memory for generating the ERROR
/* If there is no memory for generating the ERROR
...
@@ -1638,17 +1552,84 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
...
@@ -1638,17 +1552,84 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
return
retval
;
return
retval
;
}
}
/* Unpack the parameters in an INIT packet.
/* Find unrecognized parameters in the chunk.
* FIXME: There is no return status to allow callers to do
* Return values:
* error handling.
* 0 - discard the chunk
* 1 - continue with the chunk
*/
static
int
sctp_verify_param
(
const
sctp_association_t
*
asoc
,
union
sctp_params
param
,
sctp_cid_t
cid
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chunk
)
{
int
retval
=
1
;
/* FIXME - This routine is not looking at each parameter per the
* chunk type, i.e., unrecognized parameters should be further
* identified based on the chunk id.
*/
switch
(
param
.
p
->
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV6_ADDRESS
:
case
SCTP_PARAM_COOKIE_PRESERVATIVE
:
case
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES
:
case
SCTP_PARAM_STATE_COOKIE
:
case
SCTP_PARAM_HEARTBEAT_INFO
:
case
SCTP_PARAM_UNRECOGNIZED_PARAMETERS
:
case
SCTP_PARAM_ECN_CAPABLE
:
break
;
case
SCTP_PARAM_HOST_NAME_ADDRESS
:
/* Tell the peer, we won't support this param. */
return
sctp_process_hn_param
(
asoc
,
param
,
chunk
,
err_chunk
);
default:
SCTP_DEBUG_PRINTK
(
"Unrecognized param: %d for chunk %d.
\n
"
,
ntohs
(
param
.
p
->
type
),
cid
);
return
sctp_process_unk_param
(
asoc
,
param
,
chunk
,
err_chunk
);
break
;
}
return
retval
;
}
/* Verify the INIT packet before we process it. */
int
sctp_verify_init
(
const
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
sctp_init_chunk_t
*
peer_init
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
{
union
sctp_params
param
;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify
* the mandatory parameters somewhere here and generate either the
* "Missing mandatory parameter" error or the "Invalid mandatory
* parameter" error.
*/
/* Find unrecognized parameters. */
sctp_walk_params
(
param
,
peer_init
,
init_hdr
.
params
)
{
if
(
!
sctp_verify_param
(
asoc
,
param
,
cid
,
chunk
,
err_chk_p
))
return
0
;
}
/* for (loop through all parameters) */
return
1
;
}
/* Unpack the parameters in an INIT packet into an association.
* Returns 0 on failure, else success.
*/
*/
void
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
int
sctp_process_init
(
sctp_association_t
*
asoc
,
sctp_cid_t
cid
,
const
sockaddr_storage_t
*
peer_addr
,
const
union
sctp_addr
*
peer_addr
,
sctp_init_chunk_t
*
peer_init
,
sctp_init_chunk_t
*
peer_init
,
int
priority
)
int
priority
)
{
{
sctpParam_t
param
;
union
sctp_params
param
;
__u8
*
end
;
sctp_transport_t
*
transport
;
sctp_transport_t
*
transport
;
struct
list_head
*
pos
,
*
temp
;
struct
list_head
*
pos
,
*
temp
;
char
*
cookie
;
char
*
cookie
;
...
@@ -1664,15 +1645,14 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1664,15 +1645,14 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* be a a better choice than any of the embedded addresses.
* be a a better choice than any of the embedded addresses.
*/
*/
if
(
peer_addr
)
if
(
peer_addr
)
sctp_assoc_add_peer
(
asoc
,
peer_addr
,
priority
);
if
(
!
sctp_assoc_add_peer
(
asoc
,
peer_addr
,
priority
))
goto
nomem
;
/* Process the initialization parameters. */
/* Process the initialization parameters. */
end
=
((
__u8
*
)
peer_init
+
ntohs
(
peer_init
->
chunk_hdr
.
length
));
for
(
param
.
v
=
peer_init
->
init_hdr
.
params
;
sctp_walk_params
(
param
,
peer_init
,
init_hdr
.
params
)
{
param
.
v
<
end
;
param
.
v
+=
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)))
{
if
(
!
sctp_process_param
(
asoc
,
param
,
peer_addr
,
priority
))
if
(
!
sctp_process_param
(
asoc
,
param
,
peer_addr
,
cid
,
priority
))
goto
clean_up
;
goto
clean_up
;
}
}
...
@@ -1738,7 +1718,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1738,7 +1718,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* association to the same value as the Initial TSN.
* association to the same value as the Initial TSN.
*/
*/
asoc
->
peer
.
addip_serial
=
asoc
->
peer
.
i
.
initial_tsn
-
1
;
asoc
->
peer
.
addip_serial
=
asoc
->
peer
.
i
.
initial_tsn
-
1
;
return
;
return
1
;
clean_up:
clean_up:
/* Release the transport structures. */
/* Release the transport structures. */
...
@@ -1747,8 +1727,11 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1747,8 +1727,11 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
list_del
(
pos
);
list_del
(
pos
);
sctp_transport_free
(
transport
);
sctp_transport_free
(
transport
);
}
}
nomem:
return
0
;
}
}
/* Update asoc with the option described in param.
/* Update asoc with the option described in param.
*
*
* RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT
* RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT
...
@@ -1760,14 +1743,12 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
...
@@ -1760,14 +1743,12 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* work we do. In particular, we should not build transport
* work we do. In particular, we should not build transport
* structures for the addresses.
* structures for the addresses.
*/
*/
int
sctp_process_param
(
sctp_association_t
*
asoc
,
sctpParam_t
param
,
int
sctp_process_param
(
sctp_association_t
*
asoc
,
union
sctp_params
param
,
const
sockaddr_storage_t
*
peer_addr
,
const
union
sctp_addr
*
peer_addr
,
int
priority
)
sctp_cid_t
cid
,
int
priority
)
{
{
sockaddr_storage_t
addr
;
union
sctp_addr
addr
;
sctp_addr_param_t
*
addrparm
;
int
j
;
int
i
;
int
i
;
__u16
sat
;
int
retval
=
1
;
int
retval
=
1
;
sctp_scope_t
scope
;
sctp_scope_t
scope
;
...
@@ -1776,30 +1757,21 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
...
@@ -1776,30 +1757,21 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
* came from a fresh INIT, and INIT ACK, or were stored in a cookie.
* came from a fresh INIT, and INIT ACK, or were stored in a cookie.
*/
*/
switch
(
param
.
p
->
type
)
{
switch
(
param
.
p
->
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
addrparm
=
(
sctp_addr_param_t
*
)
param
.
v
;
sctp_param2sockaddr
(
&
addr
,
addrparm
,
asoc
->
peer
.
port
);
scope
=
sctp_scope
(
peer_addr
);
if
(
sctp_in_scope
(
&
addr
,
scope
))
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
);
break
;
case
SCTP_PARAM_IPV6_ADDRESS
:
case
SCTP_PARAM_IPV6_ADDRESS
:
/* Rethink this as we may need to keep for
if
(
PF_INET6
!=
asoc
->
base
.
sk
->
family
)
* restart considerations.
break
;
*/
/* Fall through. */
if
(
PF_INET6
==
asoc
->
base
.
sk
->
family
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
addrparm
=
(
sctp_addr_param_t
*
)
param
.
v
;
sctp_param2sockaddr
(
&
addr
,
param
.
addr
,
asoc
->
peer
.
port
);
sctp_param2sockaddr
(
&
addr
,
addrparm
,
asoc
->
peer
.
port
);
scope
=
sctp_scope
(
peer_addr
);
scope
=
sctp_scope
(
peer_addr
);
if
(
sctp_in_scope
(
&
addr
,
scope
))
if
(
sctp_in_scope
(
&
addr
,
scope
))
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
);
if
(
!
sctp_assoc_add_peer
(
asoc
,
&
addr
,
priority
))
}
return
0
;
break
;
break
;
case
SCTP_PARAM_COOKIE_PRESERVATIVE
:
case
SCTP_PARAM_COOKIE_PRESERVATIVE
:
asoc
->
cookie_preserve
=
asoc
->
cookie_preserve
=
ntohl
(
param
.
bht
->
lifespan_increment
);
ntohl
(
param
.
life
->
lifespan_increment
);
break
;
break
;
case
SCTP_PARAM_HOST_NAME_ADDRESS
:
case
SCTP_PARAM_HOST_NAME_ADDRESS
:
...
@@ -1813,10 +1785,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
...
@@ -1813,10 +1785,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
asoc
->
peer
.
ipv4_address
=
0
;
asoc
->
peer
.
ipv4_address
=
0
;
asoc
->
peer
.
ipv6_address
=
0
;
asoc
->
peer
.
ipv6_address
=
0
;
j
=
(
ntohs
(
param
.
p
->
length
)
-
/* Cycle through address types; avoid divide by 0. */
sizeof
(
sctp_paramhdr_t
))
/
sat
=
ntohs
(
param
.
p
->
length
)
-
sizeof
(
sctp_paramhdr_t
);
sizeof
(
__u16
);
if
(
sat
)
for
(
i
=
0
;
i
<
j
;
++
i
)
{
sat
/=
sizeof
(
__u16
);
for
(
i
=
0
;
i
<
sat
;
++
i
)
{
switch
(
param
.
sat
->
types
[
i
])
{
switch
(
param
.
sat
->
types
[
i
])
{
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV4_ADDRESS
:
asoc
->
peer
.
ipv4_address
=
1
;
asoc
->
peer
.
ipv4_address
=
1
;
...
@@ -1843,13 +1817,11 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
...
@@ -1843,13 +1817,11 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
break
;
break
;
case
SCTP_PARAM_HEARTBEAT_INFO
:
case
SCTP_PARAM_HEARTBEAT_INFO
:
SCTP_DEBUG_PRINTK
(
"unimplemented "
/* Would be odd to receive, but it causes no problems. */
"SCTP_PARAM_HEARTBEAT_INFO
\n
"
);
break
;
break
;
case
SCTP_PARAM_UNRECOGNIZED_PARAMETERS
:
case
SCTP_PARAM_UNRECOGNIZED_PARAMETERS
:
SCTP_DEBUG_PRINTK
(
"unimplemented "
/* Rejected during verify stage. */
"SCTP_PARAM_UNRECOGNIZED_PARAMETERS
\n
"
);
break
;
break
;
case
SCTP_PARAM_ECN_CAPABLE
:
case
SCTP_PARAM_ECN_CAPABLE
:
...
@@ -1898,8 +1870,8 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
...
@@ -1898,8 +1870,8 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
* 4th Level Abstractions
* 4th Level Abstractions
********************************************************************/
********************************************************************/
/* Convert from an SCTP IP parameter to a
sockaddr_storage_t
. */
/* Convert from an SCTP IP parameter to a
union sctp_addr
. */
void
sctp_param2sockaddr
(
sockaddr_storage_t
*
addr
,
sctp_addr_param_t
*
param
,
void
sctp_param2sockaddr
(
union
sctp_addr
*
addr
,
sctp_addr_param_t
*
param
,
__u16
port
)
__u16
port
)
{
{
switch
(
param
->
v4
.
param_hdr
.
type
)
{
switch
(
param
->
v4
.
param_hdr
.
type
)
{
...
@@ -1926,11 +1898,8 @@ void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param,
...
@@ -1926,11 +1898,8 @@ void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param,
/* Convert an IP address in an SCTP param into a sockaddr_in. */
/* Convert an IP address in an SCTP param into a sockaddr_in. */
/* Returns true if a valid conversion was possible. */
/* Returns true if a valid conversion was possible. */
int
sctp_addr2sockaddr
(
sctpParam_t
p
,
sockaddr_storage_t
*
sa
)
int
sctp_addr2sockaddr
(
union
sctp_params
p
,
union
sctp_addr
*
sa
)
{
{
if
(
!
p
.
v
)
return
0
;
switch
(
p
.
p
->
type
)
{
switch
(
p
.
p
->
type
)
{
case
SCTP_PARAM_IPV4_ADDRESS
:
case
SCTP_PARAM_IPV4_ADDRESS
:
sa
->
v4
.
sin_addr
=
*
((
struct
in_addr
*
)
&
p
.
v4
->
addr
);
sa
->
v4
.
sin_addr
=
*
((
struct
in_addr
*
)
&
p
.
v4
->
addr
);
...
@@ -1950,30 +1919,10 @@ int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa)
...
@@ -1950,30 +1919,10 @@ int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa)
return
1
;
return
1
;
}
}
/* Convert from an IP version number to an Address Family symbol. */
int
ipver2af
(
__u8
ipver
)
{
int
family
;
switch
(
ipver
)
{
case
4
:
family
=
AF_INET
;
break
;
case
6
:
family
=
AF_INET6
;
break
;
default:
family
=
0
;
break
;
};
return
family
;
}
/* Convert a sockaddr_in to an IP address in an SCTP param.
/* Convert a sockaddr_in to an IP address in an SCTP param.
* Returns len if a valid conversion was possible.
* Returns len if a valid conversion was possible.
*/
*/
int
sockaddr2sctp_addr
(
const
sockaddr_storage_t
*
sa
,
sctp_addr_param_t
*
p
)
int
sockaddr2sctp_addr
(
const
union
sctp_addr
*
sa
,
sctp_addr_param_t
*
p
)
{
{
int
len
=
0
;
int
len
=
0
;
...
...
net/sctp/sm_sideeffect.c
View file @
28b9daad
...
@@ -41,6 +41,7 @@
...
@@ -41,6 +41,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
...
@@ -68,11 +69,13 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
...
@@ -68,11 +69,13 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
);
static
void
sctp_cmd_init_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
);
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
static
void
sctp_cmd_assoc_failed
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
sctp_event_t
event_type
,
sctp_chunk_t
*
chunk
);
sctp_event_t
event_type
,
sctp_chunk_t
*
chunk
);
static
void
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
sctp_init_chunk_t
*
peer_init
,
int
priority
);
int
priority
);
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_hb_timers_start
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
);
static
void
sctp_cmd_hb_timers_update
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_transport_t
*
);
static
void
sctp_cmd_set_bind_addrs
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
static
void
sctp_cmd_set_bind_addrs
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_bind_addr_t
*
);
sctp_bind_addr_t
*
);
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
static
void
sctp_cmd_transport_reset
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
...
@@ -83,6 +86,8 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *,
...
@@ -83,6 +86,8 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *,
sctp_sackhdr_t
*
);
sctp_sackhdr_t
*
);
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
static
void
sctp_cmd_setup_t2
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_chunk_t
*
);
sctp_chunk_t
*
);
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
,
sctp_association_t
*
,
sctp_state_t
);
/* These three macros allow us to pull the debugging code out of the
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* main flow of sctp_do_sm() to keep attention focused on the real
...
@@ -193,6 +198,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -193,6 +198,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
/* BUG--we should now recover some memory, probably by
/* BUG--we should now recover some memory, probably by
* reneging...
* reneging...
*/
*/
error
=
-
ENOMEM
;
break
;
break
;
case
SCTP_DISPOSITION_DELETE_TCB
:
case
SCTP_DISPOSITION_DELETE_TCB
:
...
@@ -301,8 +307,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -301,8 +307,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case
SCTP_CMD_NEW_STATE
:
case
SCTP_CMD_NEW_STATE
:
/* Enter a new state. */
/* Enter a new state. */
asoc
->
state
=
command
->
obj
.
state
;
sctp_cmd_new_state
(
commands
,
asoc
,
command
->
obj
.
state
);
asoc
->
state_timestamp
=
jiffies
;
break
;
break
;
case
SCTP_CMD_REPORT_TSN
:
case
SCTP_CMD_REPORT_TSN
:
...
@@ -339,9 +344,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -339,9 +344,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break
;
break
;
case
SCTP_CMD_PEER_INIT
:
case
SCTP_CMD_PEER_INIT
:
/* Process a unified INIT from the peer. */
/* Process a unified INIT from the peer.
sctp_cmd_process_init
(
commands
,
asoc
,
chunk
,
* Note: Only used during INIT-ACK processing. If
command
->
obj
.
ptr
,
priority
);
* there is an error just return to the outter
* layer which will bail.
*/
error
=
sctp_cmd_process_init
(
commands
,
asoc
,
chunk
,
command
->
obj
.
ptr
,
priority
);
break
;
break
;
case
SCTP_CMD_GEN_COOKIE_ECHO
:
case
SCTP_CMD_GEN_COOKIE_ECHO
:
...
@@ -561,6 +571,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -561,6 +571,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_cmd_hb_timers_start
(
commands
,
asoc
);
sctp_cmd_hb_timers_start
(
commands
,
asoc
);
break
;
break
;
case
SCTP_CMD_HB_TIMERS_UPDATE
:
t
=
command
->
obj
.
transport
;
sctp_cmd_hb_timers_update
(
commands
,
asoc
,
t
);
break
;
case
SCTP_CMD_REPORT_ERROR
:
case
SCTP_CMD_REPORT_ERROR
:
error
=
command
->
obj
.
error
;
error
=
command
->
obj
.
error
;
break
;
break
;
...
@@ -581,11 +596,18 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
...
@@ -581,11 +596,18 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
chunk
->
pdiscard
=
1
;
chunk
->
pdiscard
=
1
;
break
;
break
;
case
SCTP_CMD_RTO_PENDING
:
t
=
command
->
obj
.
transport
;
t
->
rto_pending
=
1
;
break
;
default:
default:
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
printk
(
KERN_WARNING
"Impossible command: %u, %p
\n
"
,
command
->
verb
,
command
->
obj
.
ptr
);
command
->
verb
,
command
->
obj
.
ptr
);
break
;
break
;
};
};
if
(
error
)
return
error
;
}
}
return
error
;
return
error
;
...
@@ -978,7 +1000,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
...
@@ -978,7 +1000,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
*/
*/
asoc
->
overall_error_count
++
;
asoc
->
overall_error_count
++
;
if
(
transport
->
state
.
active
&&
if
(
transport
->
active
&&
(
transport
->
error_count
++
>=
transport
->
error_threshold
))
{
(
transport
->
error_count
++
>=
transport
->
error_threshold
))
{
SCTP_DEBUG_PRINTK
(
"transport_strike: transport "
SCTP_DEBUG_PRINTK
(
"transport_strike: transport "
"IP:%d.%d.%d.%d failed.
\n
"
,
"IP:%d.%d.%d.%d failed.
\n
"
,
...
@@ -1058,22 +1080,32 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
...
@@ -1058,22 +1080,32 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
}
}
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
* inside the cookie.
* inside the cookie. In reality, this is only used for INIT-ACK processing
* since all other cases use "temporary" associations and can do all
* their work in statefuns directly.
*/
*/
static
void
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
commands
,
static
int
sctp_cmd_process_init
(
sctp_cmd_seq_t
*
commands
,
sctp_association_t
*
asoc
,
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
*
chunk
,
sctp_init_chunk_t
*
peer_init
,
sctp_init_chunk_t
*
peer_init
,
int
priority
)
int
priority
)
{
{
/* The command sequence holds commands assuming that the
int
error
;
* processing will happen successfully. If this is not the
* case, rewind the sequence and add appropriate error handling
/* We only process the init as a sideeffect in a single
* to the sequence.
* case. This is when we process the INIT-ACK. If we
* fail during INIT processing (due to malloc problems),
* just return the error and stop processing the stack.
*/
*/
sctp_process_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
if
(
!
sctp_process_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
sctp_source
(
chunk
),
peer_init
,
priority
);
priority
))
error
=
-
ENOMEM
;
else
error
=
0
;
return
error
;
}
}
/* Helper function to break out starting up of heartbeat timers. */
/* Helper function to break out starting up of heartbeat timers. */
...
@@ -1096,6 +1128,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
...
@@ -1096,6 +1128,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
}
}
}
}
/* Helper function to update the heartbeat timer. */
static
void
sctp_cmd_hb_timers_update
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_transport_t
*
t
)
{
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
t
->
hb_interval
+
t
->
rto
+
jiffies
))
sctp_transport_hold
(
t
);
}
/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */
/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */
void
sctp_cmd_set_bind_addrs
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
void
sctp_cmd_set_bind_addrs
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_bind_addr_t
*
bp
)
sctp_bind_addr_t
*
bp
)
...
@@ -1131,7 +1173,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
...
@@ -1131,7 +1173,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
/* Mark the destination transport address as active if it is not so
/* Mark the destination transport address as active if it is not so
* marked.
* marked.
*/
*/
if
(
!
t
->
state
.
active
)
if
(
!
t
->
active
)
sctp_assoc_control_transport
(
asoc
,
t
,
SCTP_TRANSPORT_UP
,
sctp_assoc_control_transport
(
asoc
,
t
,
SCTP_TRANSPORT_UP
,
SCTP_HEARTBEAT_SUCCESS
);
SCTP_HEARTBEAT_SUCCESS
);
...
@@ -1154,10 +1196,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
...
@@ -1154,10 +1196,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
/* Mark one strike against a transport. */
/* Mark one strike against a transport. */
sctp_do_8_2_transport_strike
(
asoc
,
t
);
sctp_do_8_2_transport_strike
(
asoc
,
t
);
/* Update the heartbeat timer. */
if
(
!
mod_timer
(
&
t
->
hb_timer
,
t
->
hb_interval
+
t
->
rto
+
jiffies
))
sctp_transport_hold
(
t
);
}
}
/* Helper function to process the process SACK command. */
/* Helper function to process the process SACK command. */
...
@@ -1196,3 +1234,18 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
...
@@ -1196,3 +1234,18 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
asoc
->
timeouts
[
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
]
=
t
->
rto
;
asoc
->
timeouts
[
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN
]
=
t
->
rto
;
chunk
->
transport
=
t
;
chunk
->
transport
=
t
;
}
}
/* Helper function to change the state of an association. */
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_state_t
state
)
{
asoc
->
state
=
state
;
asoc
->
state_timestamp
=
jiffies
;
/* Wake up any process waiting for the association to
* get established.
*/
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
&&
(
waitqueue_active
(
&
asoc
->
wait
)))
wake_up_interruptible
(
&
asoc
->
wait
);
}
net/sctp/sm_statefuns.c
View file @
28b9daad
...
@@ -236,20 +236,18 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -236,20 +236,18 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
chunk
->
subh
.
init_hdr
=
(
sctp_inithdr_t
*
)
chunk
->
skb
->
data
;
chunk
->
subh
.
init_hdr
=
(
sctp_inithdr_t
*
)
chunk
->
skb
->
data
;
/* Tag the variable length parameters. */
/* Tag the variable length parameters. */
chunk
->
param_hdr
.
v
=
chunk
->
param_hdr
.
v
=
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_inithdr_t
));
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_inithdr_t
));
new_asoc
=
sctp_make_temp_asoc
(
ep
,
chunk
,
GFP_ATOMIC
);
new_asoc
=
sctp_make_temp_asoc
(
ep
,
chunk
,
GFP_ATOMIC
);
if
(
!
new_asoc
)
if
(
!
new_asoc
)
goto
nomem
;
goto
nomem
;
/* FIXME: sctp_process_init can fail, but there is no
/* The call, sctp_process_init(), can fail on memory allocation. */
* status nor handling.
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
*/
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
sctp_source
(
chunk
),
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
GFP_ATOMIC
);
GFP_ATOMIC
))
goto
nomem_init
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
...
@@ -302,10 +300,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
...
@@ -302,10 +300,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_DELETE_TCB
;
return
SCTP_DISPOSITION_DELETE_TCB
;
nomem_ack:
nomem_ack:
sctp_association_free
(
new_asoc
);
if
(
err_chunk
)
if
(
err_chunk
)
sctp_free_chunk
(
err_chunk
);
sctp_free_chunk
(
err_chunk
);
nomem_init:
sctp_association_free
(
new_asoc
);
nomem:
nomem:
return
SCTP_DISPOSITION_NOMEM
;
return
SCTP_DISPOSITION_NOMEM
;
}
}
...
@@ -563,9 +561,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
...
@@ -563,9 +561,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
* effects--it is safe to run them here.
* effects--it is safe to run them here.
*/
*/
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_addr
,
peer_init
,
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
GFP_ATOMIC
);
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_addr
,
peer_init
,
GFP_ATOMIC
))
goto
nomem_init
;
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
repl
=
sctp_make_cookie_ack
(
new_asoc
,
chunk
);
if
(
!
repl
)
if
(
!
repl
)
...
@@ -592,10 +592,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
...
@@ -592,10 +592,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
nomem_ev:
nomem_ev:
sctp_free_chunk
(
repl
);
sctp_free_chunk
(
repl
);
nomem_repl:
nomem_repl:
nomem_init:
sctp_association_free
(
new_asoc
);
sctp_association_free
(
new_asoc
);
nomem:
nomem:
return
SCTP_DISPOSITION_NOMEM
;
return
SCTP_DISPOSITION_NOMEM
;
}
}
...
@@ -664,8 +663,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
...
@@ -664,8 +663,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_NOMEM
;
return
SCTP_DISPOSITION_NOMEM
;
}
}
/* Generate a
HEARTBEAT packet on the given transpor
t. */
/* Generate a
nd sendout a heartbeat packe
t. */
sctp_disposition_t
sctp_sf_
sendbeat_8_3
(
const
sctp_endpoint_t
*
ep
,
sctp_disposition_t
sctp_sf_
heartbeat
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
const
sctp_subtype_t
type
,
void
*
arg
,
void
*
arg
,
...
@@ -676,6 +675,36 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
...
@@ -676,6 +675,36 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
sctp_sender_hb_info_t
hbinfo
;
sctp_sender_hb_info_t
hbinfo
;
size_t
paylen
=
0
;
size_t
paylen
=
0
;
hbinfo
.
param_hdr
.
type
=
SCTP_PARAM_HEARTBEAT_INFO
;
hbinfo
.
param_hdr
.
length
=
htons
(
sizeof
(
sctp_sender_hb_info_t
));
hbinfo
.
daddr
=
transport
->
ipaddr
;
hbinfo
.
sent_at
=
jiffies
;
/* Send a heartbeat to our peer. */
paylen
=
sizeof
(
sctp_sender_hb_info_t
);
reply
=
sctp_make_heartbeat
(
asoc
,
transport
,
&
hbinfo
,
paylen
);
if
(
!
reply
)
return
SCTP_DISPOSITION_NOMEM
;
/* Set rto_pending indicating that an RTT measurement
* is started with this heartbeat chunk.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_RTO_PENDING
,
SCTP_TRANSPORT
(
transport
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
return
SCTP_DISPOSITION_CONSUME
;
}
/* Generate a HEARTBEAT packet on the given transport. */
sctp_disposition_t
sctp_sf_sendbeat_8_3
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
sctp_transport_t
*
transport
=
(
sctp_transport_t
*
)
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. */
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_ASSOC_FAILED
,
SCTP_NULL
());
...
@@ -689,34 +718,21 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
...
@@ -689,34 +718,21 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
* HEARTBEAT is sent (see Section 8.3).
* HEARTBEAT is sent (see Section 8.3).
*/
*/
hbinfo
.
param_hdr
.
type
=
SCTP_PARAM_HEARTBEAT_INFO
;
if
(
transport
->
hb_allowed
)
{
hbinfo
.
param_hdr
.
length
=
htons
(
sizeof
(
sctp_sender_hb_info_t
));
if
(
SCTP_DISPOSITION_NOMEM
==
hbinfo
.
daddr
=
transport
->
ipaddr
;
sctp_sf_heartbeat
(
ep
,
asoc
,
type
,
arg
,
hbinfo
.
sent_at
=
jiffies
;
commands
))
return
SCTP_DISPOSITION_NOMEM
;
/* Set rto_pending indicating that an RTT measurement is started
* with this heartbeat chunk.
*/
transport
->
rto_pending
=
1
;
/* Send a heartbeat to our peer. */
paylen
=
sizeof
(
sctp_sender_hb_info_t
);
reply
=
sctp_make_heartbeat
(
asoc
,
transport
,
&
hbinfo
,
paylen
);
if
(
!
reply
)
goto
nomem
;
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
reply
));
/* Set transport error counter and association error counter
/* Set transport error counter and association error counter
* when sending heartbeat.
* when sending heartbeat.
*/
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSPORT_RESET
,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_TRANSPORT_RESET
,
SCTP_TRANSPORT
(
transport
));
SCTP_TRANSPORT
(
transport
));
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_HB_TIMERS_UPDATE
,
SCTP_TRANSPORT
(
transport
));
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
nomem:
return
SCTP_DISPOSITION_NOMEM
;
}
}
/*
/*
...
@@ -817,7 +833,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
...
@@ -817,7 +833,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
chunk
=
arg
;
sockaddr_storage_t
from_addr
;
union
sctp_addr
from_addr
;
sctp_transport_t
*
link
;
sctp_transport_t
*
link
;
sctp_sender_hb_info_t
*
hbinfo
;
sctp_sender_hb_info_t
*
hbinfo
;
unsigned
long
max_interval
;
unsigned
long
max_interval
;
...
@@ -866,7 +882,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
...
@@ -866,7 +882,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
/* Helper function to send out an abort for the restart
/* Helper function to send out an abort for the restart
* condition.
* condition.
*/
*/
static
int
sctp_sf_send_restart_abort
(
sockaddr_storage_t
*
ssa
,
static
int
sctp_sf_send_restart_abort
(
union
sctp_addr
*
ssa
,
sctp_chunk_t
*
init
,
sctp_chunk_t
*
init
,
sctp_cmd_seq_t
*
commands
)
sctp_cmd_seq_t
*
commands
)
{
{
...
@@ -1125,8 +1141,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
...
@@ -1125,8 +1141,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* Verification Tag and Peers Verification tag into a reserved
* Verification Tag and Peers Verification tag into a reserved
* place (local tie-tag and per tie-tag) within the state cookie.
* place (local tie-tag and per tie-tag) within the state cookie.
*/
*/
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
GFP_ATOMIC
);
sctp_source
(
chunk
),
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
GFP_ATOMIC
))
{
retval
=
SCTP_DISPOSITION_NOMEM
;
goto
nomem_init
;
}
/* Make sure no new addresses are being added during the
/* Make sure no new addresses are being added during the
* restart. Do not do this check for COOKIE-WAIT state,
* restart. Do not do this check for COOKIE-WAIT state,
...
@@ -1197,6 +1218,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
...
@@ -1197,6 +1218,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
nomem:
nomem:
retval
=
SCTP_DISPOSITION_NOMEM
;
retval
=
SCTP_DISPOSITION_NOMEM
;
goto
cleanup
;
goto
cleanup
;
nomem_init:
cleanup_asoc:
cleanup_asoc:
sctp_association_free
(
new_asoc
);
sctp_association_free
(
new_asoc
);
goto
cleanup
;
goto
cleanup
;
...
@@ -1326,15 +1348,16 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
...
@@ -1326,15 +1348,16 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
* side effects--it is safe to run them here.
* side effects--it is safe to run them here.
*/
*/
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
);
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
))
goto
nomem
;
/* Make sure no new addresses are being added during the
/* Make sure no new addresses are being added during the
* restart. Though this is a pretty complicated attack
* restart. Though this is a pretty complicated attack
* since you'd have to get inside the cookie.
* since you'd have to get inside the cookie.
*/
*/
if
(
!
sctp_sf_check_restart_addrs
(
new_asoc
,
asoc
,
chunk
,
commands
))
{
if
(
!
sctp_sf_check_restart_addrs
(
new_asoc
,
asoc
,
chunk
,
commands
))
{
printk
(
"cookie echo check
\n
"
);
return
SCTP_DISPOSITION_CONSUME
;
return
SCTP_DISPOSITION_CONSUME
;
}
}
...
@@ -1391,8 +1414,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
...
@@ -1391,8 +1414,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
* side effects--it is safe to run them here.
* side effects--it is safe to run them here.
*/
*/
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
peer_init
=
&
chunk
->
subh
.
cookie_hdr
->
c
.
peer_init
[
0
];
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
if
(
!
sctp_process_init
(
new_asoc
,
chunk
->
chunk_hdr
->
type
,
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
);
sctp_source
(
chunk
),
peer_init
,
GFP_ATOMIC
))
goto
nomem
;
/* Update the content of current association. */
/* Update the content of current association. */
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_UPDATE_ASSOC
,
SCTP_ASOC
(
new_asoc
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_UPDATE_ASSOC
,
SCTP_ASOC
(
new_asoc
));
...
@@ -3656,6 +3680,39 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
...
@@ -3656,6 +3680,39 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
return
sctp_sf_shutdown_sent_prm_abort
(
ep
,
asoc
,
type
,
arg
,
commands
);
return
sctp_sf_shutdown_sent_prm_abort
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
}
/*
* Process the REQUESTHEARTBEAT primitive
*
* 10.1 ULP-to-SCTP
* J) Request Heartbeat
*
* Format: REQUESTHEARTBEAT(association id, destination transport address)
*
* -> result
*
* Instructs the local endpoint to perform a HeartBeat on the specified
* destination transport address of the given association. The returned
* result should indicate whether the transmission of the HEARTBEAT
* chunk to the destination address is successful.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o destination transport address - the transport address of the
* asociation on which a heartbeat should be issued.
*/
sctp_disposition_t
sctp_sf_do_prm_requestheartbeat
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
return
sctp_sf_heartbeat
(
ep
,
asoc
,
type
,
(
sctp_transport_t
*
)
arg
,
commands
);
}
/*
/*
* Ignore the primitive event
* Ignore the primitive event
*
*
...
@@ -4257,7 +4314,8 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
...
@@ -4257,7 +4314,8 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
/* Cache a route for the transport with the chunk's destination as
/* Cache a route for the transport with the chunk's destination as
* the source address.
* the source address.
*/
*/
sctp_transport_route
(
transport
,
(
sockaddr_storage_t
*
)
&
chunk
->
dest
);
sctp_transport_route
(
transport
,
(
union
sctp_addr
*
)
&
chunk
->
dest
,
sctp_sk
(
sctp_get_ctl_sock
()));
packet
=
sctp_packet_init
(
packet
,
transport
,
sport
,
dport
);
packet
=
sctp_packet_init
(
packet
,
transport
,
sport
,
dport
);
packet
=
sctp_packet_config
(
packet
,
vtag
,
0
,
NULL
);
packet
=
sctp_packet_config
(
packet
,
vtag
,
0
,
NULL
);
...
...
net/sctp/sm_statetable.c
View file @
28b9daad
...
@@ -39,6 +39,7 @@
...
@@ -39,6 +39,7 @@
* Jon Grimm <jgrimm@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Hui Huang <hui.huang@nokia.com>
* Hui Huang <hui.huang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
* be incorporated into the next SCTP release.
...
@@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
...
@@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */
\
/* SCTP_STATE_EMPTY */
\
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */
\
/* SCTP_STATE_CLOSED */
\
{.fn = sctp_sf_
not_impl, .name = "sctp_sf_not_impl
"}, \
{.fn = sctp_sf_
bug, .name = "sctp_sf_bug
"}, \
/* SCTP_STATE_COOKIE_WAIT */
\
/* SCTP_STATE_COOKIE_WAIT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_COOKIE_ECHOED */
\
/* SCTP_STATE_COOKIE_ECHOED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_ESTABLISHED */
\
/* SCTP_STATE_ESTABLISHED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */
\
/* SCTP_STATE_SHUTDOWN_PENDING */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_SENT */
\
/* SCTP_STATE_SHUTDOWN_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
/* SCTP_STATE_SHUTDOWN_RECEIVED */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
\
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
}
/* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
}
/* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \
#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \
...
...
net/sctp/socket.c
View file @
28b9daad
...
@@ -86,15 +86,16 @@ static void sctp_wfree(struct sk_buff *skb);
...
@@ -86,15 +86,16 @@ static void sctp_wfree(struct sk_buff *skb);
static
int
sctp_wait_for_sndbuf
(
sctp_association_t
*
asoc
,
long
*
timeo_p
,
static
int
sctp_wait_for_sndbuf
(
sctp_association_t
*
asoc
,
long
*
timeo_p
,
int
msg_len
);
int
msg_len
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
sctp_association_t
*
asoc
,
long
*
timeo_p
);
static
inline
void
sctp_sk_addr_set
(
struct
sock
*
,
static
inline
void
sctp_sk_addr_set
(
struct
sock
*
,
const
sockaddr_storage_t
*
newaddr
,
const
union
sctp_addr
*
newaddr
,
sockaddr_storage_t
*
saveaddr
);
union
sctp_addr
*
saveaddr
);
static
inline
void
sctp_sk_addr_restore
(
struct
sock
*
,
static
inline
void
sctp_sk_addr_restore
(
struct
sock
*
,
const
sockaddr_storage_t
*
);
const
union
sctp_addr
*
);
static
inline
int
sctp_
sendmsg_verify_name
(
struct
sock
*
,
struct
msghdr
*
);
static
inline
int
sctp_
verify_addr
(
struct
sock
*
,
struct
sockaddr
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_do_bind
(
struct
sock
*
,
sockaddr_storage_t
*
,
int
);
static
int
sctp_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
...
@@ -122,7 +123,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
...
@@ -122,7 +123,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Disallow binding twice. */
/* Disallow binding twice. */
if
(
!
sctp_sk
(
sk
)
->
ep
->
base
.
bind_addr
.
port
)
if
(
!
sctp_sk
(
sk
)
->
ep
->
base
.
bind_addr
.
port
)
retval
=
sctp_do_bind
(
sk
,
(
sockaddr_storage_t
*
)
uaddr
,
retval
=
sctp_do_bind
(
sk
,
(
union
sctp_addr
*
)
uaddr
,
addr_len
);
addr_len
);
else
else
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
...
@@ -135,14 +136,14 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
...
@@ -135,14 +136,14 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
static
long
sctp_get_port_local
(
struct
sock
*
,
unsigned
short
);
static
long
sctp_get_port_local
(
struct
sock
*
,
unsigned
short
);
/* Bind a local address either to an endpoint or to an association. */
/* Bind a local address either to an endpoint or to an association. */
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
sockaddr_storage_t
*
newaddr
,
SCTP_STATIC
int
sctp_do_bind
(
struct
sock
*
sk
,
union
sctp_addr
*
newaddr
,
int
addr_len
)
int
addr_len
)
{
{
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_endpoint_t
*
ep
=
sp
->
ep
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
unsigned
short
sa_family
=
newaddr
->
sa
.
sa_family
;
unsigned
short
sa_family
=
newaddr
->
sa
.
sa_family
;
sockaddr_storage_t
tmpaddr
,
saveaddr
;
union
sctp_addr
tmpaddr
,
saveaddr
;
unsigned
short
*
snum
;
unsigned
short
*
snum
;
int
ret
=
0
;
int
ret
=
0
;
...
@@ -403,7 +404,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
...
@@ -403,7 +404,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
goto
err_bindx_add
;
goto
err_bindx_add
;
};
};
retval
=
sctp_do_bind
(
sk
,
(
sockaddr_storage_t
*
)
&
addrs
[
cnt
],
retval
=
sctp_do_bind
(
sk
,
(
union
sctp_addr
*
)
&
addrs
[
cnt
],
addr_len
);
addr_len
);
err_bindx_add:
err_bindx_add:
...
@@ -481,7 +482,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
...
@@ -481,7 +482,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
int
cnt
;
int
cnt
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
int
retval
=
0
;
int
retval
=
0
;
sockaddr_storage_t
saveaddr
;
union
sctp_addr
saveaddr
;
SCTP_DEBUG_PRINTK
(
"sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)
\n
"
,
SCTP_DEBUG_PRINTK
(
"sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)
\n
"
,
sk
,
addrs
,
addrcnt
);
sk
,
addrs
,
addrcnt
);
...
@@ -500,7 +501,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
...
@@ -500,7 +501,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
*/
*/
switch
(((
struct
sockaddr
*
)
&
addrs
[
cnt
])
->
sa_family
)
{
switch
(((
struct
sockaddr
*
)
&
addrs
[
cnt
])
->
sa_family
)
{
case
AF_INET
:
case
AF_INET
:
saveaddr
=
*
((
sockaddr_storage_t
*
)
saveaddr
=
*
((
union
sctp_addr
*
)
&
addrs
[
cnt
]);
&
addrs
[
cnt
]);
saveaddr
.
v4
.
sin_port
=
ntohs
(
saveaddr
.
v4
.
sin_port
);
saveaddr
.
v4
.
sin_port
=
ntohs
(
saveaddr
.
v4
.
sin_port
);
/* Verify the port. */
/* Verify the port. */
...
@@ -511,7 +512,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
...
@@ -511,7 +512,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
break
;
break
;
case
AF_INET6
:
case
AF_INET6
:
saveaddr
=
*
((
sockaddr_storage_t
*
)
saveaddr
=
*
((
union
sctp_addr
*
)
&
addrs
[
cnt
]);
&
addrs
[
cnt
]);
saveaddr
.
v6
.
sin6_port
=
saveaddr
.
v6
.
sin6_port
=
ntohs
(
saveaddr
.
v6
.
sin6_port
);
ntohs
(
saveaddr
.
v6
.
sin6_port
);
...
@@ -741,7 +742,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -741,7 +742,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
sctp_association_t
*
new_asoc
=
NULL
,
*
asoc
=
NULL
;
sctp_transport_t
*
transport
;
sctp_transport_t
*
transport
;
sctp_chunk_t
*
chunk
=
NULL
;
sctp_chunk_t
*
chunk
=
NULL
;
sockaddr_storage_t
to
;
union
sctp_addr
to
;
struct
sockaddr
*
msg_name
=
NULL
;
struct
sockaddr
*
msg_name
=
NULL
;
struct
sctp_sndrcvinfo
default_sinfo
=
{
0
};
struct
sctp_sndrcvinfo
default_sinfo
=
{
0
};
struct
sctp_sndrcvinfo
*
sinfo
;
struct
sctp_sndrcvinfo
*
sinfo
;
...
@@ -777,7 +778,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -777,7 +778,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
* For a peeled-off socket, msg_name is ignored.
* For a peeled-off socket, msg_name is ignored.
*/
*/
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sp
->
type
)
&&
msg
->
msg_name
)
{
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sp
->
type
)
&&
msg
->
msg_name
)
{
err
=
sctp_sendmsg_verify_name
(
sk
,
msg
);
err
=
sctp_verify_addr
(
sk
,
(
struct
sockaddr
*
)
msg
->
msg_name
,
msg
->
msg_namelen
);
if
(
err
)
if
(
err
)
return
err
;
return
err
;
...
@@ -826,29 +828,15 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -826,29 +828,15 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* Look for a matching association on the endpoint. */
/* Look for a matching association on the endpoint. */
asoc
=
sctp_endpoint_lookup_assoc
(
ep
,
&
to
,
&
transport
);
asoc
=
sctp_endpoint_lookup_assoc
(
ep
,
&
to
,
&
transport
);
if
(
!
asoc
)
{
if
(
!
asoc
)
{
struct
list_head
*
pos
;
/* If we could not find a matching association on the
struct
sockaddr_storage_list
*
addr
;
* endpoint, make sure that there is no peeled-off
sctp_bind_addr_t
*
bp
=
&
ep
->
base
.
bind_addr
;
* association on another socket.
sctp_read_lock
(
&
ep
->
base
.
addr_lock
);
/* If we could not find a matching association on
* the endpoint, make sure that there is no peeled-
* off association.
*/
*/
list_for_each
(
pos
,
&
bp
->
address_list
)
{
if
(
sctp_endpoint_is_peeled_off
(
ep
,
&
to
))
{
addr
=
list_entry
(
pos
,
err
=
-
EADDRNOTAVAIL
;
struct
sockaddr_storage_list
,
list
);
if
(
sctp_has_association
(
&
addr
->
a
,
&
to
))
{
err
=
-
EINVAL
;
sctp_read_unlock
(
&
ep
->
base
.
addr_lock
);
goto
out_unlock
;
goto
out_unlock
;
}
}
}
}
sctp_read_unlock
(
&
ep
->
base
.
addr_lock
);
}
}
else
{
}
else
{
/* For a peeled-off socket, ignore any associd specified by
/* For a peeled-off socket, ignore any associd specified by
* the user with SNDRCVINFO.
* the user with SNDRCVINFO.
...
@@ -1116,6 +1104,33 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
...
@@ -1116,6 +1104,33 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
#endif /* 0 */
#endif /* 0 */
}
}
/* This is an extended version of skb_pull() that removes the data from the
* start of a skb even when data is spread across the list of skb's in the
* frag_list. len specifies the total amount of data that needs to be removed.
* when 'len' bytes could be removed from the skb, it returns 0.
* If 'len' exceeds the total skb length, it returns the no. of bytes that
* could not be removed.
*/
static
int
sctp_skb_pull
(
struct
sk_buff
*
skb
,
int
len
)
{
struct
sk_buff
*
list
;
if
(
len
<=
skb
->
len
)
{
__skb_pull
(
skb
,
len
);
return
0
;
}
len
-=
skb
->
len
;
__skb_pull
(
skb
,
skb
->
len
);
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
len
=
sctp_skb_pull
(
list
,
len
);
if
(
!
len
)
return
0
;
}
return
len
;
}
/* API 3.1.3 recvmsg() - UDP Style Syntax
/* API 3.1.3 recvmsg() - UDP Style Syntax
*
*
* ssize_t recvmsg(int socket, struct msghdr *message,
* ssize_t recvmsg(int socket, struct msghdr *message,
...
@@ -1138,9 +1153,10 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1138,9 +1153,10 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
{
{
sctp_ulpevent_t
*
event
=
NULL
;
sctp_ulpevent_t
*
event
=
NULL
;
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
sctp_opt_t
*
sp
=
sctp_sk
(
sk
);
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
,
*
list
;
int
copied
;
int
copied
;
int
err
=
0
;
int
err
=
0
;
int
skb_len
;
SCTP_DEBUG_PRINTK
(
"sctp_recvmsg("
SCTP_DEBUG_PRINTK
(
"sctp_recvmsg("
"%s: %p, %s: %p, %s: %d, %s: %d, %s: "
"%s: %p, %s: %p, %s: %d, %s: %d, %s: "
...
@@ -1157,21 +1173,16 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1157,21 +1173,16 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
if
(
!
skb
)
if
(
!
skb
)
goto
out
;
goto
out
;
copied
=
skb
->
len
;
/* Get the total length of the skb including any skb's in the
* frag_list.
if
(
skb_shinfo
(
skb
)
->
frag_list
)
{
*/
struct
sk_buff
*
list
;
skb_len
=
skb
->
len
;
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
skb_len
+=
list
->
len
;
list
;
list
=
list
->
next
)
copied
+=
list
->
len
;
}
if
(
copied
>
len
)
{
copied
=
skb_len
;
if
(
copied
>
len
)
copied
=
len
;
copied
=
len
;
msg
->
msg_flags
|=
MSG_TRUNC
;
}
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
err
=
skb_copy_datagram_iovec
(
skb
,
0
,
msg
->
msg_iov
,
copied
);
...
@@ -1199,8 +1210,19 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1199,8 +1210,19 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
err
=
copied
;
err
=
copied
;
/* FIXME: We need to support MSG_EOR correctly. */
/* If skb's length exceeds the user's buffer, update the skb and
* push it back to the receive_queue so that the next call to
* recvmsg() will return the remaining data. Don't set MSG_EOR.
* Otherwise, set MSG_EOR indicating the end of a message.
*/
if
(
skb_len
>
copied
)
{
sctp_skb_pull
(
skb
,
copied
);
skb_queue_head
(
&
sk
->
receive_queue
,
skb
);
msg
->
msg_flags
&=
~
MSG_EOR
;
goto
out
;
}
else
{
msg
->
msg_flags
|=
MSG_EOR
;
msg
->
msg_flags
|=
MSG_EOR
;
}
out_free:
out_free:
sctp_ulpevent_free
(
event
);
/* Free the skb. */
sctp_ulpevent_free
(
event
);
/* Free the skb. */
...
@@ -1252,6 +1274,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
...
@@ -1252,6 +1274,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return
0
;
return
0
;
}
}
static
inline
int
sctp_setsockopt_set_peer_addr_params
(
struct
sock
*
sk
,
char
*
optval
,
int
optlen
)
{
struct
sctp_paddrparams
params
;
sctp_association_t
*
asoc
;
union
sctp_addr
*
addr
;
sctp_transport_t
*
trans
;
int
error
;
if
(
optlen
!=
sizeof
(
struct
sctp_paddrparams
))
return
-
EINVAL
;
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
);
if
(
!
trans
)
return
-
ENOENT
;
/* 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 value of the heartbeat interval, in milliseconds. 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.
*/
if
(
0xffffffff
==
params
.
spp_hbinterval
)
{
error
=
sctp_primitive_REQUESTHEARTBEAT
(
asoc
,
trans
);
if
(
error
)
return
error
;
}
else
{
/* 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.
*/
if
(
params
.
spp_hbinterval
)
{
trans
->
hb_allowed
=
1
;
trans
->
hb_interval
=
params
.
spp_hbinterval
*
HZ
/
1000
;
}
else
trans
->
hb_allowed
=
0
;
}
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
trans
->
error_threshold
=
params
.
spp_pathmaxrxt
;
return
0
;
}
/* API 6.2 setsockopt(), getsockopt()
/* API 6.2 setsockopt(), getsockopt()
*
*
* Applications use setsockopt() and getsockopt() to set or retrieve
* Applications use setsockopt() and getsockopt() to set or retrieve
...
@@ -1342,6 +1425,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1342,6 +1425,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval
=
sctp_setsockopt_autoclose
(
sk
,
optval
,
optlen
);
retval
=
sctp_setsockopt_autoclose
(
sk
,
optval
,
optlen
);
break
;
break
;
case
SCTP_SET_PEER_ADDR_PARAMS
:
retval
=
sctp_setsockopt_set_peer_addr_params
(
sk
,
optval
,
optlen
);
break
;
default:
default:
retval
=
-
ENOPROTOOPT
;
retval
=
-
ENOPROTOOPT
;
break
;
break
;
...
@@ -1354,11 +1442,107 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
...
@@ -1354,11 +1442,107 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
return
retval
;
return
retval
;
}
}
/* FIXME: Write comments. */
/* API 3.1.6 connect() - UDP Style Syntax
*
* An application may use the connect() call in the UDP model to initiate an
* association without sending data.
*
* The syntax is:
*
* ret = connect(int sd, const struct sockaddr *nam, socklen_t len);
*
* sd: the socket descriptor to have a new association added to.
*
* nam: the address structure (either struct sockaddr_in or struct
* sockaddr_in6 defined in RFC2553 [7]).
*
* len: the size of the address.
*/
SCTP_STATIC
int
sctp_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
uaddr
,
SCTP_STATIC
int
sctp_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
uaddr
,
int
addr_len
)
int
addr_len
)
{
{
return
-
EOPNOTSUPP
;
/* STUB */
sctp_opt_t
*
sp
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
asoc
;
sctp_transport_t
*
transport
;
union
sctp_addr
to
;
sctp_scope_t
scope
;
long
timeo
;
int
err
=
0
;
sctp_lock_sock
(
sk
);
SCTP_DEBUG_PRINTK
(
"%s - sk: %p, sockaddr: %p, addr_len: %d)
\n
"
,
__FUNCTION__
,
sk
,
uaddr
,
addr_len
);
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
/* connect() cannot be done on a peeled-off socket. */
if
(
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
==
sp
->
type
)
{
err
=
-
EISCONN
;
goto
out_unlock
;
}
err
=
sctp_verify_addr
(
sk
,
uaddr
,
addr_len
);
if
(
err
)
goto
out_unlock
;
memcpy
(
&
to
,
uaddr
,
addr_len
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
asoc
=
sctp_endpoint_lookup_assoc
(
ep
,
&
to
,
&
transport
);
if
(
asoc
)
{
if
(
asoc
->
state
>=
SCTP_STATE_ESTABLISHED
)
err
=
-
EISCONN
;
else
err
=
-
EALREADY
;
goto
out_unlock
;
}
/* If we could not find a matching association on the endpoint,
* make sure that there is no peeled-off association matching the
* peer address even on another socket.
*/
if
(
sctp_endpoint_is_peeled_off
(
ep
,
&
to
))
{
err
=
-
EADDRNOTAVAIL
;
goto
out_unlock
;
}
/* If a bind() or sctp_bindx() is not called prior to a connect()
* call, the system picks an ephemeral port and will choose an address
* set equivalent to binding with a wildcard address.
*/
if
(
!
ep
->
base
.
bind_addr
.
port
)
{
if
(
sctp_autobind
(
sk
))
{
err
=
-
EAGAIN
;
goto
out_unlock
;
}
}
scope
=
sctp_scope
(
&
to
);
asoc
=
sctp_association_new
(
ep
,
sk
,
scope
,
GFP_KERNEL
);
if
(
!
asoc
)
{
err
=
-
ENOMEM
;
goto
out_unlock
;
}
/* Prime the peer's transport structures. */
transport
=
sctp_assoc_add_peer
(
asoc
,
&
to
,
GFP_KERNEL
);
err
=
sctp_primitive_ASSOCIATE
(
asoc
,
NULL
);
if
(
err
<
0
)
{
sctp_association_free
(
asoc
);
goto
out_unlock
;
}
timeo
=
sock_sndtimeo
(
sk
,
sk
->
socket
->
file
->
f_flags
&
O_NONBLOCK
);
err
=
sctp_wait_for_connect
(
asoc
,
&
timeo
);
out_unlock:
sctp_release_sock
(
sk
);
return
err
;
}
}
/* FIXME: Write comments. */
/* FIXME: Write comments. */
...
@@ -1503,28 +1687,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1503,28 +1687,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if
(
len
!=
sizeof
(
status
))
{
if
(
len
!=
sizeof
(
status
))
{
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
goto
out
_nounlock
;
goto
out
;
}
}
if
(
copy_from_user
(
&
status
,
optval
,
sizeof
(
status
)))
{
if
(
copy_from_user
(
&
status
,
optval
,
sizeof
(
status
)))
{
retval
=
-
EFAULT
;
retval
=
-
EFAULT
;
goto
out
_nounlock
;
goto
out
;
}
}
sctp_lock_sock
(
sk
);
associd
=
status
.
sstat_assoc_id
;
associd
=
status
.
sstat_assoc_id
;
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sctp_sk
(
sk
)
->
type
)
&&
associd
)
{
if
((
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
!=
sctp_sk
(
sk
)
->
type
)
&&
associd
)
{
assoc
=
sctp_id2assoc
(
sk
,
associd
);
assoc
=
sctp_id2assoc
(
sk
,
associd
);
if
(
!
assoc
)
{
if
(
!
assoc
)
{
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
goto
out
_unlock
;
goto
out
;
}
}
}
else
{
}
else
{
ep
=
sctp_sk
(
sk
)
->
ep
;
ep
=
sctp_sk
(
sk
)
->
ep
;
if
(
list_empty
(
&
ep
->
asocs
))
{
if
(
list_empty
(
&
ep
->
asocs
))
{
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
goto
out
_unlock
;
goto
out
;
}
}
assoc
=
list_entry
(
ep
->
asocs
.
next
,
sctp_association_t
,
asocs
);
assoc
=
list_entry
(
ep
->
asocs
.
next
,
sctp_association_t
,
asocs
);
...
@@ -1542,8 +1724,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1542,8 +1724,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status
.
sstat_fragmentation_point
=
assoc
->
frag_point
;
status
.
sstat_fragmentation_point
=
assoc
->
frag_point
;
status
.
sstat_primary
.
spinfo_assoc_id
=
sctp_assoc2id
(
transport
->
asoc
);
status
.
sstat_primary
.
spinfo_assoc_id
=
sctp_assoc2id
(
transport
->
asoc
);
memcpy
(
&
status
.
sstat_primary
.
spinfo_address
,
memcpy
(
&
status
.
sstat_primary
.
spinfo_address
,
&
(
transport
->
ipaddr
),
sizeof
(
sockaddr_storage_t
));
&
(
transport
->
ipaddr
),
sizeof
(
union
sctp_addr
));
status
.
sstat_primary
.
spinfo_state
=
transport
->
state
.
active
;
status
.
sstat_primary
.
spinfo_state
=
transport
->
active
;
status
.
sstat_primary
.
spinfo_cwnd
=
transport
->
cwnd
;
status
.
sstat_primary
.
spinfo_cwnd
=
transport
->
cwnd
;
status
.
sstat_primary
.
spinfo_srtt
=
transport
->
srtt
;
status
.
sstat_primary
.
spinfo_srtt
=
transport
->
srtt
;
status
.
sstat_primary
.
spinfo_rto
=
transport
->
rto
;
status
.
sstat_primary
.
spinfo_rto
=
transport
->
rto
;
...
@@ -1551,7 +1733,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1551,7 +1733,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if
(
put_user
(
len
,
optlen
))
{
if
(
put_user
(
len
,
optlen
))
{
retval
=
-
EFAULT
;
retval
=
-
EFAULT
;
goto
out
_unlock
;
goto
out
;
}
}
SCTP_DEBUG_PRINTK
(
"sctp_getsockopt_sctp_status(%d): %d %d %p
\n
"
,
SCTP_DEBUG_PRINTK
(
"sctp_getsockopt_sctp_status(%d): %d %d %p
\n
"
,
...
@@ -1560,13 +1742,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1560,13 +1742,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if
(
copy_to_user
(
optval
,
&
status
,
len
))
{
if
(
copy_to_user
(
optval
,
&
status
,
len
))
{
retval
=
-
EFAULT
;
retval
=
-
EFAULT
;
goto
out
_unlock
;
goto
out
;
}
}
out_unlock:
out:
sctp_release_sock
(
sk
);
out_nounlock:
return
(
retval
);
return
(
retval
);
}
}
...
@@ -1684,25 +1863,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
...
@@ -1684,25 +1863,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
if
(
copy_from_user
(
&
peeloff
,
optval
,
len
))
if
(
copy_from_user
(
&
peeloff
,
optval
,
len
))
return
-
EFAULT
;
return
-
EFAULT
;
sctp_lock_sock
(
sk
);
assoc
=
sctp_id2assoc
(
sk
,
peeloff
.
associd
);
assoc
=
sctp_id2assoc
(
sk
,
peeloff
.
associd
);
if
(
NULL
==
assoc
)
{
if
(
NULL
==
assoc
)
{
retval
=
-
EINVAL
;
retval
=
-
EINVAL
;
goto
out
_unlock
;
goto
out
;
}
}
SCTP_DEBUG_PRINTK
(
"%s: sk: %p assoc: %p
\n
"
,
__FUNCTION__
,
sk
,
assoc
);
SCTP_DEBUG_PRINTK
(
"%s: sk: %p assoc: %p
\n
"
,
__FUNCTION__
,
sk
,
assoc
);
retval
=
sctp_do_peeloff
(
assoc
,
&
newsock
);
retval
=
sctp_do_peeloff
(
assoc
,
&
newsock
);
if
(
retval
<
0
)
if
(
retval
<
0
)
goto
out
_unlock
;
goto
out
;
/* Map the socket to an unused fd that can be returned to the user. */
/* Map the socket to an unused fd that can be returned to the user. */
retval
=
sock_map_fd
(
newsock
);
retval
=
sock_map_fd
(
newsock
);
if
(
retval
<
0
)
{
if
(
retval
<
0
)
{
sock_release
(
newsock
);
sock_release
(
newsock
);
goto
out
_unlock
;
goto
out
;
}
}
SCTP_DEBUG_PRINTK
(
"%s: sk: %p assoc: %p newsk: %p sd: %d
\n
"
,
SCTP_DEBUG_PRINTK
(
"%s: sk: %p assoc: %p newsk: %p sd: %d
\n
"
,
...
@@ -1713,11 +1890,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
...
@@ -1713,11 +1890,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
if
(
copy_to_user
(
optval
,
&
peeloff
,
len
))
if
(
copy_to_user
(
optval
,
&
peeloff
,
len
))
retval
=
-
EFAULT
;
retval
=
-
EFAULT
;
out_unlock:
out:
sctp_release_sock
(
sk
);
return
retval
;
return
retval
;
}
}
static
inline
int
sctp_getsockopt_get_peer_addr_params
(
struct
sock
*
sk
,
int
len
,
char
*
optval
,
int
*
optlen
)
{
struct
sctp_paddrparams
params
;
sctp_association_t
*
asoc
;
union
sctp_addr
*
addr
;
sctp_transport_t
*
trans
;
if
(
len
!=
sizeof
(
struct
sctp_paddrparams
))
return
-
EINVAL
;
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
);
if
(
!
trans
)
return
-
ENOENT
;
/* 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.
*/
if
(
!
trans
->
hb_allowed
)
params
.
spp_hbinterval
=
0
;
else
params
.
spp_hbinterval
=
trans
->
hb_interval
*
1000
/
HZ
;
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
params
.
spp_pathmaxrxt
=
trans
->
error_threshold
;
if
(
copy_to_user
(
optval
,
&
params
,
len
))
return
-
EFAULT
;
*
optlen
=
len
;
return
0
;
}
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
SCTP_STATIC
int
sctp_getsockopt
(
struct
sock
*
sk
,
int
level
,
int
optname
,
char
*
optval
,
int
*
optlen
)
char
*
optval
,
int
*
optlen
)
{
{
...
@@ -1748,6 +1968,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
...
@@ -1748,6 +1968,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
if
(
get_user
(
len
,
optlen
))
if
(
get_user
(
len
,
optlen
))
return
-
EFAULT
;
return
-
EFAULT
;
sctp_lock_sock
(
sk
);
switch
(
optname
)
{
switch
(
optname
)
{
case
SCTP_STATUS
:
case
SCTP_STATUS
:
retval
=
sctp_getsockopt_sctp_status
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_sctp_status
(
sk
,
len
,
optval
,
optlen
);
...
@@ -1770,11 +1992,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
...
@@ -1770,11 +1992,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval
=
sctp_getsockopt_peeloff
(
sk
,
len
,
optval
,
optlen
);
retval
=
sctp_getsockopt_peeloff
(
sk
,
len
,
optval
,
optlen
);
break
;
break
;
case
SCTP_GET_PEER_ADDR_PARAMS
:
retval
=
sctp_getsockopt_get_peer_addr_params
(
sk
,
len
,
optval
,
optlen
);
break
;
default:
default:
retval
=
-
ENOPROTOOPT
;
retval
=
-
ENOPROTOOPT
;
break
;
break
;
};
};
sctp_release_sock
(
sk
);
return
retval
;
return
retval
;
}
}
...
@@ -1880,7 +2108,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
...
@@ -1880,7 +2108,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* socket is going to be sk2.
* socket is going to be sk2.
*/
*/
int
sk_reuse
=
sk
->
reuse
;
int
sk_reuse
=
sk
->
reuse
;
sockaddr_storage_t
tmpaddr
;
union
sctp_addr
tmpaddr
;
struct
sock
*
sk2
=
pp
->
sk
;
struct
sock
*
sk2
=
pp
->
sk
;
SCTP_DEBUG_PRINTK
(
"sctp_get_port() found a "
SCTP_DEBUG_PRINTK
(
"sctp_get_port() found a "
...
@@ -1923,13 +2151,14 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
...
@@ -1923,13 +2151,14 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
sctp_endpoint_t
*
ep2
;
sctp_endpoint_t
*
ep2
;
ep2
=
sctp_sk
(
sk2
)
->
ep
;
ep2
=
sctp_sk
(
sk2
)
->
ep
;
if
(
!
sk_reuse
||
!
sk2
->
reuse
)
{
if
(
sk_reuse
&&
sk2
->
reuse
)
if
(
sctp_bind_addr_has_addr
(
continue
;
&
ep2
->
base
.
bind_addr
,
&
tmpaddr
))
{
if
(
sctp_bind_addr_match
(
&
ep2
->
base
.
bind_addr
,
&
tmpaddr
,
sctp_sk
(
sk
)))
goto
found
;
goto
found
;
}
}
}
}
found:
found:
/* If we found a conflict, fail. */
/* If we found a conflict, fail. */
...
@@ -2183,34 +2412,17 @@ void sctp_put_port(struct sock *sk)
...
@@ -2183,34 +2412,17 @@ void sctp_put_port(struct sock *sk)
*/
*/
static
int
sctp_autobind
(
struct
sock
*
sk
)
static
int
sctp_autobind
(
struct
sock
*
sk
)
{
{
sockaddr_storage_t
autoaddr
;
union
sctp_addr
autoaddr
;
int
addr_len
=
0
;
struct
sctp_func
*
af
;
unsigned
short
port
;
memset
(
&
autoaddr
,
0
,
sizeof
(
sockaddr_storage_t
));
switch
(
sk
->
family
)
{
case
PF_INET
:
autoaddr
.
v4
.
sin_family
=
AF_INET
;
autoaddr
.
v4
.
sin_addr
.
s_addr
=
INADDR_ANY
;
autoaddr
.
v4
.
sin_port
=
htons
(
inet_sk
(
sk
)
->
num
);
addr_len
=
sizeof
(
struct
sockaddr_in
);
break
;
case
PF_INET6
:
/* Initialize a local sockaddr structure to INADDR_ANY. */
SCTP_V6
(
af
=
sctp_sk
(
sk
)
->
pf
->
af
;
/* FIXME: Write me for v6! */
BUG
();
autoaddr
.
v6
.
sin6_family
=
AF_INET6
;
autoaddr
.
v6
.
sin6_port
=
htons
(
inet_sk
(
sk
)
->
num
);
addr_len
=
sizeof
(
struct
sockaddr_in6
);
);
break
;
default:
/* This should not happen. */
port
=
htons
(
inet_sk
(
sk
)
->
num
);
break
;
af
->
inaddr_any
(
&
autoaddr
,
port
);
};
return
sctp_do_bind
(
sk
,
&
autoaddr
,
addr_len
);
return
sctp_do_bind
(
sk
,
&
autoaddr
,
a
f
->
socka
ddr_len
);
}
}
/* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation.
/* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation.
...
@@ -2327,8 +2539,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
...
@@ -2327,8 +2539,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
/* Setup sk->rcv_saddr before calling get_port(). */
/* Setup sk->rcv_saddr before calling get_port(). */
static
inline
void
sctp_sk_addr_set
(
struct
sock
*
sk
,
static
inline
void
sctp_sk_addr_set
(
struct
sock
*
sk
,
const
sockaddr_storage_t
*
newaddr
,
const
union
sctp_addr
*
newaddr
,
sockaddr_storage_t
*
saveaddr
)
union
sctp_addr
*
saveaddr
)
{
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
...
@@ -2355,7 +2567,7 @@ static inline void sctp_sk_addr_set(struct sock *sk,
...
@@ -2355,7 +2567,7 @@ static inline void sctp_sk_addr_set(struct sock *sk,
}
}
/* Restore sk->rcv_saddr after failing get_port(). */
/* Restore sk->rcv_saddr after failing get_port(). */
static
inline
void
sctp_sk_addr_restore
(
struct
sock
*
sk
,
const
sockaddr_storage_t
*
addr
)
static
inline
void
sctp_sk_addr_restore
(
struct
sock
*
sk
,
const
union
sctp_addr
*
addr
)
{
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
...
@@ -2498,35 +2710,30 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
...
@@ -2498,35 +2710,30 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
return
NULL
;
return
NULL
;
}
}
static
inline
int
sctp_sendmsg_verify_name
(
struct
sock
*
sk
,
struct
msghdr
*
msg
)
/* Verify that this is a valid address. */
static
int
sctp_verify_addr
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
,
int
len
)
{
{
s
ockaddr_storage_t
*
sa
;
s
truct
sctp_func
*
af
;
if
(
msg
->
msg_namelen
<
sizeof
(
struct
sockaddr
))
/* Check minimum size. */
if
(
len
<
sizeof
(
struct
sockaddr
))
return
-
EINVAL
;
return
-
EINVAL
;
sa
=
(
sockaddr_storage_t
*
)
msg
->
msg_name
;
/* Do we support this address family in general? */
switch
(
sa
->
sa
.
sa_family
)
{
af
=
sctp_get_af_specific
(
addr
->
sa_family
);
case
AF_INET
:
if
(
!
af
)
if
(
msg
->
msg_namelen
<
sizeof
(
struct
sockaddr_in
))
return
-
EINVAL
;
return
-
EINVAL
;
break
;
case
AF_INET6
:
/* Does this PF support this AF? */
if
(
PF_INET
==
sk
->
family
)
if
(
!
sctp_sk
(
sk
)
->
pf
->
af_supported
(
addr
->
sa_family
)
)
return
-
EINVAL
;
return
-
EINVAL
;
SCTP_V6
(
if
(
msg
->
msg_namelen
<
sizeof
(
struct
sockaddr_in6
))
return
-
EINVAL
;
break
;
);
default:
/* Verify the minimum for this AF sockaddr. */
if
(
len
<
af
->
sockaddr_len
)
return
-
EINVAL
;
return
-
EINVAL
;
};
/*
Disallow any illegal addresses to be used as destinations.
*/
/*
Is this a valid SCTP address?
*/
if
(
!
sctp_addr_is_valid
(
sa
))
if
(
!
af
->
addr_valid
((
union
sctp_addr
*
)
addr
))
return
-
EINVAL
;
return
-
EINVAL
;
return
0
;
return
0
;
...
@@ -2710,6 +2917,70 @@ static int sctp_writeable(struct sock *sk)
...
@@ -2710,6 +2917,70 @@ static int sctp_writeable(struct sock *sk)
return
amt
;
return
amt
;
}
}
/* Wait for an association to go into ESTABLISHED state. If timeout is 0,
* returns immediately with EINPROGRESS.
*/
static
int
sctp_wait_for_connect
(
sctp_association_t
*
asoc
,
long
*
timeo_p
)
{
struct
sock
*
sk
=
asoc
->
base
.
sk
;
int
err
=
0
;
long
current_timeo
=
*
timeo_p
;
DECLARE_WAITQUEUE
(
wait
,
current
);
SCTP_DEBUG_PRINTK
(
"%s: asoc=%p, timeo=%ld
\n
"
,
__FUNCTION__
,
asoc
,
(
long
)(
*
timeo_p
));
add_wait_queue_exclusive
(
&
asoc
->
wait
,
&
wait
);
/* Increment the association's refcnt. */
sctp_association_hold
(
asoc
);
for
(;;)
{
__set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
!*
timeo_p
)
goto
do_nonblock
;
if
(
sk
->
err
||
asoc
->
state
>=
SCTP_STATE_SHUTDOWN_PENDING
||
asoc
->
base
.
dead
)
goto
do_error
;
if
(
signal_pending
(
current
))
goto
do_interrupted
;
if
(
asoc
->
state
==
SCTP_STATE_ESTABLISHED
)
break
;
/* Let another process have a go. Since we are going
* to sleep anyway.
*/
sctp_release_sock
(
sk
);
current_timeo
=
schedule_timeout
(
current_timeo
);
sctp_lock_sock
(
sk
);
*
timeo_p
=
current_timeo
;
}
out:
remove_wait_queue
(
&
asoc
->
wait
,
&
wait
);
/* Release the association's refcnt. */
sctp_association_put
(
asoc
);
__set_current_state
(
TASK_RUNNING
);
return
err
;
do_error:
err
=
-
ECONNABORTED
;
goto
out
;
do_interrupted:
err
=
sock_intr_errno
(
*
timeo_p
);
goto
out
;
do_nonblock:
err
=
-
EINPROGRESS
;
goto
out
;
}
/* This proto struct describes the ULP interface for SCTP. */
/* This proto struct describes the ULP interface for SCTP. */
struct
proto
sctp_prot
=
{
struct
proto
sctp_prot
=
{
.
name
=
"SCTP"
,
.
name
=
"SCTP"
,
...
...
net/sctp/transport.c
View file @
28b9daad
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
*
*
* This module provides the abstraction for an SCTP tranport representing
* This module provides the abstraction for an SCTP tranport representing
* a remote transport address. For local transport addresses, we just use
* a remote transport address. For local transport addresses, we just use
*
sockaddr_storage_t
.
*
union sctp_addr
.
*
*
* The SCTP reference implementation is free software;
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* you can redistribute it and/or modify it under the terms of
...
@@ -53,7 +53,7 @@
...
@@ -53,7 +53,7 @@
/* 1st Level Abstractions. */
/* 1st Level Abstractions. */
/* Allocate and initialize a new transport. */
/* Allocate and initialize a new transport. */
sctp_transport_t
*
sctp_transport_new
(
const
sockaddr_storage_t
*
addr
,
int
priority
)
sctp_transport_t
*
sctp_transport_new
(
const
union
sctp_addr
*
addr
,
int
priority
)
{
{
sctp_transport_t
*
transport
;
sctp_transport_t
*
transport
;
...
@@ -78,14 +78,14 @@ sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priorit
...
@@ -78,14 +78,14 @@ sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priorit
/* Intialize a new transport from provided memory. */
/* Intialize a new transport from provided memory. */
sctp_transport_t
*
sctp_transport_init
(
sctp_transport_t
*
peer
,
sctp_transport_t
*
sctp_transport_init
(
sctp_transport_t
*
peer
,
const
sockaddr_storage_t
*
addr
,
const
union
sctp_addr
*
addr
,
int
priority
)
int
priority
)
{
{
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
sctp_protocol_t
*
proto
=
sctp_get_protocol
();
/* Copy in the address. */
/* Copy in the address. */
peer
->
ipaddr
=
*
addr
;
peer
->
ipaddr
=
*
addr
;
peer
->
af_specific
=
sctp_get_af_specific
(
addr
);
peer
->
af_specific
=
sctp_get_af_specific
(
addr
->
sa
.
sa_family
);
peer
->
asoc
=
NULL
;
peer
->
asoc
=
NULL
;
/* From 6.3.1 RTO Calculation:
/* From 6.3.1 RTO Calculation:
...
@@ -104,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
...
@@ -104,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
peer
->
last_time_used
=
jiffies
;
peer
->
last_time_used
=
jiffies
;
peer
->
last_time_ecne_reduced
=
jiffies
;
peer
->
last_time_ecne_reduced
=
jiffies
;
peer
->
state
.
active
=
1
;
peer
->
active
=
1
;
peer
->
state
.
hb_allowed
=
0
;
peer
->
hb_allowed
=
0
;
/* Initialize the default path max_retrans. */
/* Initialize the default path max_retrans. */
peer
->
max_retrans
=
proto
->
max_retrans_path
;
peer
->
max_retrans
=
proto
->
max_retrans_path
;
...
@@ -203,17 +203,18 @@ void sctp_transport_set_owner(sctp_transport_t *transport,
...
@@ -203,17 +203,18 @@ void sctp_transport_set_owner(sctp_transport_t *transport,
/* Caches the dst entry for a transport's destination address and an optional
/* Caches the dst entry for a transport's destination address and an optional
* souce address.
* souce address.
*/
*/
void
sctp_transport_route
(
sctp_transport_t
*
transport
,
void
sctp_transport_route
(
sctp_transport_t
*
transport
,
union
sctp_addr
*
saddr
,
s
ockaddr_storage_t
*
saddr
)
s
truct
sctp_opt
*
opt
)
{
{
sctp_association_t
*
asoc
=
transport
->
asoc
;
sctp_association_t
*
asoc
=
transport
->
asoc
;
s
ctp_func_t
*
af
=
transport
->
af_specific
;
s
truct
sctp_func
*
af
=
transport
->
af_specific
;
sockaddr_storage_t
*
daddr
=
&
transport
->
ipaddr
;
union
sctp_addr
*
daddr
=
&
transport
->
ipaddr
;
sctp_bind_addr_t
*
bp
;
sctp_bind_addr_t
*
bp
;
rwlock_t
*
addr_lock
;
rwlock_t
*
addr_lock
;
struct
sockaddr_storage_list
*
laddr
;
struct
sockaddr_storage_list
*
laddr
;
struct
list_head
*
pos
;
struct
list_head
*
pos
;
struct
dst_entry
*
dst
;
struct
dst_entry
*
dst
;
union
sctp_addr
dst_saddr
;
dst
=
af
->
get_dst
(
daddr
,
saddr
);
dst
=
af
->
get_dst
(
daddr
,
saddr
);
...
@@ -239,7 +240,8 @@ void sctp_transport_route(sctp_transport_t *transport,
...
@@ -239,7 +240,8 @@ void sctp_transport_route(sctp_transport_t *transport,
list_for_each
(
pos
,
&
bp
->
address_list
)
{
list_for_each
(
pos
,
&
bp
->
address_list
)
{
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
laddr
=
list_entry
(
pos
,
struct
sockaddr_storage_list
,
list
);
list
);
if
(
af
->
cmp_saddr
(
dst
,
&
laddr
->
a
))
af
->
dst_saddr
(
&
dst_saddr
,
dst
);
if
(
opt
->
pf
->
cmp_addr
(
&
dst_saddr
,
&
laddr
->
a
,
opt
))
goto
out_unlock
;
goto
out_unlock
;
}
}
sctp_read_unlock
(
addr_lock
);
sctp_read_unlock
(
addr_lock
);
...
...
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