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.
7 * This file is part of the SCTP kernel implementation
9 * These functions manipulate sctp tsn mapping array.
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)
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.
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/>.
27 * Please send any bug reports or fixes you make to the
29 * lksctp developers <linux-sctp@vger.kernel.org>
31 * Written or modified by:
32 * Xin Long <lucien.xin@gmail.com>
35 #include <net/sctp/sctp.h>
36 #include <net/sctp/sm.h>
38 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
41 struct sctp_stream_out *out;
43 out = kmalloc_array(outcnt, sizeof(*out), gfp);
48 memcpy(out, stream->out, min(outcnt, stream->outcnt) *
53 if (outcnt > stream->outcnt)
54 memset(out + stream->outcnt, 0,
55 (outcnt - stream->outcnt) * sizeof(*out));
62 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
69 /* Initial stream->out size may be very big, so free it and alloc
70 * a new one with new outcnt to save memory if needed.
72 if (outcnt == stream->outcnt)
75 i = sctp_stream_alloc_out(stream, outcnt, gfp);
79 stream->outcnt = outcnt;
80 for (i = 0; i < stream->outcnt; i++)
81 stream->out[i].state = SCTP_STREAM_OPEN;
87 stream->in = kcalloc(incnt, sizeof(*stream->in), gfp);
94 stream->incnt = incnt;
99 void sctp_stream_free(struct sctp_stream *stream)
105 void sctp_stream_clear(struct sctp_stream *stream)
109 for (i = 0; i < stream->outcnt; i++)
110 stream->out[i].ssn = 0;
112 for (i = 0; i < stream->incnt; i++)
113 stream->in[i].ssn = 0;
116 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
118 sctp_stream_free(stream);
120 stream->out = new->out;
121 stream->in = new->in;
122 stream->outcnt = new->outcnt;
123 stream->incnt = new->incnt;
129 static int sctp_send_reconf(struct sctp_association *asoc,
130 struct sctp_chunk *chunk)
132 struct net *net = sock_net(asoc->base.sk);
135 retval = sctp_primitive_RECONF(net, asoc, chunk);
137 sctp_chunk_free(chunk);
142 int sctp_send_reset_streams(struct sctp_association *asoc,
143 struct sctp_reset_streams *params)
145 struct sctp_stream *stream = &asoc->stream;
146 __u16 i, str_nums, *str_list;
147 struct sctp_chunk *chunk;
148 int retval = -EINVAL;
151 if (!asoc->peer.reconf_capable ||
152 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
153 retval = -ENOPROTOOPT;
157 if (asoc->strreset_outstanding) {
158 retval = -EINPROGRESS;
162 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
163 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
167 str_nums = params->srs_number_streams;
168 str_list = params->srs_stream_list;
170 for (i = 0; i < str_nums; i++)
171 if (str_list[i] >= stream->outcnt)
175 for (i = 0; i < str_nums; i++)
176 if (str_list[i] >= stream->incnt)
179 for (i = 0; i < str_nums; i++)
180 str_list[i] = htons(str_list[i]);
182 chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in);
184 for (i = 0; i < str_nums; i++)
185 str_list[i] = ntohs(str_list[i]);
194 for (i = 0; i < str_nums; i++)
195 stream->out[str_list[i]].state =
198 for (i = 0; i < stream->outcnt; i++)
199 stream->out[i].state = SCTP_STREAM_CLOSED;
202 asoc->strreset_chunk = chunk;
203 sctp_chunk_hold(asoc->strreset_chunk);
205 retval = sctp_send_reconf(asoc, chunk);
207 sctp_chunk_put(asoc->strreset_chunk);
208 asoc->strreset_chunk = NULL;
213 for (i = 0; i < str_nums; i++)
214 stream->out[str_list[i]].state =
217 for (i = 0; i < stream->outcnt; i++)
218 stream->out[i].state = SCTP_STREAM_OPEN;
223 asoc->strreset_outstanding = out + in;
229 int sctp_send_reset_assoc(struct sctp_association *asoc)
231 struct sctp_stream *stream = &asoc->stream;
232 struct sctp_chunk *chunk = NULL;
236 if (!asoc->peer.reconf_capable ||
237 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
240 if (asoc->strreset_outstanding)
243 chunk = sctp_make_strreset_tsnreq(asoc);
247 /* Block further xmit of data until this request is completed */
248 for (i = 0; i < stream->outcnt; i++)
249 stream->out[i].state = SCTP_STREAM_CLOSED;
251 asoc->strreset_chunk = chunk;
252 sctp_chunk_hold(asoc->strreset_chunk);
254 retval = sctp_send_reconf(asoc, chunk);
256 sctp_chunk_put(asoc->strreset_chunk);
257 asoc->strreset_chunk = NULL;
259 for (i = 0; i < stream->outcnt; i++)
260 stream->out[i].state = SCTP_STREAM_OPEN;
265 asoc->strreset_outstanding = 1;
270 int sctp_send_add_streams(struct sctp_association *asoc,
271 struct sctp_add_streams *params)
273 struct sctp_stream *stream = &asoc->stream;
274 struct sctp_chunk *chunk = NULL;
275 int retval = -ENOMEM;
279 if (!asoc->peer.reconf_capable ||
280 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
281 retval = -ENOPROTOOPT;
285 if (asoc->strreset_outstanding) {
286 retval = -EINPROGRESS;
290 out = params->sas_outstrms;
291 in = params->sas_instrms;
292 outcnt = stream->outcnt + out;
293 incnt = stream->incnt + in;
294 if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
301 retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
306 chunk = sctp_make_strreset_addstrm(asoc, out, in);
310 asoc->strreset_chunk = chunk;
311 sctp_chunk_hold(asoc->strreset_chunk);
313 retval = sctp_send_reconf(asoc, chunk);
315 sctp_chunk_put(asoc->strreset_chunk);
316 asoc->strreset_chunk = NULL;
320 stream->incnt = incnt;
321 stream->outcnt = outcnt;
323 asoc->strreset_outstanding = !!out + !!in;
329 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
330 struct sctp_association *asoc, __u32 resp_seq,
333 struct sctp_chunk *chunk = asoc->strreset_chunk;
334 struct sctp_reconf_chunk *hdr;
335 union sctp_params param;
340 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
341 sctp_walk_params(param, hdr, params) {
342 /* sctp_strreset_tsnreq is actually the basic structure
343 * of all stream reconf params, so it's safe to use it
344 * to access request_seq.
346 struct sctp_strreset_tsnreq *req = param.v;
348 if ((!resp_seq || req->request_seq == resp_seq) &&
349 (!type || type == req->param_hdr.type))
356 static void sctp_update_strreset_result(struct sctp_association *asoc,
359 asoc->strreset_result[1] = asoc->strreset_result[0];
360 asoc->strreset_result[0] = result;
363 struct sctp_chunk *sctp_process_strreset_outreq(
364 struct sctp_association *asoc,
365 union sctp_params param,
366 struct sctp_ulpevent **evp)
368 struct sctp_strreset_outreq *outreq = param.v;
369 struct sctp_stream *stream = &asoc->stream;
370 __u16 i, nums, flags = 0, *str_p = NULL;
371 __u32 result = SCTP_STRRESET_DENIED;
374 request_seq = ntohl(outreq->request_seq);
376 if (ntohl(outreq->send_reset_at_tsn) >
377 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
378 result = SCTP_STRRESET_IN_PROGRESS;
382 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
383 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
384 result = SCTP_STRRESET_ERR_BAD_SEQNO;
386 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
387 i = asoc->strreset_inseq - request_seq - 1;
388 result = asoc->strreset_result[i];
391 asoc->strreset_inseq++;
393 /* Check strreset_enable after inseq inc, as sender cannot tell
394 * the peer doesn't enable strreset after receiving response with
395 * result denied, as well as to keep consistent with bsd.
397 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
400 if (asoc->strreset_chunk) {
401 if (!sctp_chunk_lookup_strreset_param(
402 asoc, outreq->response_seq,
403 SCTP_PARAM_RESET_IN_REQUEST)) {
404 /* same process with outstanding isn't 0 */
405 result = SCTP_STRRESET_ERR_IN_PROGRESS;
409 asoc->strreset_outstanding--;
410 asoc->strreset_outseq++;
412 if (!asoc->strreset_outstanding) {
413 struct sctp_transport *t;
415 t = asoc->strreset_chunk->transport;
416 if (del_timer(&t->reconf_timer))
417 sctp_transport_put(t);
419 sctp_chunk_put(asoc->strreset_chunk);
420 asoc->strreset_chunk = NULL;
423 flags = SCTP_STREAM_RESET_INCOMING_SSN;
426 nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2;
428 str_p = outreq->list_of_streams;
429 for (i = 0; i < nums; i++) {
430 if (ntohs(str_p[i]) >= stream->incnt) {
431 result = SCTP_STRRESET_ERR_WRONG_SSN;
436 for (i = 0; i < nums; i++)
437 stream->in[ntohs(str_p[i])].ssn = 0;
439 for (i = 0; i < stream->incnt; i++)
440 stream->in[i].ssn = 0;
443 result = SCTP_STRRESET_PERFORMED;
445 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
446 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
450 sctp_update_strreset_result(asoc, result);
452 return sctp_make_strreset_resp(asoc, result, request_seq);
455 struct sctp_chunk *sctp_process_strreset_inreq(
456 struct sctp_association *asoc,
457 union sctp_params param,
458 struct sctp_ulpevent **evp)
460 struct sctp_strreset_inreq *inreq = param.v;
461 struct sctp_stream *stream = &asoc->stream;
462 __u32 result = SCTP_STRRESET_DENIED;
463 struct sctp_chunk *chunk = NULL;
464 __u16 i, nums, *str_p;
467 request_seq = ntohl(inreq->request_seq);
468 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
469 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
470 result = SCTP_STRRESET_ERR_BAD_SEQNO;
472 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
473 i = asoc->strreset_inseq - request_seq - 1;
474 result = asoc->strreset_result[i];
475 if (result == SCTP_STRRESET_PERFORMED)
479 asoc->strreset_inseq++;
481 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
484 if (asoc->strreset_outstanding) {
485 result = SCTP_STRRESET_ERR_IN_PROGRESS;
489 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
490 str_p = inreq->list_of_streams;
491 for (i = 0; i < nums; i++) {
492 if (ntohs(str_p[i]) >= stream->outcnt) {
493 result = SCTP_STRRESET_ERR_WRONG_SSN;
498 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
503 for (i = 0; i < nums; i++)
504 stream->out[ntohs(str_p[i])].state =
507 for (i = 0; i < stream->outcnt; i++)
508 stream->out[i].state = SCTP_STREAM_CLOSED;
510 asoc->strreset_chunk = chunk;
511 asoc->strreset_outstanding = 1;
512 sctp_chunk_hold(asoc->strreset_chunk);
514 result = SCTP_STRRESET_PERFORMED;
516 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
517 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
520 sctp_update_strreset_result(asoc, result);
523 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
528 struct sctp_chunk *sctp_process_strreset_tsnreq(
529 struct sctp_association *asoc,
530 union sctp_params param,
531 struct sctp_ulpevent **evp)
533 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
534 struct sctp_strreset_tsnreq *tsnreq = param.v;
535 struct sctp_stream *stream = &asoc->stream;
536 __u32 result = SCTP_STRRESET_DENIED;
540 request_seq = ntohl(tsnreq->request_seq);
541 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
542 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
543 result = SCTP_STRRESET_ERR_BAD_SEQNO;
545 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
546 i = asoc->strreset_inseq - request_seq - 1;
547 result = asoc->strreset_result[i];
548 if (result == SCTP_STRRESET_PERFORMED) {
549 next_tsn = asoc->next_tsn;
551 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
555 asoc->strreset_inseq++;
557 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
560 if (asoc->strreset_outstanding) {
561 result = SCTP_STRRESET_ERR_IN_PROGRESS;
565 /* G3: The same processing as though a SACK chunk with no gap report
566 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
567 * received MUST be performed.
569 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
570 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
571 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
573 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
574 * TSN that the peer should use to send the next DATA chunk. The
575 * value SHOULD be the smallest TSN not acknowledged by the
576 * receiver of the request plus 2^31.
578 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
579 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
580 init_tsn, GFP_ATOMIC);
582 /* G4: The same processing as though a FWD-TSN chunk (as defined in
583 * [RFC3758]) with all streams affected and a new cumulative TSN
584 * ACK of the Receiver's Next TSN minus 1 were received MUST be
587 sctp_outq_free(&asoc->outqueue);
589 /* G2: Compute an appropriate value for the local endpoint's next TSN,
590 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
591 * chunk. The value SHOULD be the highest TSN sent by the receiver
592 * of the request plus 1.
594 next_tsn = asoc->next_tsn;
595 asoc->ctsn_ack_point = next_tsn - 1;
596 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
598 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
599 * incoming and outgoing streams.
601 for (i = 0; i < stream->outcnt; i++)
602 stream->out[i].ssn = 0;
603 for (i = 0; i < stream->incnt; i++)
604 stream->in[i].ssn = 0;
606 result = SCTP_STRRESET_PERFORMED;
608 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
609 next_tsn, GFP_ATOMIC);
612 sctp_update_strreset_result(asoc, result);
614 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
618 struct sctp_chunk *sctp_process_strreset_addstrm_out(
619 struct sctp_association *asoc,
620 union sctp_params param,
621 struct sctp_ulpevent **evp)
623 struct sctp_strreset_addstrm *addstrm = param.v;
624 struct sctp_stream *stream = &asoc->stream;
625 __u32 result = SCTP_STRRESET_DENIED;
626 struct sctp_stream_in *streamin;
627 __u32 request_seq, incnt;
630 request_seq = ntohl(addstrm->request_seq);
631 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
632 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
633 result = SCTP_STRRESET_ERR_BAD_SEQNO;
635 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
636 i = asoc->strreset_inseq - request_seq - 1;
637 result = asoc->strreset_result[i];
640 asoc->strreset_inseq++;
642 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
645 if (asoc->strreset_chunk) {
646 if (!sctp_chunk_lookup_strreset_param(
647 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
648 /* same process with outstanding isn't 0 */
649 result = SCTP_STRRESET_ERR_IN_PROGRESS;
653 asoc->strreset_outstanding--;
654 asoc->strreset_outseq++;
656 if (!asoc->strreset_outstanding) {
657 struct sctp_transport *t;
659 t = asoc->strreset_chunk->transport;
660 if (del_timer(&t->reconf_timer))
661 sctp_transport_put(t);
663 sctp_chunk_put(asoc->strreset_chunk);
664 asoc->strreset_chunk = NULL;
668 in = ntohs(addstrm->number_of_streams);
669 incnt = stream->incnt + in;
670 if (!in || incnt > SCTP_MAX_STREAM)
673 streamin = krealloc(stream->in, incnt * sizeof(*streamin),
678 memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
679 stream->in = streamin;
680 stream->incnt = incnt;
682 result = SCTP_STRRESET_PERFORMED;
684 *evp = sctp_ulpevent_make_stream_change_event(asoc,
685 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
688 sctp_update_strreset_result(asoc, result);
690 return sctp_make_strreset_resp(asoc, result, request_seq);
693 struct sctp_chunk *sctp_process_strreset_addstrm_in(
694 struct sctp_association *asoc,
695 union sctp_params param,
696 struct sctp_ulpevent **evp)
698 struct sctp_strreset_addstrm *addstrm = param.v;
699 struct sctp_stream *stream = &asoc->stream;
700 __u32 result = SCTP_STRRESET_DENIED;
701 struct sctp_chunk *chunk = NULL;
702 __u32 request_seq, outcnt;
706 request_seq = ntohl(addstrm->request_seq);
707 if (TSN_lt(asoc->strreset_inseq, request_seq) ||
708 TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
709 result = SCTP_STRRESET_ERR_BAD_SEQNO;
711 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
712 i = asoc->strreset_inseq - request_seq - 1;
713 result = asoc->strreset_result[i];
714 if (result == SCTP_STRRESET_PERFORMED)
718 asoc->strreset_inseq++;
720 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
723 if (asoc->strreset_outstanding) {
724 result = SCTP_STRRESET_ERR_IN_PROGRESS;
728 out = ntohs(addstrm->number_of_streams);
729 outcnt = stream->outcnt + out;
730 if (!out || outcnt > SCTP_MAX_STREAM)
733 ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
737 chunk = sctp_make_strreset_addstrm(asoc, out, 0);
741 asoc->strreset_chunk = chunk;
742 asoc->strreset_outstanding = 1;
743 sctp_chunk_hold(asoc->strreset_chunk);
745 stream->outcnt = outcnt;
747 result = SCTP_STRRESET_PERFORMED;
749 *evp = sctp_ulpevent_make_stream_change_event(asoc,
750 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
753 sctp_update_strreset_result(asoc, result);
756 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
761 struct sctp_chunk *sctp_process_strreset_resp(
762 struct sctp_association *asoc,
763 union sctp_params param,
764 struct sctp_ulpevent **evp)
766 struct sctp_stream *stream = &asoc->stream;
767 struct sctp_strreset_resp *resp = param.v;
768 struct sctp_transport *t;
769 __u16 i, nums, flags = 0;
770 struct sctp_paramhdr *req;
773 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
777 result = ntohl(resp->result);
778 if (result != SCTP_STRRESET_PERFORMED) {
779 /* if in progress, do nothing but retransmit */
780 if (result == SCTP_STRRESET_IN_PROGRESS)
782 else if (result == SCTP_STRRESET_DENIED)
783 flags = SCTP_STREAM_RESET_DENIED;
785 flags = SCTP_STREAM_RESET_FAILED;
788 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
789 struct sctp_strreset_outreq *outreq;
792 outreq = (struct sctp_strreset_outreq *)req;
793 str_p = outreq->list_of_streams;
794 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
796 if (result == SCTP_STRRESET_PERFORMED) {
798 for (i = 0; i < nums; i++)
799 stream->out[ntohs(str_p[i])].ssn = 0;
801 for (i = 0; i < stream->outcnt; i++)
802 stream->out[i].ssn = 0;
805 flags = SCTP_STREAM_RESET_OUTGOING_SSN;
808 for (i = 0; i < stream->outcnt; i++)
809 stream->out[i].state = SCTP_STREAM_OPEN;
811 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
812 nums, str_p, GFP_ATOMIC);
813 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
814 struct sctp_strreset_inreq *inreq;
817 /* if the result is performed, it's impossible for inreq */
818 if (result == SCTP_STRRESET_PERFORMED)
821 inreq = (struct sctp_strreset_inreq *)req;
822 str_p = inreq->list_of_streams;
823 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
825 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
826 nums, str_p, GFP_ATOMIC);
827 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
828 struct sctp_strreset_resptsn *resptsn;
831 /* check for resptsn, as sctp_verify_reconf didn't do it*/
832 if (ntohs(param.p->length) != sizeof(*resptsn))
835 resptsn = (struct sctp_strreset_resptsn *)resp;
836 stsn = ntohl(resptsn->senders_next_tsn);
837 rtsn = ntohl(resptsn->receivers_next_tsn);
839 if (result == SCTP_STRRESET_PERFORMED) {
840 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
841 &asoc->peer.tsn_map);
843 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
844 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
846 sctp_tsnmap_init(&asoc->peer.tsn_map,
847 SCTP_TSN_MAP_INITIAL,
850 sctp_outq_free(&asoc->outqueue);
852 asoc->next_tsn = rtsn;
853 asoc->ctsn_ack_point = asoc->next_tsn - 1;
854 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
856 for (i = 0; i < stream->outcnt; i++)
857 stream->out[i].ssn = 0;
858 for (i = 0; i < stream->incnt; i++)
859 stream->in[i].ssn = 0;
862 for (i = 0; i < stream->outcnt; i++)
863 stream->out[i].state = SCTP_STREAM_OPEN;
865 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
866 stsn, rtsn, GFP_ATOMIC);
867 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
868 struct sctp_strreset_addstrm *addstrm;
871 addstrm = (struct sctp_strreset_addstrm *)req;
872 nums = ntohs(addstrm->number_of_streams);
873 number = stream->outcnt - nums;
875 if (result == SCTP_STRRESET_PERFORMED)
876 for (i = number; i < stream->outcnt; i++)
877 stream->out[i].state = SCTP_STREAM_OPEN;
879 stream->outcnt = number;
881 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
882 0, nums, GFP_ATOMIC);
883 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
884 struct sctp_strreset_addstrm *addstrm;
886 /* if the result is performed, it's impossible for addstrm in
889 if (result == SCTP_STRRESET_PERFORMED)
892 addstrm = (struct sctp_strreset_addstrm *)req;
893 nums = ntohs(addstrm->number_of_streams);
895 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
896 nums, 0, GFP_ATOMIC);
899 asoc->strreset_outstanding--;
900 asoc->strreset_outseq++;
902 /* remove everything for this reconf request */
903 if (!asoc->strreset_outstanding) {
904 t = asoc->strreset_chunk->transport;
905 if (del_timer(&t->reconf_timer))
906 sctp_transport_put(t);
908 sctp_chunk_put(asoc->strreset_chunk);
909 asoc->strreset_chunk = NULL;