GNU Linux-libre 4.14.290-gnu1
[releases.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  * These functions manipulate sctp tsn mapping array.
10  *
11  * This SCTP implementation is free software;
12  * you can redistribute it and/or modify it under the terms of
13  * the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * This SCTP implementation is distributed in the hope that it
18  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19  *                 ************************
20  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21  * See the GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with GNU CC; see the file COPYING.  If not, see
25  * <http://www.gnu.org/licenses/>.
26  *
27  * Please send any bug reports or fixes you make to the
28  * email address(es):
29  *    lksctp developers <linux-sctp@vger.kernel.org>
30  *
31  * Written or modified by:
32  *    Xin Long <lucien.xin@gmail.com>
33  */
34
35 #include <net/sctp/sctp.h>
36 #include <net/sctp/sm.h>
37
38 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
39                      gfp_t gfp)
40 {
41         int i;
42
43         gfp |= __GFP_NOWARN;
44
45         /* Initial stream->out size may be very big, so free it and alloc
46          * a new one with new outcnt to save memory if needed.
47          */
48         if (outcnt == stream->outcnt)
49                 goto in;
50
51         kfree(stream->out);
52
53         stream->out = kcalloc(outcnt, sizeof(*stream->out), gfp);
54         if (!stream->out)
55                 return -ENOMEM;
56
57         stream->outcnt = outcnt;
58         for (i = 0; i < stream->outcnt; i++)
59                 stream->out[i].state = SCTP_STREAM_OPEN;
60
61 in:
62         if (!incnt)
63                 return 0;
64
65         stream->in = kcalloc(incnt, sizeof(*stream->in), gfp);
66         if (!stream->in) {
67                 kfree(stream->out);
68                 stream->out = NULL;
69                 return -ENOMEM;
70         }
71
72         stream->incnt = incnt;
73
74         return 0;
75 }
76
77 void sctp_stream_free(struct sctp_stream *stream)
78 {
79         kfree(stream->out);
80         kfree(stream->in);
81 }
82
83 void sctp_stream_clear(struct sctp_stream *stream)
84 {
85         int i;
86
87         for (i = 0; i < stream->outcnt; i++)
88                 stream->out[i].ssn = 0;
89
90         for (i = 0; i < stream->incnt; i++)
91                 stream->in[i].ssn = 0;
92 }
93
94 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
95 {
96         sctp_stream_free(stream);
97
98         stream->out = new->out;
99         stream->in  = new->in;
100         stream->outcnt = new->outcnt;
101         stream->incnt  = new->incnt;
102
103         new->out = NULL;
104         new->in  = NULL;
105 }
106
107 static int sctp_send_reconf(struct sctp_association *asoc,
108                             struct sctp_chunk *chunk)
109 {
110         struct net *net = sock_net(asoc->base.sk);
111         int retval = 0;
112
113         retval = sctp_primitive_RECONF(net, asoc, chunk);
114         if (retval)
115                 sctp_chunk_free(chunk);
116
117         return retval;
118 }
119
120 int sctp_send_reset_streams(struct sctp_association *asoc,
121                             struct sctp_reset_streams *params)
122 {
123         struct sctp_stream *stream = &asoc->stream;
124         __u16 i, str_nums, *str_list;
125         struct sctp_chunk *chunk;
126         int retval = -EINVAL;
127         __be16 *nstr_list;
128         bool out, in;
129
130         if (!asoc->peer.reconf_capable ||
131             !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
132                 retval = -ENOPROTOOPT;
133                 goto out;
134         }
135
136         if (asoc->strreset_outstanding) {
137                 retval = -EINPROGRESS;
138                 goto out;
139         }
140
141         out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
142         in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
143         if (!out && !in)
144                 goto out;
145
146         str_nums = params->srs_number_streams;
147         str_list = params->srs_stream_list;
148         if (out && str_nums)
149                 for (i = 0; i < str_nums; i++)
150                         if (str_list[i] >= stream->outcnt)
151                                 goto out;
152
153         if (in && str_nums)
154                 for (i = 0; i < str_nums; i++)
155                         if (str_list[i] >= stream->incnt)
156                                 goto out;
157
158         nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
159         if (!nstr_list) {
160                 retval = -ENOMEM;
161                 goto out;
162         }
163
164         for (i = 0; i < str_nums; i++)
165                 nstr_list[i] = htons(str_list[i]);
166
167         chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
168
169         kfree(nstr_list);
170
171         if (!chunk) {
172                 retval = -ENOMEM;
173                 goto out;
174         }
175
176         if (out) {
177                 if (str_nums)
178                         for (i = 0; i < str_nums; i++)
179                                 stream->out[str_list[i]].state =
180                                                        SCTP_STREAM_CLOSED;
181                 else
182                         for (i = 0; i < stream->outcnt; i++)
183                                 stream->out[i].state = SCTP_STREAM_CLOSED;
184         }
185
186         asoc->strreset_chunk = chunk;
187         sctp_chunk_hold(asoc->strreset_chunk);
188
189         retval = sctp_send_reconf(asoc, chunk);
190         if (retval) {
191                 sctp_chunk_put(asoc->strreset_chunk);
192                 asoc->strreset_chunk = NULL;
193                 if (!out)
194                         goto out;
195
196                 if (str_nums)
197                         for (i = 0; i < str_nums; i++)
198                                 stream->out[str_list[i]].state =
199                                                        SCTP_STREAM_OPEN;
200                 else
201                         for (i = 0; i < stream->outcnt; i++)
202                                 stream->out[i].state = SCTP_STREAM_OPEN;
203
204                 goto out;
205         }
206
207         asoc->strreset_outstanding = out + in;
208
209 out:
210         return retval;
211 }
212
213 int sctp_send_reset_assoc(struct sctp_association *asoc)
214 {
215         struct sctp_stream *stream = &asoc->stream;
216         struct sctp_chunk *chunk = NULL;
217         int retval;
218         __u16 i;
219
220         if (!asoc->peer.reconf_capable ||
221             !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
222                 return -ENOPROTOOPT;
223
224         if (asoc->strreset_outstanding)
225                 return -EINPROGRESS;
226
227         if (!sctp_outq_is_empty(&asoc->outqueue))
228                 return -EAGAIN;
229
230         chunk = sctp_make_strreset_tsnreq(asoc);
231         if (!chunk)
232                 return -ENOMEM;
233
234         /* Block further xmit of data until this request is completed */
235         for (i = 0; i < stream->outcnt; i++)
236                 stream->out[i].state = SCTP_STREAM_CLOSED;
237
238         asoc->strreset_chunk = chunk;
239         sctp_chunk_hold(asoc->strreset_chunk);
240
241         retval = sctp_send_reconf(asoc, chunk);
242         if (retval) {
243                 sctp_chunk_put(asoc->strreset_chunk);
244                 asoc->strreset_chunk = NULL;
245
246                 for (i = 0; i < stream->outcnt; i++)
247                         stream->out[i].state = SCTP_STREAM_OPEN;
248
249                 return retval;
250         }
251
252         asoc->strreset_outstanding = 1;
253
254         return 0;
255 }
256
257 int sctp_send_add_streams(struct sctp_association *asoc,
258                           struct sctp_add_streams *params)
259 {
260         struct sctp_stream *stream = &asoc->stream;
261         struct sctp_chunk *chunk = NULL;
262         int retval = -ENOMEM;
263         __u32 outcnt, incnt;
264         __u16 out, in;
265
266         if (!asoc->peer.reconf_capable ||
267             !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
268                 retval = -ENOPROTOOPT;
269                 goto out;
270         }
271
272         if (asoc->strreset_outstanding) {
273                 retval = -EINPROGRESS;
274                 goto out;
275         }
276
277         out = params->sas_outstrms;
278         in  = params->sas_instrms;
279         outcnt = stream->outcnt + out;
280         incnt = stream->incnt + in;
281         if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
282             (!out && !in)) {
283                 retval = -EINVAL;
284                 goto out;
285         }
286
287         if (out) {
288                 struct sctp_stream_out *streamout;
289
290                 streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
291                                      GFP_KERNEL);
292                 if (!streamout)
293                         goto out;
294
295                 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
296                 stream->out = streamout;
297         }
298
299         chunk = sctp_make_strreset_addstrm(asoc, out, in);
300         if (!chunk)
301                 goto out;
302
303         asoc->strreset_chunk = chunk;
304         sctp_chunk_hold(asoc->strreset_chunk);
305
306         retval = sctp_send_reconf(asoc, chunk);
307         if (retval) {
308                 sctp_chunk_put(asoc->strreset_chunk);
309                 asoc->strreset_chunk = NULL;
310                 goto out;
311         }
312
313         stream->outcnt = outcnt;
314
315         asoc->strreset_outstanding = !!out + !!in;
316
317 out:
318         return retval;
319 }
320
321 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
322                         struct sctp_association *asoc, __be32 resp_seq,
323                         __be16 type)
324 {
325         struct sctp_chunk *chunk = asoc->strreset_chunk;
326         struct sctp_reconf_chunk *hdr;
327         union sctp_params param;
328
329         if (!chunk)
330                 return NULL;
331
332         hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
333         sctp_walk_params(param, hdr, params) {
334                 /* sctp_strreset_tsnreq is actually the basic structure
335                  * of all stream reconf params, so it's safe to use it
336                  * to access request_seq.
337                  */
338                 struct sctp_strreset_tsnreq *req = param.v;
339
340                 if ((!resp_seq || req->request_seq == resp_seq) &&
341                     (!type || type == req->param_hdr.type))
342                         return param.v;
343         }
344
345         return NULL;
346 }
347
348 static void sctp_update_strreset_result(struct sctp_association *asoc,
349                                         __u32 result)
350 {
351         asoc->strreset_result[1] = asoc->strreset_result[0];
352         asoc->strreset_result[0] = result;
353 }
354
355 struct sctp_chunk *sctp_process_strreset_outreq(
356                                 struct sctp_association *asoc,
357                                 union sctp_params param,
358                                 struct sctp_ulpevent **evp)
359 {
360         struct sctp_strreset_outreq *outreq = param.v;
361         struct sctp_stream *stream = &asoc->stream;
362         __u32 result = SCTP_STRRESET_DENIED;
363         __be16 *str_p = NULL;
364         __u32 request_seq;
365         __u16 i, nums;
366
367         request_seq = ntohl(outreq->request_seq);
368
369         if (ntohl(outreq->send_reset_at_tsn) >
370             sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
371                 result = SCTP_STRRESET_IN_PROGRESS;
372                 goto err;
373         }
374
375         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
376             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
377                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
378                 goto err;
379         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
380                 i = asoc->strreset_inseq - request_seq - 1;
381                 result = asoc->strreset_result[i];
382                 goto err;
383         }
384         asoc->strreset_inseq++;
385
386         /* Check strreset_enable after inseq inc, as sender cannot tell
387          * the peer doesn't enable strreset after receiving response with
388          * result denied, as well as to keep consistent with bsd.
389          */
390         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
391                 goto out;
392
393         nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
394         str_p = outreq->list_of_streams;
395         for (i = 0; i < nums; i++) {
396                 if (ntohs(str_p[i]) >= stream->incnt) {
397                         result = SCTP_STRRESET_ERR_WRONG_SSN;
398                         goto out;
399                 }
400         }
401
402         if (asoc->strreset_chunk) {
403                 if (!sctp_chunk_lookup_strreset_param(
404                                 asoc, outreq->response_seq,
405                                 SCTP_PARAM_RESET_IN_REQUEST)) {
406                         /* same process with outstanding isn't 0 */
407                         result = SCTP_STRRESET_ERR_IN_PROGRESS;
408                         goto out;
409                 }
410
411                 asoc->strreset_outstanding--;
412                 asoc->strreset_outseq++;
413
414                 if (!asoc->strreset_outstanding) {
415                         struct sctp_transport *t;
416
417                         t = asoc->strreset_chunk->transport;
418                         if (del_timer(&t->reconf_timer))
419                                 sctp_transport_put(t);
420
421                         sctp_chunk_put(asoc->strreset_chunk);
422                         asoc->strreset_chunk = NULL;
423                 }
424         }
425
426         if (nums)
427                 for (i = 0; i < nums; i++)
428                         stream->in[ntohs(str_p[i])].ssn = 0;
429         else
430                 for (i = 0; i < stream->incnt; i++)
431                         stream->in[i].ssn = 0;
432
433         result = SCTP_STRRESET_PERFORMED;
434
435         *evp = sctp_ulpevent_make_stream_reset_event(asoc,
436                 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
437
438 out:
439         sctp_update_strreset_result(asoc, result);
440 err:
441         return sctp_make_strreset_resp(asoc, result, request_seq);
442 }
443
444 struct sctp_chunk *sctp_process_strreset_inreq(
445                                 struct sctp_association *asoc,
446                                 union sctp_params param,
447                                 struct sctp_ulpevent **evp)
448 {
449         struct sctp_strreset_inreq *inreq = param.v;
450         struct sctp_stream *stream = &asoc->stream;
451         __u32 result = SCTP_STRRESET_DENIED;
452         struct sctp_chunk *chunk = NULL;
453         __u32 request_seq;
454         __u16 i, nums;
455         __be16 *str_p;
456
457         request_seq = ntohl(inreq->request_seq);
458         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
459             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
460                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
461                 goto err;
462         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
463                 i = asoc->strreset_inseq - request_seq - 1;
464                 result = asoc->strreset_result[i];
465                 if (result == SCTP_STRRESET_PERFORMED)
466                         return NULL;
467                 goto err;
468         }
469         asoc->strreset_inseq++;
470
471         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
472                 goto out;
473
474         if (asoc->strreset_outstanding) {
475                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
476                 goto out;
477         }
478
479         nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
480         str_p = inreq->list_of_streams;
481         for (i = 0; i < nums; i++) {
482                 if (ntohs(str_p[i]) >= stream->outcnt) {
483                         result = SCTP_STRRESET_ERR_WRONG_SSN;
484                         goto out;
485                 }
486         }
487
488         chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
489         if (!chunk)
490                 goto out;
491
492         if (nums)
493                 for (i = 0; i < nums; i++)
494                         stream->out[ntohs(str_p[i])].state =
495                                                SCTP_STREAM_CLOSED;
496         else
497                 for (i = 0; i < stream->outcnt; i++)
498                         stream->out[i].state = SCTP_STREAM_CLOSED;
499
500         asoc->strreset_chunk = chunk;
501         asoc->strreset_outstanding = 1;
502         sctp_chunk_hold(asoc->strreset_chunk);
503
504         result = SCTP_STRRESET_PERFORMED;
505
506 out:
507         sctp_update_strreset_result(asoc, result);
508 err:
509         if (!chunk)
510                 chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
511
512         return chunk;
513 }
514
515 struct sctp_chunk *sctp_process_strreset_tsnreq(
516                                 struct sctp_association *asoc,
517                                 union sctp_params param,
518                                 struct sctp_ulpevent **evp)
519 {
520         __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
521         struct sctp_strreset_tsnreq *tsnreq = param.v;
522         struct sctp_stream *stream = &asoc->stream;
523         __u32 result = SCTP_STRRESET_DENIED;
524         __u32 request_seq;
525         __u16 i;
526
527         request_seq = ntohl(tsnreq->request_seq);
528         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
529             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
530                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
531                 goto err;
532         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
533                 i = asoc->strreset_inseq - request_seq - 1;
534                 result = asoc->strreset_result[i];
535                 if (result == SCTP_STRRESET_PERFORMED) {
536                         next_tsn = asoc->ctsn_ack_point + 1;
537                         init_tsn =
538                                 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
539                 }
540                 goto err;
541         }
542
543         if (!sctp_outq_is_empty(&asoc->outqueue)) {
544                 result = SCTP_STRRESET_IN_PROGRESS;
545                 goto err;
546         }
547
548         asoc->strreset_inseq++;
549
550         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
551                 goto out;
552
553         if (asoc->strreset_outstanding) {
554                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
555                 goto out;
556         }
557
558         /* G4: The same processing as though a FWD-TSN chunk (as defined in
559          *     [RFC3758]) with all streams affected and a new cumulative TSN
560          *     ACK of the Receiver's Next TSN minus 1 were received MUST be
561          *     performed.
562          */
563         max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
564         sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
565         sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
566
567         /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
568          *     TSN that the peer should use to send the next DATA chunk.  The
569          *     value SHOULD be the smallest TSN not acknowledged by the
570          *     receiver of the request plus 2^31.
571          */
572         init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
573         sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
574                          init_tsn, GFP_ATOMIC);
575
576         /* G3: The same processing as though a SACK chunk with no gap report
577          *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
578          *     received MUST be performed.
579          */
580         sctp_outq_free(&asoc->outqueue);
581
582         /* G2: Compute an appropriate value for the local endpoint's next TSN,
583          *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
584          *     chunk.  The value SHOULD be the highest TSN sent by the receiver
585          *     of the request plus 1.
586          */
587         next_tsn = asoc->next_tsn;
588         asoc->ctsn_ack_point = next_tsn - 1;
589         asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
590
591         /* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
592          *      incoming and outgoing streams.
593          */
594         for (i = 0; i < stream->outcnt; i++)
595                 stream->out[i].ssn = 0;
596         for (i = 0; i < stream->incnt; i++)
597                 stream->in[i].ssn = 0;
598
599         result = SCTP_STRRESET_PERFORMED;
600
601         *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
602                                                     next_tsn, GFP_ATOMIC);
603
604 out:
605         sctp_update_strreset_result(asoc, result);
606 err:
607         return sctp_make_strreset_tsnresp(asoc, result, request_seq,
608                                           next_tsn, init_tsn);
609 }
610
611 struct sctp_chunk *sctp_process_strreset_addstrm_out(
612                                 struct sctp_association *asoc,
613                                 union sctp_params param,
614                                 struct sctp_ulpevent **evp)
615 {
616         struct sctp_strreset_addstrm *addstrm = param.v;
617         struct sctp_stream *stream = &asoc->stream;
618         __u32 result = SCTP_STRRESET_DENIED;
619         struct sctp_stream_in *streamin;
620         __u32 request_seq, incnt;
621         __u16 in, i;
622
623         request_seq = ntohl(addstrm->request_seq);
624         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
625             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
626                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
627                 goto err;
628         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
629                 i = asoc->strreset_inseq - request_seq - 1;
630                 result = asoc->strreset_result[i];
631                 goto err;
632         }
633         asoc->strreset_inseq++;
634
635         if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
636                 goto out;
637
638         in = ntohs(addstrm->number_of_streams);
639         incnt = stream->incnt + in;
640         if (!in || incnt > SCTP_MAX_STREAM)
641                 goto out;
642
643         streamin = krealloc(stream->in, incnt * sizeof(*streamin),
644                             GFP_ATOMIC);
645         if (!streamin)
646                 goto out;
647
648         if (asoc->strreset_chunk) {
649                 if (!sctp_chunk_lookup_strreset_param(
650                         asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
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         memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
672         stream->in = streamin;
673         stream->incnt = incnt;
674
675         result = SCTP_STRRESET_PERFORMED;
676
677         *evp = sctp_ulpevent_make_stream_change_event(asoc,
678                 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
679
680 out:
681         sctp_update_strreset_result(asoc, result);
682 err:
683         return sctp_make_strreset_resp(asoc, result, request_seq);
684 }
685
686 struct sctp_chunk *sctp_process_strreset_addstrm_in(
687                                 struct sctp_association *asoc,
688                                 union sctp_params param,
689                                 struct sctp_ulpevent **evp)
690 {
691         struct sctp_strreset_addstrm *addstrm = param.v;
692         struct sctp_stream *stream = &asoc->stream;
693         __u32 result = SCTP_STRRESET_DENIED;
694         struct sctp_stream_out *streamout;
695         struct sctp_chunk *chunk = NULL;
696         __u32 request_seq, outcnt;
697         __u16 out, i;
698
699         request_seq = ntohl(addstrm->request_seq);
700         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
701             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
702                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
703                 goto err;
704         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
705                 i = asoc->strreset_inseq - request_seq - 1;
706                 result = asoc->strreset_result[i];
707                 if (result == SCTP_STRRESET_PERFORMED)
708                         return NULL;
709                 goto err;
710         }
711         asoc->strreset_inseq++;
712
713         if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
714                 goto out;
715
716         if (asoc->strreset_outstanding) {
717                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
718                 goto out;
719         }
720
721         out = ntohs(addstrm->number_of_streams);
722         outcnt = stream->outcnt + out;
723         if (!out || outcnt > SCTP_MAX_STREAM)
724                 goto out;
725
726         streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
727                              GFP_ATOMIC);
728         if (!streamout)
729                 goto out;
730
731         memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
732         stream->out = streamout;
733
734         chunk = sctp_make_strreset_addstrm(asoc, out, 0);
735         if (!chunk)
736                 goto out;
737
738         asoc->strreset_chunk = chunk;
739         asoc->strreset_outstanding = 1;
740         sctp_chunk_hold(asoc->strreset_chunk);
741
742         stream->outcnt = outcnt;
743
744         result = SCTP_STRRESET_PERFORMED;
745
746 out:
747         sctp_update_strreset_result(asoc, result);
748 err:
749         if (!chunk)
750                 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
751
752         return chunk;
753 }
754
755 struct sctp_chunk *sctp_process_strreset_resp(
756                                 struct sctp_association *asoc,
757                                 union sctp_params param,
758                                 struct sctp_ulpevent **evp)
759 {
760         struct sctp_stream *stream = &asoc->stream;
761         struct sctp_strreset_resp *resp = param.v;
762         struct sctp_transport *t;
763         __u16 i, nums, flags = 0;
764         struct sctp_paramhdr *req;
765         __u32 result;
766
767         req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
768         if (!req)
769                 return NULL;
770
771         result = ntohl(resp->result);
772         if (result != SCTP_STRRESET_PERFORMED) {
773                 /* if in progress, do nothing but retransmit */
774                 if (result == SCTP_STRRESET_IN_PROGRESS)
775                         return NULL;
776                 else if (result == SCTP_STRRESET_DENIED)
777                         flags = SCTP_STREAM_RESET_DENIED;
778                 else
779                         flags = SCTP_STREAM_RESET_FAILED;
780         }
781
782         if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
783                 struct sctp_strreset_outreq *outreq;
784                 __be16 *str_p;
785
786                 outreq = (struct sctp_strreset_outreq *)req;
787                 str_p = outreq->list_of_streams;
788                 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
789
790                 if (result == SCTP_STRRESET_PERFORMED) {
791                         if (nums) {
792                                 for (i = 0; i < nums; i++)
793                                         stream->out[ntohs(str_p[i])].ssn = 0;
794                         } else {
795                                 for (i = 0; i < stream->outcnt; i++)
796                                         stream->out[i].ssn = 0;
797                         }
798                 }
799
800                 flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
801
802                 for (i = 0; i < stream->outcnt; i++)
803                         stream->out[i].state = SCTP_STREAM_OPEN;
804
805                 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
806                         nums, str_p, GFP_ATOMIC);
807         } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
808                 struct sctp_strreset_inreq *inreq;
809                 __be16 *str_p;
810
811                 /* if the result is performed, it's impossible for inreq */
812                 if (result == SCTP_STRRESET_PERFORMED)
813                         return NULL;
814
815                 inreq = (struct sctp_strreset_inreq *)req;
816                 str_p = inreq->list_of_streams;
817                 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
818
819                 flags |= SCTP_STREAM_RESET_INCOMING_SSN;
820
821                 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
822                         nums, str_p, GFP_ATOMIC);
823         } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
824                 struct sctp_strreset_resptsn *resptsn;
825                 __u32 stsn, rtsn;
826
827                 /* check for resptsn, as sctp_verify_reconf didn't do it*/
828                 if (ntohs(param.p->length) != sizeof(*resptsn))
829                         return NULL;
830
831                 resptsn = (struct sctp_strreset_resptsn *)resp;
832                 stsn = ntohl(resptsn->senders_next_tsn);
833                 rtsn = ntohl(resptsn->receivers_next_tsn);
834
835                 if (result == SCTP_STRRESET_PERFORMED) {
836                         __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
837                                                 &asoc->peer.tsn_map);
838                         LIST_HEAD(temp);
839
840                         sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
841                         sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
842
843                         sctp_tsnmap_init(&asoc->peer.tsn_map,
844                                          SCTP_TSN_MAP_INITIAL,
845                                          stsn, GFP_ATOMIC);
846
847                         /* Clean up sacked and abandoned queues only. As the
848                          * out_chunk_list may not be empty, splice it to temp,
849                          * then get it back after sctp_outq_free is done.
850                          */
851                         list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
852                         sctp_outq_free(&asoc->outqueue);
853                         list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
854
855                         asoc->next_tsn = rtsn;
856                         asoc->ctsn_ack_point = asoc->next_tsn - 1;
857                         asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
858
859                         for (i = 0; i < stream->outcnt; i++)
860                                 stream->out[i].ssn = 0;
861                         for (i = 0; i < stream->incnt; i++)
862                                 stream->in[i].ssn = 0;
863                 }
864
865                 for (i = 0; i < stream->outcnt; i++)
866                         stream->out[i].state = SCTP_STREAM_OPEN;
867
868                 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
869                         stsn, rtsn, GFP_ATOMIC);
870         } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
871                 struct sctp_strreset_addstrm *addstrm;
872                 __u16 number;
873
874                 addstrm = (struct sctp_strreset_addstrm *)req;
875                 nums = ntohs(addstrm->number_of_streams);
876                 number = stream->outcnt - nums;
877
878                 if (result == SCTP_STRRESET_PERFORMED)
879                         for (i = number; i < stream->outcnt; i++)
880                                 stream->out[i].state = SCTP_STREAM_OPEN;
881                 else
882                         stream->outcnt = number;
883
884                 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
885                         0, nums, GFP_ATOMIC);
886         } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
887                 struct sctp_strreset_addstrm *addstrm;
888
889                 /* if the result is performed, it's impossible for addstrm in
890                  * request.
891                  */
892                 if (result == SCTP_STRRESET_PERFORMED)
893                         return NULL;
894
895                 addstrm = (struct sctp_strreset_addstrm *)req;
896                 nums = ntohs(addstrm->number_of_streams);
897
898                 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
899                         nums, 0, GFP_ATOMIC);
900         }
901
902         asoc->strreset_outstanding--;
903         asoc->strreset_outseq++;
904
905         /* remove everything for this reconf request */
906         if (!asoc->strreset_outstanding) {
907                 t = asoc->strreset_chunk->transport;
908                 if (del_timer(&t->reconf_timer))
909                         sctp_transport_put(t);
910
911                 sctp_chunk_put(asoc->strreset_chunk);
912                 asoc->strreset_chunk = NULL;
913         }
914
915         return NULL;
916 }