[SCTP]: Implement the Supported Extensions Parameter
SCTP Supported Extenions parameter is specified in Section 4.2.7 of the ADD-IP draft (soon to be RFC). The parameter is encoded as: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Parameter Type = 0x8008 | Parameter Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | CHUNK TYPE 1 | CHUNK TYPE 2 | CHUNK TYPE 3 | CHUNK TYPE 4 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | CHUNK TYPE N | PAD | PAD | PAD | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ It contains a list of chunks that a particular SCTP extension uses. Current extensions supported are Partial Reliability (FWD-TSN) and ADD-IP (ASCONF and ASCONF-ACK). When implementing new extensions (AUTH, PKT-DROP, etc..), new chunks need to be added to this parameter. Parameter processing would be modified to negotiate support for these new features. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
76c72d4f44
commit
131a47e31a
@@ -180,6 +180,9 @@ typedef enum {
|
|||||||
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12),
|
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12),
|
||||||
SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000),
|
SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000),
|
||||||
|
|
||||||
|
/* Add-IP: Supported Extensions, Section 4.2 */
|
||||||
|
SCTP_PARAM_SUPPORTED_EXT = __constant_htons(0x8008),
|
||||||
|
|
||||||
/* PR-SCTP Sec 3.1 */
|
/* PR-SCTP Sec 3.1 */
|
||||||
SCTP_PARAM_FWD_TSN_SUPPORT = __constant_htons(0xc000),
|
SCTP_PARAM_FWD_TSN_SUPPORT = __constant_htons(0xc000),
|
||||||
|
|
||||||
@@ -296,6 +299,12 @@ typedef struct sctp_adaptation_ind_param {
|
|||||||
__be32 adaptation_ind;
|
__be32 adaptation_ind;
|
||||||
} __attribute__((packed)) sctp_adaptation_ind_param_t;
|
} __attribute__((packed)) sctp_adaptation_ind_param_t;
|
||||||
|
|
||||||
|
/* ADDIP Section 4.2.7 Supported Extensions Parameter */
|
||||||
|
typedef struct sctp_supported_ext_param {
|
||||||
|
struct sctp_paramhdr param_hdr;
|
||||||
|
__u8 chunks[0];
|
||||||
|
} __attribute__((packed)) sctp_supported_ext_param_t;
|
||||||
|
|
||||||
/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
|
/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
|
||||||
* The INIT ACK chunk is used to acknowledge the initiation of an SCTP
|
* The INIT ACK chunk is used to acknowledge the initiation of an SCTP
|
||||||
* association.
|
* association.
|
||||||
|
@@ -440,6 +440,7 @@ union sctp_params {
|
|||||||
struct sctp_ipv6addr_param *v6;
|
struct sctp_ipv6addr_param *v6;
|
||||||
union sctp_addr_param *addr;
|
union sctp_addr_param *addr;
|
||||||
struct sctp_adaptation_ind_param *aind;
|
struct sctp_adaptation_ind_param *aind;
|
||||||
|
struct sctp_supported_ext_param *ext;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RFC 2960. Section 3.3.5 Heartbeat.
|
/* RFC 2960. Section 3.3.5 Heartbeat.
|
||||||
|
@@ -179,6 +179,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
|||||||
sctp_supported_addrs_param_t sat;
|
sctp_supported_addrs_param_t sat;
|
||||||
__be16 types[2];
|
__be16 types[2];
|
||||||
sctp_adaptation_ind_param_t aiparam;
|
sctp_adaptation_ind_param_t aiparam;
|
||||||
|
sctp_supported_ext_param_t ext_param;
|
||||||
|
int num_ext = 0;
|
||||||
|
__u8 extensions[3];
|
||||||
|
|
||||||
/* RFC 2960 3.3.2 Initiation (INIT) (1)
|
/* RFC 2960 3.3.2 Initiation (INIT) (1)
|
||||||
*
|
*
|
||||||
@@ -202,11 +205,31 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
|||||||
|
|
||||||
chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
|
chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
|
||||||
chunksize += sizeof(ecap_param);
|
chunksize += sizeof(ecap_param);
|
||||||
if (sctp_prsctp_enable)
|
if (sctp_prsctp_enable) {
|
||||||
chunksize += sizeof(prsctp_param);
|
chunksize += sizeof(prsctp_param);
|
||||||
|
extensions[num_ext] = SCTP_CID_FWD_TSN;
|
||||||
|
num_ext += 1;
|
||||||
|
}
|
||||||
|
/* ADDIP: Section 4.2.7:
|
||||||
|
* An implementation supporting this extension [ADDIP] MUST list
|
||||||
|
* the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and
|
||||||
|
* INIT-ACK parameters.
|
||||||
|
* XXX: We don't support AUTH just yet, so don't list it. AUTH
|
||||||
|
* support should add it.
|
||||||
|
*/
|
||||||
|
if (sctp_addip_enable) {
|
||||||
|
extensions[num_ext] = SCTP_CID_ASCONF;
|
||||||
|
extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
|
||||||
|
num_ext += 2;
|
||||||
|
}
|
||||||
|
|
||||||
chunksize += sizeof(aiparam);
|
chunksize += sizeof(aiparam);
|
||||||
chunksize += vparam_len;
|
chunksize += vparam_len;
|
||||||
|
|
||||||
|
/* If we have any extensions to report, account for that */
|
||||||
|
if (num_ext)
|
||||||
|
chunksize += sizeof(sctp_supported_ext_param_t) + num_ext;
|
||||||
|
|
||||||
/* RFC 2960 3.3.2 Initiation (INIT) (1)
|
/* RFC 2960 3.3.2 Initiation (INIT) (1)
|
||||||
*
|
*
|
||||||
* Note 3: An INIT chunk MUST NOT contain more than one Host
|
* Note 3: An INIT chunk MUST NOT contain more than one Host
|
||||||
@@ -241,12 +264,27 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
|||||||
sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
|
sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
|
||||||
|
|
||||||
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
|
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
|
||||||
|
|
||||||
|
/* Add the supported extensions paramter. Be nice and add this
|
||||||
|
* fist before addiding the parameters for the extensions themselves
|
||||||
|
*/
|
||||||
|
if (num_ext) {
|
||||||
|
ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
|
||||||
|
ext_param.param_hdr.length =
|
||||||
|
htons(sizeof(sctp_supported_ext_param_t) + num_ext);
|
||||||
|
sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t),
|
||||||
|
&ext_param);
|
||||||
|
sctp_addto_chunk(retval, num_ext, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
if (sctp_prsctp_enable)
|
if (sctp_prsctp_enable)
|
||||||
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
|
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
|
||||||
|
|
||||||
aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
|
aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
|
||||||
aiparam.param_hdr.length = htons(sizeof(aiparam));
|
aiparam.param_hdr.length = htons(sizeof(aiparam));
|
||||||
aiparam.adaptation_ind = htonl(sp->adaptation_ind);
|
aiparam.adaptation_ind = htonl(sp->adaptation_ind);
|
||||||
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
|
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
|
||||||
|
|
||||||
nodata:
|
nodata:
|
||||||
kfree(addrs.v);
|
kfree(addrs.v);
|
||||||
return retval;
|
return retval;
|
||||||
@@ -264,6 +302,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
|||||||
int cookie_len;
|
int cookie_len;
|
||||||
size_t chunksize;
|
size_t chunksize;
|
||||||
sctp_adaptation_ind_param_t aiparam;
|
sctp_adaptation_ind_param_t aiparam;
|
||||||
|
sctp_supported_ext_param_t ext_param;
|
||||||
|
int num_ext = 0;
|
||||||
|
__u8 extensions[3];
|
||||||
|
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
|
|
||||||
@@ -294,9 +335,19 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
|||||||
chunksize += sizeof(ecap_param);
|
chunksize += sizeof(ecap_param);
|
||||||
|
|
||||||
/* Tell peer that we'll do PR-SCTP only if peer advertised. */
|
/* Tell peer that we'll do PR-SCTP only if peer advertised. */
|
||||||
if (asoc->peer.prsctp_capable)
|
if (asoc->peer.prsctp_capable) {
|
||||||
chunksize += sizeof(prsctp_param);
|
chunksize += sizeof(prsctp_param);
|
||||||
|
extensions[num_ext] = SCTP_CID_FWD_TSN;
|
||||||
|
num_ext += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sctp_addip_enable) {
|
||||||
|
extensions[num_ext] = SCTP_CID_ASCONF;
|
||||||
|
extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
|
||||||
|
num_ext += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunksize += sizeof(ext_param) + num_ext;
|
||||||
chunksize += sizeof(aiparam);
|
chunksize += sizeof(aiparam);
|
||||||
|
|
||||||
/* Now allocate and fill out the chunk. */
|
/* Now allocate and fill out the chunk. */
|
||||||
@@ -314,6 +365,14 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
|||||||
sctp_addto_chunk(retval, cookie_len, cookie);
|
sctp_addto_chunk(retval, cookie_len, cookie);
|
||||||
if (asoc->peer.ecn_capable)
|
if (asoc->peer.ecn_capable)
|
||||||
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
|
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
|
||||||
|
if (num_ext) {
|
||||||
|
ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT;
|
||||||
|
ext_param.param_hdr.length =
|
||||||
|
htons(sizeof(sctp_supported_ext_param_t) + num_ext);
|
||||||
|
sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t),
|
||||||
|
&ext_param);
|
||||||
|
sctp_addto_chunk(retval, num_ext, extensions);
|
||||||
|
}
|
||||||
if (asoc->peer.prsctp_capable)
|
if (asoc->peer.prsctp_capable)
|
||||||
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
|
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
|
||||||
|
|
||||||
@@ -1664,6 +1723,28 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sctp_process_ext_param(struct sctp_association *asoc,
|
||||||
|
union sctp_params param)
|
||||||
|
{
|
||||||
|
__u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_ext; i++) {
|
||||||
|
switch (param.ext->chunks[i]) {
|
||||||
|
case SCTP_CID_FWD_TSN:
|
||||||
|
if (sctp_prsctp_enable &&
|
||||||
|
!asoc->peer.prsctp_capable)
|
||||||
|
asoc->peer.prsctp_capable = 1;
|
||||||
|
break;
|
||||||
|
case SCTP_CID_ASCONF:
|
||||||
|
case SCTP_CID_ASCONF_ACK:
|
||||||
|
/* don't need to do anything for ASCONF */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* RFC 3.2.1 & the Implementers Guide 2.2.
|
/* RFC 3.2.1 & the Implementers Guide 2.2.
|
||||||
*
|
*
|
||||||
* The Parameter Types are encoded such that the
|
* The Parameter Types are encoded such that the
|
||||||
@@ -1780,11 +1861,13 @@ static int sctp_verify_param(const struct sctp_association *asoc,
|
|||||||
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
|
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
|
||||||
case SCTP_PARAM_ECN_CAPABLE:
|
case SCTP_PARAM_ECN_CAPABLE:
|
||||||
case SCTP_PARAM_ADAPTATION_LAYER_IND:
|
case SCTP_PARAM_ADAPTATION_LAYER_IND:
|
||||||
|
case SCTP_PARAM_SUPPORTED_EXT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCTP_PARAM_HOST_NAME_ADDRESS:
|
case SCTP_PARAM_HOST_NAME_ADDRESS:
|
||||||
/* Tell the peer, we won't support this param. */
|
/* Tell the peer, we won't support this param. */
|
||||||
return sctp_process_hn_param(asoc, param, chunk, err_chunk);
|
return sctp_process_hn_param(asoc, param, chunk, err_chunk);
|
||||||
|
|
||||||
case SCTP_PARAM_FWD_TSN_SUPPORT:
|
case SCTP_PARAM_FWD_TSN_SUPPORT:
|
||||||
if (sctp_prsctp_enable)
|
if (sctp_prsctp_enable)
|
||||||
break;
|
break;
|
||||||
@@ -2129,6 +2212,10 @@ static int sctp_process_param(struct sctp_association *asoc,
|
|||||||
asoc->peer.adaptation_ind = param.aind->adaptation_ind;
|
asoc->peer.adaptation_ind = param.aind->adaptation_ind;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SCTP_PARAM_SUPPORTED_EXT:
|
||||||
|
sctp_process_ext_param(asoc, param);
|
||||||
|
break;
|
||||||
|
|
||||||
case SCTP_PARAM_FWD_TSN_SUPPORT:
|
case SCTP_PARAM_FWD_TSN_SUPPORT:
|
||||||
if (sctp_prsctp_enable) {
|
if (sctp_prsctp_enable) {
|
||||||
asoc->peer.prsctp_capable = 1;
|
asoc->peer.prsctp_capable = 1;
|
||||||
|
Reference in New Issue
Block a user