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