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