diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 118 |
1 files changed, 76 insertions, 42 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 17cb400ecd6a..d8261f3d7715 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -108,7 +108,7 @@ static const struct sctp_paramhdr prsctp_param = { | |||
| 108 | cpu_to_be16(sizeof(struct sctp_paramhdr)), | 108 | cpu_to_be16(sizeof(struct sctp_paramhdr)), |
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | /* A helper to initialize to initialize an op error inside a | 111 | /* A helper to initialize an op error inside a |
| 112 | * provided chunk, as most cause codes will be embedded inside an | 112 | * provided chunk, as most cause codes will be embedded inside an |
| 113 | * abort chunk. | 113 | * abort chunk. |
| 114 | */ | 114 | */ |
| @@ -125,6 +125,29 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, | |||
| 125 | chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); | 125 | chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /* A helper to initialize an op error inside a | ||
| 129 | * provided chunk, as most cause codes will be embedded inside an | ||
| 130 | * abort chunk. Differs from sctp_init_cause in that it won't oops | ||
| 131 | * if there isn't enough space in the op error chunk | ||
| 132 | */ | ||
| 133 | int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code, | ||
| 134 | size_t paylen) | ||
| 135 | { | ||
| 136 | sctp_errhdr_t err; | ||
| 137 | __u16 len; | ||
| 138 | |||
| 139 | /* Cause code constants are now defined in network order. */ | ||
| 140 | err.cause = cause_code; | ||
| 141 | len = sizeof(sctp_errhdr_t) + paylen; | ||
| 142 | err.length = htons(len); | ||
| 143 | |||
| 144 | if (skb_tailroom(chunk->skb) > len) | ||
| 145 | return -ENOSPC; | ||
| 146 | chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk, | ||
| 147 | sizeof(sctp_errhdr_t), | ||
| 148 | &err); | ||
| 149 | return 0; | ||
| 150 | } | ||
| 128 | /* 3.3.2 Initiation (INIT) (1) | 151 | /* 3.3.2 Initiation (INIT) (1) |
| 129 | * | 152 | * |
| 130 | * This chunk is used to initiate a SCTP association between two | 153 | * This chunk is used to initiate a SCTP association between two |
| @@ -208,7 +231,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
| 208 | sp = sctp_sk(asoc->base.sk); | 231 | sp = sctp_sk(asoc->base.sk); |
| 209 | num_types = sp->pf->supported_addrs(sp, types); | 232 | num_types = sp->pf->supported_addrs(sp, types); |
| 210 | 233 | ||
| 211 | chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); | 234 | chunksize = sizeof(init) + addrs_len; |
| 235 | chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types)); | ||
| 212 | chunksize += sizeof(ecap_param); | 236 | chunksize += sizeof(ecap_param); |
| 213 | 237 | ||
| 214 | if (sctp_prsctp_enable) | 238 | if (sctp_prsctp_enable) |
| @@ -238,14 +262,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
| 238 | /* Add HMACS parameter length if any were defined */ | 262 | /* Add HMACS parameter length if any were defined */ |
| 239 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; | 263 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; |
| 240 | if (auth_hmacs->length) | 264 | if (auth_hmacs->length) |
| 241 | chunksize += ntohs(auth_hmacs->length); | 265 | chunksize += WORD_ROUND(ntohs(auth_hmacs->length)); |
| 242 | else | 266 | else |
| 243 | auth_hmacs = NULL; | 267 | auth_hmacs = NULL; |
| 244 | 268 | ||
| 245 | /* Add CHUNKS parameter length */ | 269 | /* Add CHUNKS parameter length */ |
| 246 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; | 270 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; |
| 247 | if (auth_chunks->length) | 271 | if (auth_chunks->length) |
| 248 | chunksize += ntohs(auth_chunks->length); | 272 | chunksize += WORD_ROUND(ntohs(auth_chunks->length)); |
| 249 | else | 273 | else |
| 250 | auth_chunks = NULL; | 274 | auth_chunks = NULL; |
| 251 | 275 | ||
| @@ -255,7 +279,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, | |||
| 255 | 279 | ||
| 256 | /* If we have any extensions to report, account for that */ | 280 | /* If we have any extensions to report, account for that */ |
| 257 | if (num_ext) | 281 | if (num_ext) |
| 258 | chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; | 282 | chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + |
| 283 | num_ext); | ||
| 259 | 284 | ||
| 260 | /* RFC 2960 3.3.2 Initiation (INIT) (1) | 285 | /* RFC 2960 3.3.2 Initiation (INIT) (1) |
| 261 | * | 286 | * |
| @@ -397,13 +422,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
| 397 | 422 | ||
| 398 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; | 423 | auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; |
| 399 | if (auth_hmacs->length) | 424 | if (auth_hmacs->length) |
| 400 | chunksize += ntohs(auth_hmacs->length); | 425 | chunksize += WORD_ROUND(ntohs(auth_hmacs->length)); |
| 401 | else | 426 | else |
| 402 | auth_hmacs = NULL; | 427 | auth_hmacs = NULL; |
| 403 | 428 | ||
| 404 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; | 429 | auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; |
| 405 | if (auth_chunks->length) | 430 | if (auth_chunks->length) |
| 406 | chunksize += ntohs(auth_chunks->length); | 431 | chunksize += WORD_ROUND(ntohs(auth_chunks->length)); |
| 407 | else | 432 | else |
| 408 | auth_chunks = NULL; | 433 | auth_chunks = NULL; |
| 409 | 434 | ||
| @@ -412,17 +437,25 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
| 412 | } | 437 | } |
| 413 | 438 | ||
| 414 | if (num_ext) | 439 | if (num_ext) |
| 415 | chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; | 440 | chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + |
| 441 | num_ext); | ||
| 416 | 442 | ||
| 417 | /* Now allocate and fill out the chunk. */ | 443 | /* Now allocate and fill out the chunk. */ |
| 418 | retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); | 444 | retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); |
| 419 | if (!retval) | 445 | if (!retval) |
| 420 | goto nomem_chunk; | 446 | goto nomem_chunk; |
| 421 | 447 | ||
| 422 | /* Per the advice in RFC 2960 6.4, send this reply to | 448 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
| 423 | * the source of the INIT packet. | 449 | * |
| 450 | * An endpoint SHOULD transmit reply chunks (e.g., SACK, | ||
| 451 | * HEARTBEAT ACK, * etc.) to the same destination transport | ||
| 452 | * address from which it received the DATA or control chunk | ||
| 453 | * to which it is replying. | ||
| 454 | * | ||
| 455 | * [INIT ACK back to where the INIT came from.] | ||
| 424 | */ | 456 | */ |
| 425 | retval->transport = chunk->transport; | 457 | retval->transport = chunk->transport; |
| 458 | |||
| 426 | retval->subh.init_hdr = | 459 | retval->subh.init_hdr = |
| 427 | sctp_addto_chunk(retval, sizeof(initack), &initack); | 460 | sctp_addto_chunk(retval, sizeof(initack), &initack); |
| 428 | retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); | 461 | retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); |
| @@ -461,18 +494,6 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
| 461 | /* We need to remove the const qualifier at this point. */ | 494 | /* We need to remove the const qualifier at this point. */ |
| 462 | retval->asoc = (struct sctp_association *) asoc; | 495 | retval->asoc = (struct sctp_association *) asoc; |
| 463 | 496 | ||
| 464 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints | ||
| 465 | * | ||
| 466 | * An endpoint SHOULD transmit reply chunks (e.g., SACK, | ||
| 467 | * HEARTBEAT ACK, * etc.) to the same destination transport | ||
| 468 | * address from which it received the DATA or control chunk | ||
| 469 | * to which it is replying. | ||
| 470 | * | ||
| 471 | * [INIT ACK back to where the INIT came from.] | ||
| 472 | */ | ||
| 473 | if (chunk) | ||
| 474 | retval->transport = chunk->transport; | ||
| 475 | |||
| 476 | nomem_chunk: | 497 | nomem_chunk: |
| 477 | kfree(cookie); | 498 | kfree(cookie); |
| 478 | nomem_cookie: | 499 | nomem_cookie: |
| @@ -1129,6 +1150,24 @@ nodata: | |||
| 1129 | return retval; | 1150 | return retval; |
| 1130 | } | 1151 | } |
| 1131 | 1152 | ||
| 1153 | /* Create an Operation Error chunk of a fixed size, | ||
| 1154 | * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) | ||
| 1155 | * This is a helper function to allocate an error chunk for | ||
| 1156 | * for those invalid parameter codes in which we may not want | ||
| 1157 | * to report all the errors, if the incomming chunk is large | ||
| 1158 | */ | ||
| 1159 | static inline struct sctp_chunk *sctp_make_op_error_fixed( | ||
| 1160 | const struct sctp_association *asoc, | ||
| 1161 | const struct sctp_chunk *chunk) | ||
| 1162 | { | ||
| 1163 | size_t size = asoc ? asoc->pathmtu : 0; | ||
| 1164 | |||
| 1165 | if (!size) | ||
| 1166 | size = SCTP_DEFAULT_MAXSEGMENT; | ||
| 1167 | |||
| 1168 | return sctp_make_op_error_space(asoc, chunk, size); | ||
| 1169 | } | ||
| 1170 | |||
| 1132 | /* Create an Operation Error chunk. */ | 1171 | /* Create an Operation Error chunk. */ |
| 1133 | struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, | 1172 | struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, |
| 1134 | const struct sctp_chunk *chunk, | 1173 | const struct sctp_chunk *chunk, |
| @@ -1210,7 +1249,6 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, | |||
| 1210 | INIT_LIST_HEAD(&retval->list); | 1249 | INIT_LIST_HEAD(&retval->list); |
| 1211 | retval->skb = skb; | 1250 | retval->skb = skb; |
| 1212 | retval->asoc = (struct sctp_association *)asoc; | 1251 | retval->asoc = (struct sctp_association *)asoc; |
| 1213 | retval->resent = 0; | ||
| 1214 | retval->has_tsn = 0; | 1252 | retval->has_tsn = 0; |
| 1215 | retval->has_ssn = 0; | 1253 | retval->has_ssn = 0; |
| 1216 | retval->rtt_in_progress = 0; | 1254 | retval->rtt_in_progress = 0; |
| @@ -1371,6 +1409,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) | |||
| 1371 | return target; | 1409 | return target; |
| 1372 | } | 1410 | } |
| 1373 | 1411 | ||
| 1412 | /* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient | ||
| 1413 | * space in the chunk | ||
| 1414 | */ | ||
| 1415 | void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk, | ||
| 1416 | int len, const void *data) | ||
| 1417 | { | ||
| 1418 | if (skb_tailroom(chunk->skb) > len) | ||
| 1419 | return sctp_addto_chunk(chunk, len, data); | ||
| 1420 | else | ||
| 1421 | return NULL; | ||
| 1422 | } | ||
| 1423 | |||
| 1374 | /* Append bytes from user space to the end of a chunk. Will panic if | 1424 | /* Append bytes from user space to the end of a chunk. Will panic if |
| 1375 | * chunk is not big enough. | 1425 | * chunk is not big enough. |
| 1376 | * Returns a kernel err value. | 1426 | * Returns a kernel err value. |
| @@ -1974,13 +2024,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc, | |||
| 1974 | * returning multiple unknown parameters. | 2024 | * returning multiple unknown parameters. |
| 1975 | */ | 2025 | */ |
| 1976 | if (NULL == *errp) | 2026 | if (NULL == *errp) |
| 1977 | *errp = sctp_make_op_error_space(asoc, chunk, | 2027 | *errp = sctp_make_op_error_fixed(asoc, chunk); |
| 1978 | ntohs(chunk->chunk_hdr->length)); | ||
| 1979 | 2028 | ||
| 1980 | if (*errp) { | 2029 | if (*errp) { |
| 1981 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, | 2030 | sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM, |
| 1982 | WORD_ROUND(ntohs(param.p->length))); | 2031 | WORD_ROUND(ntohs(param.p->length))); |
| 1983 | sctp_addto_chunk(*errp, | 2032 | sctp_addto_chunk_fixed(*errp, |
| 1984 | WORD_ROUND(ntohs(param.p->length)), | 2033 | WORD_ROUND(ntohs(param.p->length)), |
| 1985 | param.v); | 2034 | param.v); |
| 1986 | } else { | 2035 | } else { |
| @@ -3315,21 +3364,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, | |||
| 3315 | sctp_chunk_free(asconf); | 3364 | sctp_chunk_free(asconf); |
| 3316 | asoc->addip_last_asconf = NULL; | 3365 | asoc->addip_last_asconf = NULL; |
| 3317 | 3366 | ||
| 3318 | /* Send the next asconf chunk from the addip chunk queue. */ | ||
| 3319 | if (!list_empty(&asoc->addip_chunk_list)) { | ||
| 3320 | struct list_head *entry = asoc->addip_chunk_list.next; | ||
| 3321 | asconf = list_entry(entry, struct sctp_chunk, list); | ||
| 3322 | |||
| 3323 | list_del_init(entry); | ||
| 3324 | |||
| 3325 | /* Hold the chunk until an ASCONF_ACK is received. */ | ||
| 3326 | sctp_chunk_hold(asconf); | ||
| 3327 | if (sctp_primitive_ASCONF(asoc, asconf)) | ||
| 3328 | sctp_chunk_free(asconf); | ||
| 3329 | else | ||
| 3330 | asoc->addip_last_asconf = asconf; | ||
| 3331 | } | ||
| 3332 | |||
| 3333 | return retval; | 3367 | return retval; |
| 3334 | } | 3368 | } |
| 3335 | 3369 | ||
