blob: 82e6d40052a8dd9ad2049ec506d132ab1305a64f [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;
121 bool out, in;
122
123 if (!asoc->peer.reconf_capable ||
124 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
125 retval = -ENOPROTOOPT;
126 goto out;
127 }
128
129 if (asoc->strreset_outstanding) {
130 retval = -EINPROGRESS;
131 goto out;
132 }
133
134 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
135 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
136 if (!out && !in)
137 goto out;
138
139 str_nums = params->srs_number_streams;
140 str_list = params->srs_stream_list;
141 if (out && str_nums)
142 for (i = 0; i < str_nums; i++)
143 if (str_list[i] >= stream->outcnt)
144 goto out;
145
146 if (in && str_nums)
147 for (i = 0; i < str_nums; i++)
148 if (str_list[i] >= stream->incnt)
149 goto out;
150
Xin Long16e1a912017-02-17 12:45:40 +0800151 for (i = 0; i < str_nums; i++)
152 str_list[i] = htons(str_list[i]);
153
Xin Long7f9d68a2017-01-18 00:44:47 +0800154 chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in);
Xin Long16e1a912017-02-17 12:45:40 +0800155
156 for (i = 0; i < str_nums; i++)
157 str_list[i] = ntohs(str_list[i]);
158
Xin Long119aecb2017-02-09 01:18:16 +0800159 if (!chunk) {
160 retval = -ENOMEM;
Xin Long7f9d68a2017-01-18 00:44:47 +0800161 goto out;
Xin Long119aecb2017-02-09 01:18:16 +0800162 }
Xin Long7f9d68a2017-01-18 00:44:47 +0800163
164 if (out) {
165 if (str_nums)
166 for (i = 0; i < str_nums; i++)
167 stream->out[str_list[i]].state =
168 SCTP_STREAM_CLOSED;
169 else
170 for (i = 0; i < stream->outcnt; i++)
171 stream->out[i].state = SCTP_STREAM_CLOSED;
172 }
173
Xin Long7f9d68a2017-01-18 00:44:47 +0800174 asoc->strreset_chunk = chunk;
175 sctp_chunk_hold(asoc->strreset_chunk);
176
177 retval = sctp_send_reconf(asoc, chunk);
178 if (retval) {
179 sctp_chunk_put(asoc->strreset_chunk);
180 asoc->strreset_chunk = NULL;
Xin Long119aecb2017-02-09 01:18:16 +0800181 if (!out)
182 goto out;
183
184 if (str_nums)
185 for (i = 0; i < str_nums; i++)
186 stream->out[str_list[i]].state =
187 SCTP_STREAM_OPEN;
188 else
189 for (i = 0; i < stream->outcnt; i++)
190 stream->out[i].state = SCTP_STREAM_OPEN;
191
192 goto out;
Xin Long7f9d68a2017-01-18 00:44:47 +0800193 }
194
Xin Long119aecb2017-02-09 01:18:16 +0800195 asoc->strreset_outstanding = out + in;
196
Xin Long7f9d68a2017-01-18 00:44:47 +0800197out:
198 return retval;
199}
Xin Longa92ce1a2017-02-09 01:18:18 +0800200
201int sctp_send_reset_assoc(struct sctp_association *asoc)
202{
Xin Longcee360a2017-05-31 16:36:31 +0800203 struct sctp_stream *stream = &asoc->stream;
Xin Longa92ce1a2017-02-09 01:18:18 +0800204 struct sctp_chunk *chunk = NULL;
205 int retval;
206 __u16 i;
207
208 if (!asoc->peer.reconf_capable ||
209 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
210 return -ENOPROTOOPT;
211
212 if (asoc->strreset_outstanding)
213 return -EINPROGRESS;
214
215 chunk = sctp_make_strreset_tsnreq(asoc);
216 if (!chunk)
217 return -ENOMEM;
218
219 /* Block further xmit of data until this request is completed */
Xin Longcee360a2017-05-31 16:36:31 +0800220 for (i = 0; i < stream->outcnt; i++)
221 stream->out[i].state = SCTP_STREAM_CLOSED;
Xin Longa92ce1a2017-02-09 01:18:18 +0800222
223 asoc->strreset_chunk = chunk;
224 sctp_chunk_hold(asoc->strreset_chunk);
225
226 retval = sctp_send_reconf(asoc, chunk);
227 if (retval) {
228 sctp_chunk_put(asoc->strreset_chunk);
229 asoc->strreset_chunk = NULL;
230
Xin Longcee360a2017-05-31 16:36:31 +0800231 for (i = 0; i < stream->outcnt; i++)
232 stream->out[i].state = SCTP_STREAM_OPEN;
Xin Longa92ce1a2017-02-09 01:18:18 +0800233
234 return retval;
235 }
236
237 asoc->strreset_outstanding = 1;
238
239 return 0;
240}
Xin Long242bd2d2017-02-09 01:18:20 +0800241
242int sctp_send_add_streams(struct sctp_association *asoc,
243 struct sctp_add_streams *params)
244{
Xin Longcee360a2017-05-31 16:36:31 +0800245 struct sctp_stream *stream = &asoc->stream;
Xin Long242bd2d2017-02-09 01:18:20 +0800246 struct sctp_chunk *chunk = NULL;
247 int retval = -ENOMEM;
248 __u32 outcnt, incnt;
249 __u16 out, in;
250
251 if (!asoc->peer.reconf_capable ||
252 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
253 retval = -ENOPROTOOPT;
254 goto out;
255 }
256
257 if (asoc->strreset_outstanding) {
258 retval = -EINPROGRESS;
259 goto out;
260 }
261
262 out = params->sas_outstrms;
263 in = params->sas_instrms;
264 outcnt = stream->outcnt + out;
265 incnt = stream->incnt + in;
266 if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
267 (!out && !in)) {
268 retval = -EINVAL;
269 goto out;
270 }
271
272 if (out) {
273 struct sctp_stream_out *streamout;
274
275 streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
276 GFP_KERNEL);
277 if (!streamout)
278 goto out;
279
280 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
281 stream->out = streamout;
282 }
283
Xin Long242bd2d2017-02-09 01:18:20 +0800284 chunk = sctp_make_strreset_addstrm(asoc, out, in);
285 if (!chunk)
286 goto out;
287
288 asoc->strreset_chunk = chunk;
289 sctp_chunk_hold(asoc->strreset_chunk);
290
291 retval = sctp_send_reconf(asoc, chunk);
292 if (retval) {
293 sctp_chunk_put(asoc->strreset_chunk);
294 asoc->strreset_chunk = NULL;
295 goto out;
296 }
297
298 stream->incnt = incnt;
299 stream->outcnt = outcnt;
300
301 asoc->strreset_outstanding = !!out + !!in;
302
303out:
304 return retval;
305}
Xin Long81054472017-02-17 12:45:39 +0800306
307static sctp_paramhdr_t *sctp_chunk_lookup_strreset_param(
Xin Long50a41592017-03-10 12:11:09 +0800308 struct sctp_association *asoc, __u32 resp_seq,
309 __be16 type)
Xin Long81054472017-02-17 12:45:39 +0800310{
311 struct sctp_chunk *chunk = asoc->strreset_chunk;
312 struct sctp_reconf_chunk *hdr;
313 union sctp_params param;
314
Xin Long50a41592017-03-10 12:11:09 +0800315 if (!chunk)
Xin Long81054472017-02-17 12:45:39 +0800316 return NULL;
317
318 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
319 sctp_walk_params(param, hdr, params) {
320 /* sctp_strreset_tsnreq is actually the basic structure
321 * of all stream reconf params, so it's safe to use it
322 * to access request_seq.
323 */
324 struct sctp_strreset_tsnreq *req = param.v;
325
Xin Long50a41592017-03-10 12:11:09 +0800326 if ((!resp_seq || req->request_seq == resp_seq) &&
327 (!type || type == req->param_hdr.type))
Xin Long81054472017-02-17 12:45:39 +0800328 return param.v;
329 }
330
331 return NULL;
332}
333
Xin Longe4dc99c2017-04-15 22:00:27 +0800334static void sctp_update_strreset_result(struct sctp_association *asoc,
335 __u32 result)
336{
337 asoc->strreset_result[1] = asoc->strreset_result[0];
338 asoc->strreset_result[0] = result;
339}
340
Xin Long81054472017-02-17 12:45:39 +0800341struct sctp_chunk *sctp_process_strreset_outreq(
342 struct sctp_association *asoc,
343 union sctp_params param,
344 struct sctp_ulpevent **evp)
345{
346 struct sctp_strreset_outreq *outreq = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800347 struct sctp_stream *stream = &asoc->stream;
Xin Long81054472017-02-17 12:45:39 +0800348 __u16 i, nums, flags = 0, *str_p = NULL;
349 __u32 result = SCTP_STRRESET_DENIED;
350 __u32 request_seq;
351
352 request_seq = ntohl(outreq->request_seq);
353
354 if (ntohl(outreq->send_reset_at_tsn) >
355 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
356 result = SCTP_STRRESET_IN_PROGRESS;
Xin Longe4dc99c2017-04-15 22:00:27 +0800357 goto err;
Xin Long81054472017-02-17 12:45:39 +0800358 }
359
Xin Longe4dc99c2017-04-15 22:00:27 +0800360 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
361 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long81054472017-02-17 12:45:39 +0800362 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longe4dc99c2017-04-15 22:00:27 +0800363 goto err;
364 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
365 i = asoc->strreset_inseq - request_seq - 1;
366 result = asoc->strreset_result[i];
367 goto err;
Xin Long81054472017-02-17 12:45:39 +0800368 }
Xin Longe4dc99c2017-04-15 22:00:27 +0800369 asoc->strreset_inseq++;
Xin Long81054472017-02-17 12:45:39 +0800370
371 /* Check strreset_enable after inseq inc, as sender cannot tell
372 * the peer doesn't enable strreset after receiving response with
373 * result denied, as well as to keep consistent with bsd.
374 */
375 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
376 goto out;
377
378 if (asoc->strreset_chunk) {
Xin Long50a41592017-03-10 12:11:09 +0800379 if (!sctp_chunk_lookup_strreset_param(
380 asoc, outreq->response_seq,
381 SCTP_PARAM_RESET_IN_REQUEST)) {
Xin Long81054472017-02-17 12:45:39 +0800382 /* same process with outstanding isn't 0 */
383 result = SCTP_STRRESET_ERR_IN_PROGRESS;
384 goto out;
385 }
386
387 asoc->strreset_outstanding--;
388 asoc->strreset_outseq++;
389
390 if (!asoc->strreset_outstanding) {
Xin Long50a41592017-03-10 12:11:09 +0800391 struct sctp_transport *t;
392
Xin Long81054472017-02-17 12:45:39 +0800393 t = asoc->strreset_chunk->transport;
394 if (del_timer(&t->reconf_timer))
395 sctp_transport_put(t);
396
397 sctp_chunk_put(asoc->strreset_chunk);
398 asoc->strreset_chunk = NULL;
399 }
400
401 flags = SCTP_STREAM_RESET_INCOMING_SSN;
402 }
403
404 nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2;
405 if (nums) {
406 str_p = outreq->list_of_streams;
407 for (i = 0; i < nums; i++) {
408 if (ntohs(str_p[i]) >= stream->incnt) {
409 result = SCTP_STRRESET_ERR_WRONG_SSN;
410 goto out;
411 }
412 }
413
414 for (i = 0; i < nums; i++)
415 stream->in[ntohs(str_p[i])].ssn = 0;
416 } else {
417 for (i = 0; i < stream->incnt; i++)
418 stream->in[i].ssn = 0;
419 }
420
421 result = SCTP_STRRESET_PERFORMED;
422
423 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
424 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
425 GFP_ATOMIC);
426
427out:
Xin Longe4dc99c2017-04-15 22:00:27 +0800428 sctp_update_strreset_result(asoc, result);
429err:
Xin Long81054472017-02-17 12:45:39 +0800430 return sctp_make_strreset_resp(asoc, result, request_seq);
431}
Xin Long16e1a912017-02-17 12:45:40 +0800432
433struct sctp_chunk *sctp_process_strreset_inreq(
434 struct sctp_association *asoc,
435 union sctp_params param,
436 struct sctp_ulpevent **evp)
437{
438 struct sctp_strreset_inreq *inreq = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800439 struct sctp_stream *stream = &asoc->stream;
Xin Long16e1a912017-02-17 12:45:40 +0800440 __u32 result = SCTP_STRRESET_DENIED;
441 struct sctp_chunk *chunk = NULL;
442 __u16 i, nums, *str_p;
443 __u32 request_seq;
444
445 request_seq = ntohl(inreq->request_seq);
Xin Longd0f025e2017-04-15 22:00:28 +0800446 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
447 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long16e1a912017-02-17 12:45:40 +0800448 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longd0f025e2017-04-15 22:00:28 +0800449 goto err;
450 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
451 i = asoc->strreset_inseq - request_seq - 1;
452 result = asoc->strreset_result[i];
453 if (result == SCTP_STRRESET_PERFORMED)
454 return NULL;
455 goto err;
Xin Long16e1a912017-02-17 12:45:40 +0800456 }
Xin Longd0f025e2017-04-15 22:00:28 +0800457 asoc->strreset_inseq++;
Xin Long16e1a912017-02-17 12:45:40 +0800458
459 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
460 goto out;
461
462 if (asoc->strreset_outstanding) {
463 result = SCTP_STRRESET_ERR_IN_PROGRESS;
464 goto out;
465 }
466
467 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
468 str_p = inreq->list_of_streams;
469 for (i = 0; i < nums; i++) {
470 if (ntohs(str_p[i]) >= stream->outcnt) {
471 result = SCTP_STRRESET_ERR_WRONG_SSN;
472 goto out;
473 }
474 }
475
476 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
477 if (!chunk)
478 goto out;
479
480 if (nums)
481 for (i = 0; i < nums; i++)
482 stream->out[ntohs(str_p[i])].state =
483 SCTP_STREAM_CLOSED;
484 else
485 for (i = 0; i < stream->outcnt; i++)
486 stream->out[i].state = SCTP_STREAM_CLOSED;
487
488 asoc->strreset_chunk = chunk;
489 asoc->strreset_outstanding = 1;
490 sctp_chunk_hold(asoc->strreset_chunk);
491
Xin Longd0f025e2017-04-15 22:00:28 +0800492 result = SCTP_STRRESET_PERFORMED;
493
Xin Long16e1a912017-02-17 12:45:40 +0800494 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
495 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
496
497out:
Xin Longd0f025e2017-04-15 22:00:28 +0800498 sctp_update_strreset_result(asoc, result);
499err:
Xin Long16e1a912017-02-17 12:45:40 +0800500 if (!chunk)
501 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
502
503 return chunk;
504}
Xin Long692787c2017-03-10 12:11:07 +0800505
506struct sctp_chunk *sctp_process_strreset_tsnreq(
507 struct sctp_association *asoc,
508 union sctp_params param,
509 struct sctp_ulpevent **evp)
510{
511 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
512 struct sctp_strreset_tsnreq *tsnreq = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800513 struct sctp_stream *stream = &asoc->stream;
Xin Long692787c2017-03-10 12:11:07 +0800514 __u32 result = SCTP_STRRESET_DENIED;
515 __u32 request_seq;
516 __u16 i;
517
518 request_seq = ntohl(tsnreq->request_seq);
Xin Long6c801382017-04-15 22:00:29 +0800519 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
520 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long692787c2017-03-10 12:11:07 +0800521 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Long6c801382017-04-15 22:00:29 +0800522 goto err;
523 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
524 i = asoc->strreset_inseq - request_seq - 1;
525 result = asoc->strreset_result[i];
526 if (result == SCTP_STRRESET_PERFORMED) {
527 next_tsn = asoc->next_tsn;
528 init_tsn =
529 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
530 }
531 goto err;
Xin Long692787c2017-03-10 12:11:07 +0800532 }
Xin Long6c801382017-04-15 22:00:29 +0800533 asoc->strreset_inseq++;
Xin Long692787c2017-03-10 12:11:07 +0800534
535 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
536 goto out;
537
538 if (asoc->strreset_outstanding) {
539 result = SCTP_STRRESET_ERR_IN_PROGRESS;
540 goto out;
541 }
542
543 /* G3: The same processing as though a SACK chunk with no gap report
544 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
545 * received MUST be performed.
546 */
547 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
548 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
549 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
550
551 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
552 * TSN that the peer should use to send the next DATA chunk. The
553 * value SHOULD be the smallest TSN not acknowledged by the
554 * receiver of the request plus 2^31.
555 */
556 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
557 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
558 init_tsn, GFP_ATOMIC);
559
560 /* G4: The same processing as though a FWD-TSN chunk (as defined in
561 * [RFC3758]) with all streams affected and a new cumulative TSN
562 * ACK of the Receiver's Next TSN minus 1 were received MUST be
563 * performed.
564 */
565 sctp_outq_free(&asoc->outqueue);
566
567 /* G2: Compute an appropriate value for the local endpoint's next TSN,
568 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
569 * chunk. The value SHOULD be the highest TSN sent by the receiver
570 * of the request plus 1.
571 */
572 next_tsn = asoc->next_tsn;
573 asoc->ctsn_ack_point = next_tsn - 1;
574 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
575
576 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
577 * incoming and outgoing streams.
578 */
579 for (i = 0; i < stream->outcnt; i++)
580 stream->out[i].ssn = 0;
581 for (i = 0; i < stream->incnt; i++)
582 stream->in[i].ssn = 0;
583
584 result = SCTP_STRRESET_PERFORMED;
585
586 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
587 next_tsn, GFP_ATOMIC);
588
589out:
Xin Long6c801382017-04-15 22:00:29 +0800590 sctp_update_strreset_result(asoc, result);
591err:
Xin Long692787c2017-03-10 12:11:07 +0800592 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
593 next_tsn, init_tsn);
594}
Xin Long50a41592017-03-10 12:11:09 +0800595
596struct sctp_chunk *sctp_process_strreset_addstrm_out(
597 struct sctp_association *asoc,
598 union sctp_params param,
599 struct sctp_ulpevent **evp)
600{
601 struct sctp_strreset_addstrm *addstrm = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800602 struct sctp_stream *stream = &asoc->stream;
Xin Long50a41592017-03-10 12:11:09 +0800603 __u32 result = SCTP_STRRESET_DENIED;
604 struct sctp_stream_in *streamin;
605 __u32 request_seq, incnt;
Xin Longe4dc99c2017-04-15 22:00:27 +0800606 __u16 in, i;
Xin Long50a41592017-03-10 12:11:09 +0800607
608 request_seq = ntohl(addstrm->request_seq);
Xin Longe4dc99c2017-04-15 22:00:27 +0800609 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
610 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Long50a41592017-03-10 12:11:09 +0800611 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longe4dc99c2017-04-15 22:00:27 +0800612 goto err;
613 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
614 i = asoc->strreset_inseq - request_seq - 1;
615 result = asoc->strreset_result[i];
616 goto err;
Xin Long50a41592017-03-10 12:11:09 +0800617 }
Xin Longe4dc99c2017-04-15 22:00:27 +0800618 asoc->strreset_inseq++;
Xin Long50a41592017-03-10 12:11:09 +0800619
620 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
621 goto out;
622
623 if (asoc->strreset_chunk) {
624 if (!sctp_chunk_lookup_strreset_param(
625 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
626 /* same process with outstanding isn't 0 */
627 result = SCTP_STRRESET_ERR_IN_PROGRESS;
628 goto out;
629 }
630
631 asoc->strreset_outstanding--;
632 asoc->strreset_outseq++;
633
634 if (!asoc->strreset_outstanding) {
635 struct sctp_transport *t;
636
637 t = asoc->strreset_chunk->transport;
638 if (del_timer(&t->reconf_timer))
639 sctp_transport_put(t);
640
641 sctp_chunk_put(asoc->strreset_chunk);
642 asoc->strreset_chunk = NULL;
643 }
644 }
645
646 in = ntohs(addstrm->number_of_streams);
647 incnt = stream->incnt + in;
648 if (!in || incnt > SCTP_MAX_STREAM)
649 goto out;
650
651 streamin = krealloc(stream->in, incnt * sizeof(*streamin),
652 GFP_ATOMIC);
653 if (!streamin)
654 goto out;
655
656 memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
657 stream->in = streamin;
658 stream->incnt = incnt;
659
660 result = SCTP_STRRESET_PERFORMED;
661
662 *evp = sctp_ulpevent_make_stream_change_event(asoc,
663 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
664
665out:
Xin Longe4dc99c2017-04-15 22:00:27 +0800666 sctp_update_strreset_result(asoc, result);
667err:
Xin Long50a41592017-03-10 12:11:09 +0800668 return sctp_make_strreset_resp(asoc, result, request_seq);
669}
Xin Longc5c4ebb2017-03-10 12:11:10 +0800670
671struct sctp_chunk *sctp_process_strreset_addstrm_in(
672 struct sctp_association *asoc,
673 union sctp_params param,
674 struct sctp_ulpevent **evp)
675{
676 struct sctp_strreset_addstrm *addstrm = param.v;
Xin Longcee360a2017-05-31 16:36:31 +0800677 struct sctp_stream *stream = &asoc->stream;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800678 __u32 result = SCTP_STRRESET_DENIED;
679 struct sctp_stream_out *streamout;
680 struct sctp_chunk *chunk = NULL;
681 __u32 request_seq, outcnt;
Xin Longd0f025e2017-04-15 22:00:28 +0800682 __u16 out, i;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800683
684 request_seq = ntohl(addstrm->request_seq);
Xin Longd0f025e2017-04-15 22:00:28 +0800685 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
686 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
Xin Longc5c4ebb2017-03-10 12:11:10 +0800687 result = SCTP_STRRESET_ERR_BAD_SEQNO;
Xin Longd0f025e2017-04-15 22:00:28 +0800688 goto err;
689 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
690 i = asoc->strreset_inseq - request_seq - 1;
691 result = asoc->strreset_result[i];
692 if (result == SCTP_STRRESET_PERFORMED)
693 return NULL;
694 goto err;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800695 }
Xin Longd0f025e2017-04-15 22:00:28 +0800696 asoc->strreset_inseq++;
Xin Longc5c4ebb2017-03-10 12:11:10 +0800697
698 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
699 goto out;
700
701 if (asoc->strreset_outstanding) {
702 result = SCTP_STRRESET_ERR_IN_PROGRESS;
703 goto out;
704 }
705
706 out = ntohs(addstrm->number_of_streams);
707 outcnt = stream->outcnt + out;
708 if (!out || outcnt > SCTP_MAX_STREAM)
709 goto out;
710
711 streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
712 GFP_ATOMIC);
713 if (!streamout)
714 goto out;
715
716 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
717 stream->out = streamout;
718
719 chunk = sctp_make_strreset_addstrm(asoc, out, 0);
720 if (!chunk)
721 goto out;
722
723 asoc->strreset_chunk = chunk;
724 asoc->strreset_outstanding = 1;
725 sctp_chunk_hold(asoc->strreset_chunk);
726
727 stream->outcnt = outcnt;
728
Xin Longd0f025e2017-04-15 22:00:28 +0800729 result = SCTP_STRRESET_PERFORMED;
730
Xin Longc5c4ebb2017-03-10 12:11:10 +0800731 *evp = sctp_ulpevent_make_stream_change_event(asoc,
732 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
733
734out:
Xin Longd0f025e2017-04-15 22:00:28 +0800735 sctp_update_strreset_result(asoc, result);
736err:
Xin Longc5c4ebb2017-03-10 12:11:10 +0800737 if (!chunk)
738 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
739
740 return chunk;
741}
Xin Long11ae76e2017-03-10 12:11:11 +0800742
743struct sctp_chunk *sctp_process_strreset_resp(
744 struct sctp_association *asoc,
745 union sctp_params param,
746 struct sctp_ulpevent **evp)
747{
Xin Longcee360a2017-05-31 16:36:31 +0800748 struct sctp_stream *stream = &asoc->stream;
Xin Long11ae76e2017-03-10 12:11:11 +0800749 struct sctp_strreset_resp *resp = param.v;
Xin Long11ae76e2017-03-10 12:11:11 +0800750 struct sctp_transport *t;
751 __u16 i, nums, flags = 0;
752 sctp_paramhdr_t *req;
753 __u32 result;
754
755 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
756 if (!req)
757 return NULL;
758
759 result = ntohl(resp->result);
760 if (result != SCTP_STRRESET_PERFORMED) {
761 /* if in progress, do nothing but retransmit */
762 if (result == SCTP_STRRESET_IN_PROGRESS)
763 return NULL;
764 else if (result == SCTP_STRRESET_DENIED)
765 flags = SCTP_STREAM_RESET_DENIED;
766 else
767 flags = SCTP_STREAM_RESET_FAILED;
768 }
769
770 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
771 struct sctp_strreset_outreq *outreq;
Xin Longedb12f22017-04-15 21:56:57 +0800772 __u16 *str_p;
Xin Long11ae76e2017-03-10 12:11:11 +0800773
774 outreq = (struct sctp_strreset_outreq *)req;
Xin Longedb12f22017-04-15 21:56:57 +0800775 str_p = outreq->list_of_streams;
Xin Long11ae76e2017-03-10 12:11:11 +0800776 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
777
778 if (result == SCTP_STRRESET_PERFORMED) {
779 if (nums) {
Xin Long11ae76e2017-03-10 12:11:11 +0800780 for (i = 0; i < nums; i++)
781 stream->out[ntohs(str_p[i])].ssn = 0;
782 } else {
783 for (i = 0; i < stream->outcnt; i++)
784 stream->out[i].ssn = 0;
785 }
786
787 flags = SCTP_STREAM_RESET_OUTGOING_SSN;
788 }
789
790 for (i = 0; i < stream->outcnt; i++)
791 stream->out[i].state = SCTP_STREAM_OPEN;
792
793 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
794 nums, str_p, GFP_ATOMIC);
795 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
796 struct sctp_strreset_inreq *inreq;
Xin Longedb12f22017-04-15 21:56:57 +0800797 __u16 *str_p;
Xin Long11ae76e2017-03-10 12:11:11 +0800798
799 /* if the result is performed, it's impossible for inreq */
800 if (result == SCTP_STRRESET_PERFORMED)
801 return NULL;
802
803 inreq = (struct sctp_strreset_inreq *)req;
Xin Longedb12f22017-04-15 21:56:57 +0800804 str_p = inreq->list_of_streams;
Xin Long11ae76e2017-03-10 12:11:11 +0800805 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
806
Xin Long11ae76e2017-03-10 12:11:11 +0800807 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
808 nums, str_p, GFP_ATOMIC);
809 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
810 struct sctp_strreset_resptsn *resptsn;
811 __u32 stsn, rtsn;
812
813 /* check for resptsn, as sctp_verify_reconf didn't do it*/
814 if (ntohs(param.p->length) != sizeof(*resptsn))
815 return NULL;
816
817 resptsn = (struct sctp_strreset_resptsn *)resp;
818 stsn = ntohl(resptsn->senders_next_tsn);
819 rtsn = ntohl(resptsn->receivers_next_tsn);
820
821 if (result == SCTP_STRRESET_PERFORMED) {
822 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
823 &asoc->peer.tsn_map);
824
825 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
826 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
827
828 sctp_tsnmap_init(&asoc->peer.tsn_map,
829 SCTP_TSN_MAP_INITIAL,
830 stsn, GFP_ATOMIC);
831
832 sctp_outq_free(&asoc->outqueue);
833
834 asoc->next_tsn = rtsn;
835 asoc->ctsn_ack_point = asoc->next_tsn - 1;
836 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
837
838 for (i = 0; i < stream->outcnt; i++)
839 stream->out[i].ssn = 0;
840 for (i = 0; i < stream->incnt; i++)
841 stream->in[i].ssn = 0;
842 }
843
844 for (i = 0; i < stream->outcnt; i++)
845 stream->out[i].state = SCTP_STREAM_OPEN;
846
847 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
848 stsn, rtsn, GFP_ATOMIC);
849 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
850 struct sctp_strreset_addstrm *addstrm;
851 __u16 number;
852
853 addstrm = (struct sctp_strreset_addstrm *)req;
854 nums = ntohs(addstrm->number_of_streams);
855 number = stream->outcnt - nums;
856
857 if (result == SCTP_STRRESET_PERFORMED)
858 for (i = number; i < stream->outcnt; i++)
859 stream->out[i].state = SCTP_STREAM_OPEN;
860 else
861 stream->outcnt = number;
862
863 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
864 0, nums, GFP_ATOMIC);
865 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
866 struct sctp_strreset_addstrm *addstrm;
867
868 /* if the result is performed, it's impossible for addstrm in
869 * request.
870 */
871 if (result == SCTP_STRRESET_PERFORMED)
872 return NULL;
873
874 addstrm = (struct sctp_strreset_addstrm *)req;
875 nums = ntohs(addstrm->number_of_streams);
876
877 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
878 nums, 0, GFP_ATOMIC);
879 }
880
881 asoc->strreset_outstanding--;
882 asoc->strreset_outseq++;
883
884 /* remove everything for this reconf request */
885 if (!asoc->strreset_outstanding) {
886 t = asoc->strreset_chunk->transport;
887 if (del_timer(&t->reconf_timer))
888 sctp_transport_put(t);
889
890 sctp_chunk_put(asoc->strreset_chunk);
891 asoc->strreset_chunk = NULL;
892 }
893
894 return NULL;
895}