diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-09-16 18:53:56 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:51:23 -0400 |
commit | 131a47e31ab1a9defd50ff16b04008ab94c21c0d (patch) | |
tree | 8ac3eb522333d1b6f9bd5741a8decbfb4220f432 | |
parent | 76c72d4f44ec5fb7f88eda8a0d3aa30922c891d1 (diff) |
[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>
-rw-r--r-- | include/linux/sctp.h | 9 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 1 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 91 |
3 files changed, 99 insertions, 2 deletions
diff --git a/include/linux/sctp.h b/include/linux/sctp.h index d70df61a029f..f4d717b72ddd 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h | |||
@@ -180,6 +180,9 @@ typedef enum { | |||
180 | SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), | 180 | SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), |
181 | SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), | 181 | SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), |
182 | 182 | ||
183 | /* Add-IP: Supported Extensions, Section 4.2 */ | ||
184 | SCTP_PARAM_SUPPORTED_EXT = __constant_htons(0x8008), | ||
185 | |||
183 | /* PR-SCTP Sec 3.1 */ | 186 | /* PR-SCTP Sec 3.1 */ |
184 | SCTP_PARAM_FWD_TSN_SUPPORT = __constant_htons(0xc000), | 187 | SCTP_PARAM_FWD_TSN_SUPPORT = __constant_htons(0xc000), |
185 | 188 | ||
@@ -296,6 +299,12 @@ typedef struct sctp_adaptation_ind_param { | |||
296 | __be32 adaptation_ind; | 299 | __be32 adaptation_ind; |
297 | } __attribute__((packed)) sctp_adaptation_ind_param_t; | 300 | } __attribute__((packed)) sctp_adaptation_ind_param_t; |
298 | 301 | ||
302 | /* ADDIP Section 4.2.7 Supported Extensions Parameter */ | ||
303 | typedef struct sctp_supported_ext_param { | ||
304 | struct sctp_paramhdr param_hdr; | ||
305 | __u8 chunks[0]; | ||
306 | } __attribute__((packed)) sctp_supported_ext_param_t; | ||
307 | |||
299 | /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): | 308 | /* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): |
300 | * The INIT ACK chunk is used to acknowledge the initiation of an SCTP | 309 | * The INIT ACK chunk is used to acknowledge the initiation of an SCTP |
301 | * association. | 310 | * association. |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 67c91d01b635..b4812a2d3bb0 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -440,6 +440,7 @@ union sctp_params { | |||
440 | struct sctp_ipv6addr_param *v6; | 440 | struct sctp_ipv6addr_param *v6; |
441 | union sctp_addr_param *addr; | 441 | union sctp_addr_param *addr; |
442 | struct sctp_adaptation_ind_param *aind; | 442 | struct sctp_adaptation_ind_param *aind; |
443 | struct sctp_supported_ext_param *ext; | ||
443 | }; | 444 | }; |
444 | 445 | ||
445 | /* RFC 2960. Section 3.3.5 Heartbeat. | 446 | /* RFC 2960. Section 3.3.5 Heartbeat. |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index d84e575f7409..71cc204a9ea5 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -179,6 +179,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
179 | sctp_supported_addrs_param_t sat; | 179 | sctp_supported_addrs_param_t sat; |
180 | __be16 types[2]; | 180 | __be16 types[2]; |
181 | sctp_adaptation_ind_param_t aiparam; | 181 | sctp_adaptation_ind_param_t aiparam; |
182 | sctp_supported_ext_param_t ext_param; | ||
183 | int num_ext = 0; | ||
184 | __u8 extensions[3]; | ||
182 | 185 | ||
183 | /* RFC 2960 3.3.2 Initiation (INIT) (1) | 186 | /* RFC 2960 3.3.2 Initiation (INIT) (1) |
184 | * | 187 | * |
@@ -202,11 +205,31 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
202 | 205 | ||
203 | chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); | 206 | chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); |
204 | chunksize += sizeof(ecap_param); | 207 | chunksize += sizeof(ecap_param); |
205 | if (sctp_prsctp_enable) | 208 | if (sctp_prsctp_enable) { |
206 | chunksize += sizeof(prsctp_param); | 209 | chunksize += sizeof(prsctp_param); |
210 | extensions[num_ext] = SCTP_CID_FWD_TSN; | ||
211 | num_ext += 1; | ||
212 | } | ||
213 | /* ADDIP: Section 4.2.7: | ||
214 | * An implementation supporting this extension [ADDIP] MUST list | ||
215 | * the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and | ||
216 | * INIT-ACK parameters. | ||
217 | * XXX: We don't support AUTH just yet, so don't list it. AUTH | ||
218 | * support should add it. | ||
219 | */ | ||
220 | if (sctp_addip_enable) { | ||
221 | extensions[num_ext] = SCTP_CID_ASCONF; | ||
222 | extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; | ||
223 | num_ext += 2; | ||
224 | } | ||
225 | |||
207 | chunksize += sizeof(aiparam); | 226 | chunksize += sizeof(aiparam); |
208 | chunksize += vparam_len; | 227 | chunksize += vparam_len; |
209 | 228 | ||
229 | /* If we have any extensions to report, account for that */ | ||
230 | if (num_ext) | ||
231 | chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; | ||
232 | |||
210 | /* RFC 2960 3.3.2 Initiation (INIT) (1) | 233 | /* RFC 2960 3.3.2 Initiation (INIT) (1) |
211 | * | 234 | * |
212 | * Note 3: An INIT chunk MUST NOT contain more than one Host | 235 | * 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, | |||
241 | sctp_addto_chunk(retval, num_types * sizeof(__u16), &types); | 264 | sctp_addto_chunk(retval, num_types * sizeof(__u16), &types); |
242 | 265 | ||
243 | sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); | 266 | sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); |
267 | |||
268 | /* Add the supported extensions paramter. Be nice and add this | ||
269 | * fist before addiding the parameters for the extensions themselves | ||
270 | */ | ||
271 | if (num_ext) { | ||
272 | ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT; | ||
273 | ext_param.param_hdr.length = | ||
274 | htons(sizeof(sctp_supported_ext_param_t) + num_ext); | ||
275 | sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t), | ||
276 | &ext_param); | ||
277 | sctp_addto_chunk(retval, num_ext, extensions); | ||
278 | } | ||
279 | |||
244 | if (sctp_prsctp_enable) | 280 | if (sctp_prsctp_enable) |
245 | sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); | 281 | sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); |
282 | |||
246 | aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND; | 283 | aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND; |
247 | aiparam.param_hdr.length = htons(sizeof(aiparam)); | 284 | aiparam.param_hdr.length = htons(sizeof(aiparam)); |
248 | aiparam.adaptation_ind = htonl(sp->adaptation_ind); | 285 | aiparam.adaptation_ind = htonl(sp->adaptation_ind); |
249 | sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); | 286 | sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); |
287 | |||
250 | nodata: | 288 | nodata: |
251 | kfree(addrs.v); | 289 | kfree(addrs.v); |
252 | return retval; | 290 | return retval; |
@@ -264,6 +302,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
264 | int cookie_len; | 302 | int cookie_len; |
265 | size_t chunksize; | 303 | size_t chunksize; |
266 | sctp_adaptation_ind_param_t aiparam; | 304 | sctp_adaptation_ind_param_t aiparam; |
305 | sctp_supported_ext_param_t ext_param; | ||
306 | int num_ext = 0; | ||
307 | __u8 extensions[3]; | ||
267 | 308 | ||
268 | retval = NULL; | 309 | retval = NULL; |
269 | 310 | ||
@@ -294,9 +335,19 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
294 | chunksize += sizeof(ecap_param); | 335 | chunksize += sizeof(ecap_param); |
295 | 336 | ||
296 | /* Tell peer that we'll do PR-SCTP only if peer advertised. */ | 337 | /* Tell peer that we'll do PR-SCTP only if peer advertised. */ |
297 | if (asoc->peer.prsctp_capable) | 338 | if (asoc->peer.prsctp_capable) { |
298 | chunksize += sizeof(prsctp_param); | 339 | chunksize += sizeof(prsctp_param); |
340 | extensions[num_ext] = SCTP_CID_FWD_TSN; | ||
341 | num_ext += 1; | ||
342 | } | ||
299 | 343 | ||
344 | if (sctp_addip_enable) { | ||
345 | extensions[num_ext] = SCTP_CID_ASCONF; | ||
346 | extensions[num_ext+1] = SCTP_CID_ASCONF_ACK; | ||
347 | num_ext += 2; | ||
348 | } | ||
349 | |||
350 | chunksize += sizeof(ext_param) + num_ext; | ||
300 | chunksize += sizeof(aiparam); | 351 | chunksize += sizeof(aiparam); |
301 | 352 | ||
302 | /* Now allocate and fill out the chunk. */ | 353 | /* Now allocate and fill out the chunk. */ |
@@ -314,6 +365,14 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
314 | sctp_addto_chunk(retval, cookie_len, cookie); | 365 | sctp_addto_chunk(retval, cookie_len, cookie); |
315 | if (asoc->peer.ecn_capable) | 366 | if (asoc->peer.ecn_capable) |
316 | sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); | 367 | sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); |
368 | if (num_ext) { | ||
369 | ext_param.param_hdr.type = SCTP_PARAM_SUPPORTED_EXT; | ||
370 | ext_param.param_hdr.length = | ||
371 | htons(sizeof(sctp_supported_ext_param_t) + num_ext); | ||
372 | sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t), | ||
373 | &ext_param); | ||
374 | sctp_addto_chunk(retval, num_ext, extensions); | ||
375 | } | ||
317 | if (asoc->peer.prsctp_capable) | 376 | if (asoc->peer.prsctp_capable) |
318 | sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); | 377 | sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param); |
319 | 378 | ||
@@ -1664,6 +1723,28 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, | |||
1664 | return 0; | 1723 | return 0; |
1665 | } | 1724 | } |
1666 | 1725 | ||
1726 | static void sctp_process_ext_param(struct sctp_association *asoc, | ||
1727 | union sctp_params param) | ||
1728 | { | ||
1729 | __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t); | ||
1730 | int i; | ||
1731 | |||
1732 | for (i = 0; i < num_ext; i++) { | ||
1733 | switch (param.ext->chunks[i]) { | ||
1734 | case SCTP_CID_FWD_TSN: | ||
1735 | if (sctp_prsctp_enable && | ||
1736 | !asoc->peer.prsctp_capable) | ||
1737 | asoc->peer.prsctp_capable = 1; | ||
1738 | break; | ||
1739 | case SCTP_CID_ASCONF: | ||
1740 | case SCTP_CID_ASCONF_ACK: | ||
1741 | /* don't need to do anything for ASCONF */ | ||
1742 | default: | ||
1743 | break; | ||
1744 | } | ||
1745 | } | ||
1746 | } | ||
1747 | |||
1667 | /* RFC 3.2.1 & the Implementers Guide 2.2. | 1748 | /* RFC 3.2.1 & the Implementers Guide 2.2. |
1668 | * | 1749 | * |
1669 | * The Parameter Types are encoded such that the | 1750 | * The Parameter Types are encoded such that the |
@@ -1780,11 +1861,13 @@ static int sctp_verify_param(const struct sctp_association *asoc, | |||
1780 | case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: | 1861 | case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: |
1781 | case SCTP_PARAM_ECN_CAPABLE: | 1862 | case SCTP_PARAM_ECN_CAPABLE: |
1782 | case SCTP_PARAM_ADAPTATION_LAYER_IND: | 1863 | case SCTP_PARAM_ADAPTATION_LAYER_IND: |
1864 | case SCTP_PARAM_SUPPORTED_EXT: | ||
1783 | break; | 1865 | break; |
1784 | 1866 | ||
1785 | case SCTP_PARAM_HOST_NAME_ADDRESS: | 1867 | case SCTP_PARAM_HOST_NAME_ADDRESS: |
1786 | /* Tell the peer, we won't support this param. */ | 1868 | /* Tell the peer, we won't support this param. */ |
1787 | return sctp_process_hn_param(asoc, param, chunk, err_chunk); | 1869 | return sctp_process_hn_param(asoc, param, chunk, err_chunk); |
1870 | |||
1788 | case SCTP_PARAM_FWD_TSN_SUPPORT: | 1871 | case SCTP_PARAM_FWD_TSN_SUPPORT: |
1789 | if (sctp_prsctp_enable) | 1872 | if (sctp_prsctp_enable) |
1790 | break; | 1873 | break; |
@@ -2129,6 +2212,10 @@ static int sctp_process_param(struct sctp_association *asoc, | |||
2129 | asoc->peer.adaptation_ind = param.aind->adaptation_ind; | 2212 | asoc->peer.adaptation_ind = param.aind->adaptation_ind; |
2130 | break; | 2213 | break; |
2131 | 2214 | ||
2215 | case SCTP_PARAM_SUPPORTED_EXT: | ||
2216 | sctp_process_ext_param(asoc, param); | ||
2217 | break; | ||
2218 | |||
2132 | case SCTP_PARAM_FWD_TSN_SUPPORT: | 2219 | case SCTP_PARAM_FWD_TSN_SUPPORT: |
2133 | if (sctp_prsctp_enable) { | 2220 | if (sctp_prsctp_enable) { |
2134 | asoc->peer.prsctp_capable = 1; | 2221 | asoc->peer.prsctp_capable = 1; |