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