Linux 4.19.133
[linux/fpc-iii.git] / net / sctp / stream.c
blob87061a4bb44b6a9d4bf80de1ce4201d64f34192b
1 /* 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.
7 * This file is part of the SCTP kernel implementation
9 * This file contains sctp stream maniuplation primitives and helpers.
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.
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.
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/>.
27 * Please send any bug reports or fixes you make to the
28 * email address(es):
29 * lksctp developers <linux-sctp@vger.kernel.org>
31 * Written or modified by:
32 * Xin Long <lucien.xin@gmail.com>
35 #include <linux/list.h>
36 #include <net/sctp/sctp.h>
37 #include <net/sctp/sm.h>
38 #include <net/sctp/stream_sched.h>
40 static struct flex_array *fa_alloc(size_t elem_size, size_t elem_count,
41 gfp_t gfp)
43 struct flex_array *result;
44 int err;
46 result = flex_array_alloc(elem_size, elem_count, gfp);
47 if (result) {
48 err = flex_array_prealloc(result, 0, elem_count, gfp);
49 if (err) {
50 flex_array_free(result);
51 result = NULL;
55 return result;
58 static void fa_free(struct flex_array *fa)
60 if (fa)
61 flex_array_free(fa);
64 static void fa_copy(struct flex_array *fa, struct flex_array *from,
65 size_t index, size_t count)
67 void *elem;
69 while (count--) {
70 elem = flex_array_get(from, index);
71 flex_array_put(fa, index, elem, 0);
72 index++;
76 static void fa_zero(struct flex_array *fa, size_t index, size_t count)
78 void *elem;
80 while (count--) {
81 elem = flex_array_get(fa, index);
82 memset(elem, 0, fa->element_size);
83 index++;
87 static size_t fa_index(struct flex_array *fa, void *elem, size_t count)
89 size_t index = 0;
91 while (count--) {
92 if (elem == flex_array_get(fa, index))
93 break;
94 index++;
97 return index;
100 /* Migrates chunks from stream queues to new stream queues if needed,
101 * but not across associations. Also, removes those chunks to streams
102 * higher than the new max.
104 static void sctp_stream_outq_migrate(struct sctp_stream *stream,
105 struct sctp_stream *new, __u16 outcnt)
107 struct sctp_association *asoc;
108 struct sctp_chunk *ch, *temp;
109 struct sctp_outq *outq;
110 int i;
112 asoc = container_of(stream, struct sctp_association, stream);
113 outq = &asoc->outqueue;
115 list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
116 __u16 sid = sctp_chunk_stream_no(ch);
118 if (sid < outcnt)
119 continue;
121 sctp_sched_dequeue_common(outq, ch);
122 /* No need to call dequeue_done here because
123 * the chunks are not scheduled by now.
126 /* Mark as failed send. */
127 sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
128 if (asoc->peer.prsctp_capable &&
129 SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
130 asoc->sent_cnt_removable--;
132 sctp_chunk_free(ch);
135 if (new) {
136 /* Here we actually move the old ext stuff into the new
137 * buffer, because we want to keep it. Then
138 * sctp_stream_update will swap ->out pointers.
140 for (i = 0; i < outcnt; i++) {
141 kfree(SCTP_SO(new, i)->ext);
142 SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
143 SCTP_SO(stream, i)->ext = NULL;
147 for (i = outcnt; i < stream->outcnt; i++) {
148 kfree(SCTP_SO(stream, i)->ext);
149 SCTP_SO(stream, i)->ext = NULL;
153 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
154 gfp_t gfp)
156 struct flex_array *out;
157 size_t elem_size = sizeof(struct sctp_stream_out);
159 out = fa_alloc(elem_size, outcnt, gfp);
160 if (!out)
161 return -ENOMEM;
163 if (stream->out) {
164 fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt));
165 if (stream->out_curr) {
166 size_t index = fa_index(stream->out, stream->out_curr,
167 stream->outcnt);
169 BUG_ON(index == stream->outcnt);
170 stream->out_curr = flex_array_get(out, index);
172 fa_free(stream->out);
175 if (outcnt > stream->outcnt)
176 fa_zero(out, stream->outcnt, (outcnt - stream->outcnt));
178 stream->out = out;
180 return 0;
183 static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
184 gfp_t gfp)
186 struct flex_array *in;
187 size_t elem_size = sizeof(struct sctp_stream_in);
189 in = fa_alloc(elem_size, incnt, gfp);
190 if (!in)
191 return -ENOMEM;
193 if (stream->in) {
194 fa_copy(in, stream->in, 0, min(incnt, stream->incnt));
195 fa_free(stream->in);
198 if (incnt > stream->incnt)
199 fa_zero(in, stream->incnt, (incnt - stream->incnt));
201 stream->in = in;
203 return 0;
206 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
207 gfp_t gfp)
209 struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
210 int i, ret = 0;
212 gfp |= __GFP_NOWARN;
214 /* Initial stream->out size may be very big, so free it and alloc
215 * a new one with new outcnt to save memory if needed.
217 if (outcnt == stream->outcnt)
218 goto in;
220 /* Filter out chunks queued on streams that won't exist anymore */
221 sched->unsched_all(stream);
222 sctp_stream_outq_migrate(stream, NULL, outcnt);
223 sched->sched_all(stream);
225 ret = sctp_stream_alloc_out(stream, outcnt, gfp);
226 if (ret)
227 goto out;
229 stream->outcnt = outcnt;
230 for (i = 0; i < stream->outcnt; i++)
231 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
234 sctp_stream_interleave_init(stream);
235 if (!incnt)
236 goto out;
238 ret = sctp_stream_alloc_in(stream, incnt, gfp);
239 if (ret) {
240 sched->free(stream);
241 fa_free(stream->out);
242 stream->out = NULL;
243 stream->outcnt = 0;
244 goto out;
247 stream->incnt = incnt;
249 out:
250 return ret;
253 int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
255 struct sctp_stream_out_ext *soute;
256 int ret;
258 soute = kzalloc(sizeof(*soute), GFP_KERNEL);
259 if (!soute)
260 return -ENOMEM;
261 SCTP_SO(stream, sid)->ext = soute;
263 ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
264 if (ret) {
265 kfree(SCTP_SO(stream, sid)->ext);
266 SCTP_SO(stream, sid)->ext = NULL;
269 return ret;
272 void sctp_stream_free(struct sctp_stream *stream)
274 struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
275 int i;
277 sched->free(stream);
278 for (i = 0; i < stream->outcnt; i++)
279 kfree(SCTP_SO(stream, i)->ext);
280 fa_free(stream->out);
281 fa_free(stream->in);
284 void sctp_stream_clear(struct sctp_stream *stream)
286 int i;
288 for (i = 0; i < stream->outcnt; i++) {
289 SCTP_SO(stream, i)->mid = 0;
290 SCTP_SO(stream, i)->mid_uo = 0;
293 for (i = 0; i < stream->incnt; i++)
294 SCTP_SI(stream, i)->mid = 0;
297 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
299 struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
301 sched->unsched_all(stream);
302 sctp_stream_outq_migrate(stream, new, new->outcnt);
303 sctp_stream_free(stream);
305 stream->out = new->out;
306 stream->in = new->in;
307 stream->outcnt = new->outcnt;
308 stream->incnt = new->incnt;
310 sched->sched_all(stream);
312 new->out = NULL;
313 new->in = NULL;
314 new->outcnt = 0;
315 new->incnt = 0;
318 static int sctp_send_reconf(struct sctp_association *asoc,
319 struct sctp_chunk *chunk)
321 struct net *net = sock_net(asoc->base.sk);
322 int retval = 0;
324 retval = sctp_primitive_RECONF(net, asoc, chunk);
325 if (retval)
326 sctp_chunk_free(chunk);
328 return retval;
331 static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
332 __u16 str_nums, __be16 *str_list)
334 struct sctp_association *asoc;
335 __u16 i;
337 asoc = container_of(stream, struct sctp_association, stream);
338 if (!asoc->outqueue.out_qlen)
339 return true;
341 if (!str_nums)
342 return false;
344 for (i = 0; i < str_nums; i++) {
345 __u16 sid = ntohs(str_list[i]);
347 if (SCTP_SO(stream, sid)->ext &&
348 !list_empty(&SCTP_SO(stream, sid)->ext->outq))
349 return false;
352 return true;
355 int sctp_send_reset_streams(struct sctp_association *asoc,
356 struct sctp_reset_streams *params)
358 struct sctp_stream *stream = &asoc->stream;
359 __u16 i, str_nums, *str_list;
360 struct sctp_chunk *chunk;
361 int retval = -EINVAL;
362 __be16 *nstr_list;
363 bool out, in;
365 if (!asoc->peer.reconf_capable ||
366 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
367 retval = -ENOPROTOOPT;
368 goto out;
371 if (asoc->strreset_outstanding) {
372 retval = -EINPROGRESS;
373 goto out;
376 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
377 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
378 if (!out && !in)
379 goto out;
381 str_nums = params->srs_number_streams;
382 str_list = params->srs_stream_list;
383 if (str_nums) {
384 int param_len = 0;
386 if (out) {
387 for (i = 0; i < str_nums; i++)
388 if (str_list[i] >= stream->outcnt)
389 goto out;
391 param_len = str_nums * sizeof(__u16) +
392 sizeof(struct sctp_strreset_outreq);
395 if (in) {
396 for (i = 0; i < str_nums; i++)
397 if (str_list[i] >= stream->incnt)
398 goto out;
400 param_len += str_nums * sizeof(__u16) +
401 sizeof(struct sctp_strreset_inreq);
404 if (param_len > SCTP_MAX_CHUNK_LEN -
405 sizeof(struct sctp_reconf_chunk))
406 goto out;
409 nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
410 if (!nstr_list) {
411 retval = -ENOMEM;
412 goto out;
415 for (i = 0; i < str_nums; i++)
416 nstr_list[i] = htons(str_list[i]);
418 if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
419 kfree(nstr_list);
420 retval = -EAGAIN;
421 goto out;
424 chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
426 kfree(nstr_list);
428 if (!chunk) {
429 retval = -ENOMEM;
430 goto out;
433 if (out) {
434 if (str_nums)
435 for (i = 0; i < str_nums; i++)
436 SCTP_SO(stream, str_list[i])->state =
437 SCTP_STREAM_CLOSED;
438 else
439 for (i = 0; i < stream->outcnt; i++)
440 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
443 asoc->strreset_chunk = chunk;
444 sctp_chunk_hold(asoc->strreset_chunk);
446 retval = sctp_send_reconf(asoc, chunk);
447 if (retval) {
448 sctp_chunk_put(asoc->strreset_chunk);
449 asoc->strreset_chunk = NULL;
450 if (!out)
451 goto out;
453 if (str_nums)
454 for (i = 0; i < str_nums; i++)
455 SCTP_SO(stream, str_list[i])->state =
456 SCTP_STREAM_OPEN;
457 else
458 for (i = 0; i < stream->outcnt; i++)
459 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
461 goto out;
464 asoc->strreset_outstanding = out + in;
466 out:
467 return retval;
470 int sctp_send_reset_assoc(struct sctp_association *asoc)
472 struct sctp_stream *stream = &asoc->stream;
473 struct sctp_chunk *chunk = NULL;
474 int retval;
475 __u16 i;
477 if (!asoc->peer.reconf_capable ||
478 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
479 return -ENOPROTOOPT;
481 if (asoc->strreset_outstanding)
482 return -EINPROGRESS;
484 if (!sctp_outq_is_empty(&asoc->outqueue))
485 return -EAGAIN;
487 chunk = sctp_make_strreset_tsnreq(asoc);
488 if (!chunk)
489 return -ENOMEM;
491 /* Block further xmit of data until this request is completed */
492 for (i = 0; i < stream->outcnt; i++)
493 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
495 asoc->strreset_chunk = chunk;
496 sctp_chunk_hold(asoc->strreset_chunk);
498 retval = sctp_send_reconf(asoc, chunk);
499 if (retval) {
500 sctp_chunk_put(asoc->strreset_chunk);
501 asoc->strreset_chunk = NULL;
503 for (i = 0; i < stream->outcnt; i++)
504 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
506 return retval;
509 asoc->strreset_outstanding = 1;
511 return 0;
514 int sctp_send_add_streams(struct sctp_association *asoc,
515 struct sctp_add_streams *params)
517 struct sctp_stream *stream = &asoc->stream;
518 struct sctp_chunk *chunk = NULL;
519 int retval;
520 __u32 outcnt, incnt;
521 __u16 out, in;
523 if (!asoc->peer.reconf_capable ||
524 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
525 retval = -ENOPROTOOPT;
526 goto out;
529 if (asoc->strreset_outstanding) {
530 retval = -EINPROGRESS;
531 goto out;
534 out = params->sas_outstrms;
535 in = params->sas_instrms;
536 outcnt = stream->outcnt + out;
537 incnt = stream->incnt + in;
538 if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
539 (!out && !in)) {
540 retval = -EINVAL;
541 goto out;
544 if (out) {
545 retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
546 if (retval)
547 goto out;
550 chunk = sctp_make_strreset_addstrm(asoc, out, in);
551 if (!chunk) {
552 retval = -ENOMEM;
553 goto out;
556 asoc->strreset_chunk = chunk;
557 sctp_chunk_hold(asoc->strreset_chunk);
559 retval = sctp_send_reconf(asoc, chunk);
560 if (retval) {
561 sctp_chunk_put(asoc->strreset_chunk);
562 asoc->strreset_chunk = NULL;
563 goto out;
566 stream->outcnt = outcnt;
568 asoc->strreset_outstanding = !!out + !!in;
570 out:
571 return retval;
574 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
575 struct sctp_association *asoc, __be32 resp_seq,
576 __be16 type)
578 struct sctp_chunk *chunk = asoc->strreset_chunk;
579 struct sctp_reconf_chunk *hdr;
580 union sctp_params param;
582 if (!chunk)
583 return NULL;
585 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
586 sctp_walk_params(param, hdr, params) {
587 /* sctp_strreset_tsnreq is actually the basic structure
588 * of all stream reconf params, so it's safe to use it
589 * to access request_seq.
591 struct sctp_strreset_tsnreq *req = param.v;
593 if ((!resp_seq || req->request_seq == resp_seq) &&
594 (!type || type == req->param_hdr.type))
595 return param.v;
598 return NULL;
601 static void sctp_update_strreset_result(struct sctp_association *asoc,
602 __u32 result)
604 asoc->strreset_result[1] = asoc->strreset_result[0];
605 asoc->strreset_result[0] = result;
608 struct sctp_chunk *sctp_process_strreset_outreq(
609 struct sctp_association *asoc,
610 union sctp_params param,
611 struct sctp_ulpevent **evp)
613 struct sctp_strreset_outreq *outreq = param.v;
614 struct sctp_stream *stream = &asoc->stream;
615 __u32 result = SCTP_STRRESET_DENIED;
616 __be16 *str_p = NULL;
617 __u32 request_seq;
618 __u16 i, nums;
620 request_seq = ntohl(outreq->request_seq);
622 if (ntohl(outreq->send_reset_at_tsn) >
623 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
624 result = SCTP_STRRESET_IN_PROGRESS;
625 goto err;
628 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
629 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
630 result = SCTP_STRRESET_ERR_BAD_SEQNO;
631 goto err;
632 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
633 i = asoc->strreset_inseq - request_seq - 1;
634 result = asoc->strreset_result[i];
635 goto err;
637 asoc->strreset_inseq++;
639 /* Check strreset_enable after inseq inc, as sender cannot tell
640 * the peer doesn't enable strreset after receiving response with
641 * result denied, as well as to keep consistent with bsd.
643 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
644 goto out;
646 nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
647 str_p = outreq->list_of_streams;
648 for (i = 0; i < nums; i++) {
649 if (ntohs(str_p[i]) >= stream->incnt) {
650 result = SCTP_STRRESET_ERR_WRONG_SSN;
651 goto out;
655 if (asoc->strreset_chunk) {
656 if (!sctp_chunk_lookup_strreset_param(
657 asoc, outreq->response_seq,
658 SCTP_PARAM_RESET_IN_REQUEST)) {
659 /* same process with outstanding isn't 0 */
660 result = SCTP_STRRESET_ERR_IN_PROGRESS;
661 goto out;
664 asoc->strreset_outstanding--;
665 asoc->strreset_outseq++;
667 if (!asoc->strreset_outstanding) {
668 struct sctp_transport *t;
670 t = asoc->strreset_chunk->transport;
671 if (del_timer(&t->reconf_timer))
672 sctp_transport_put(t);
674 sctp_chunk_put(asoc->strreset_chunk);
675 asoc->strreset_chunk = NULL;
679 if (nums)
680 for (i = 0; i < nums; i++)
681 SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
682 else
683 for (i = 0; i < stream->incnt; i++)
684 SCTP_SI(stream, i)->mid = 0;
686 result = SCTP_STRRESET_PERFORMED;
688 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
689 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
691 out:
692 sctp_update_strreset_result(asoc, result);
693 err:
694 return sctp_make_strreset_resp(asoc, result, request_seq);
697 struct sctp_chunk *sctp_process_strreset_inreq(
698 struct sctp_association *asoc,
699 union sctp_params param,
700 struct sctp_ulpevent **evp)
702 struct sctp_strreset_inreq *inreq = param.v;
703 struct sctp_stream *stream = &asoc->stream;
704 __u32 result = SCTP_STRRESET_DENIED;
705 struct sctp_chunk *chunk = NULL;
706 __u32 request_seq;
707 __u16 i, nums;
708 __be16 *str_p;
710 request_seq = ntohl(inreq->request_seq);
711 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
712 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
713 result = SCTP_STRRESET_ERR_BAD_SEQNO;
714 goto err;
715 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
716 i = asoc->strreset_inseq - request_seq - 1;
717 result = asoc->strreset_result[i];
718 if (result == SCTP_STRRESET_PERFORMED)
719 return NULL;
720 goto err;
722 asoc->strreset_inseq++;
724 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
725 goto out;
727 if (asoc->strreset_outstanding) {
728 result = SCTP_STRRESET_ERR_IN_PROGRESS;
729 goto out;
732 nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
733 str_p = inreq->list_of_streams;
734 for (i = 0; i < nums; i++) {
735 if (ntohs(str_p[i]) >= stream->outcnt) {
736 result = SCTP_STRRESET_ERR_WRONG_SSN;
737 goto out;
741 if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
742 result = SCTP_STRRESET_IN_PROGRESS;
743 asoc->strreset_inseq--;
744 goto err;
747 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
748 if (!chunk)
749 goto out;
751 if (nums)
752 for (i = 0; i < nums; i++)
753 SCTP_SO(stream, ntohs(str_p[i]))->state =
754 SCTP_STREAM_CLOSED;
755 else
756 for (i = 0; i < stream->outcnt; i++)
757 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
759 asoc->strreset_chunk = chunk;
760 asoc->strreset_outstanding = 1;
761 sctp_chunk_hold(asoc->strreset_chunk);
763 result = SCTP_STRRESET_PERFORMED;
765 out:
766 sctp_update_strreset_result(asoc, result);
767 err:
768 if (!chunk)
769 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
771 return chunk;
774 struct sctp_chunk *sctp_process_strreset_tsnreq(
775 struct sctp_association *asoc,
776 union sctp_params param,
777 struct sctp_ulpevent **evp)
779 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
780 struct sctp_strreset_tsnreq *tsnreq = param.v;
781 struct sctp_stream *stream = &asoc->stream;
782 __u32 result = SCTP_STRRESET_DENIED;
783 __u32 request_seq;
784 __u16 i;
786 request_seq = ntohl(tsnreq->request_seq);
787 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
788 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
789 result = SCTP_STRRESET_ERR_BAD_SEQNO;
790 goto err;
791 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
792 i = asoc->strreset_inseq - request_seq - 1;
793 result = asoc->strreset_result[i];
794 if (result == SCTP_STRRESET_PERFORMED) {
795 next_tsn = asoc->ctsn_ack_point + 1;
796 init_tsn =
797 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
799 goto err;
802 if (!sctp_outq_is_empty(&asoc->outqueue)) {
803 result = SCTP_STRRESET_IN_PROGRESS;
804 goto err;
807 asoc->strreset_inseq++;
809 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
810 goto out;
812 if (asoc->strreset_outstanding) {
813 result = SCTP_STRRESET_ERR_IN_PROGRESS;
814 goto out;
817 /* G4: The same processing as though a FWD-TSN chunk (as defined in
818 * [RFC3758]) with all streams affected and a new cumulative TSN
819 * ACK of the Receiver's Next TSN minus 1 were received MUST be
820 * performed.
822 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
823 asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
825 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
826 * TSN that the peer should use to send the next DATA chunk. The
827 * value SHOULD be the smallest TSN not acknowledged by the
828 * receiver of the request plus 2^31.
830 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
831 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
832 init_tsn, GFP_ATOMIC);
834 /* G3: The same processing as though a SACK chunk with no gap report
835 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
836 * received MUST be performed.
838 sctp_outq_free(&asoc->outqueue);
840 /* G2: Compute an appropriate value for the local endpoint's next TSN,
841 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
842 * chunk. The value SHOULD be the highest TSN sent by the receiver
843 * of the request plus 1.
845 next_tsn = asoc->next_tsn;
846 asoc->ctsn_ack_point = next_tsn - 1;
847 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
849 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
850 * incoming and outgoing streams.
852 for (i = 0; i < stream->outcnt; i++) {
853 SCTP_SO(stream, i)->mid = 0;
854 SCTP_SO(stream, i)->mid_uo = 0;
856 for (i = 0; i < stream->incnt; i++)
857 SCTP_SI(stream, i)->mid = 0;
859 result = SCTP_STRRESET_PERFORMED;
861 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
862 next_tsn, GFP_ATOMIC);
864 out:
865 sctp_update_strreset_result(asoc, result);
866 err:
867 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
868 next_tsn, init_tsn);
871 struct sctp_chunk *sctp_process_strreset_addstrm_out(
872 struct sctp_association *asoc,
873 union sctp_params param,
874 struct sctp_ulpevent **evp)
876 struct sctp_strreset_addstrm *addstrm = param.v;
877 struct sctp_stream *stream = &asoc->stream;
878 __u32 result = SCTP_STRRESET_DENIED;
879 __u32 request_seq, incnt;
880 __u16 in, i;
882 request_seq = ntohl(addstrm->request_seq);
883 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
884 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
885 result = SCTP_STRRESET_ERR_BAD_SEQNO;
886 goto err;
887 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
888 i = asoc->strreset_inseq - request_seq - 1;
889 result = asoc->strreset_result[i];
890 goto err;
892 asoc->strreset_inseq++;
894 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
895 goto out;
897 in = ntohs(addstrm->number_of_streams);
898 incnt = stream->incnt + in;
899 if (!in || incnt > SCTP_MAX_STREAM)
900 goto out;
902 if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
903 goto out;
905 if (asoc->strreset_chunk) {
906 if (!sctp_chunk_lookup_strreset_param(
907 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
908 /* same process with outstanding isn't 0 */
909 result = SCTP_STRRESET_ERR_IN_PROGRESS;
910 goto out;
913 asoc->strreset_outstanding--;
914 asoc->strreset_outseq++;
916 if (!asoc->strreset_outstanding) {
917 struct sctp_transport *t;
919 t = asoc->strreset_chunk->transport;
920 if (del_timer(&t->reconf_timer))
921 sctp_transport_put(t);
923 sctp_chunk_put(asoc->strreset_chunk);
924 asoc->strreset_chunk = NULL;
928 stream->incnt = incnt;
930 result = SCTP_STRRESET_PERFORMED;
932 *evp = sctp_ulpevent_make_stream_change_event(asoc,
933 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
935 out:
936 sctp_update_strreset_result(asoc, result);
937 err:
938 return sctp_make_strreset_resp(asoc, result, request_seq);
941 struct sctp_chunk *sctp_process_strreset_addstrm_in(
942 struct sctp_association *asoc,
943 union sctp_params param,
944 struct sctp_ulpevent **evp)
946 struct sctp_strreset_addstrm *addstrm = param.v;
947 struct sctp_stream *stream = &asoc->stream;
948 __u32 result = SCTP_STRRESET_DENIED;
949 struct sctp_chunk *chunk = NULL;
950 __u32 request_seq, outcnt;
951 __u16 out, i;
952 int ret;
954 request_seq = ntohl(addstrm->request_seq);
955 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
956 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
957 result = SCTP_STRRESET_ERR_BAD_SEQNO;
958 goto err;
959 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
960 i = asoc->strreset_inseq - request_seq - 1;
961 result = asoc->strreset_result[i];
962 if (result == SCTP_STRRESET_PERFORMED)
963 return NULL;
964 goto err;
966 asoc->strreset_inseq++;
968 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
969 goto out;
971 if (asoc->strreset_outstanding) {
972 result = SCTP_STRRESET_ERR_IN_PROGRESS;
973 goto out;
976 out = ntohs(addstrm->number_of_streams);
977 outcnt = stream->outcnt + out;
978 if (!out || outcnt > SCTP_MAX_STREAM)
979 goto out;
981 ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
982 if (ret)
983 goto out;
985 chunk = sctp_make_strreset_addstrm(asoc, out, 0);
986 if (!chunk)
987 goto out;
989 asoc->strreset_chunk = chunk;
990 asoc->strreset_outstanding = 1;
991 sctp_chunk_hold(asoc->strreset_chunk);
993 stream->outcnt = outcnt;
995 result = SCTP_STRRESET_PERFORMED;
997 out:
998 sctp_update_strreset_result(asoc, result);
999 err:
1000 if (!chunk)
1001 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
1003 return chunk;
1006 struct sctp_chunk *sctp_process_strreset_resp(
1007 struct sctp_association *asoc,
1008 union sctp_params param,
1009 struct sctp_ulpevent **evp)
1011 struct sctp_stream *stream = &asoc->stream;
1012 struct sctp_strreset_resp *resp = param.v;
1013 struct sctp_transport *t;
1014 __u16 i, nums, flags = 0;
1015 struct sctp_paramhdr *req;
1016 __u32 result;
1018 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
1019 if (!req)
1020 return NULL;
1022 result = ntohl(resp->result);
1023 if (result != SCTP_STRRESET_PERFORMED) {
1024 /* if in progress, do nothing but retransmit */
1025 if (result == SCTP_STRRESET_IN_PROGRESS)
1026 return NULL;
1027 else if (result == SCTP_STRRESET_DENIED)
1028 flags = SCTP_STREAM_RESET_DENIED;
1029 else
1030 flags = SCTP_STREAM_RESET_FAILED;
1033 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
1034 struct sctp_strreset_outreq *outreq;
1035 __be16 *str_p;
1037 outreq = (struct sctp_strreset_outreq *)req;
1038 str_p = outreq->list_of_streams;
1039 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
1040 sizeof(__u16);
1042 if (result == SCTP_STRRESET_PERFORMED) {
1043 struct sctp_stream_out *sout;
1044 if (nums) {
1045 for (i = 0; i < nums; i++) {
1046 sout = SCTP_SO(stream, ntohs(str_p[i]));
1047 sout->mid = 0;
1048 sout->mid_uo = 0;
1050 } else {
1051 for (i = 0; i < stream->outcnt; i++) {
1052 sout = SCTP_SO(stream, i);
1053 sout->mid = 0;
1054 sout->mid_uo = 0;
1059 flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
1061 for (i = 0; i < stream->outcnt; i++)
1062 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1064 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
1065 nums, str_p, GFP_ATOMIC);
1066 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
1067 struct sctp_strreset_inreq *inreq;
1068 __be16 *str_p;
1070 /* if the result is performed, it's impossible for inreq */
1071 if (result == SCTP_STRRESET_PERFORMED)
1072 return NULL;
1074 inreq = (struct sctp_strreset_inreq *)req;
1075 str_p = inreq->list_of_streams;
1076 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
1077 sizeof(__u16);
1079 flags |= SCTP_STREAM_RESET_INCOMING_SSN;
1081 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
1082 nums, str_p, GFP_ATOMIC);
1083 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
1084 struct sctp_strreset_resptsn *resptsn;
1085 __u32 stsn, rtsn;
1087 /* check for resptsn, as sctp_verify_reconf didn't do it*/
1088 if (ntohs(param.p->length) != sizeof(*resptsn))
1089 return NULL;
1091 resptsn = (struct sctp_strreset_resptsn *)resp;
1092 stsn = ntohl(resptsn->senders_next_tsn);
1093 rtsn = ntohl(resptsn->receivers_next_tsn);
1095 if (result == SCTP_STRRESET_PERFORMED) {
1096 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
1097 &asoc->peer.tsn_map);
1098 LIST_HEAD(temp);
1100 asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
1102 sctp_tsnmap_init(&asoc->peer.tsn_map,
1103 SCTP_TSN_MAP_INITIAL,
1104 stsn, GFP_ATOMIC);
1106 /* Clean up sacked and abandoned queues only. As the
1107 * out_chunk_list may not be empty, splice it to temp,
1108 * then get it back after sctp_outq_free is done.
1110 list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
1111 sctp_outq_free(&asoc->outqueue);
1112 list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
1114 asoc->next_tsn = rtsn;
1115 asoc->ctsn_ack_point = asoc->next_tsn - 1;
1116 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1118 for (i = 0; i < stream->outcnt; i++) {
1119 SCTP_SO(stream, i)->mid = 0;
1120 SCTP_SO(stream, i)->mid_uo = 0;
1122 for (i = 0; i < stream->incnt; i++)
1123 SCTP_SI(stream, i)->mid = 0;
1126 for (i = 0; i < stream->outcnt; i++)
1127 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1129 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
1130 stsn, rtsn, GFP_ATOMIC);
1131 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
1132 struct sctp_strreset_addstrm *addstrm;
1133 __u16 number;
1135 addstrm = (struct sctp_strreset_addstrm *)req;
1136 nums = ntohs(addstrm->number_of_streams);
1137 number = stream->outcnt - nums;
1139 if (result == SCTP_STRRESET_PERFORMED)
1140 for (i = number; i < stream->outcnt; i++)
1141 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1142 else
1143 stream->outcnt = number;
1145 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1146 0, nums, GFP_ATOMIC);
1147 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
1148 struct sctp_strreset_addstrm *addstrm;
1150 /* if the result is performed, it's impossible for addstrm in
1151 * request.
1153 if (result == SCTP_STRRESET_PERFORMED)
1154 return NULL;
1156 addstrm = (struct sctp_strreset_addstrm *)req;
1157 nums = ntohs(addstrm->number_of_streams);
1159 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1160 nums, 0, GFP_ATOMIC);
1163 asoc->strreset_outstanding--;
1164 asoc->strreset_outseq++;
1166 /* remove everything for this reconf request */
1167 if (!asoc->strreset_outstanding) {
1168 t = asoc->strreset_chunk->transport;
1169 if (del_timer(&t->reconf_timer))
1170 sctp_transport_put(t);
1172 sctp_chunk_put(asoc->strreset_chunk);
1173 asoc->strreset_chunk = NULL;
1176 return NULL;