]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - net/sctp/stream.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[mirror_ubuntu-artful-kernel.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 struct sctp_chunk *sctp_process_strreset_outreq(
348 struct sctp_association *asoc,
349 union sctp_params param,
350 struct sctp_ulpevent **evp)
351 {
352 struct sctp_strreset_outreq *outreq = param.v;
353 struct sctp_stream *stream = asoc->stream;
354 __u16 i, nums, flags = 0, *str_p = NULL;
355 __u32 result = SCTP_STRRESET_DENIED;
356 __u32 request_seq;
357
358 request_seq = ntohl(outreq->request_seq);
359
360 if (ntohl(outreq->send_reset_at_tsn) >
361 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
362 result = SCTP_STRRESET_IN_PROGRESS;
363 goto out;
364 }
365
366 if (request_seq > asoc->strreset_inseq) {
367 result = SCTP_STRRESET_ERR_BAD_SEQNO;
368 goto out;
369 } else if (request_seq == asoc->strreset_inseq) {
370 asoc->strreset_inseq++;
371 }
372
373 /* Check strreset_enable after inseq inc, as sender cannot tell
374 * the peer doesn't enable strreset after receiving response with
375 * result denied, as well as to keep consistent with bsd.
376 */
377 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
378 goto out;
379
380 if (asoc->strreset_chunk) {
381 if (!sctp_chunk_lookup_strreset_param(
382 asoc, outreq->response_seq,
383 SCTP_PARAM_RESET_IN_REQUEST)) {
384 /* same process with outstanding isn't 0 */
385 result = SCTP_STRRESET_ERR_IN_PROGRESS;
386 goto out;
387 }
388
389 asoc->strreset_outstanding--;
390 asoc->strreset_outseq++;
391
392 if (!asoc->strreset_outstanding) {
393 struct sctp_transport *t;
394
395 t = asoc->strreset_chunk->transport;
396 if (del_timer(&t->reconf_timer))
397 sctp_transport_put(t);
398
399 sctp_chunk_put(asoc->strreset_chunk);
400 asoc->strreset_chunk = NULL;
401 }
402
403 flags = SCTP_STREAM_RESET_INCOMING_SSN;
404 }
405
406 nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2;
407 if (nums) {
408 str_p = outreq->list_of_streams;
409 for (i = 0; i < nums; i++) {
410 if (ntohs(str_p[i]) >= stream->incnt) {
411 result = SCTP_STRRESET_ERR_WRONG_SSN;
412 goto out;
413 }
414 }
415
416 for (i = 0; i < nums; i++)
417 stream->in[ntohs(str_p[i])].ssn = 0;
418 } else {
419 for (i = 0; i < stream->incnt; i++)
420 stream->in[i].ssn = 0;
421 }
422
423 result = SCTP_STRRESET_PERFORMED;
424
425 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
426 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
427 GFP_ATOMIC);
428
429 out:
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 (request_seq > asoc->strreset_inseq) {
447 result = SCTP_STRRESET_ERR_BAD_SEQNO;
448 goto out;
449 } else if (request_seq == asoc->strreset_inseq) {
450 asoc->strreset_inseq++;
451 }
452
453 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
454 goto out;
455
456 if (asoc->strreset_outstanding) {
457 result = SCTP_STRRESET_ERR_IN_PROGRESS;
458 goto out;
459 }
460
461 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
462 str_p = inreq->list_of_streams;
463 for (i = 0; i < nums; i++) {
464 if (ntohs(str_p[i]) >= stream->outcnt) {
465 result = SCTP_STRRESET_ERR_WRONG_SSN;
466 goto out;
467 }
468 }
469
470 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
471 if (!chunk)
472 goto out;
473
474 if (nums)
475 for (i = 0; i < nums; i++)
476 stream->out[ntohs(str_p[i])].state =
477 SCTP_STREAM_CLOSED;
478 else
479 for (i = 0; i < stream->outcnt; i++)
480 stream->out[i].state = SCTP_STREAM_CLOSED;
481
482 asoc->strreset_chunk = chunk;
483 asoc->strreset_outstanding = 1;
484 sctp_chunk_hold(asoc->strreset_chunk);
485
486 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
487 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
488
489 out:
490 if (!chunk)
491 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
492
493 return chunk;
494 }
495
496 struct sctp_chunk *sctp_process_strreset_tsnreq(
497 struct sctp_association *asoc,
498 union sctp_params param,
499 struct sctp_ulpevent **evp)
500 {
501 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
502 struct sctp_strreset_tsnreq *tsnreq = param.v;
503 struct sctp_stream *stream = asoc->stream;
504 __u32 result = SCTP_STRRESET_DENIED;
505 __u32 request_seq;
506 __u16 i;
507
508 request_seq = ntohl(tsnreq->request_seq);
509 if (request_seq > asoc->strreset_inseq) {
510 result = SCTP_STRRESET_ERR_BAD_SEQNO;
511 goto out;
512 } else if (request_seq == asoc->strreset_inseq) {
513 asoc->strreset_inseq++;
514 }
515
516 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
517 goto out;
518
519 if (asoc->strreset_outstanding) {
520 result = SCTP_STRRESET_ERR_IN_PROGRESS;
521 goto out;
522 }
523
524 /* G3: The same processing as though a SACK chunk with no gap report
525 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
526 * received MUST be performed.
527 */
528 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
529 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
530 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
531
532 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
533 * TSN that the peer should use to send the next DATA chunk. The
534 * value SHOULD be the smallest TSN not acknowledged by the
535 * receiver of the request plus 2^31.
536 */
537 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
538 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
539 init_tsn, GFP_ATOMIC);
540
541 /* G4: The same processing as though a FWD-TSN chunk (as defined in
542 * [RFC3758]) with all streams affected and a new cumulative TSN
543 * ACK of the Receiver's Next TSN minus 1 were received MUST be
544 * performed.
545 */
546 sctp_outq_free(&asoc->outqueue);
547
548 /* G2: Compute an appropriate value for the local endpoint's next TSN,
549 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
550 * chunk. The value SHOULD be the highest TSN sent by the receiver
551 * of the request plus 1.
552 */
553 next_tsn = asoc->next_tsn;
554 asoc->ctsn_ack_point = next_tsn - 1;
555 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
556
557 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
558 * incoming and outgoing streams.
559 */
560 for (i = 0; i < stream->outcnt; i++)
561 stream->out[i].ssn = 0;
562 for (i = 0; i < stream->incnt; i++)
563 stream->in[i].ssn = 0;
564
565 result = SCTP_STRRESET_PERFORMED;
566
567 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
568 next_tsn, GFP_ATOMIC);
569
570 out:
571 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
572 next_tsn, init_tsn);
573 }
574
575 struct sctp_chunk *sctp_process_strreset_addstrm_out(
576 struct sctp_association *asoc,
577 union sctp_params param,
578 struct sctp_ulpevent **evp)
579 {
580 struct sctp_strreset_addstrm *addstrm = param.v;
581 struct sctp_stream *stream = asoc->stream;
582 __u32 result = SCTP_STRRESET_DENIED;
583 struct sctp_stream_in *streamin;
584 __u32 request_seq, incnt;
585 __u16 in;
586
587 request_seq = ntohl(addstrm->request_seq);
588 if (request_seq > asoc->strreset_inseq) {
589 result = SCTP_STRRESET_ERR_BAD_SEQNO;
590 goto out;
591 } else if (request_seq == asoc->strreset_inseq) {
592 asoc->strreset_inseq++;
593 }
594
595 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
596 goto out;
597
598 if (asoc->strreset_chunk) {
599 if (!sctp_chunk_lookup_strreset_param(
600 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
601 /* same process with outstanding isn't 0 */
602 result = SCTP_STRRESET_ERR_IN_PROGRESS;
603 goto out;
604 }
605
606 asoc->strreset_outstanding--;
607 asoc->strreset_outseq++;
608
609 if (!asoc->strreset_outstanding) {
610 struct sctp_transport *t;
611
612 t = asoc->strreset_chunk->transport;
613 if (del_timer(&t->reconf_timer))
614 sctp_transport_put(t);
615
616 sctp_chunk_put(asoc->strreset_chunk);
617 asoc->strreset_chunk = NULL;
618 }
619 }
620
621 in = ntohs(addstrm->number_of_streams);
622 incnt = stream->incnt + in;
623 if (!in || incnt > SCTP_MAX_STREAM)
624 goto out;
625
626 streamin = krealloc(stream->in, incnt * sizeof(*streamin),
627 GFP_ATOMIC);
628 if (!streamin)
629 goto out;
630
631 memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
632 stream->in = streamin;
633 stream->incnt = incnt;
634
635 result = SCTP_STRRESET_PERFORMED;
636
637 *evp = sctp_ulpevent_make_stream_change_event(asoc,
638 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
639
640 out:
641 return sctp_make_strreset_resp(asoc, result, request_seq);
642 }
643
644 struct sctp_chunk *sctp_process_strreset_addstrm_in(
645 struct sctp_association *asoc,
646 union sctp_params param,
647 struct sctp_ulpevent **evp)
648 {
649 struct sctp_strreset_addstrm *addstrm = param.v;
650 struct sctp_stream *stream = asoc->stream;
651 __u32 result = SCTP_STRRESET_DENIED;
652 struct sctp_stream_out *streamout;
653 struct sctp_chunk *chunk = NULL;
654 __u32 request_seq, outcnt;
655 __u16 out;
656
657 request_seq = ntohl(addstrm->request_seq);
658 if (request_seq > asoc->strreset_inseq) {
659 result = SCTP_STRRESET_ERR_BAD_SEQNO;
660 goto out;
661 } else if (request_seq == asoc->strreset_inseq) {
662 asoc->strreset_inseq++;
663 }
664
665 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
666 goto out;
667
668 if (asoc->strreset_outstanding) {
669 result = SCTP_STRRESET_ERR_IN_PROGRESS;
670 goto out;
671 }
672
673 out = ntohs(addstrm->number_of_streams);
674 outcnt = stream->outcnt + out;
675 if (!out || outcnt > SCTP_MAX_STREAM)
676 goto out;
677
678 streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
679 GFP_ATOMIC);
680 if (!streamout)
681 goto out;
682
683 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
684 stream->out = streamout;
685
686 chunk = sctp_make_strreset_addstrm(asoc, out, 0);
687 if (!chunk)
688 goto out;
689
690 asoc->strreset_chunk = chunk;
691 asoc->strreset_outstanding = 1;
692 sctp_chunk_hold(asoc->strreset_chunk);
693
694 stream->outcnt = outcnt;
695
696 *evp = sctp_ulpevent_make_stream_change_event(asoc,
697 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
698
699 out:
700 if (!chunk)
701 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
702
703 return chunk;
704 }
705
706 struct sctp_chunk *sctp_process_strreset_resp(
707 struct sctp_association *asoc,
708 union sctp_params param,
709 struct sctp_ulpevent **evp)
710 {
711 struct sctp_strreset_resp *resp = param.v;
712 struct sctp_stream *stream = asoc->stream;
713 struct sctp_transport *t;
714 __u16 i, nums, flags = 0;
715 sctp_paramhdr_t *req;
716 __u32 result;
717
718 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
719 if (!req)
720 return NULL;
721
722 result = ntohl(resp->result);
723 if (result != SCTP_STRRESET_PERFORMED) {
724 /* if in progress, do nothing but retransmit */
725 if (result == SCTP_STRRESET_IN_PROGRESS)
726 return NULL;
727 else if (result == SCTP_STRRESET_DENIED)
728 flags = SCTP_STREAM_RESET_DENIED;
729 else
730 flags = SCTP_STREAM_RESET_FAILED;
731 }
732
733 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
734 struct sctp_strreset_outreq *outreq;
735 __u16 *str_p = NULL;
736
737 outreq = (struct sctp_strreset_outreq *)req;
738 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
739
740 if (result == SCTP_STRRESET_PERFORMED) {
741 if (nums) {
742 str_p = outreq->list_of_streams;
743 for (i = 0; i < nums; i++)
744 stream->out[ntohs(str_p[i])].ssn = 0;
745 } else {
746 for (i = 0; i < stream->outcnt; i++)
747 stream->out[i].ssn = 0;
748 }
749
750 flags = SCTP_STREAM_RESET_OUTGOING_SSN;
751 }
752
753 for (i = 0; i < stream->outcnt; i++)
754 stream->out[i].state = SCTP_STREAM_OPEN;
755
756 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
757 nums, str_p, GFP_ATOMIC);
758 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
759 struct sctp_strreset_inreq *inreq;
760 __u16 *str_p = NULL;
761
762 /* if the result is performed, it's impossible for inreq */
763 if (result == SCTP_STRRESET_PERFORMED)
764 return NULL;
765
766 inreq = (struct sctp_strreset_inreq *)req;
767 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
768
769 str_p = inreq->list_of_streams;
770 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
771 nums, str_p, GFP_ATOMIC);
772 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
773 struct sctp_strreset_resptsn *resptsn;
774 __u32 stsn, rtsn;
775
776 /* check for resptsn, as sctp_verify_reconf didn't do it*/
777 if (ntohs(param.p->length) != sizeof(*resptsn))
778 return NULL;
779
780 resptsn = (struct sctp_strreset_resptsn *)resp;
781 stsn = ntohl(resptsn->senders_next_tsn);
782 rtsn = ntohl(resptsn->receivers_next_tsn);
783
784 if (result == SCTP_STRRESET_PERFORMED) {
785 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
786 &asoc->peer.tsn_map);
787
788 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
789 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
790
791 sctp_tsnmap_init(&asoc->peer.tsn_map,
792 SCTP_TSN_MAP_INITIAL,
793 stsn, GFP_ATOMIC);
794
795 sctp_outq_free(&asoc->outqueue);
796
797 asoc->next_tsn = rtsn;
798 asoc->ctsn_ack_point = asoc->next_tsn - 1;
799 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
800
801 for (i = 0; i < stream->outcnt; i++)
802 stream->out[i].ssn = 0;
803 for (i = 0; i < stream->incnt; i++)
804 stream->in[i].ssn = 0;
805 }
806
807 for (i = 0; i < stream->outcnt; i++)
808 stream->out[i].state = SCTP_STREAM_OPEN;
809
810 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
811 stsn, rtsn, GFP_ATOMIC);
812 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
813 struct sctp_strreset_addstrm *addstrm;
814 __u16 number;
815
816 addstrm = (struct sctp_strreset_addstrm *)req;
817 nums = ntohs(addstrm->number_of_streams);
818 number = stream->outcnt - nums;
819
820 if (result == SCTP_STRRESET_PERFORMED)
821 for (i = number; i < stream->outcnt; i++)
822 stream->out[i].state = SCTP_STREAM_OPEN;
823 else
824 stream->outcnt = number;
825
826 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
827 0, nums, GFP_ATOMIC);
828 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
829 struct sctp_strreset_addstrm *addstrm;
830
831 /* if the result is performed, it's impossible for addstrm in
832 * request.
833 */
834 if (result == SCTP_STRRESET_PERFORMED)
835 return NULL;
836
837 addstrm = (struct sctp_strreset_addstrm *)req;
838 nums = ntohs(addstrm->number_of_streams);
839
840 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
841 nums, 0, GFP_ATOMIC);
842 }
843
844 asoc->strreset_outstanding--;
845 asoc->strreset_outseq++;
846
847 /* remove everything for this reconf request */
848 if (!asoc->strreset_outstanding) {
849 t = asoc->strreset_chunk->transport;
850 if (del_timer(&t->reconf_timer))
851 sctp_transport_put(t);
852
853 sctp_chunk_put(asoc->strreset_chunk);
854 asoc->strreset_chunk = NULL;
855 }
856
857 return NULL;
858 }