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
1967937f
Commit
1967937f
authored
Oct 28, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SCTP] ADDIP: Support for processing ASCONF chunks and respond with
ASCONF_ACK chunks.
parent
018c8581
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
330 additions
and
37 deletions
+330
-37
include/net/sctp/constants.h
include/net/sctp/constants.h
+1
-3
include/net/sctp/sm.h
include/net/sctp/sm.h
+4
-6
include/net/sctp/structs.h
include/net/sctp/structs.h
+2
-0
net/sctp/associola.c
net/sctp/associola.c
+43
-0
net/sctp/sm_make_chunk.c
net/sctp/sm_make_chunk.c
+224
-10
net/sctp/sm_statefuns.c
net/sctp/sm_statefuns.c
+49
-11
net/sctp/sm_statetable.c
net/sctp/sm_statetable.c
+7
-7
No files found.
include/net/sctp/constants.h
View file @
1967937f
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
...
...
@@ -75,8 +75,6 @@ enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
#define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1)
#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2)
#define SCTP_CID_ADDIP_MIN SCTP_CID_ASCONF
#define SCTP_CID_ADDIP_MAX SCTP_CID_ASCONF_ACK
#define SCTP_NUM_ADDIP_CHUNK_TYPES 2
/* These are the different flavours of event. */
...
...
include/net/sctp/sm.h
View file @
1967937f
...
...
@@ -268,15 +268,13 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
struct
sctp_chunk
*
sctp_make_asconf_update_ip
(
struct
sctp_association
*
,
union
sctp_addr
*
,
struct
sockaddr
*
,
int
,
int
);
int
,
__u16
);
struct
sctp_chunk
*
sctp_make_asconf_set_prim
(
struct
sctp_association
*
asoc
,
union
sctp_addr
*
addr
);
struct
sctp_chunk
*
sctp_make_asconf_ack
(
struct
sctp_association
*
asoc
,
int
serial
,
int
vparam_len
);
struct
sctp_chunk
*
sctp_make_asconf_ack
(
const
struct
sctp_association
*
asoc
,
__u32
serial
,
int
vparam_len
);
struct
sctp_chunk
*
sctp_process_asconf
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
int
vparam_len
);
struct
sctp_chunk
*
asconf
);
void
sctp_chunk_assign_tsn
(
struct
sctp_chunk
*
);
void
sctp_chunk_assign_ssn
(
struct
sctp_chunk
*
);
...
...
include/net/sctp/structs.h
View file @
1967937f
...
...
@@ -1708,6 +1708,8 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
struct
sctp_transport
*
sctp_assoc_add_peer
(
struct
sctp_association
*
,
const
union
sctp_addr
*
address
,
const
int
gfp
);
void
sctp_assoc_del_peer
(
struct
sctp_association
*
asoc
,
const
union
sctp_addr
*
addr
);
void
sctp_assoc_control_transport
(
struct
sctp_association
*
,
struct
sctp_transport
*
,
sctp_transport_cmd_t
,
sctp_sn_error_t
);
...
...
net/sctp/associola.c
View file @
1967937f
...
...
@@ -361,6 +361,10 @@ void sctp_association_free(struct sctp_association *asoc)
asoc
->
eyecatcher
=
0
;
/* Free any cached ASCONF_ACK chunk. */
if
(
asoc
->
addip_last_asconf_ack
)
sctp_chunk_free
(
asoc
->
addip_last_asconf_ack
);
sctp_association_put
(
asoc
);
}
...
...
@@ -524,6 +528,45 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
return
peer
;
}
/* Delete a transport address from an association. */
void
sctp_assoc_del_peer
(
struct
sctp_association
*
asoc
,
const
union
sctp_addr
*
addr
)
{
struct
list_head
*
pos
;
struct
list_head
*
temp
;
struct
sctp_transport
*
peer
=
NULL
;
struct
sctp_transport
*
transport
;
list_for_each_safe
(
pos
,
temp
,
&
asoc
->
peer
.
transport_addr_list
)
{
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
if
(
sctp_cmp_addr_exact
(
addr
,
&
transport
->
ipaddr
))
{
peer
=
transport
;
list_del
(
pos
);
break
;
}
}
/* The address we want delete is not in the association. */
if
(
!
peer
)
return
;
/* Get the first transport of asoc. */
pos
=
asoc
->
peer
.
transport_addr_list
.
next
;
transport
=
list_entry
(
pos
,
struct
sctp_transport
,
transports
);
/* Update any entries that match the peer to be deleted. */
if
(
asoc
->
peer
.
primary_path
==
peer
)
sctp_assoc_set_primary
(
asoc
,
transport
);
if
(
asoc
->
peer
.
active_path
==
peer
)
asoc
->
peer
.
active_path
=
transport
;
if
(
asoc
->
peer
.
retran_path
==
peer
)
asoc
->
peer
.
retran_path
=
transport
;
if
(
asoc
->
peer
.
last_data_from
==
peer
)
asoc
->
peer
.
last_data_from
=
transport
;
sctp_transport_free
(
peer
);
}
/* Lookup a transport by address. */
struct
sctp_transport
*
sctp_assoc_lookup_paddr
(
const
struct
sctp_association
*
asoc
,
...
...
net/sctp/sm_make_chunk.c
View file @
1967937f
...
...
@@ -1441,6 +1441,7 @@ struct sctp_association *sctp_unpack_cookie(
retval
->
next_tsn
=
retval
->
c
.
initial_tsn
;
retval
->
ctsn_ack_point
=
retval
->
next_tsn
-
1
;
retval
->
addip_serial
=
retval
->
c
.
initial_tsn
;
/* The INIT stuff will be done by the side effects. */
return
retval
;
...
...
@@ -2035,7 +2036,7 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
if
(
!
retval
)
return
NULL
;
asconf
.
serial
=
asoc
->
addip_serial
++
;
asconf
.
serial
=
htonl
(
asoc
->
addip_serial
++
)
;
retval
->
subh
.
addip_hdr
=
sctp_addto_chunk
(
retval
,
sizeof
(
asconf
),
&
asconf
);
...
...
@@ -2073,7 +2074,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
union
sctp_addr
*
laddr
,
struct
sockaddr
*
addrs
,
int
addrcnt
,
int
flags
)
__u16
flags
)
{
sctp_addip_param_t
param
;
struct
sctp_chunk
*
retval
;
...
...
@@ -2112,7 +2113,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
addr_param_len
=
af
->
to_addr_param
(
addr
,
&
addr_param
);
param
.
param_hdr
.
type
=
flags
;
param
.
param_hdr
.
length
=
htons
(
paramlen
+
addr_param_len
);
param
.
crr_id
=
htonl
(
i
)
;
param
.
crr_id
=
i
;
sctp_addto_chunk
(
retval
,
paramlen
,
&
param
);
sctp_addto_chunk
(
retval
,
addr_param_len
,
&
addr_param
);
...
...
@@ -2185,8 +2186,8 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
*
* Create an ASCONF_ACK chunk with enough space for the parameter responses.
*/
struct
sctp_chunk
*
sctp_make_asconf_ack
(
struct
sctp_association
*
asoc
,
int
serial
,
int
vparam_len
)
struct
sctp_chunk
*
sctp_make_asconf_ack
(
const
struct
sctp_association
*
asoc
,
__u32
serial
,
int
vparam_len
)
{
sctp_addiphdr_t
asconf
;
struct
sctp_chunk
*
retval
;
...
...
@@ -2197,7 +2198,7 @@ struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
if
(
!
retval
)
return
NULL
;
asconf
.
serial
=
serial
;
asconf
.
serial
=
htonl
(
serial
)
;
retval
->
subh
.
addip_hdr
=
sctp_addto_chunk
(
retval
,
sizeof
(
asconf
),
&
asconf
);
...
...
@@ -2205,10 +2206,223 @@ struct sctp_chunk *sctp_make_asconf_ack(struct sctp_association *asoc,
return
retval
;
}
/* Add response parameters to an ASCONF_ACK chunk. */
void
sctp_add_asconf_response
(
struct
sctp_chunk
*
chunk
,
__u32
crr_id
,
__u16
err_code
,
sctp_addip_param_t
*
asconf_param
)
{
sctp_addip_param_t
ack_param
;
sctp_errhdr_t
err_param
;
int
asconf_param_len
=
0
;
int
err_param_len
=
0
;
__u16
response_type
;
if
(
SCTP_ERROR_NO_ERROR
==
err_code
)
{
response_type
=
SCTP_PARAM_SUCCESS_REPORT
;
}
else
{
response_type
=
SCTP_PARAM_ERR_CAUSE
;
err_param_len
=
sizeof
(
err_param
);
if
(
asconf_param
)
asconf_param_len
=
ntohs
(
asconf_param
->
param_hdr
.
length
);
}
/* Add Success Indication or Error Cause Indication parameter. */
ack_param
.
param_hdr
.
type
=
response_type
;
ack_param
.
param_hdr
.
length
=
htons
(
sizeof
(
ack_param
)
+
err_param_len
+
asconf_param_len
);
ack_param
.
crr_id
=
crr_id
;
sctp_addto_chunk
(
chunk
,
sizeof
(
ack_param
),
&
ack_param
);
if
(
SCTP_ERROR_NO_ERROR
==
err_code
)
return
;
/* Add Error Cause parameter. */
err_param
.
cause
=
err_code
;
err_param
.
length
=
htons
(
err_param_len
+
asconf_param_len
);
sctp_addto_chunk
(
chunk
,
err_param_len
,
&
err_param
);
/* Add the failed TLV copied from ASCONF chunk. */
if
(
asconf_param
)
sctp_addto_chunk
(
chunk
,
asconf_param_len
,
asconf_param
);
}
/* Process a asconf parameter. */
__u16
sctp_process_asconf_param
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
sctp_addip_param_t
*
asconf_param
,
union
sctp_addr_param
*
addr_param
)
{
struct
sctp_transport
*
peer
;
struct
sctp_af
*
af
;
union
sctp_addr
addr
;
struct
list_head
*
pos
;
af
=
sctp_get_af_specific
(
param_type2af
(
addr_param
->
v4
.
param_hdr
.
type
));
if
(
unlikely
(
!
af
))
return
SCTP_ERROR_INV_PARAM
;
af
->
from_addr_param
(
&
addr
,
addr_param
,
asoc
->
peer
.
port
,
0
);
switch
(
asconf_param
->
param_hdr
.
type
)
{
case
SCTP_PARAM_ADD_IP
:
/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
* request and does not have the local resources to add this
* new address to the association, it MUST return an Error
* Cause TLV set to the new error code 'Operation Refused
* Due to Resource Shortage'.
*/
peer
=
sctp_assoc_add_peer
(
asoc
,
&
addr
,
GFP_ATOMIC
);
if
(
!
peer
)
return
SCTP_ERROR_RSRC_LOW
;
/* Start the heartbeat timer. */
if
(
!
mod_timer
(
&
peer
->
hb_timer
,
sctp_transport_timeout
(
peer
)))
sctp_transport_hold
(
peer
);
break
;
case
SCTP_PARAM_DEL_IP
:
/* ADDIP 4.3 D7) If a request is received to delete the
* last remaining IP address of a peer endpoint, the receiver
* MUST send an Error Cause TLV with the error cause set to the
* new error code 'Request to Delete Last Remaining IP Address'.
*/
pos
=
asoc
->
peer
.
transport_addr_list
.
next
;
if
(
pos
->
next
==
&
asoc
->
peer
.
transport_addr_list
)
return
SCTP_ERROR_DEL_LAST_IP
;
/* ADDIP 4.3 D8) If a request is received to delete an IP
* address which is also the source address of the IP packet
* which contained the ASCONF chunk, the receiver MUST reject
* this request. To reject the request the receiver MUST send
* an Error Cause TLV set to the new error code 'Request to
* Delete Source IP Address'
*/
if
(
sctp_cmp_addr_exact
(
sctp_source
(
asconf
),
&
addr
))
return
SCTP_ERROR_DEL_SRC_IP
;
sctp_assoc_del_peer
(
asoc
,
&
addr
);
break
;
case
SCTP_PARAM_SET_PRIMARY
:
peer
=
sctp_assoc_lookup_paddr
(
asoc
,
&
addr
);
if
(
!
peer
)
return
SCTP_ERROR_INV_PARAM
;
sctp_assoc_set_primary
(
asoc
,
peer
);
break
;
default:
return
SCTP_ERROR_INV_PARAM
;
break
;
}
return
SCTP_ERROR_NO_ERROR
;
}
/* Process an incoming ASCONF chunk with the next expected serial no. and
* return an ASCONF_ACK chunk to be sent in response.
*/
struct
sctp_chunk
*
sctp_process_asconf
(
struct
sctp_association
*
asoc
,
struct
sctp_chunk
*
asconf
,
int
vparam_len
)
struct
sctp_chunk
*
asconf
)
{
// FIXME: process asconf chunk
return
NULL
;
sctp_addiphdr_t
*
hdr
;
union
sctp_addr_param
*
addr_param
;
sctp_addip_param_t
*
asconf_param
;
struct
sctp_chunk
*
asconf_ack
;
__u16
err_code
;
int
length
=
0
;
int
chunk_len
=
ntohs
(
asconf
->
chunk_hdr
->
length
);
int
asconf_param_len
;
__u32
serial
;
int
all_param_pass
=
1
;
hdr
=
(
sctp_addiphdr_t
*
)
asconf
->
skb
->
data
;
serial
=
ntohl
(
hdr
->
serial
);
/* Skip the chunkhdr. */
chunk_len
-=
sizeof
(
sctp_chunkhdr_t
);
/* Skip the addiphdr and store a pointer to address parameter. */
length
=
sizeof
(
sctp_addiphdr_t
);
addr_param
=
(
union
sctp_addr_param
*
)
skb_pull
(
asconf
->
skb
,
length
);
chunk_len
-=
length
;
/* Skip the address parameter and store a pointer to the first
* asconf paramter.
*/
length
=
ntohs
(
addr_param
->
v4
.
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)
skb_pull
(
asconf
->
skb
,
length
);
chunk_len
-=
length
;
/* create an ASCONF_ACK chunk.
* Based on the definitions of parameters, we know that the size of
* ASCONF_ACK parameters are less than or equal to the twice of ASCONF
* paramter.
*/
asconf_ack
=
sctp_make_asconf_ack
(
asoc
,
serial
,
chunk_len
*
2
);
if
(
!
asconf_ack
)
goto
done
;
/* Process the TLVs contained within the ASCONF chunk. */
while
(
chunk_len
>
0
)
{
asconf_param_len
=
ntohs
(
asconf_param
->
param_hdr
.
length
);
length
=
sizeof
(
sctp_addip_param_t
);
/* Unrecognized or unsupported paramter. */
if
(
asconf_param_len
<=
length
)
{
sctp_add_asconf_response
(
asconf_ack
,
0
,
SCTP_ERROR_UNKNOWN_PARAM
,
NULL
);
goto
done
;
}
addr_param
=
(
union
sctp_addr_param
*
)
skb_pull
(
asconf
->
skb
,
length
);
err_code
=
sctp_process_asconf_param
(
asoc
,
asconf
,
asconf_param
,
addr_param
);
/* ADDIP 4.1 A7)
* If an error response is received for a TLV parameter,
* all TLVs with no response before the failed TLV are
* considered successful if not reported. All TLVs after
* the failed response are considered unsuccessful unless
* a specific success indication is present for the parameter.
*/
if
(
SCTP_ERROR_NO_ERROR
!=
err_code
)
all_param_pass
=
0
;
if
(
!
all_param_pass
)
sctp_add_asconf_response
(
asconf_ack
,
asconf_param
->
crr_id
,
err_code
,
asconf_param
);
/* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add
* an IP address sends an 'Out of Resource' in its response, it
* MUST also fail any subsequent add or delete requests bundled
* in the ASCONF.
*/
if
(
SCTP_ERROR_RSRC_LOW
==
err_code
)
goto
done
;
/* Move to the next ASCONF param. */
length
=
ntohs
(
addr_param
->
v4
.
param_hdr
.
length
);
asconf_param
=
(
sctp_addip_param_t
*
)
skb_pull
(
asconf
->
skb
,
length
);
chunk_len
-=
asconf_param_len
;
}
done:
asoc
->
peer
.
addip_serial
++
;
/* If we are sending a new ASCONF_ACK hold a reference to it in assoc
* after freeing the reference to old asconf ack if any.
*/
if
(
asconf_ack
)
{
if
(
asoc
->
addip_last_asconf_ack
)
sctp_chunk_free
(
asoc
->
addip_last_asconf_ack
);
sctp_chunk_hold
(
asconf_ack
);
asoc
->
addip_last_asconf_ack
=
asconf_ack
;
}
return
asconf_ack
;
}
net/sctp/sm_statefuns.c
View file @
1967937f
...
...
@@ -3066,19 +3066,57 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
return
sctp_sf_shut_8_4_5
(
ep
,
NULL
,
type
,
arg
,
commands
);
}
/*
* ADDIP Section 4.2 Upon reception of an ASCONF Chunk
* When an endpoint receive an ASCONF Chunk from the remote peer
* special procedures MAY be needed to identify the association the
* ASCONF Chunk is associated with. To properly find the association
* the following procedures should be L1 to L4 and C1 to C5
*/
/* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. */
sctp_disposition_t
sctp_sf_do_asconf
(
const
struct
sctp_endpoint
*
ep
,
const
struct
sctp_association
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
const
struct
sctp_association
*
asoc
,
const
sctp_subtype_t
type
,
void
*
arg
,
sctp_cmd_seq_t
*
commands
)
{
// FIXME: Handle the ASCONF chunk
struct
sctp_chunk
*
chunk
=
arg
;
struct
sctp_chunk
*
asconf_ack
=
NULL
;
sctp_addiphdr_t
*
hdr
;
__u32
serial
;
hdr
=
(
sctp_addiphdr_t
*
)
chunk
->
skb
->
data
;
serial
=
ntohl
(
hdr
->
serial
);
/* ADDIP 4.2 C1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable
* 'Peer-Serial-Number'.
*/
if
(
serial
==
asoc
->
peer
.
addip_serial
+
1
)
{
/* ADDIP 4.2 C2) If the value found in the serial number is
* equal to the ('Peer-Serial-Number' + 1), the endpoint MUST
* do V1-V5.
*/
asconf_ack
=
sctp_process_asconf
((
struct
sctp_association
*
)
asoc
,
chunk
);
if
(
!
asconf_ack
)
return
SCTP_DISPOSITION_NOMEM
;
}
else
if
(
serial
==
asoc
->
peer
.
addip_serial
)
{
/* ADDIP 4.2 C3) If the value found in the serial number is
* equal to the value stored in the 'Peer-Serial-Number'
* IMPLEMENTATION NOTE: As an optimization a receiver may wish
* to save the last ASCONF-ACK for some predetermined period of * time and instead of re-processing the ASCONF (with the same
* serial number) it may just re-transmit the ASCONF-ACK.
*/
if
(
asoc
->
addip_last_asconf_ack
)
asconf_ack
=
asoc
->
addip_last_asconf_ack
;
else
return
SCTP_DISPOSITION_DISCARD
;
}
else
{
/* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since
* it must be either a stale packet or from an attacker.
*/
return
SCTP_DISPOSITION_DISCARD
;
}
/* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent
* back to the source address contained in the IP header of the ASCONF
* being responded to.
*/
sctp_add_cmd_sf
(
commands
,
SCTP_CMD_REPLY
,
SCTP_CHUNK
(
asconf_ack
));
return
SCTP_DISPOSITION_CONSUME
;
}
...
...
net/sctp/sm_statetable.c
View file @
1967937f
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
*
...
...
@@ -921,14 +921,14 @@ const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
if
(
state
>
SCTP_STATE_MAX
)
return
&
bug
;
if
(
cid
>=
0
&&
cid
<=
SCTP_CID_BASE_MAX
)
{
if
(
cid
>=
0
&&
cid
<=
SCTP_CID_BASE_MAX
)
return
&
chunk_event_table
[
cid
][
state
];
}
if
(
cid
>=
SCTP_CID_ADDIP_MIN
&&
cid
<=
SCTP_CID_ADDIP_MAX
)
{
return
&
addip_chunk_event_table
[
cid
-
SCTP_CID_ADDIP_MIN
][
state
];
}
if
(
cid
==
SCTP_CID_ASCONF
)
return
&
addip_chunk_event_table
[
0
][
state
];
if
(
cid
==
SCTP_CID_ASCONF_ACK
)
return
&
addip_chunk_event_table
[
1
][
state
];
return
&
chunk_event_table_unknown
[
state
];
}
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