aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/sm_make_chunk.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
-rw-r--r--net/sctp/sm_make_chunk.c108
1 files changed, 77 insertions, 31 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 9d881a61ac02..30c1767186b8 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -58,6 +58,7 @@
58#include <linux/inet.h> 58#include <linux/inet.h>
59#include <linux/scatterlist.h> 59#include <linux/scatterlist.h>
60#include <linux/crypto.h> 60#include <linux/crypto.h>
61#include <linux/slab.h>
61#include <net/sock.h> 62#include <net/sock.h>
62 63
63#include <linux/skbuff.h> 64#include <linux/skbuff.h>
@@ -107,7 +108,7 @@ static const struct sctp_paramhdr prsctp_param = {
107 cpu_to_be16(sizeof(struct sctp_paramhdr)), 108 cpu_to_be16(sizeof(struct sctp_paramhdr)),
108}; 109};
109 110
110/* A helper to initialize to initialize an op error inside a 111/* A helper to initialize an op error inside a
111 * provided chunk, as most cause codes will be embedded inside an 112 * provided chunk, as most cause codes will be embedded inside an
112 * abort chunk. 113 * abort chunk.
113 */ 114 */
@@ -124,6 +125,29 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
124 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);
125} 126}
126 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 */
133int 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}
127/* 3.3.2 Initiation (INIT) (1) 151/* 3.3.2 Initiation (INIT) (1)
128 * 152 *
129 * This chunk is used to initiate a SCTP association between two 153 * This chunk is used to initiate a SCTP association between two
@@ -207,7 +231,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
207 sp = sctp_sk(asoc->base.sk); 231 sp = sctp_sk(asoc->base.sk);
208 num_types = sp->pf->supported_addrs(sp, types); 232 num_types = sp->pf->supported_addrs(sp, types);
209 233
210 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));
211 chunksize += sizeof(ecap_param); 236 chunksize += sizeof(ecap_param);
212 237
213 if (sctp_prsctp_enable) 238 if (sctp_prsctp_enable)
@@ -237,14 +262,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
237 /* Add HMACS parameter length if any were defined */ 262 /* Add HMACS parameter length if any were defined */
238 auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; 263 auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
239 if (auth_hmacs->length) 264 if (auth_hmacs->length)
240 chunksize += ntohs(auth_hmacs->length); 265 chunksize += WORD_ROUND(ntohs(auth_hmacs->length));
241 else 266 else
242 auth_hmacs = NULL; 267 auth_hmacs = NULL;
243 268
244 /* Add CHUNKS parameter length */ 269 /* Add CHUNKS parameter length */
245 auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; 270 auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
246 if (auth_chunks->length) 271 if (auth_chunks->length)
247 chunksize += ntohs(auth_chunks->length); 272 chunksize += WORD_ROUND(ntohs(auth_chunks->length));
248 else 273 else
249 auth_chunks = NULL; 274 auth_chunks = NULL;
250 275
@@ -254,7 +279,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
254 279
255 /* If we have any extensions to report, account for that */ 280 /* If we have any extensions to report, account for that */
256 if (num_ext) 281 if (num_ext)
257 chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; 282 chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) +
283 num_ext);
258 284
259 /* RFC 2960 3.3.2 Initiation (INIT) (1) 285 /* RFC 2960 3.3.2 Initiation (INIT) (1)
260 * 286 *
@@ -396,13 +422,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
396 422
397 auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs; 423 auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
398 if (auth_hmacs->length) 424 if (auth_hmacs->length)
399 chunksize += ntohs(auth_hmacs->length); 425 chunksize += WORD_ROUND(ntohs(auth_hmacs->length));
400 else 426 else
401 auth_hmacs = NULL; 427 auth_hmacs = NULL;
402 428
403 auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks; 429 auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
404 if (auth_chunks->length) 430 if (auth_chunks->length)
405 chunksize += ntohs(auth_chunks->length); 431 chunksize += WORD_ROUND(ntohs(auth_chunks->length));
406 else 432 else
407 auth_chunks = NULL; 433 auth_chunks = NULL;
408 434
@@ -411,7 +437,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
411 } 437 }
412 438
413 if (num_ext) 439 if (num_ext)
414 chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; 440 chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) +
441 num_ext);
415 442
416 /* Now allocate and fill out the chunk. */ 443 /* Now allocate and fill out the chunk. */
417 retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); 444 retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
@@ -987,7 +1014,10 @@ static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
987 1014
988 target = skb_put(chunk->skb, len); 1015 target = skb_put(chunk->skb, len);
989 1016
990 memcpy(target, data, len); 1017 if (data)
1018 memcpy(target, data, len);
1019 else
1020 memset(target, 0, len);
991 1021
992 /* Adjust the chunk length field. */ 1022 /* Adjust the chunk length field. */
993 chunk->chunk_hdr->length = htons(chunklen + len); 1023 chunk->chunk_hdr->length = htons(chunklen + len);
@@ -1125,20 +1155,40 @@ nodata:
1125 return retval; 1155 return retval;
1126} 1156}
1127 1157
1158/* Create an Operation Error chunk of a fixed size,
1159 * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT)
1160 * This is a helper function to allocate an error chunk for
1161 * for those invalid parameter codes in which we may not want
1162 * to report all the errors, if the incomming chunk is large
1163 */
1164static inline struct sctp_chunk *sctp_make_op_error_fixed(
1165 const struct sctp_association *asoc,
1166 const struct sctp_chunk *chunk)
1167{
1168 size_t size = asoc ? asoc->pathmtu : 0;
1169
1170 if (!size)
1171 size = SCTP_DEFAULT_MAXSEGMENT;
1172
1173 return sctp_make_op_error_space(asoc, chunk, size);
1174}
1175
1128/* Create an Operation Error chunk. */ 1176/* Create an Operation Error chunk. */
1129struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, 1177struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
1130 const struct sctp_chunk *chunk, 1178 const struct sctp_chunk *chunk,
1131 __be16 cause_code, const void *payload, 1179 __be16 cause_code, const void *payload,
1132 size_t paylen) 1180 size_t paylen, size_t reserve_tail)
1133{ 1181{
1134 struct sctp_chunk *retval; 1182 struct sctp_chunk *retval;
1135 1183
1136 retval = sctp_make_op_error_space(asoc, chunk, paylen); 1184 retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
1137 if (!retval) 1185 if (!retval)
1138 goto nodata; 1186 goto nodata;
1139 1187
1140 sctp_init_cause(retval, cause_code, paylen); 1188 sctp_init_cause(retval, cause_code, paylen + reserve_tail);
1141 sctp_addto_chunk(retval, paylen, payload); 1189 sctp_addto_chunk(retval, paylen, payload);
1190 if (reserve_tail)
1191 sctp_addto_param(retval, reserve_tail, NULL);
1142 1192
1143nodata: 1193nodata:
1144 return retval; 1194 return retval;
@@ -1365,6 +1415,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
1365 return target; 1415 return target;
1366} 1416}
1367 1417
1418/* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient
1419 * space in the chunk
1420 */
1421void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
1422 int len, const void *data)
1423{
1424 if (skb_tailroom(chunk->skb) > len)
1425 return sctp_addto_chunk(chunk, len, data);
1426 else
1427 return NULL;
1428}
1429
1368/* Append bytes from user space to the end of a chunk. Will panic if 1430/* Append bytes from user space to the end of a chunk. Will panic if
1369 * chunk is not big enough. 1431 * chunk is not big enough.
1370 * Returns a kernel err value. 1432 * Returns a kernel err value.
@@ -1968,13 +2030,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
1968 * returning multiple unknown parameters. 2030 * returning multiple unknown parameters.
1969 */ 2031 */
1970 if (NULL == *errp) 2032 if (NULL == *errp)
1971 *errp = sctp_make_op_error_space(asoc, chunk, 2033 *errp = sctp_make_op_error_fixed(asoc, chunk);
1972 ntohs(chunk->chunk_hdr->length));
1973 2034
1974 if (*errp) { 2035 if (*errp) {
1975 sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, 2036 sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
1976 WORD_ROUND(ntohs(param.p->length))); 2037 WORD_ROUND(ntohs(param.p->length)));
1977 sctp_addto_chunk(*errp, 2038 sctp_addto_chunk_fixed(*errp,
1978 WORD_ROUND(ntohs(param.p->length)), 2039 WORD_ROUND(ntohs(param.p->length)),
1979 param.v); 2040 param.v);
1980 } else { 2041 } else {
@@ -3309,21 +3370,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
3309 sctp_chunk_free(asconf); 3370 sctp_chunk_free(asconf);
3310 asoc->addip_last_asconf = NULL; 3371 asoc->addip_last_asconf = NULL;
3311 3372
3312 /* Send the next asconf chunk from the addip chunk queue. */
3313 if (!list_empty(&asoc->addip_chunk_list)) {
3314 struct list_head *entry = asoc->addip_chunk_list.next;
3315 asconf = list_entry(entry, struct sctp_chunk, list);
3316
3317 list_del_init(entry);
3318
3319 /* Hold the chunk until an ASCONF_ACK is received. */
3320 sctp_chunk_hold(asconf);
3321 if (sctp_primitive_ASCONF(asoc, asconf))
3322 sctp_chunk_free(asconf);
3323 else
3324 asoc->addip_last_asconf = asconf;
3325 }
3326
3327 return retval; 3373 return retval;
3328} 3374}
3329 3375