OSDN Git Service

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