diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
-rw-r--r-- | net/sctp/sm_make_chunk.c | 86 |
1 files changed, 66 insertions, 20 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 0fd5b4c88358..bd2a50b482ac 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 |
@@ -422,10 +445,17 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
422 | if (!retval) | 445 | if (!retval) |
423 | goto nomem_chunk; | 446 | goto nomem_chunk; |
424 | 447 | ||
425 | /* Per the advice in RFC 2960 6.4, send this reply to | 448 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
426 | * 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.] | ||
427 | */ | 456 | */ |
428 | retval->transport = chunk->transport; | 457 | retval->transport = chunk->transport; |
458 | |||
429 | retval->subh.init_hdr = | 459 | retval->subh.init_hdr = |
430 | sctp_addto_chunk(retval, sizeof(initack), &initack); | 460 | sctp_addto_chunk(retval, sizeof(initack), &initack); |
431 | 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); |
@@ -464,18 +494,6 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, | |||
464 | /* We need to remove the const qualifier at this point. */ | 494 | /* We need to remove the const qualifier at this point. */ |
465 | retval->asoc = (struct sctp_association *) asoc; | 495 | retval->asoc = (struct sctp_association *) asoc; |
466 | 496 | ||
467 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints | ||
468 | * | ||
469 | * An endpoint SHOULD transmit reply chunks (e.g., SACK, | ||
470 | * HEARTBEAT ACK, * etc.) to the same destination transport | ||
471 | * address from which it received the DATA or control chunk | ||
472 | * to which it is replying. | ||
473 | * | ||
474 | * [INIT ACK back to where the INIT came from.] | ||
475 | */ | ||
476 | if (chunk) | ||
477 | retval->transport = chunk->transport; | ||
478 | |||
479 | nomem_chunk: | 497 | nomem_chunk: |
480 | kfree(cookie); | 498 | kfree(cookie); |
481 | nomem_cookie: | 499 | nomem_cookie: |
@@ -1132,6 +1150,24 @@ nodata: | |||
1132 | return retval; | 1150 | return retval; |
1133 | } | 1151 | } |
1134 | 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 | |||
1135 | /* Create an Operation Error chunk. */ | 1171 | /* Create an Operation Error chunk. */ |
1136 | 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, |
1137 | const struct sctp_chunk *chunk, | 1173 | const struct sctp_chunk *chunk, |
@@ -1213,7 +1249,6 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, | |||
1213 | INIT_LIST_HEAD(&retval->list); | 1249 | INIT_LIST_HEAD(&retval->list); |
1214 | retval->skb = skb; | 1250 | retval->skb = skb; |
1215 | retval->asoc = (struct sctp_association *)asoc; | 1251 | retval->asoc = (struct sctp_association *)asoc; |
1216 | retval->resent = 0; | ||
1217 | retval->has_tsn = 0; | 1252 | retval->has_tsn = 0; |
1218 | retval->has_ssn = 0; | 1253 | retval->has_ssn = 0; |
1219 | retval->rtt_in_progress = 0; | 1254 | retval->rtt_in_progress = 0; |
@@ -1374,6 +1409,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) | |||
1374 | return target; | 1409 | return target; |
1375 | } | 1410 | } |
1376 | 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 | |||
1377 | /* 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 |
1378 | * chunk is not big enough. | 1425 | * chunk is not big enough. |
1379 | * Returns a kernel err value. | 1426 | * Returns a kernel err value. |
@@ -1977,13 +2024,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc, | |||
1977 | * returning multiple unknown parameters. | 2024 | * returning multiple unknown parameters. |
1978 | */ | 2025 | */ |
1979 | if (NULL == *errp) | 2026 | if (NULL == *errp) |
1980 | *errp = sctp_make_op_error_space(asoc, chunk, | 2027 | *errp = sctp_make_op_error_fixed(asoc, chunk); |
1981 | ntohs(chunk->chunk_hdr->length)); | ||
1982 | 2028 | ||
1983 | if (*errp) { | 2029 | if (*errp) { |
1984 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, | 2030 | sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM, |
1985 | WORD_ROUND(ntohs(param.p->length))); | 2031 | WORD_ROUND(ntohs(param.p->length))); |
1986 | sctp_addto_chunk(*errp, | 2032 | sctp_addto_chunk_fixed(*errp, |
1987 | WORD_ROUND(ntohs(param.p->length)), | 2033 | WORD_ROUND(ntohs(param.p->length)), |
1988 | param.v); | 2034 | param.v); |
1989 | } else { | 2035 | } else { |