1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* SCTP kernel implementation
3 * (C) Copyright IBM Corp. 2001, 2004
4 * Copyright (c) 1999-2000 Cisco, Inc.
5 * Copyright (c) 1999-2001 Motorola, Inc.
6 * Copyright (c) 2001 Intel Corp.
7 *
8 * This file is part of the SCTP kernel implementation
9 *
10 * This file contains sctp stream maniuplation primitives and helpers.
11 *
12 * Please send any bug reports or fixes you make to the
13 * email address(es):
14 * lksctp developers <linux-sctp@vger.kernel.org>
15 *
16 * Written or modified by:
17 * Xin Long <lucien.xin@gmail.com>
18 */
19
20 #include <linux/list.h>
21 #include <net/sctp/sctp.h>
22 #include <net/sctp/sm.h>
23 #include <net/sctp/stream_sched.h>
24
25 #define SCTP_STRRESET_MASK(type) \
26 BIT(ntohs(type) - ntohs(SCTP_PARAM_RESET_OUT_REQUEST))
27 #define SCTP_STRRESET_TEST(asoc, type) \
28 ((asoc)->strreset_outstanding & SCTP_STRRESET_MASK(type))
29 #define SCTP_STRRESET_SET(asoc, type) \
30 ((asoc)->strreset_outstanding |= SCTP_STRRESET_MASK(type))
31 #define SCTP_STRRESET_CLEAR(asoc, type) \
32 ((asoc)->strreset_outstanding &= ~SCTP_STRRESET_MASK(type))
33
sctp_stream_shrink_out(struct sctp_stream * stream,__u16 outcnt)34 static void sctp_stream_shrink_out(struct sctp_stream *stream, __u16 outcnt)
35 {
36 struct sctp_association *asoc;
37 struct sctp_chunk *ch, *temp;
38 struct sctp_outq *outq;
39
40 asoc = container_of(stream, struct sctp_association, stream);
41 outq = &asoc->outqueue;
42
43 list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
44 __u16 sid = sctp_chunk_stream_no(ch);
45
46 if (sid < outcnt)
47 continue;
48
49 sctp_sched_dequeue_common(outq, ch);
50 /* No need to call dequeue_done here because
51 * the chunks are not scheduled by now.
52 */
53
54 /* Mark as failed send. */
55 sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
56 if (asoc->peer.prsctp_capable &&
57 SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
58 asoc->sent_cnt_removable--;
59
60 sctp_chunk_free(ch);
61 }
62 }
63
sctp_stream_free_ext(struct sctp_stream * stream,__u16 sid)64 static void sctp_stream_free_ext(struct sctp_stream *stream, __u16 sid)
65 {
66 const struct sctp_sched_ops *sched;
67
68 if (!SCTP_SO(stream, sid)->ext)
69 return;
70
71 sched = sctp_sched_ops_from_stream(stream);
72 sched->free_sid(stream, sid);
73 kfree(SCTP_SO(stream, sid)->ext);
74 SCTP_SO(stream, sid)->ext = NULL;
75 }
76
77 /* Migrates chunks from stream queues to new stream queues if needed,
78 * but not across associations. Also, removes those chunks to streams
79 * higher than the new max.
80 */
sctp_stream_outq_migrate(struct sctp_stream * stream,struct sctp_stream * new,__u16 outcnt)81 static void sctp_stream_outq_migrate(struct sctp_stream *stream,
82 struct sctp_stream *new, __u16 outcnt)
83 {
84 int i;
85
86 if (stream->outcnt > outcnt)
87 sctp_stream_shrink_out(stream, outcnt);
88
89 if (new) {
90 /* Here we actually move the old ext stuff into the new
91 * buffer, because we want to keep it. Then
92 * sctp_stream_update will swap ->out pointers.
93 */
94 for (i = 0; i < outcnt; i++) {
95 sctp_stream_free_ext(new, i);
96 SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
97 SCTP_SO(stream, i)->ext = NULL;
98 }
99 }
100
101 for (i = outcnt; i < stream->outcnt; i++)
102 sctp_stream_free_ext(stream, i);
103 }
104
sctp_stream_alloc_out(struct sctp_stream * stream,__u16 outcnt,gfp_t gfp)105 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
106 gfp_t gfp)
107 {
108 int ret;
109
110 if (outcnt <= stream->outcnt)
111 goto out;
112
113 ret = genradix_prealloc(&stream->out, outcnt, gfp);
114 if (ret)
115 return ret;
116
117 out:
118 stream->outcnt = outcnt;
119 return 0;
120 }
121
sctp_stream_alloc_in(struct sctp_stream * stream,__u16 incnt,gfp_t gfp)122 static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
123 gfp_t gfp)
124 {
125 int ret;
126
127 if (incnt <= stream->incnt)
128 goto out;
129
130 ret = genradix_prealloc(&stream->in, incnt, gfp);
131 if (ret)
132 return ret;
133
134 out:
135 stream->incnt = incnt;
136 return 0;
137 }
138
sctp_stream_init(struct sctp_stream * stream,__u16 outcnt,__u16 incnt,gfp_t gfp)139 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
140 gfp_t gfp)
141 {
142 const struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
143 int i, ret = 0;
144
145 gfp |= __GFP_NOWARN;
146
147 /* Initial stream->out size may be very big, so free it and alloc
148 * a new one with new outcnt to save memory if needed.
149 */
150 if (outcnt == stream->outcnt)
151 goto handle_in;
152
153 /* Filter out chunks queued on streams that won't exist anymore */
154 sched->unsched_all(stream);
155 sctp_stream_outq_migrate(stream, NULL, outcnt);
156 sched->sched_all(stream);
157
158 ret = sctp_stream_alloc_out(stream, outcnt, gfp);
159 if (ret)
160 return ret;
161
162 for (i = 0; i < stream->outcnt; i++)
163 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
164
165 handle_in:
166 sctp_stream_interleave_init(stream);
167 if (!incnt)
168 return 0;
169
170 return sctp_stream_alloc_in(stream, incnt, gfp);
171 }
172
sctp_stream_init_ext(struct sctp_stream * stream,__u16 sid)173 int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
174 {
175 struct sctp_stream_out_ext *soute;
176 int ret;
177
178 soute = kzalloc_obj(*soute);
179 if (!soute)
180 return -ENOMEM;
181 SCTP_SO(stream, sid)->ext = soute;
182
183 ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
184 if (ret) {
185 kfree(SCTP_SO(stream, sid)->ext);
186 SCTP_SO(stream, sid)->ext = NULL;
187 }
188
189 return ret;
190 }
191
sctp_stream_free(struct sctp_stream * stream)192 void sctp_stream_free(struct sctp_stream *stream)
193 {
194 const struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
195 int i;
196
197 sched->unsched_all(stream);
198 for (i = 0; i < stream->outcnt; i++)
199 sctp_stream_free_ext(stream, i);
200 genradix_free(&stream->out);
201 genradix_free(&stream->in);
202 }
203
sctp_stream_clear(struct sctp_stream * stream)204 void sctp_stream_clear(struct sctp_stream *stream)
205 {
206 int i;
207
208 for (i = 0; i < stream->outcnt; i++) {
209 SCTP_SO(stream, i)->mid = 0;
210 SCTP_SO(stream, i)->mid_uo = 0;
211 }
212
213 for (i = 0; i < stream->incnt; i++)
214 SCTP_SI(stream, i)->mid = 0;
215 }
216
sctp_stream_update(struct sctp_stream * stream,struct sctp_stream * new)217 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
218 {
219 const struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
220
221 sched->unsched_all(stream);
222 sctp_stream_outq_migrate(stream, new, new->outcnt);
223 sctp_stream_free(stream);
224
225 stream->out = new->out;
226 stream->in = new->in;
227 stream->outcnt = new->outcnt;
228 stream->incnt = new->incnt;
229
230 sched->sched_all(stream);
231
232 new->out.tree.root = NULL;
233 new->in.tree.root = NULL;
234 new->outcnt = 0;
235 new->incnt = 0;
236 }
237
sctp_send_reconf(struct sctp_association * asoc,struct sctp_chunk * chunk)238 static int sctp_send_reconf(struct sctp_association *asoc,
239 struct sctp_chunk *chunk)
240 {
241 int retval = 0;
242
243 retval = sctp_primitive_RECONF(asoc->base.net, asoc, chunk);
244 if (retval)
245 sctp_chunk_free(chunk);
246
247 return retval;
248 }
249
sctp_stream_outq_is_empty(struct sctp_stream * stream,__u16 str_nums,__be16 * str_list)250 static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
251 __u16 str_nums, __be16 *str_list)
252 {
253 struct sctp_association *asoc;
254 __u16 i;
255
256 asoc = container_of(stream, struct sctp_association, stream);
257 if (!asoc->outqueue.out_qlen)
258 return true;
259
260 if (!str_nums)
261 return false;
262
263 for (i = 0; i < str_nums; i++) {
264 __u16 sid = ntohs(str_list[i]);
265
266 if (SCTP_SO(stream, sid)->ext &&
267 !list_empty(&SCTP_SO(stream, sid)->ext->outq))
268 return false;
269 }
270
271 return true;
272 }
273
sctp_send_reset_streams(struct sctp_association * asoc,struct sctp_reset_streams * params)274 int sctp_send_reset_streams(struct sctp_association *asoc,
275 struct sctp_reset_streams *params)
276 {
277 struct sctp_stream *stream = &asoc->stream;
278 __u16 i, str_nums, *str_list;
279 struct sctp_chunk *chunk;
280 int retval = -EINVAL;
281 __be16 *nstr_list;
282 bool out, in;
283
284 if (!asoc->peer.reconf_capable ||
285 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
286 retval = -ENOPROTOOPT;
287 goto out;
288 }
289
290 if (asoc->strreset_outstanding) {
291 retval = -EINPROGRESS;
292 goto out;
293 }
294
295 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
296 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
297 if (!out && !in)
298 goto out;
299
300 str_nums = params->srs_number_streams;
301 str_list = params->srs_stream_list;
302 if (str_nums) {
303 int param_len = 0;
304
305 if (out) {
306 for (i = 0; i < str_nums; i++)
307 if (str_list[i] >= stream->outcnt)
308 goto out;
309
310 param_len = str_nums * sizeof(__u16) +
311 sizeof(struct sctp_strreset_outreq);
312 }
313
314 if (in) {
315 for (i = 0; i < str_nums; i++)
316 if (str_list[i] >= stream->incnt)
317 goto out;
318
319 param_len += str_nums * sizeof(__u16) +
320 (out ? sizeof(struct sctp_strreset_inreq)
321 : sizeof(struct sctp_strreset_outreq));
322 }
323
324 if (param_len > SCTP_MAX_CHUNK_LEN -
325 sizeof(struct sctp_reconf_chunk))
326 goto out;
327 }
328
329 nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
330 if (!nstr_list) {
331 retval = -ENOMEM;
332 goto out;
333 }
334
335 for (i = 0; i < str_nums; i++)
336 nstr_list[i] = htons(str_list[i]);
337
338 if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
339 kfree(nstr_list);
340 retval = -EAGAIN;
341 goto out;
342 }
343
344 chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
345
346 kfree(nstr_list);
347
348 if (!chunk) {
349 retval = -ENOMEM;
350 goto out;
351 }
352
353 if (out) {
354 if (str_nums)
355 for (i = 0; i < str_nums; i++)
356 SCTP_SO(stream, str_list[i])->state =
357 SCTP_STREAM_CLOSED;
358 else
359 for (i = 0; i < stream->outcnt; i++)
360 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
361 }
362
363 asoc->strreset_chunk = chunk;
364 sctp_chunk_hold(asoc->strreset_chunk);
365
366 retval = sctp_send_reconf(asoc, chunk);
367 if (retval) {
368 sctp_chunk_put(asoc->strreset_chunk);
369 asoc->strreset_chunk = NULL;
370 if (!out)
371 goto out;
372
373 if (str_nums)
374 for (i = 0; i < str_nums; i++)
375 SCTP_SO(stream, str_list[i])->state =
376 SCTP_STREAM_OPEN;
377 else
378 for (i = 0; i < stream->outcnt; i++)
379 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
380
381 goto out;
382 }
383
384 if (out)
385 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_OUT_REQUEST);
386 if (in)
387 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_IN_REQUEST);
388
389 out:
390 return retval;
391 }
392
sctp_send_reset_assoc(struct sctp_association * asoc)393 int sctp_send_reset_assoc(struct sctp_association *asoc)
394 {
395 struct sctp_stream *stream = &asoc->stream;
396 struct sctp_chunk *chunk = NULL;
397 int retval;
398 __u16 i;
399
400 if (!asoc->peer.reconf_capable ||
401 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
402 return -ENOPROTOOPT;
403
404 if (asoc->strreset_outstanding)
405 return -EINPROGRESS;
406
407 if (!sctp_outq_is_empty(&asoc->outqueue))
408 return -EAGAIN;
409
410 chunk = sctp_make_strreset_tsnreq(asoc);
411 if (!chunk)
412 return -ENOMEM;
413
414 /* Block further xmit of data until this request is completed */
415 for (i = 0; i < stream->outcnt; i++)
416 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
417
418 asoc->strreset_chunk = chunk;
419 sctp_chunk_hold(asoc->strreset_chunk);
420
421 retval = sctp_send_reconf(asoc, chunk);
422 if (retval) {
423 sctp_chunk_put(asoc->strreset_chunk);
424 asoc->strreset_chunk = NULL;
425
426 for (i = 0; i < stream->outcnt; i++)
427 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
428
429 return retval;
430 }
431
432 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_TSN_REQUEST);
433
434 return 0;
435 }
436
sctp_send_add_streams(struct sctp_association * asoc,struct sctp_add_streams * params)437 int sctp_send_add_streams(struct sctp_association *asoc,
438 struct sctp_add_streams *params)
439 {
440 struct sctp_stream *stream = &asoc->stream;
441 struct sctp_chunk *chunk = NULL;
442 int retval;
443 __u32 outcnt, incnt;
444 __u16 out, in;
445
446 if (!asoc->peer.reconf_capable ||
447 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
448 retval = -ENOPROTOOPT;
449 goto out;
450 }
451
452 if (asoc->strreset_outstanding) {
453 retval = -EINPROGRESS;
454 goto out;
455 }
456
457 out = params->sas_outstrms;
458 in = params->sas_instrms;
459 outcnt = stream->outcnt + out;
460 incnt = stream->incnt + in;
461 if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
462 (!out && !in)) {
463 retval = -EINVAL;
464 goto out;
465 }
466
467 if (out) {
468 retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
469 if (retval)
470 goto out;
471 }
472
473 chunk = sctp_make_strreset_addstrm(asoc, out, in);
474 if (!chunk) {
475 retval = -ENOMEM;
476 goto out;
477 }
478
479 asoc->strreset_chunk = chunk;
480 sctp_chunk_hold(asoc->strreset_chunk);
481
482 retval = sctp_send_reconf(asoc, chunk);
483 if (retval) {
484 sctp_chunk_put(asoc->strreset_chunk);
485 asoc->strreset_chunk = NULL;
486 goto out;
487 }
488
489 if (out)
490 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_ADD_OUT_STREAMS);
491 if (in)
492 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_ADD_IN_STREAMS);
493
494 out:
495 return retval;
496 }
497
sctp_chunk_lookup_strreset_param(struct sctp_association * asoc,__be32 resp_seq,__be16 type,bool match_seq)498 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
499 struct sctp_association *asoc, __be32 resp_seq,
500 __be16 type, bool match_seq)
501 {
502 struct sctp_chunk *chunk = asoc->strreset_chunk;
503 struct sctp_reconf_chunk *hdr;
504 union sctp_params param;
505
506 if (!chunk || !chunk->transport)
507 return NULL;
508
509 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
510 sctp_walk_params(param, hdr) {
511 /* sctp_strreset_tsnreq is actually the basic structure
512 * of all stream reconf params, so it's safe to use it
513 * to access request_seq.
514 */
515 struct sctp_strreset_tsnreq *req = param.v;
516
517 if ((!match_seq || req->request_seq == resp_seq) &&
518 (!type || type == req->param_hdr.type))
519 return param.v;
520 }
521
522 return NULL;
523 }
524
sctp_update_strreset_result(struct sctp_association * asoc,__u32 result)525 static void sctp_update_strreset_result(struct sctp_association *asoc,
526 __u32 result)
527 {
528 asoc->strreset_result[1] = asoc->strreset_result[0];
529 asoc->strreset_result[0] = result;
530 }
531
sctp_process_strreset_outreq(struct sctp_association * asoc,union sctp_params param,struct sctp_ulpevent ** evp)532 struct sctp_chunk *sctp_process_strreset_outreq(
533 struct sctp_association *asoc,
534 union sctp_params param,
535 struct sctp_ulpevent **evp)
536 {
537 struct sctp_strreset_outreq *outreq = param.v;
538 struct sctp_stream *stream = &asoc->stream;
539 __u32 result = SCTP_STRRESET_DENIED;
540 __be16 *str_p = NULL;
541 __u32 request_seq;
542 __u16 i, nums;
543
544 request_seq = ntohl(outreq->request_seq);
545
546 if (ntohl(outreq->send_reset_at_tsn) >
547 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
548 result = SCTP_STRRESET_IN_PROGRESS;
549 goto err;
550 }
551
552 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
553 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
554 result = SCTP_STRRESET_ERR_BAD_SEQNO;
555 goto err;
556 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
557 i = asoc->strreset_inseq - request_seq - 1;
558 result = asoc->strreset_result[i];
559 goto err;
560 }
561 asoc->strreset_inseq++;
562
563 /* Check strreset_enable after inseq inc, as sender cannot tell
564 * the peer doesn't enable strreset after receiving response with
565 * result denied, as well as to keep consistent with bsd.
566 */
567 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
568 goto out;
569
570 nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
571 str_p = outreq->list_of_streams;
572 for (i = 0; i < nums; i++) {
573 if (ntohs(str_p[i]) >= stream->incnt) {
574 result = SCTP_STRRESET_ERR_WRONG_SSN;
575 goto out;
576 }
577 }
578
579 if (asoc->strreset_chunk) {
580 if (!sctp_chunk_lookup_strreset_param(
581 asoc, outreq->response_seq,
582 SCTP_PARAM_RESET_IN_REQUEST, true) ||
583 !SCTP_STRRESET_TEST(asoc, SCTP_PARAM_RESET_IN_REQUEST)) {
584 /* same process with outstanding isn't 0 */
585 result = SCTP_STRRESET_ERR_IN_PROGRESS;
586 goto out;
587 }
588
589 SCTP_STRRESET_CLEAR(asoc, SCTP_PARAM_RESET_IN_REQUEST);
590 asoc->strreset_outseq++;
591
592 if (!asoc->strreset_outstanding) {
593 struct sctp_transport *t;
594
595 t = asoc->strreset_chunk->transport;
596 if (timer_delete(&t->reconf_timer))
597 sctp_transport_put(t);
598
599 sctp_chunk_put(asoc->strreset_chunk);
600 asoc->strreset_chunk = NULL;
601 }
602 }
603
604 if (nums)
605 for (i = 0; i < nums; i++)
606 SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
607 else
608 for (i = 0; i < stream->incnt; i++)
609 SCTP_SI(stream, i)->mid = 0;
610
611 result = SCTP_STRRESET_PERFORMED;
612
613 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
614 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
615
616 out:
617 sctp_update_strreset_result(asoc, result);
618 err:
619 return sctp_make_strreset_resp(asoc, result, request_seq);
620 }
621
sctp_process_strreset_inreq(struct sctp_association * asoc,union sctp_params param,struct sctp_ulpevent ** evp)622 struct sctp_chunk *sctp_process_strreset_inreq(
623 struct sctp_association *asoc,
624 union sctp_params param,
625 struct sctp_ulpevent **evp)
626 {
627 struct sctp_strreset_inreq *inreq = param.v;
628 struct sctp_stream *stream = &asoc->stream;
629 __u32 result = SCTP_STRRESET_DENIED;
630 struct sctp_chunk *chunk = NULL;
631 __u32 request_seq;
632 __u16 i, nums;
633 __be16 *str_p;
634
635 request_seq = ntohl(inreq->request_seq);
636 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
637 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
638 result = SCTP_STRRESET_ERR_BAD_SEQNO;
639 goto err;
640 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
641 i = asoc->strreset_inseq - request_seq - 1;
642 result = asoc->strreset_result[i];
643 if (result == SCTP_STRRESET_PERFORMED)
644 return NULL;
645 goto err;
646 }
647 asoc->strreset_inseq++;
648
649 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
650 goto out;
651
652 if (asoc->strreset_outstanding) {
653 result = SCTP_STRRESET_ERR_IN_PROGRESS;
654 goto out;
655 }
656
657 nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
658 str_p = inreq->list_of_streams;
659 if (nums * sizeof(__u16) + sizeof(struct sctp_strreset_outreq) >
660 SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_reconf_chunk))
661 goto out;
662 for (i = 0; i < nums; i++) {
663 if (ntohs(str_p[i]) >= stream->outcnt) {
664 result = SCTP_STRRESET_ERR_WRONG_SSN;
665 goto out;
666 }
667 }
668
669 if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
670 result = SCTP_STRRESET_IN_PROGRESS;
671 asoc->strreset_inseq--;
672 goto err;
673 }
674
675 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
676 if (!chunk)
677 goto out;
678
679 if (nums)
680 for (i = 0; i < nums; i++)
681 SCTP_SO(stream, ntohs(str_p[i]))->state =
682 SCTP_STREAM_CLOSED;
683 else
684 for (i = 0; i < stream->outcnt; i++)
685 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
686
687 asoc->strreset_chunk = chunk;
688 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_OUT_REQUEST);
689 sctp_chunk_hold(asoc->strreset_chunk);
690
691 result = SCTP_STRRESET_PERFORMED;
692
693 out:
694 sctp_update_strreset_result(asoc, result);
695 err:
696 if (!chunk)
697 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
698
699 return chunk;
700 }
701
sctp_process_strreset_tsnreq(struct sctp_association * asoc,union sctp_params param,struct sctp_ulpevent ** evp)702 struct sctp_chunk *sctp_process_strreset_tsnreq(
703 struct sctp_association *asoc,
704 union sctp_params param,
705 struct sctp_ulpevent **evp)
706 {
707 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
708 struct sctp_strreset_tsnreq *tsnreq = param.v;
709 struct sctp_stream *stream = &asoc->stream;
710 __u32 result = SCTP_STRRESET_DENIED;
711 __u32 request_seq;
712 __u16 i;
713
714 request_seq = ntohl(tsnreq->request_seq);
715 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
716 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
717 result = SCTP_STRRESET_ERR_BAD_SEQNO;
718 goto err;
719 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
720 i = asoc->strreset_inseq - request_seq - 1;
721 result = asoc->strreset_result[i];
722 if (result == SCTP_STRRESET_PERFORMED) {
723 next_tsn = asoc->ctsn_ack_point + 1;
724 init_tsn =
725 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
726 }
727 goto err;
728 }
729
730 if (!sctp_outq_is_empty(&asoc->outqueue)) {
731 result = SCTP_STRRESET_IN_PROGRESS;
732 goto err;
733 }
734
735 asoc->strreset_inseq++;
736
737 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
738 goto out;
739
740 if (asoc->strreset_outstanding) {
741 result = SCTP_STRRESET_ERR_IN_PROGRESS;
742 goto out;
743 }
744
745 /* G4: The same processing as though a FWD-TSN chunk (as defined in
746 * [RFC3758]) with all streams affected and a new cumulative TSN
747 * ACK of the Receiver's Next TSN minus 1 were received MUST be
748 * performed.
749 */
750 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
751 asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
752
753 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
754 * TSN that the peer should use to send the next DATA chunk. The
755 * value SHOULD be the smallest TSN not acknowledged by the
756 * receiver of the request plus 2^31.
757 */
758 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1U << 31);
759 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
760 init_tsn, GFP_ATOMIC);
761
762 /* G3: The same processing as though a SACK chunk with no gap report
763 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
764 * received MUST be performed.
765 */
766 sctp_outq_free(&asoc->outqueue);
767
768 /* G2: Compute an appropriate value for the local endpoint's next TSN,
769 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
770 * chunk. The value SHOULD be the highest TSN sent by the receiver
771 * of the request plus 1.
772 */
773 next_tsn = asoc->next_tsn;
774 asoc->ctsn_ack_point = next_tsn - 1;
775 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
776
777 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
778 * incoming and outgoing streams.
779 */
780 for (i = 0; i < stream->outcnt; i++) {
781 SCTP_SO(stream, i)->mid = 0;
782 SCTP_SO(stream, i)->mid_uo = 0;
783 }
784 for (i = 0; i < stream->incnt; i++)
785 SCTP_SI(stream, i)->mid = 0;
786
787 result = SCTP_STRRESET_PERFORMED;
788
789 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
790 next_tsn, GFP_ATOMIC);
791
792 out:
793 sctp_update_strreset_result(asoc, result);
794 err:
795 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
796 next_tsn, init_tsn);
797 }
798
sctp_process_strreset_addstrm_out(struct sctp_association * asoc,union sctp_params param,struct sctp_ulpevent ** evp)799 struct sctp_chunk *sctp_process_strreset_addstrm_out(
800 struct sctp_association *asoc,
801 union sctp_params param,
802 struct sctp_ulpevent **evp)
803 {
804 struct sctp_strreset_addstrm *addstrm = param.v;
805 struct sctp_stream *stream = &asoc->stream;
806 __u32 result = SCTP_STRRESET_DENIED;
807 __u32 request_seq, incnt;
808 __u16 in, i;
809
810 request_seq = ntohl(addstrm->request_seq);
811 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
812 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
813 result = SCTP_STRRESET_ERR_BAD_SEQNO;
814 goto err;
815 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
816 i = asoc->strreset_inseq - request_seq - 1;
817 result = asoc->strreset_result[i];
818 goto err;
819 }
820 asoc->strreset_inseq++;
821
822 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
823 goto out;
824
825 in = ntohs(addstrm->number_of_streams);
826 incnt = stream->incnt + in;
827 if (!in || incnt > SCTP_MAX_STREAM)
828 goto out;
829
830 if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
831 goto out;
832
833 if (asoc->strreset_chunk) {
834 if (!sctp_chunk_lookup_strreset_param(
835 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS, false) ||
836 !SCTP_STRRESET_TEST(asoc, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
837 /* same process with outstanding isn't 0 */
838 result = SCTP_STRRESET_ERR_IN_PROGRESS;
839 goto out;
840 }
841
842 SCTP_STRRESET_CLEAR(asoc, SCTP_PARAM_RESET_ADD_IN_STREAMS);
843 asoc->strreset_outseq++;
844
845 if (!asoc->strreset_outstanding) {
846 struct sctp_transport *t;
847
848 t = asoc->strreset_chunk->transport;
849 if (timer_delete(&t->reconf_timer))
850 sctp_transport_put(t);
851
852 sctp_chunk_put(asoc->strreset_chunk);
853 asoc->strreset_chunk = NULL;
854 }
855 }
856
857 stream->incnt = incnt;
858
859 result = SCTP_STRRESET_PERFORMED;
860
861 *evp = sctp_ulpevent_make_stream_change_event(asoc,
862 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
863
864 out:
865 sctp_update_strreset_result(asoc, result);
866 err:
867 return sctp_make_strreset_resp(asoc, result, request_seq);
868 }
869
sctp_process_strreset_addstrm_in(struct sctp_association * asoc,union sctp_params param,struct sctp_ulpevent ** evp)870 struct sctp_chunk *sctp_process_strreset_addstrm_in(
871 struct sctp_association *asoc,
872 union sctp_params param,
873 struct sctp_ulpevent **evp)
874 {
875 struct sctp_strreset_addstrm *addstrm = param.v;
876 struct sctp_stream *stream = &asoc->stream;
877 __u32 result = SCTP_STRRESET_DENIED;
878 struct sctp_chunk *chunk = NULL;
879 __u32 request_seq, outcnt;
880 __u16 out, i;
881 int ret;
882
883 request_seq = ntohl(addstrm->request_seq);
884 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
885 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
886 result = SCTP_STRRESET_ERR_BAD_SEQNO;
887 goto err;
888 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
889 i = asoc->strreset_inseq - request_seq - 1;
890 result = asoc->strreset_result[i];
891 if (result == SCTP_STRRESET_PERFORMED)
892 return NULL;
893 goto err;
894 }
895 asoc->strreset_inseq++;
896
897 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
898 goto out;
899
900 if (asoc->strreset_outstanding) {
901 result = SCTP_STRRESET_ERR_IN_PROGRESS;
902 goto out;
903 }
904
905 out = ntohs(addstrm->number_of_streams);
906 outcnt = stream->outcnt + out;
907 if (!out || outcnt > SCTP_MAX_STREAM)
908 goto out;
909
910 ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
911 if (ret)
912 goto out;
913
914 chunk = sctp_make_strreset_addstrm(asoc, out, 0);
915 if (!chunk)
916 goto out;
917
918 asoc->strreset_chunk = chunk;
919 SCTP_STRRESET_SET(asoc, SCTP_PARAM_RESET_ADD_OUT_STREAMS);
920 sctp_chunk_hold(asoc->strreset_chunk);
921
922 stream->outcnt = outcnt;
923
924 result = SCTP_STRRESET_PERFORMED;
925
926 out:
927 sctp_update_strreset_result(asoc, result);
928 err:
929 if (!chunk)
930 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
931
932 return chunk;
933 }
934
sctp_process_strreset_resp(struct sctp_association * asoc,union sctp_params param,struct sctp_ulpevent ** evp)935 struct sctp_chunk *sctp_process_strreset_resp(
936 struct sctp_association *asoc,
937 union sctp_params param,
938 struct sctp_ulpevent **evp)
939 {
940 struct sctp_stream *stream = &asoc->stream;
941 struct sctp_strreset_resp *resp = param.v;
942 struct sctp_transport *t;
943 __u16 i, nums, flags = 0;
944 struct sctp_paramhdr *req;
945 __u32 result;
946
947 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0,
948 true);
949 if (!req || !SCTP_STRRESET_TEST(asoc, req->type))
950 return NULL;
951
952 result = ntohl(resp->result);
953 if (result != SCTP_STRRESET_PERFORMED) {
954 /* if in progress, do nothing but retransmit */
955 if (result == SCTP_STRRESET_IN_PROGRESS)
956 return NULL;
957 else if (result == SCTP_STRRESET_DENIED)
958 flags = SCTP_STREAM_RESET_DENIED;
959 else
960 flags = SCTP_STREAM_RESET_FAILED;
961 }
962
963 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
964 struct sctp_strreset_outreq *outreq;
965 __be16 *str_p;
966
967 outreq = (struct sctp_strreset_outreq *)req;
968 str_p = outreq->list_of_streams;
969 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
970 sizeof(__u16);
971
972 if (result == SCTP_STRRESET_PERFORMED) {
973 struct sctp_stream_out *sout;
974 if (nums) {
975 for (i = 0; i < nums; i++) {
976 sout = SCTP_SO(stream, ntohs(str_p[i]));
977 sout->mid = 0;
978 sout->mid_uo = 0;
979 }
980 } else {
981 for (i = 0; i < stream->outcnt; i++) {
982 sout = SCTP_SO(stream, i);
983 sout->mid = 0;
984 sout->mid_uo = 0;
985 }
986 }
987 }
988
989 flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
990
991 for (i = 0; i < stream->outcnt; i++)
992 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
993
994 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
995 nums, str_p, GFP_ATOMIC);
996 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
997 struct sctp_strreset_inreq *inreq;
998 __be16 *str_p;
999
1000 /* if the result is performed, it's impossible for inreq */
1001 if (result == SCTP_STRRESET_PERFORMED)
1002 return NULL;
1003
1004 inreq = (struct sctp_strreset_inreq *)req;
1005 str_p = inreq->list_of_streams;
1006 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
1007 sizeof(__u16);
1008
1009 flags |= SCTP_STREAM_RESET_INCOMING_SSN;
1010
1011 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
1012 nums, str_p, GFP_ATOMIC);
1013 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
1014 struct sctp_strreset_resptsn *resptsn;
1015 __u32 stsn, rtsn;
1016
1017 /* check for resptsn, as sctp_verify_reconf didn't do it*/
1018 if (ntohs(param.p->length) != sizeof(*resptsn))
1019 return NULL;
1020
1021 resptsn = (struct sctp_strreset_resptsn *)resp;
1022 stsn = ntohl(resptsn->senders_next_tsn);
1023 rtsn = ntohl(resptsn->receivers_next_tsn);
1024
1025 if (result == SCTP_STRRESET_PERFORMED) {
1026 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
1027 &asoc->peer.tsn_map);
1028 LIST_HEAD(temp);
1029
1030 asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
1031
1032 sctp_tsnmap_init(&asoc->peer.tsn_map,
1033 SCTP_TSN_MAP_INITIAL,
1034 stsn, GFP_ATOMIC);
1035
1036 /* Clean up sacked and abandoned queues only. As the
1037 * out_chunk_list may not be empty, splice it to temp,
1038 * then get it back after sctp_outq_free is done.
1039 */
1040 list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
1041 sctp_outq_free(&asoc->outqueue);
1042 list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
1043
1044 asoc->next_tsn = rtsn;
1045 asoc->ctsn_ack_point = asoc->next_tsn - 1;
1046 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1047
1048 for (i = 0; i < stream->outcnt; i++) {
1049 SCTP_SO(stream, i)->mid = 0;
1050 SCTP_SO(stream, i)->mid_uo = 0;
1051 }
1052 for (i = 0; i < stream->incnt; i++)
1053 SCTP_SI(stream, i)->mid = 0;
1054 }
1055
1056 for (i = 0; i < stream->outcnt; i++)
1057 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1058
1059 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
1060 stsn, rtsn, GFP_ATOMIC);
1061 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
1062 struct sctp_strreset_addstrm *addstrm;
1063 const struct sctp_sched_ops *sched;
1064 __u16 number;
1065
1066 addstrm = (struct sctp_strreset_addstrm *)req;
1067 nums = ntohs(addstrm->number_of_streams);
1068 number = stream->outcnt - nums;
1069
1070 if (result == SCTP_STRRESET_PERFORMED) {
1071 for (i = number; i < stream->outcnt; i++)
1072 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1073 } else {
1074 sched = sctp_sched_ops_from_stream(stream);
1075 sched->unsched_all(stream);
1076 sctp_stream_outq_migrate(stream, NULL, number);
1077 sched->sched_all(stream);
1078 stream->outcnt = number;
1079 }
1080
1081 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1082 0, nums, GFP_ATOMIC);
1083 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
1084 struct sctp_strreset_addstrm *addstrm;
1085
1086 /* if the result is performed, it's impossible for addstrm in
1087 * request.
1088 */
1089 if (result == SCTP_STRRESET_PERFORMED)
1090 return NULL;
1091
1092 addstrm = (struct sctp_strreset_addstrm *)req;
1093 nums = ntohs(addstrm->number_of_streams);
1094
1095 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1096 nums, 0, GFP_ATOMIC);
1097 }
1098
1099 SCTP_STRRESET_CLEAR(asoc, req->type);
1100 asoc->strreset_outseq++;
1101
1102 /* remove everything for this reconf request */
1103 if (!asoc->strreset_outstanding) {
1104 t = asoc->strreset_chunk->transport;
1105 if (timer_delete(&t->reconf_timer))
1106 sctp_transport_put(t);
1107
1108 sctp_chunk_put(asoc->strreset_chunk);
1109 asoc->strreset_chunk = NULL;
1110 }
1111
1112 return NULL;
1113 }
1114