sctp: improve the events for sctp stream reset
[GitHub/moto-9609/android_kernel_motorola_exynos9610.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 }