blob: fa8371ff05c43f31a7a0c5947161e08508671bcc [file] [log] [blame]
Xin Longa8386312017-01-06 22:18:33 +08001/* SCTP kernel implementation
2 * (C) Copyright IBM Corp. 2001, 2004
3 * Copyright (c) 1999-2000 Cisco, Inc.
4 * Copyright (c) 1999-2001 Motorola, Inc.
5 * Copyright (c) 2001 Intel Corp.
6 *
7 * This file is part of the SCTP kernel implementation
8 *
9 * These functions manipulate sctp tsn mapping array.
10 *
11 * This SCTP implementation is free software;
12 * you can redistribute it and/or modify it under the terms of
13 * the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
15 * any later version.
16 *
17 * This SCTP implementation is distributed in the hope that it
18 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19 * ************************
20 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 * See the GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with GNU CC; see the file COPYING. If not, see
25 * <http://www.gnu.org/licenses/>.
26 *
27 * Please send any bug reports or fixes you make to the
28 * email address(es):
29 * lksctp developers <linux-sctp@vger.kernel.org>
30 *
31 * Written or modified by:
32 * Xin Long <lucien.xin@gmail.com>
33 */
34
35#include <net/sctp/sctp.h>
Xin Long7f9d68a2017-01-18 00:44:47 +080036#include <net/sctp/sm.h>
Xin Longa8386312017-01-06 22:18:33 +080037
Xin Longff356412017-05-31 16:36:32 +080038int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
39 gfp_t gfp)
Xin Longa8386312017-01-06 22:18:33 +080040{
Xin Long3dbcc102017-03-30 01:00:53 +080041 int i;
42
43 /* Initial stream->out size may be very big, so free it and alloc
44 * a new one with new outcnt to save memory.
45 */
46 kfree(stream->out);
Xin Longff356412017-05-31 16:36:32 +080047
48 stream->out = kcalloc(outcnt, sizeof(*stream->out), gfp);
Xin Long3dbcc102017-03-30 01:00:53 +080049 if (!stream->out)
Xin Longcee360a2017-05-31 16:36:31 +080050 return -ENOMEM;
Xin Long3dbcc102017-03-30 01:00:53 +080051
Xin Longff356412017-05-31 16:36:32 +080052 stream->outcnt = outcnt;
Xin Long3dbcc102017-03-30 01:00:53 +080053 for (i = 0; i < stream->outcnt; i++)
54 stream->out[i].state = SCTP_STREAM_OPEN;
55
Xin Longff356412017-05-31 16:36:32 +080056 if (!incnt)
57 return 0;
58
59 stream->in = kcalloc(incnt, sizeof(*stream->in), gfp);
Xin Longa8386312017-01-06 22:18:33 +080060 if (!stream->in) {
61 kfree(stream->out);
Xin Longcee360a2017-05-31 16:36:31 +080062 stream->out = NULL;
63 return -ENOMEM;
Xin Longa8386312017-01-06 22:18:33 +080064 }
65
Xin Longff356412017-05-31 16:36:32 +080066 stream->incnt = incnt;
67
Xin Long3dbcc102017-03-30 01:00:53 +080068 return 0;
Xin Longa8386312017-01-06 22:18:33 +080069}
70
71void sctp_stream_free(struct sctp_stream *stream)
72{
Xin Longa8386312017-01-06 22:18:33 +080073 kfree(stream->out);
74 kfree(stream->in);
Xin Longa8386312017-01-06 22:18:33 +080075}
76
77void sctp_stream_clear(struct sctp_stream *stream)
78{
79 int i;
80
81 for (i = 0; i < stream->outcnt; i++)
82 stream->out[i].ssn = 0;
83
84 for (i = 0; i < stream->incnt; i++)
85 stream->in[i].ssn = 0;
86}
Xin Long7f9d68a2017-01-18 00:44:47 +080087
Xin Longcee360a2017-05-31 16:36:31 +080088void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
89{
90 sctp_stream_free(stream);
91
92 stream->out = new->out;
93 stream->in = new->in;
94 stream->outcnt = new->outcnt;
95 stream->incnt = new->incnt;
96
97 new->out = NULL;
98 new->in = NULL;
99}
100
Xin Long7f9d68a2017-01-18 00:44:47 +0800101static int sctp_send_reconf(struct sctp_association *asoc,
102 struct sctp_chunk *chunk)
103{
104 struct net *net = sock_net(asoc->base.sk);
105 int retval = 0;
106
107 retval = sctp_primitive_RECONF(net, asoc, chunk);
108 if (retval)
109 sctp_chunk_free(chunk);
110
111 return retval;
112}
113
114int sctp_send_reset_streams(struct sctp_association *asoc,
115 struct sctp_reset_streams *params)
116{
Xin Longcee360a2017-05-31 16:36:31 +0800117 struct sctp_stream *stream = &asoc->stream;
Xin Long7f9d68a2017-01-18 00:44:47 +0800118 __u16 i, str_nums, *str_list;
119 struct sctp_chunk *chunk;
120 int retval = -EINVAL;
Xin Long1da4fc92017-10-28 19:43:54 +0800121 __be16 *nstr_list;
Xin Long7f9d68a2017-01-18 00:44:47 +0800122 bool out, in;
123
124 if (!asoc->peer.reconf_capable ||
125 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
126 retval = -ENOPROTOOPT;
127 goto out;
128 }
129
130 if (asoc->strreset_outstanding) {
131 retval = -EINPROGRESS;
132 goto out;
133 }
134
135 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
136 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
137 if (!out && !in)
138 goto out;
139
140 str_nums = params->srs_number_streams;
141 str_list = params->srs_stream_list;
142 if (out && str_nums)
143 for (i = 0; i < str_nums; i++)
144 if (str_list[i] >= stream->outcnt)
145 goto out;
146
147 if (in && str_nums)
148 for (i = 0; i < str_nums; i++)
149 if (str_list[i] >= stream->incnt)
150 goto out;
151
Xin Long1da4fc92017-10-28 19:43:54 +0800152 nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
153 if (!nstr_list) {
154 retval = -ENOMEM;
155 goto out;
156 }
Xin Long16e1a912017-02-17 12:45:40 +0800157
158 for (i = 0; i < str_nums; i++)
Xin Long1da4fc92017-10-28 19:43:54 +0800159 nstr_list[i] = htons(str_list[i]);
160
161 chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
162
163 kfree(nstr_list);
Xin Long16e1a912017-02-17 12:45:40 +0800164
Xin Long119aecb2017-02-09 01:18:16 +0800165 if (!chunk) {
166 retval = -ENOMEM;
Xin Long7f9d68a2017-01-18 00:44:47 +0800167 goto out;
Xin Long119aecb2017-02-09 01:18:16 +0800168 }
Xin Long7f9d68a2017-01-18 00:44:47 +0800169
170 if (out) {
171 if (str_nums)
172 for (i = 0; i < str_nums; i++)
173 stream->out[str_list[i]].state =
174 SCTP_STREAM_CLOSED;
175 else
176 for (i = 0; i < stream->outcnt; i++)
177 stream->out[i].state = SCTP_STREAM_CLOSED;
178 }
179
Xin Long7f9d68a2017-01-18 00:44:47 +0800180 asoc->strreset_chunk = chunk;
181 sctp_chunk_hold(asoc->strreset_chunk);
182
183 retval = sctp_send_reconf(asoc, chunk);
184 if (retval) {
185 sctp_chunk_put(asoc->strreset_chunk);
186 asoc->strreset_chunk = NULL;
Xin Long119aecb2017-02-09 01:18:16 +0800187 if (!out)
188 goto out;
189
190 if (str_nums)
191 for (i = 0; i < str_nums; i++)
192 stream->out[str_list[i]].state =
193 SCTP_STREAM_OPEN;
194 else
195 for (i = 0; i < stream->outcnt; i++)
196 stream->out[i].state = SCTP_STREAM_OPEN;
197
198 goto out;
Xin Long7f9d68a2017-01-18 00:44:47 +0800199 }
200
Xin Long119aecb2017-02-09 01:18:16 +0800201 asoc->strreset_outstanding = out + in;
202
Xin Long7f9d68a2017-01-18 00:44:47 +0800203out:
204 return retval;
205}
Xin Longa92ce1a2017-02-09 01:18:18 +0800206
207int sctp_send_reset_assoc(struct sctp_association *asoc)
208{
Xin Longcee360a2017-05-31 16:36:31 +0800209 struct sctp_stream *stream = &asoc->stream;
Xin Longa92ce1a2017-02-09 01:18:18 +0800210 struct sctp_chunk *chunk = NULL;
211 int retval;
212 __u16 i;
213
214 if (!asoc->peer.reconf_capable ||
215 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
216 return -ENOPROTOOPT;
217
218 if (asoc->strreset_outstanding)
219 return -EINPROGRESS;
220
221 chunk = sctp_make_strreset_tsnreq(asoc);
222 if (!chunk)
223 return -ENOMEM;
224
225 /* Block further xmit of data until this request is completed */
Xin Longcee360a2017-05-31 16:36:31 +0800226 for (i = 0; i < stream->outcnt; i++)
227 stream->out[i].state = SCTP_STREAM_CLOSED;
Xin Longa92ce1a2017-02-09 01:18:18 +0800228
229 asoc->strreset_chunk = chunk;
230 sctp_chunk_hold(asoc->strreset_chunk);
231
232 retval = sctp_send_reconf(asoc, chunk);
233 if (retval) {
234 sctp_chunk_put(asoc->strreset_chunk);
235 asoc->strreset_chunk = NULL;
236
Xin Longcee360a2017-05-31 16:36:31 +0800237 for (i = 0; i < stream->outcnt; i++)
238 stream->out[i].state = SCTP_STREAM_OPEN;
Xin Longa92ce1a2017-02-09 01:18:18 +0800239
240 return retval;
241 }
242
243 asoc->strreset_outstanding = 1;
244
245 return 0;
246}
Xin Long242bd2d2017-02-09 01:18:20 +0800247
248int sctp_send_add_streams(struct sctp_association *asoc,
249 struct sctp_add_streams *params)
250{
Xin Longcee360a2017-05-31 16:36:31 +0800251 struct sctp_stream *stream = &asoc->stream;
Xin Long242bd2d2017-02-09 01:18:20 +0800252 struct sctp_chunk *chunk = NULL;
253 int retval = -ENOMEM;
254 __u32 outcnt, incnt;
255 __u16 out, in;
256
257 if (!asoc->peer.reconf_capable ||
258 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
259 retval = -ENOPROTOOPT;
260 goto out;
261 }
262
263 if (asoc->strreset_outstanding) {
264 retval = -EINPROGRESS;
265 goto out;
266 }
267
268 out = params->sas_outstrms;
269 in = params->sas_instrms;
270 outcnt = stream->outcnt + out;
271 incnt = stream->incnt + in;
272 if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
273 (!out && !in)) {
274 retval = -EINVAL;
275 goto out;
276 }
277
278 if (out) {
279 struct sctp_stream_out *streamout;
280
281 streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
282 GFP_KERNEL);
283 if (!streamout)
284 goto out;
285
286 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
287 stream->out = streamout;
288 }
289
Xin Long242bd2d2017-02-09 01:18:20 +0800290 chunk = sctp_make_strreset_addstrm(asoc, out, in);
291 if (!chunk)
292 goto out;
293
294 asoc->strreset_chunk = chunk;
295 sctp_chunk_hold(asoc->strreset_chunk);
296
297 retval = sctp_send_reconf(asoc, chunk);
298 if (retval) {
299 sctp_chunk_put(asoc->strreset_chunk);
300 asoc->strreset_chunk = NULL;
301 goto out;
302 }
303
304 stream->incnt = incnt;
305 stream->outcnt = outcnt;
306
307 asoc->strreset_outstanding = !!out + !!in;
308
309out:
310 return retval;
311}
Xin Long81054472017-02-17 12:45:39 +0800312
Xin Long3c918702017-06-30 11:52:16 +0800313static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
Xin Long1da4fc92017-10-28 19:43:54 +0800314 struct sctp_association *asoc, __be32 resp_seq,
Xin Long50a41592017-03-10 12:11:09 +0800315 __be16 type)
Xin Long81054472017-02-17 12:45:39 +0800316{
317 struct sctp_chunk *chunk = asoc->strreset_chunk;
318 struct sctp_reconf_chunk *hdr;
319 union sctp_params param;
320
Xin Long50a41592017-03-10 12:11:09 +0800321 if (!chunk)
Xin Long81054472017-02-17 12:45:39 +0800322 return NULL;
323
324 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
325 sctp_walk_params(param, hdr, params) {
326 /* sctp_strreset_tsnreq is actually the basic structure
327 * of all stream reconf params, so it's safe to use it
328 * to access request_seq.
329 */
330 struct sctp_strreset_tsnreq *req = param.v;
331
Xin Long50a41592017-03-10 12:11:09 +0800332 if ((!resp_seq || req->request_seq == resp_seq) &&
333 (!type || type == req->param_hdr.type))
Xin Long81054472017-02-17 12:45:39 +0800334 return param.v;
335 }
336
337 return NULL;
338}
339
Xin Longe4dc99c2017-04-15 22:00:27 +0800340static void sctp_update_strreset_result(struct sctp_association *asoc,
341 __u32 result)
342{
343 asoc->strreset_result[1] = asoc->strreset_result[0];
344 asoc->strreset_result[0] = result;
345}
346
Xin Long81054472017-02-17 12:45:39 +0800347struct sctp_chunk *sctp_process_strreset_outreq(
348 struct sctp_association *asoc,
349 union sctp_params param,
350 struct sctp_ulpevent **evp)
351{
352 struct sctp_strreset_outreq *outreq = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800353 struct sctp_stream *stream = &asoc->stream;
Xin Long81054472017-02-17 12:45:39 +0800354 __u32 result = SCTP_STRRESET_DENIED;
Xin Long1da4fc92017-10-28 19:43:54 +0800355 __u16 i, nums, flags = 0;
356 __be16 *str_p = NULL;
Xin Long81054472017-02-17 12:45:39 +0800357 __u32 request_seq;
358
359 request_seq = ntohl(outreq->request_seq);
360
361 if (ntohl(outreq->send_reset_at_tsn) >
362 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
363 result = SCTP_STRRESET_IN_PROGRESS;
Xin Longe4dc99c2017-04-15 22:00:27 +0800364 goto err;
Xin Long81054472017-02-17 12:45:39 +0800365 }
366
Xin Longe4dc99c2017-04-15 22:00:27 +0800367 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
368 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long81054472017-02-17 12:45:39 +0800369 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longe4dc99c2017-04-15 22:00:27 +0800370 goto err;
371 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
372 i = asoc->strreset_inseq - request_seq - 1;
373 result = asoc->strreset_result[i];
374 goto err;
Xin Long81054472017-02-17 12:45:39 +0800375 }
Xin Longe4dc99c2017-04-15 22:00:27 +0800376 asoc->strreset_inseq++;
Xin Long81054472017-02-17 12:45:39 +0800377
378 /* Check strreset_enable after inseq inc, as sender cannot tell
379 * the peer doesn't enable strreset after receiving response with
380 * result denied, as well as to keep consistent with bsd.
381 */
382 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
383 goto out;
384
385 if (asoc->strreset_chunk) {
Xin Long50a41592017-03-10 12:11:09 +0800386 if (!sctp_chunk_lookup_strreset_param(
387 asoc, outreq->response_seq,
388 SCTP_PARAM_RESET_IN_REQUEST)) {
Xin Long81054472017-02-17 12:45:39 +0800389 /* same process with outstanding isn't 0 */
390 result = SCTP_STRRESET_ERR_IN_PROGRESS;
391 goto out;
392 }
393
394 asoc->strreset_outstanding--;
395 asoc->strreset_outseq++;
396
397 if (!asoc->strreset_outstanding) {
Xin Long50a41592017-03-10 12:11:09 +0800398 struct sctp_transport *t;
399
Xin Long81054472017-02-17 12:45:39 +0800400 t = asoc->strreset_chunk->transport;
401 if (del_timer(&t->reconf_timer))
402 sctp_transport_put(t);
403
404 sctp_chunk_put(asoc->strreset_chunk);
405 asoc->strreset_chunk = NULL;
406 }
407
408 flags = SCTP_STREAM_RESET_INCOMING_SSN;
409 }
410
411 nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2;
412 if (nums) {
413 str_p = outreq->list_of_streams;
414 for (i = 0; i < nums; i++) {
415 if (ntohs(str_p[i]) >= stream->incnt) {
416 result = SCTP_STRRESET_ERR_WRONG_SSN;
417 goto out;
418 }
419 }
420
421 for (i = 0; i < nums; i++)
422 stream->in[ntohs(str_p[i])].ssn = 0;
423 } else {
424 for (i = 0; i < stream->incnt; i++)
425 stream->in[i].ssn = 0;
426 }
427
428 result = SCTP_STRRESET_PERFORMED;
429
430 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
431 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
432 GFP_ATOMIC);
433
434out:
Xin Longe4dc99c2017-04-15 22:00:27 +0800435 sctp_update_strreset_result(asoc, result);
436err:
Xin Long81054472017-02-17 12:45:39 +0800437 return sctp_make_strreset_resp(asoc, result, request_seq);
438}
Xin Long16e1a912017-02-17 12:45:40 +0800439
440struct sctp_chunk *sctp_process_strreset_inreq(
441 struct sctp_association *asoc,
442 union sctp_params param,
443 struct sctp_ulpevent **evp)
444{
445 struct sctp_strreset_inreq *inreq = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800446 struct sctp_stream *stream = &asoc->stream;
Xin Long16e1a912017-02-17 12:45:40 +0800447 __u32 result = SCTP_STRRESET_DENIED;
448 struct sctp_chunk *chunk = NULL;
Xin Long16e1a912017-02-17 12:45:40 +0800449 __u32 request_seq;
Xin Long1da4fc92017-10-28 19:43:54 +0800450 __u16 i, nums;
451 __be16 *str_p;
Xin Long16e1a912017-02-17 12:45:40 +0800452
453 request_seq = ntohl(inreq->request_seq);
Xin Longd0f025e2017-04-15 22:00:28 +0800454 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
455 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long16e1a912017-02-17 12:45:40 +0800456 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longd0f025e2017-04-15 22:00:28 +0800457 goto err;
458 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
459 i = asoc->strreset_inseq - request_seq - 1;
460 result = asoc->strreset_result[i];
461 if (result == SCTP_STRRESET_PERFORMED)
462 return NULL;
463 goto err;
Xin Long16e1a912017-02-17 12:45:40 +0800464 }
Xin Longd0f025e2017-04-15 22:00:28 +0800465 asoc->strreset_inseq++;
Xin Long16e1a912017-02-17 12:45:40 +0800466
467 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
468 goto out;
469
470 if (asoc->strreset_outstanding) {
471 result = SCTP_STRRESET_ERR_IN_PROGRESS;
472 goto out;
473 }
474
475 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
476 str_p = inreq->list_of_streams;
477 for (i = 0; i < nums; i++) {
478 if (ntohs(str_p[i]) >= stream->outcnt) {
479 result = SCTP_STRRESET_ERR_WRONG_SSN;
480 goto out;
481 }
482 }
483
484 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
485 if (!chunk)
486 goto out;
487
488 if (nums)
489 for (i = 0; i < nums; i++)
490 stream->out[ntohs(str_p[i])].state =
491 SCTP_STREAM_CLOSED;
492 else
493 for (i = 0; i < stream->outcnt; i++)
494 stream->out[i].state = SCTP_STREAM_CLOSED;
495
496 asoc->strreset_chunk = chunk;
497 asoc->strreset_outstanding = 1;
498 sctp_chunk_hold(asoc->strreset_chunk);
499
Xin Longd0f025e2017-04-15 22:00:28 +0800500 result = SCTP_STRRESET_PERFORMED;
501
Xin Long16e1a912017-02-17 12:45:40 +0800502 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
503 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
504
505out:
Xin Longd0f025e2017-04-15 22:00:28 +0800506 sctp_update_strreset_result(asoc, result);
507err:
Xin Long16e1a912017-02-17 12:45:40 +0800508 if (!chunk)
509 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
510
511 return chunk;
512}
Xin Long692787c2017-03-10 12:11:07 +0800513
514struct sctp_chunk *sctp_process_strreset_tsnreq(
515 struct sctp_association *asoc,
516 union sctp_params param,
517 struct sctp_ulpevent **evp)
518{
519 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
520 struct sctp_strreset_tsnreq *tsnreq = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800521 struct sctp_stream *stream = &asoc->stream;
Xin Long692787c2017-03-10 12:11:07 +0800522 __u32 result = SCTP_STRRESET_DENIED;
523 __u32 request_seq;
524 __u16 i;
525
526 request_seq = ntohl(tsnreq->request_seq);
Xin Long6c801382017-04-15 22:00:29 +0800527 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
528 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long692787c2017-03-10 12:11:07 +0800529 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Long6c801382017-04-15 22:00:29 +0800530 goto err;
531 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
532 i = asoc->strreset_inseq - request_seq - 1;
533 result = asoc->strreset_result[i];
534 if (result == SCTP_STRRESET_PERFORMED) {
535 next_tsn = asoc->next_tsn;
536 init_tsn =
537 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
538 }
539 goto err;
Xin Long692787c2017-03-10 12:11:07 +0800540 }
Xin Long6c801382017-04-15 22:00:29 +0800541 asoc->strreset_inseq++;
Xin Long692787c2017-03-10 12:11:07 +0800542
543 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
544 goto out;
545
546 if (asoc->strreset_outstanding) {
547 result = SCTP_STRRESET_ERR_IN_PROGRESS;
548 goto out;
549 }
550
551 /* G3: The same processing as though a SACK chunk with no gap report
552 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
553 * received MUST be performed.
554 */
555 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
556 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
557 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
558
559 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
560 * TSN that the peer should use to send the next DATA chunk. The
561 * value SHOULD be the smallest TSN not acknowledged by the
562 * receiver of the request plus 2^31.
563 */
564 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
565 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
566 init_tsn, GFP_ATOMIC);
567
568 /* G4: The same processing as though a FWD-TSN chunk (as defined in
569 * [RFC3758]) with all streams affected and a new cumulative TSN
570 * ACK of the Receiver's Next TSN minus 1 were received MUST be
571 * performed.
572 */
573 sctp_outq_free(&asoc->outqueue);
574
575 /* G2: Compute an appropriate value for the local endpoint's next TSN,
576 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
577 * chunk. The value SHOULD be the highest TSN sent by the receiver
578 * of the request plus 1.
579 */
580 next_tsn = asoc->next_tsn;
581 asoc->ctsn_ack_point = next_tsn - 1;
582 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
583
584 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
585 * incoming and outgoing streams.
586 */
587 for (i = 0; i < stream->outcnt; i++)
588 stream->out[i].ssn = 0;
589 for (i = 0; i < stream->incnt; i++)
590 stream->in[i].ssn = 0;
591
592 result = SCTP_STRRESET_PERFORMED;
593
594 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
595 next_tsn, GFP_ATOMIC);
596
597out:
Xin Long6c801382017-04-15 22:00:29 +0800598 sctp_update_strreset_result(asoc, result);
599err:
Xin Long692787c2017-03-10 12:11:07 +0800600 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
601 next_tsn, init_tsn);
602}
Xin Long50a41592017-03-10 12:11:09 +0800603
604struct sctp_chunk *sctp_process_strreset_addstrm_out(
605 struct sctp_association *asoc,
606 union sctp_params param,
607 struct sctp_ulpevent **evp)
608{
609 struct sctp_strreset_addstrm *addstrm = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800610 struct sctp_stream *stream = &asoc->stream;
Xin Long50a41592017-03-10 12:11:09 +0800611 __u32 result = SCTP_STRRESET_DENIED;
612 struct sctp_stream_in *streamin;
613 __u32 request_seq, incnt;
Xin Longe4dc99c2017-04-15 22:00:27 +0800614 __u16 in, i;
Xin Long50a41592017-03-10 12:11:09 +0800615
616 request_seq = ntohl(addstrm->request_seq);
Xin Longe4dc99c2017-04-15 22:00:27 +0800617 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
618 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long50a41592017-03-10 12:11:09 +0800619 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longe4dc99c2017-04-15 22:00:27 +0800620 goto err;
621 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
622 i = asoc->strreset_inseq - request_seq - 1;
623 result = asoc->strreset_result[i];
624 goto err;
Xin Long50a41592017-03-10 12:11:09 +0800625 }
Xin Longe4dc99c2017-04-15 22:00:27 +0800626 asoc->strreset_inseq++;
Xin Long50a41592017-03-10 12:11:09 +0800627
628 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
629 goto out;
630
631 if (asoc->strreset_chunk) {
632 if (!sctp_chunk_lookup_strreset_param(
633 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
634 /* same process with outstanding isn't 0 */
635 result = SCTP_STRRESET_ERR_IN_PROGRESS;
636 goto out;
637 }
638
639 asoc->strreset_outstanding--;
640 asoc->strreset_outseq++;
641
642 if (!asoc->strreset_outstanding) {
643 struct sctp_transport *t;
644
645 t = asoc->strreset_chunk->transport;
646 if (del_timer(&t->reconf_timer))
647 sctp_transport_put(t);
648
649 sctp_chunk_put(asoc->strreset_chunk);
650 asoc->strreset_chunk = NULL;
651 }
652 }
653
654 in = ntohs(addstrm->number_of_streams);
655 incnt = stream->incnt + in;
656 if (!in || incnt > SCTP_MAX_STREAM)
657 goto out;
658
659 streamin = krealloc(stream->in, incnt * sizeof(*streamin),
660 GFP_ATOMIC);
661 if (!streamin)
662 goto out;
663
664 memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
665 stream->in = streamin;
666 stream->incnt = incnt;
667
668 result = SCTP_STRRESET_PERFORMED;
669
670 *evp = sctp_ulpevent_make_stream_change_event(asoc,
671 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
672
673out:
Xin Longe4dc99c2017-04-15 22:00:27 +0800674 sctp_update_strreset_result(asoc, result);
675err:
Xin Long50a41592017-03-10 12:11:09 +0800676 return sctp_make_strreset_resp(asoc, result, request_seq);
677}
Xin Longc5c4ebb2017-03-10 12:11:10 +0800678
679struct sctp_chunk *sctp_process_strreset_addstrm_in(
680 struct sctp_association *asoc,
681 union sctp_params param,
682 struct sctp_ulpevent **evp)
683{
684 struct sctp_strreset_addstrm *addstrm = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800685 struct sctp_stream *stream = &asoc->stream;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800686 __u32 result = SCTP_STRRESET_DENIED;
687 struct sctp_stream_out *streamout;
688 struct sctp_chunk *chunk = NULL;
689 __u32 request_seq, outcnt;
Xin Longd0f025e2017-04-15 22:00:28 +0800690 __u16 out, i;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800691
692 request_seq = ntohl(addstrm->request_seq);
Xin Longd0f025e2017-04-15 22:00:28 +0800693 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
694 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Longc5c4ebb2017-03-10 12:11:10 +0800695 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longd0f025e2017-04-15 22:00:28 +0800696 goto err;
697 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
698 i = asoc->strreset_inseq - request_seq - 1;
699 result = asoc->strreset_result[i];
700 if (result == SCTP_STRRESET_PERFORMED)
701 return NULL;
702 goto err;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800703 }
Xin Longd0f025e2017-04-15 22:00:28 +0800704 asoc->strreset_inseq++;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800705
706 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
707 goto out;
708
709 if (asoc->strreset_outstanding) {
710 result = SCTP_STRRESET_ERR_IN_PROGRESS;
711 goto out;
712 }
713
714 out = ntohs(addstrm->number_of_streams);
715 outcnt = stream->outcnt + out;
716 if (!out || outcnt > SCTP_MAX_STREAM)
717 goto out;
718
719 streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
720 GFP_ATOMIC);
721 if (!streamout)
722 goto out;
723
724 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
725 stream->out = streamout;
726
727 chunk = sctp_make_strreset_addstrm(asoc, out, 0);
728 if (!chunk)
729 goto out;
730
731 asoc->strreset_chunk = chunk;
732 asoc->strreset_outstanding = 1;
733 sctp_chunk_hold(asoc->strreset_chunk);
734
735 stream->outcnt = outcnt;
736
Xin Longd0f025e2017-04-15 22:00:28 +0800737 result = SCTP_STRRESET_PERFORMED;
738
Xin Longc5c4ebb2017-03-10 12:11:10 +0800739 *evp = sctp_ulpevent_make_stream_change_event(asoc,
740 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
741
742out:
Xin Longd0f025e2017-04-15 22:00:28 +0800743 sctp_update_strreset_result(asoc, result);
744err:
Xin Longc5c4ebb2017-03-10 12:11:10 +0800745 if (!chunk)
746 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
747
748 return chunk;
749}
Xin Long11ae76e2017-03-10 12:11:11 +0800750
751struct sctp_chunk *sctp_process_strreset_resp(
752 struct sctp_association *asoc,
753 union sctp_params param,
754 struct sctp_ulpevent **evp)
755{
Xin Longcee360a2017-05-31 16:36:31 +0800756 struct sctp_stream *stream = &asoc->stream;
Xin Long11ae76e2017-03-10 12:11:11 +0800757 struct sctp_strreset_resp *resp = param.v;
Xin Long11ae76e2017-03-10 12:11:11 +0800758 struct sctp_transport *t;
759 __u16 i, nums, flags = 0;
Xin Long3c918702017-06-30 11:52:16 +0800760 struct sctp_paramhdr *req;
Xin Long11ae76e2017-03-10 12:11:11 +0800761 __u32 result;
762
763 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
764 if (!req)
765 return NULL;
766
767 result = ntohl(resp->result);
768 if (result != SCTP_STRRESET_PERFORMED) {
769 /* if in progress, do nothing but retransmit */
770 if (result == SCTP_STRRESET_IN_PROGRESS)
771 return NULL;
772 else if (result == SCTP_STRRESET_DENIED)
773 flags = SCTP_STREAM_RESET_DENIED;
774 else
775 flags = SCTP_STREAM_RESET_FAILED;
776 }
777
778 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
779 struct sctp_strreset_outreq *outreq;
Xin Long1da4fc92017-10-28 19:43:54 +0800780 __be16 *str_p;
Xin Long11ae76e2017-03-10 12:11:11 +0800781
782 outreq = (struct sctp_strreset_outreq *)req;
Xin Longedb12f22017-04-15 21:56:57 +0800783 str_p = outreq->list_of_streams;
Xin Long11ae76e2017-03-10 12:11:11 +0800784 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
785
786 if (result == SCTP_STRRESET_PERFORMED) {
787 if (nums) {
Xin Long11ae76e2017-03-10 12:11:11 +0800788 for (i = 0; i < nums; i++)
789 stream->out[ntohs(str_p[i])].ssn = 0;
790 } else {
791 for (i = 0; i < stream->outcnt; i++)
792 stream->out[i].ssn = 0;
793 }
794
795 flags = SCTP_STREAM_RESET_OUTGOING_SSN;
796 }
797
798 for (i = 0; i < stream->outcnt; i++)
799 stream->out[i].state = SCTP_STREAM_OPEN;
800
801 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
802 nums, str_p, GFP_ATOMIC);
803 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
804 struct sctp_strreset_inreq *inreq;
Xin Long1da4fc92017-10-28 19:43:54 +0800805 __be16 *str_p;
Xin Long11ae76e2017-03-10 12:11:11 +0800806
807 /* if the result is performed, it's impossible for inreq */
808 if (result == SCTP_STRRESET_PERFORMED)
809 return NULL;
810
811 inreq = (struct sctp_strreset_inreq *)req;
Xin Longedb12f22017-04-15 21:56:57 +0800812 str_p = inreq->list_of_streams;
Xin Long11ae76e2017-03-10 12:11:11 +0800813 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
814
Xin Long11ae76e2017-03-10 12:11:11 +0800815 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
816 nums, str_p, GFP_ATOMIC);
817 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
818 struct sctp_strreset_resptsn *resptsn;
819 __u32 stsn, rtsn;
820
821 /* check for resptsn, as sctp_verify_reconf didn't do it*/
822 if (ntohs(param.p->length) != sizeof(*resptsn))
823 return NULL;
824
825 resptsn = (struct sctp_strreset_resptsn *)resp;
826 stsn = ntohl(resptsn->senders_next_tsn);
827 rtsn = ntohl(resptsn->receivers_next_tsn);
828
829 if (result == SCTP_STRRESET_PERFORMED) {
830 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
831 &asoc->peer.tsn_map);
832
833 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
834 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
835
836 sctp_tsnmap_init(&asoc->peer.tsn_map,
837 SCTP_TSN_MAP_INITIAL,
838 stsn, GFP_ATOMIC);
839
840 sctp_outq_free(&asoc->outqueue);
841
842 asoc->next_tsn = rtsn;
843 asoc->ctsn_ack_point = asoc->next_tsn - 1;
844 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
845
846 for (i = 0; i < stream->outcnt; i++)
847 stream->out[i].ssn = 0;
848 for (i = 0; i < stream->incnt; i++)
849 stream->in[i].ssn = 0;
850 }
851
852 for (i = 0; i < stream->outcnt; i++)
853 stream->out[i].state = SCTP_STREAM_OPEN;
854
855 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
856 stsn, rtsn, GFP_ATOMIC);
857 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
858 struct sctp_strreset_addstrm *addstrm;
859 __u16 number;
860
861 addstrm = (struct sctp_strreset_addstrm *)req;
862 nums = ntohs(addstrm->number_of_streams);
863 number = stream->outcnt - nums;
864
865 if (result == SCTP_STRRESET_PERFORMED)
866 for (i = number; i < stream->outcnt; i++)
867 stream->out[i].state = SCTP_STREAM_OPEN;
868 else
869 stream->outcnt = number;
870
871 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
872 0, nums, GFP_ATOMIC);
873 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
874 struct sctp_strreset_addstrm *addstrm;
875
876 /* if the result is performed, it's impossible for addstrm in
877 * request.
878 */
879 if (result == SCTP_STRRESET_PERFORMED)
880 return NULL;
881
882 addstrm = (struct sctp_strreset_addstrm *)req;
883 nums = ntohs(addstrm->number_of_streams);
884
885 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
886 nums, 0, GFP_ATOMIC);
887 }
888
889 asoc->strreset_outstanding--;
890 asoc->strreset_outseq++;
891
892 /* remove everything for this reconf request */
893 if (!asoc->strreset_outstanding) {
894 t = asoc->strreset_chunk->transport;
895 if (del_timer(&t->reconf_timer))
896 sctp_transport_put(t);
897
898 sctp_chunk_put(asoc->strreset_chunk);
899 asoc->strreset_chunk = NULL;
900 }
901
902 return NULL;
903}