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
a4cae070
Commit
a4cae070
authored
Oct 01, 2002
by
Daisy Chang
Committed by
Jon Grimm
Oct 01, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sctp: Added the 'Unrecognized Parameter' handling.
parent
22bf2be7
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
578 additions
and
124 deletions
+578
-124
include/linux/sctp.h
include/linux/sctp.h
+2
-1
include/net/sctp/sm.h
include/net/sctp/sm.h
+10
-1
include/net/sctp/structs.h
include/net/sctp/structs.h
+14
-0
net/sctp/debug.c
net/sctp/debug.c
+1
-1
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+205
-22
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+14
-4
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+332
-95
No files found.
include/linux/sctp.h
View file @
a4cae070
...
...
@@ -155,7 +155,7 @@ typedef struct sctp_paramhdr {
typedef
enum
{
/* RFC 2960 Section 3.3.5 */
SCTP_PARAM_HEATBEAT_INFO
=
__constant_htons
(
1
),
SCTP_PARAM_HEA
R
TBEAT_INFO
=
__constant_htons
(
1
),
/* RFC 2960 Section 3.3.2.1 */
SCTP_PARAM_IPV4_ADDRESS
=
__constant_htons
(
5
),
SCTP_PARAM_IPV6_ADDRESS
=
__constant_htons
(
6
),
...
...
@@ -190,6 +190,7 @@ typedef enum {
SCTP_PARAM_ACTION_SKIP_ERR
=
__constant_htons
(
0xc000
),
}
sctp_param_action_t
;
enum
{
SCTP_PARAM_ACTION_MASK
=
__constant_htons
(
0xc000
),
};
/* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */
...
...
include/net/sctp/sm.h
View file @
a4cae070
...
...
@@ -215,7 +215,8 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *,
int
priority
);
sctp_chunk_t
*
sctp_make_init_ack
(
const
sctp_association_t
*
,
const
sctp_chunk_t
*
,
const
int
priority
);
const
int
priority
,
const
int
unkparam_len
);
sctp_chunk_t
*
sctp_make_cookie_echo
(
const
sctp_association_t
*
,
const
sctp_chunk_t
*
);
sctp_chunk_t
*
sctp_make_cookie_ack
(
const
sctp_association_t
*
,
...
...
@@ -304,6 +305,14 @@ void sctp_generate_t3_rtx_event(unsigned long peer);
void
sctp_generate_heartbeat_event
(
unsigned
long
peer
);
sctp_sackhdr_t
*
sctp_sm_pull_sack
(
sctp_chunk_t
*
);
sctp_packet_t
*
sctp_abort_pkt_new
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
const
void
*
payload
,
size_t
paylen
);
sctp_packet_t
*
sctp_ootb_pkt_new
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
);
void
sctp_ootb_pkt_free
(
sctp_packet_t
*
packet
);
sctp_cookie_param_t
*
sctp_pack_cookie
(
const
sctp_endpoint_t
*
,
const
sctp_association_t
*
,
...
...
include/net/sctp/structs.h
View file @
a4cae070
...
...
@@ -1044,6 +1044,20 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
sctp_endpoint_t
*
sctp_endpoint_is_match
(
sctp_endpoint_t
*
,
const
sockaddr_storage_t
*
);
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_chunk
);
int
sctp_verify_param
(
const
sctp_association_t
*
asoc
,
sctpParam_t
param
,
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
);
...
...
net/sctp/debug.c
View file @
a4cae070
...
...
@@ -97,7 +97,7 @@ const char *sctp_cname(const sctp_subtype_t cid)
/* These are printable form of variable-length parameters. */
const
char
*
sctp_param_tbl
[
SCTP_PARAM_ECN_CAPABLE
+
1
]
=
{
""
,
"PARAM_HEATBEAT_INFO"
,
"PARAM_HEA
R
TBEAT_INFO"
,
""
,
""
,
""
,
...
...
net/sctp/sm_make_chunk.c
View file @
a4cae070
...
...
@@ -223,7 +223,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
sctp_chunk_t
*
sctp_make_init_ack
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
,
int
priority
)
int
priority
,
int
unkparam_len
)
{
sctp_inithdr_t
initack
;
sctp_chunk_t
*
retval
;
...
...
@@ -278,7 +278,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
if
(
!
cookie
)
goto
nomem_cookie
;
chunksize
=
sizeof
(
initack
)
+
addrs_len
+
cookie_len
;
/* Calculate the total size of allocation, include the reserved
* space for reporting unknown parameters if it is specified.
*/
chunksize
=
sizeof
(
initack
)
+
addrs_len
+
cookie_len
+
unkparam_len
;
/* Tell peer that we'll do ECN only if peer advertised such cap. */
if
(
asoc
->
peer
.
ecn_capable
)
...
...
@@ -883,28 +886,48 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc,
return
retval
;
}
/* Create an Operation Error chunk with the specified space reserved.
* This routine can be used for containing multiple causes in the chunk.
*/
sctp_chunk_t
*
sctp_make_op_error_space
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
,
size_t
size
)
{
sctp_chunk_t
*
retval
;
retval
=
sctp_make_chunk
(
asoc
,
SCTP_CID_ERROR
,
0
,
sizeof
(
sctp_errhdr_t
)
+
size
);
if
(
!
retval
)
goto
nodata
;
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
*
* An endpoint SHOULD transmit reply chunks (e.g., SACK,
* HEARTBEAT ACK, etc.) to the same destination transport
* address from which it received the DATA or control chunk
* to which it is replying.
*
*/
if
(
chunk
)
retval
->
transport
=
chunk
->
transport
;
nodata:
return
retval
;
}
/* Create an Operation Error chunk. */
sctp_chunk_t
*
sctp_make_op_error
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
,
__u16
cause_code
,
const
void
*
payload
,
size_t
paylen
)
{
sctp_chunk_t
*
retval
=
sctp_make_chunk
(
asoc
,
SCTP_CID_ERROR
,
0
,
sizeof
(
sctp_errhdr_t
)
+
paylen
);
sctp_chunk_t
*
retval
=
sctp_make_op_error_space
(
asoc
,
chunk
,
paylen
);
if
(
!
retval
)
goto
nodata
;
sctp_init_cause
(
retval
,
cause_code
,
payload
,
paylen
);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints
*
* An endpoint SHOULD transmit reply chunks (e.g., SACK,
* HEARTBEAT ACK, * etc.) to the same destination transport
* address from which it * received the DATA or control chunk
* to which it is replying.
*/
if
(
chunk
)
retval
->
transport
=
chunk
->
transport
;
sctp_init_cause
(
retval
,
cause_code
,
payload
,
paylen
);
nodata:
return
retval
;
...
...
@@ -1405,6 +1428,167 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions
********************************************************************/
/* 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
)
{
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
,
sctpParam_t
param
,
sctp_cid_t
cid
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
{
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
:
/* 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
;
}
return
retval
;
}
/* RFC 3.2.1 & the Implementers Guide 2.2.
*
* The Parameter Types are encoded such that the
* highest-order two bits specify the action that must be
* taken if the processing endpoint does not recognize the
* Parameter Type.
*
* 00 - Stop processing this SCTP chunk and discard it,
* do not process any further chunks within it.
*
* 01 - Stop processing this SCTP chunk and discard it,
* do not process any further chunks within it, and report
* the unrecognized parameter in an 'Unrecognized
* Parameter Type' (in either an ERROR or in the INIT ACK).
*
* 10 - Skip this parameter and continue processing.
*
* 11 - Skip this parameter and continue processing but
* report the unrecognized parameter in an
* 'Unrecognized Parameter Type' (in either an ERROR or in
* the INIT ACK).
*
* Return value:
* 0 - discard the chunk
* 1 - continue with the chunk
*/
int
sctp_process_unk_param
(
const
sctp_association_t
*
asoc
,
sctpParam_t
param
,
sctp_chunk_t
*
chunk
,
sctp_chunk_t
**
err_chk_p
)
{
int
retval
=
1
;
switch
(
param
.
p
->
type
&
SCTP_PARAM_ACTION_MASK
)
{
case
SCTP_PARAM_ACTION_DISCARD
:
retval
=
0
;
break
;
case
SCTP_PARAM_ACTION_DISCARD_ERR
:
retval
=
0
;
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if
(
NULL
==
*
err_chk_p
)
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
ntohs
(
chunk
->
chunk_hdr
->
length
));
if
(
*
err_chk_p
)
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_UNKNOWN_PARAM
,
(
const
void
*
)
param
.
p
,
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)));
break
;
case
SCTP_PARAM_ACTION_SKIP
:
break
;
case
SCTP_PARAM_ACTION_SKIP_ERR
:
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if
(
NULL
==
*
err_chk_p
)
*
err_chk_p
=
sctp_make_op_error_space
(
asoc
,
chunk
,
ntohs
(
chunk
->
chunk_hdr
->
length
));
if
(
*
err_chk_p
)
{
sctp_init_cause
(
*
err_chk_p
,
SCTP_ERROR_UNKNOWN_PARAM
,
(
const
void
*
)
param
.
p
,
WORD_ROUND
(
ntohs
(
param
.
p
->
length
)));
}
else
{
/* If there is no memory for generating the ERROR
* report as specified, an ABORT will be triggered
* to the peer and the association won't be established.
*/
retval
=
0
;
}
break
;
default:
break
;
}
return
retval
;
}
/* Unpack the parameters in an INIT packet.
* FIXME: There is no return status to allow callers to do
* error handling.
...
...
@@ -1609,9 +1793,9 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
asoc
->
peer
.
cookie
=
param
.
cookie
->
body
;
break
;
case
SCTP_PARAM_HEATBEAT_INFO
:
case
SCTP_PARAM_HEA
R
TBEAT_INFO
:
SCTP_DEBUG_PRINTK
(
"unimplemented "
"SCTP_PARAM_HEATBEAT_INFO
\n
"
);
"SCTP_PARAM_HEA
R
TBEAT_INFO
\n
"
);
break
;
case
SCTP_PARAM_UNRECOGNIZED_PARAMETERS
:
...
...
@@ -1624,14 +1808,13 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
break
;
default:
/* Any unrecognized parameters should have been caught
* and handled by sctp_verify_param() which should be
* called prior to this routine. Simply log the error
* here.
*/
SCTP_DEBUG_PRINTK
(
"Ignoring param: %d for association %p.
\n
"
,
ntohs
(
param
.
p
->
type
),
asoc
);
/* FIXME: The entire parameter processing really needs
* redesigned. For now, always return success as doing
* otherwise craters the system.
*/
retval
=
1
;
break
;
};
...
...
net/sctp/sm_sideeffect.c
View file @
a4cae070
...
...
@@ -327,7 +327,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case
SCTP_CMD_GEN_INIT_ACK
:
/* Generate an INIT ACK chunk. */
new_obj
=
sctp_make_init_ack
(
asoc
,
chunk
,
GFP_ATOMIC
);
new_obj
=
sctp_make_init_ack
(
asoc
,
chunk
,
GFP_ATOMIC
,
0
);
if
(
!
new_obj
)
goto
nomem
;
...
...
@@ -344,10 +345,20 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case
SCTP_CMD_GEN_COOKIE_ECHO
:
/* Generate a COOKIE ECHO chunk. */
new_obj
=
sctp_make_cookie_echo
(
asoc
,
chunk
);
if
(
!
new_obj
)
if
(
!
new_obj
)
{
if
(
command
->
obj
.
ptr
)
sctp_free_chunk
(
command
->
obj
.
ptr
);
goto
nomem
;
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
new_obj
));
/* If there is an ERROR chunk to be sent along with
* the COOKIE_ECHO, send it, too.
*/
if
(
command
->
obj
.
ptr
)
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
command
->
obj
.
ptr
));
break
;
case
SCTP_CMD_GEN_SHUTDOWN
:
...
...
@@ -397,8 +408,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
/* Send a full packet to our peer. */
packet
=
command
->
obj
.
ptr
;
sctp_packet_transmit
(
packet
);
sctp_transport_free
(
packet
->
transport
);
sctp_packet_free
(
packet
);
sctp_ootb_pkt_free
(
packet
);
break
;
case
SCTP_CMD_RETRAN
:
...
...
net/sctp/sm_statefuns.c
View file @
a4cae070
...
...
@@ -194,6 +194,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
repl
;
sctp_association_t
*
new_asoc
;
sctp_chunk_t
*
err_chunk
;
sctp_packet_t
*
packet
;
sctp_unrecognized_param_t
*
unk_param
;
int
len
;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, responding with an ABORT.
...
...
@@ -208,6 +212,37 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if
(
!
chunk
->
singleton
)
return
SCTP_DISPOSITION_VIOLATION
;
/* Verify the INIT chunk before processing it. */
err_chunk
=
NULL
;
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
chunk
,
&
err_chunk
))
{
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
*/
if
(
err_chunk
)
{
packet
=
sctp_abort_pkt_new
(
ep
,
asoc
,
arg
,
(
__u8
*
)(
err_chunk
->
chunk_hdr
)
+
sizeof
(
sctp_chunkhdr_t
),
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
));
sctp_free_chunk
(
err_chunk
);
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
return
SCTP_DISPOSITION_CONSUME
;
}
else
{
return
SCTP_DISPOSITION_NOMEM
;
}
}
else
{
return
sctp_sf_tabort_8_4_8
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
}
/* Grab the INIT header. */
chunk
->
subh
.
init_hdr
=
(
sctp_inithdr_t
*
)
chunk
->
skb
->
data
;
...
...
@@ -230,10 +265,41 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
/* B) "Z" shall respond immediately with an INIT ACK chunk. */
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
);
/* If there are errors need to be reported for unknown parameters,
* make sure to reserve enough room in the INIT ACK for them.
*/
len
=
0
;
if
(
err_chunk
)
len
=
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
);
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
,
len
);
if
(
!
repl
)
goto
nomem_ack
;
/* If there are errors need to be reported for unknown parameters,
* include them in the outgoing INIT ACK as "Unrecognized parameter"
* parameter.
*/
if
(
err_chunk
)
{
/* Get the "Unrecognized parameter" parameter(s) out of the
* ERROR chunk generated by sctp_verify_init(). Since the
* error cause code for "unknown parameter" and the
* "Unrecognized parameter" type is the same, we can
* construct the parameters in INIT ACK by copying the
* ERROR causes over.
*/
unk_param
=
(
sctp_unrecognized_param_t
*
)
((
__u8
*
)(
err_chunk
->
chunk_hdr
)
+
sizeof
(
sctp_chunkhdr_t
));
/* Replace the cause code with the "Unrecognized parameter"
* parameter type.
*/
sctp_addto_chunk
(
repl
,
len
,
unk_param
);
sctp_free_chunk
(
err_chunk
);
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
/*
...
...
@@ -248,6 +314,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
nomem_ack:
sctp_association_free
(
new_asoc
);
if
(
err_chunk
)
sctp_free_chunk
(
err_chunk
);
nomem:
return
SCTP_DISPOSITION_NOMEM
;
}
...
...
@@ -289,6 +358,10 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
sctp_chunk_t
*
chunk
=
arg
;
sctp_init_chunk_t
*
initchunk
;
__u32
init_tag
;
sctp_chunk_t
*
err_chunk
;
sctp_packet_t
*
packet
;
sctp_disposition_t
ret
;
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
...
...
@@ -319,6 +392,49 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
return
SCTP_DISPOSITION_DELETE_TCB
;
}
/* Verify the INIT chunk before processing it. */
err_chunk
=
NULL
;
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
chunk
,
&
err_chunk
))
{
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
*/
if
(
err_chunk
)
{
packet
=
sctp_abort_pkt_new
(
ep
,
asoc
,
arg
,
(
__u8
*
)(
err_chunk
->
chunk_hdr
)
+
sizeof
(
sctp_chunkhdr_t
),
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
));
sctp_free_chunk
(
err_chunk
);
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_CONSUME
;
}
else
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
SCTP_DISPOSITION_NOMEM
;
}
}
else
{
ret
=
sctp_sf_tabort_8_4_8
(
ep
,
asoc
,
type
,
arg
,
commands
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_STATE
,
SCTP_STATE
(
SCTP_STATE_CLOSED
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_DELETE_TCB
,
SCTP_NULL
());
return
ret
;
}
}
/* Tag the variable length paramters. Note that we never
* convert the parameters in an INIT chunk.
*/
...
...
@@ -345,7 +461,12 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
/* 5.1 C) "A" shall then send the State Cookie received in the
* INIT ACK chunk in a COOKIE ECHO chunk, ...
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_GEN_COOKIE_ECHO
,
SCTP_NULL
());
/* If there is any errors to report, send the ERROR chunk generated
* for unknown parameters as well.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_GEN_COOKIE_ECHO
,
SCTP_CHUNK
(
err_chunk
));
return
SCTP_DISPOSITION_CONSUME
;
nomem:
...
...
@@ -579,7 +700,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
* HEARTBEAT is sent (see Section 8.3).
*/
hbinfo
.
param_hdr
.
type
=
SCTP_PARAM_HEATBEAT_INFO
;
hbinfo
.
param_hdr
.
type
=
SCTP_PARAM_HEA
R
TBEAT_INFO
;
hbinfo
.
param_hdr
.
length
=
htons
(
sizeof
(
sctp_sender_hb_info_t
));
hbinfo
.
daddr
=
transport
->
ipaddr
;
hbinfo
.
sent_at
=
jiffies
;
...
...
@@ -852,6 +973,11 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
repl
;
sctp_association_t
*
new_asoc
;
sctp_chunk_t
*
err_chunk
;
sctp_packet_t
*
packet
;
sctp_unrecognized_param_t
*
unk_param
;
int
len
;
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
...
...
@@ -866,6 +992,36 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
/* Tag the variable length parameters. */
chunk
->
param_hdr
.
v
=
skb_pull
(
chunk
->
skb
,
sizeof
(
sctp_inithdr_t
));
/* Verify the INIT chunk before processing it. */
err_chunk
=
NULL
;
if
(
!
sctp_verify_init
(
asoc
,
chunk
->
chunk_hdr
->
type
,
(
sctp_init_chunk_t
*
)
chunk
->
chunk_hdr
,
chunk
,
&
err_chunk
))
{
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
*/
if
(
err_chunk
)
{
packet
=
sctp_abort_pkt_new
(
ep
,
asoc
,
arg
,
(
__u8
*
)(
err_chunk
->
chunk_hdr
)
+
sizeof
(
sctp_chunkhdr_t
),
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
));
sctp_free_chunk
(
err_chunk
);
if
(
packet
)
{
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
return
SCTP_DISPOSITION_CONSUME
;
}
else
{
return
SCTP_DISPOSITION_NOMEM
;
}
}
else
{
return
sctp_sf_tabort_8_4_8
(
ep
,
asoc
,
type
,
arg
,
commands
);
}
}
/*
* Other parameters for the endpoint SHOULD be copied from the
* existing parameters of the association (e.g. number of
...
...
@@ -887,10 +1043,41 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
sctp_tietags_populate
(
new_asoc
,
asoc
);
/* B) "Z" shall respond immediately with an INIT ACK chunk. */
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
);
/* If there are errors need to be reported for unknown parameters,
* make sure to reserve enough room in the INIT ACK for them.
*/
len
=
0
;
if
(
err_chunk
)
{
len
=
ntohs
(
err_chunk
->
chunk_hdr
->
length
)
-
sizeof
(
sctp_chunkhdr_t
);
}
repl
=
sctp_make_init_ack
(
new_asoc
,
chunk
,
GFP_ATOMIC
,
len
);
if
(
!
repl
)
goto
nomem
;
/* If there are errors need to be reported for unknown parameters,
* include them in the outgoing INIT ACK as "Unrecognized parameter"
* parameter.
*/
if
(
err_chunk
)
{
/* Get the "Unrecognized parameter" parameter(s) out of the
* ERROR chunk generated by sctp_verify_init(). Since the
* error cause code for "unknown parameter" and the
* "Unrecognized parameter" type is the same, we can
* construct the parameters in INIT ACK by copying the
* ERROR causes over.
*/
unk_param
=
(
sctp_unrecognized_param_t
*
)
((
__u8
*
)(
err_chunk
->
chunk_hdr
)
+
sizeof
(
sctp_chunkhdr_t
));
/* Replace the cause code with the "Unrecognized parameter"
* parameter type.
*/
sctp_addto_chunk
(
repl
,
len
,
unk_param
);
sctp_free_chunk
(
err_chunk
);
}
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_NEW_ASOC
,
SCTP_ASOC
(
new_asoc
));
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
repl
));
...
...
@@ -903,6 +1090,9 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
return
SCTP_DISPOSITION_CONSUME
;
nomem:
if
(
err_chunk
)
sctp_free_chunk
(
err_chunk
);
return
SCTP_DISPOSITION_NOMEM
;
}
...
...
@@ -2330,60 +2520,35 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
{
sctp_packet_t
*
packet
=
NULL
;
sctp_transport_t
*
transport
=
NULL
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
abort
;
__u16
sport
;
__u16
dport
;
__u32
vtag
;
/* Grub in chunk and endpoint for kewl bitz. */
sport
=
ntohs
(
chunk
->
sctp_hdr
->
dest
);
dport
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
/* -- Make sure the ABORT packet's V-tag is the same as the
* inbound packet if no association exists, otherwise use
* the peer's vtag.
*/
if
(
asoc
)
vtag
=
asoc
->
peer
.
i
.
init_tag
;
else
vtag
=
ntohl
(
chunk
->
sctp_hdr
->
vtag
);
/* Make a transport for the bucket, Eliza... */
transport
=
sctp_transport_new
(
sctp_source
(
chunk
),
GFP_ATOMIC
);
if
(
!
transport
)
goto
nomem
;
/* Make a packet for the ABORT to go into. */
packet
=
t_new
(
sctp_packet_t
,
GFP_ATOMIC
);
if
(
!
packet
)
goto
nomem_packet
;
packet
=
sctp_packet_init
(
packet
,
transport
,
sport
,
dport
);
packet
=
sctp_packet_config
(
packet
,
vtag
,
0
,
NULL
);
/* Make an ABORT.
* This will set the T bit since we have no association.
*/
abort
=
sctp_make_abort
(
NULL
,
chunk
,
0
);
if
(
!
abort
)
goto
nomem_chunk
;
/* Set the skb to the belonging sock for accounting. */
abort
->
skb
->
sk
=
ep
->
base
.
sk
;
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
if
(
packet
)
{
/* Make an ABORT. The T bit will be set if the asoc
* is NULL.
*/
abort
=
sctp_make_abort
(
asoc
,
chunk
,
0
);
if
(
!
abort
)
{
sctp_ootb_pkt_free
(
packet
);
return
SCTP_DISPOSITION_NOMEM
;
}
sctp_packet_append_chunk
(
packet
,
abort
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
return
SCTP_DISPOSITION_DISCARD
;
/* Set the skb to the belonging sock for accounting. */
abort
->
skb
->
sk
=
ep
->
base
.
sk
;
nomem_chunk:
sctp_packet_free
(
packet
);
sctp_packet_append_chunk
(
packet
,
abort
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
nomem_packet:
sctp_transport_free
(
transport
);
return
SCTP_DISPOSITION_CONSUME
;
}
nomem:
return
SCTP_DISPOSITION_NOMEM
;
}
/*
...
...
@@ -2560,59 +2725,35 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
sctp_cmd_seq_t
*
commands
)
{
sctp_packet_t
*
packet
=
NULL
;
sctp_transport_t
*
transport
=
NULL
;
sctp_chunk_t
*
chunk
=
arg
;
sctp_chunk_t
*
shut
;
__u16
sport
;
__u16
dport
;
__u32
vtag
;
/* Grub in chunk and endpoint for kewl bitz. */
sport
=
ntohs
(
chunk
->
sctp_hdr
->
dest
);
dport
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
/* Make sure the ABORT packet's V-tag is the same as the
* inbound packet if no association exists, otherwise use
* the peer's vtag.
*/
vtag
=
ntohl
(
chunk
->
sctp_hdr
->
vtag
);
/* Make a transport for the bucket, Eliza... */
transport
=
sctp_transport_new
(
sctp_source
(
chunk
),
GFP_ATOMIC
);
if
(
!
transport
)
goto
nomem
;
/* Make a packet for the ABORT to go into. */
packet
=
t_new
(
sctp_packet_t
,
GFP_ATOMIC
);
if
(
!
packet
)
goto
nomem_packet
;
packet
=
sctp_packet_init
(
packet
,
transport
,
sport
,
dport
);
packet
=
sctp_packet_config
(
packet
,
vtag
,
0
,
NULL
);
/* Make an ABORT.
* This will set the T bit since we have no association.
*/
shut
=
sctp_make_shutdown_complete
(
NULL
,
chunk
);
if
(
!
shut
)
goto
nomem_chunk
;
/* Set the skb to the belonging sock for accounting. */
shut
->
skb
->
sk
=
ep
->
base
.
sk
;
sctp_packet_append_chunk
(
packet
,
shut
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
if
(
packet
)
{
/* Make an SHUTDOWN_COMPLETE.
* The T bit will be set if the asoc is NULL.
*/
shut
=
sctp_make_shutdown_complete
(
asoc
,
chunk
);
if
(
!
shut
)
{
sctp_ootb_pkt_free
(
packet
);
return
SCTP_DISPOSITION_NOMEM
;
}
return
SCTP_DISPOSITION_CONSUME
;
/* Set the skb to the belonging sock for accounting. */
shut
->
skb
->
sk
=
ep
->
base
.
sk
;
nomem_chunk:
sctp_packet_free
(
packet
);
sctp_packet_append_chunk
(
packet
,
shut
);
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_SEND_PKT
,
SCTP_PACKET
(
packet
));
nomem_packet:
sctp_transport_free
(
transport
);
return
SCTP_DISPOSITION_CONSUME
;
}
nomem:
return
SCTP_DISPOSITION_NOMEM
;
}
/*
* Process an unknown chunk.
...
...
@@ -3949,3 +4090,99 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
skb_pull
(
chunk
->
skb
,
(
num_blocks
+
num_dup_tsns
)
*
sizeof
(
__u32
));
return
sack
;
}
/* Create an ABORT packet to be sent as a response, with the specified
* error causes.
*/
sctp_packet_t
*
sctp_abort_pkt_new
(
const
sctp_endpoint_t
*
ep
,
const
sctp_association_t
*
asoc
,
sctp_chunk_t
*
chunk
,
const
void
*
payload
,
size_t
paylen
)
{
sctp_packet_t
*
packet
;
sctp_chunk_t
*
abort
;
packet
=
sctp_ootb_pkt_new
(
asoc
,
chunk
);
if
(
packet
)
{
/* Make an ABORT.
* The T bit will be set if the asoc is NULL.
*/
abort
=
sctp_make_abort
(
asoc
,
chunk
,
paylen
);
if
(
!
abort
)
{
sctp_ootb_pkt_free
(
packet
);
return
NULL
;
}
/* Add specified error causes, i.e., payload, to the
* end of the chunk.
*/
sctp_addto_chunk
(
abort
,
paylen
,
payload
);
/* Set the skb to the belonging sock for accounting. */
abort
->
skb
->
sk
=
ep
->
base
.
sk
;
sctp_packet_append_chunk
(
packet
,
abort
);
}
return
packet
;
}
/* Allocate a packet for responding in the OOTB conditions. */
sctp_packet_t
*
sctp_ootb_pkt_new
(
const
sctp_association_t
*
asoc
,
const
sctp_chunk_t
*
chunk
)
{
sctp_packet_t
*
packet
;
sctp_transport_t
*
transport
;
__u16
sport
;
__u16
dport
;
__u32
vtag
;
/* Get the source and destination port from the inbound packet. */
sport
=
ntohs
(
chunk
->
sctp_hdr
->
dest
);
dport
=
ntohs
(
chunk
->
sctp_hdr
->
source
);
/* The V-tag is going to be the same as the inbound packet if no
* association exists, otherwise, use the peer's vtag.
*/
if
(
asoc
)
{
vtag
=
asoc
->
peer
.
i
.
init_tag
;
}
else
{
vtag
=
ntohl
(
chunk
->
sctp_hdr
->
vtag
);
}
/* Make a transport for the bucket, Eliza... */
transport
=
sctp_transport_new
(
sctp_source
(
chunk
),
GFP_ATOMIC
);
if
(
!
transport
)
goto
nomem
;
/* Allocate a new packet for sending the response. */
packet
=
t_new
(
sctp_packet_t
,
GFP_ATOMIC
);
if
(
!
packet
)
goto
nomem_packet
;
packet
=
sctp_packet_init
(
packet
,
transport
,
sport
,
dport
);
packet
=
sctp_packet_config
(
packet
,
vtag
,
0
,
NULL
);
return
packet
;
nomem_packet:
sctp_transport_free
(
transport
);
nomem:
return
NULL
;
}
/* Free the packet allocated earlier for responding in the OOTB condition. */
void
sctp_ootb_pkt_free
(
sctp_packet_t
*
packet
)
{
sctp_transport_free
(
packet
->
transport
);
sctp_packet_free
(
packet
);
}
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