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 int sctp_stream_new(struct sctp_association
*asoc
, gfp_t gfp
)
40 struct sctp_stream
*stream
;
43 stream
= kzalloc(sizeof(*stream
), gfp
);
47 stream
->outcnt
= asoc
->c
.sinit_num_ostreams
;
48 stream
->out
= kcalloc(stream
->outcnt
, sizeof(*stream
->out
), gfp
);
53 for (i
= 0; i
< stream
->outcnt
; i
++)
54 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
56 asoc
->stream
= stream
;
61 int sctp_stream_init(struct sctp_association
*asoc
, gfp_t gfp
)
63 struct sctp_stream
*stream
= asoc
->stream
;
66 /* Initial stream->out size may be very big, so free it and alloc
67 * a new one with new outcnt to save memory.
70 stream
->outcnt
= asoc
->c
.sinit_num_ostreams
;
71 stream
->out
= kcalloc(stream
->outcnt
, sizeof(*stream
->out
), gfp
);
75 for (i
= 0; i
< stream
->outcnt
; i
++)
76 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
78 stream
->incnt
= asoc
->c
.sinit_max_instreams
;
79 stream
->in
= kcalloc(stream
->incnt
, sizeof(*stream
->in
), gfp
);
94 void sctp_stream_free(struct sctp_stream
*stream
)
96 if (unlikely(!stream
))
104 void sctp_stream_clear(struct sctp_stream
*stream
)
108 for (i
= 0; i
< stream
->outcnt
; i
++)
109 stream
->out
[i
].ssn
= 0;
111 for (i
= 0; i
< stream
->incnt
; i
++)
112 stream
->in
[i
].ssn
= 0;
115 static int sctp_send_reconf(struct sctp_association
*asoc
,
116 struct sctp_chunk
*chunk
)
118 struct net
*net
= sock_net(asoc
->base
.sk
);
121 retval
= sctp_primitive_RECONF(net
, asoc
, chunk
);
123 sctp_chunk_free(chunk
);
128 int sctp_send_reset_streams(struct sctp_association
*asoc
,
129 struct sctp_reset_streams
*params
)
131 struct sctp_stream
*stream
= asoc
->stream
;
132 __u16 i
, str_nums
, *str_list
;
133 struct sctp_chunk
*chunk
;
134 int retval
= -EINVAL
;
137 if (!asoc
->peer
.reconf_capable
||
138 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
)) {
139 retval
= -ENOPROTOOPT
;
143 if (asoc
->strreset_outstanding
) {
144 retval
= -EINPROGRESS
;
148 out
= params
->srs_flags
& SCTP_STREAM_RESET_OUTGOING
;
149 in
= params
->srs_flags
& SCTP_STREAM_RESET_INCOMING
;
153 str_nums
= params
->srs_number_streams
;
154 str_list
= params
->srs_stream_list
;
156 for (i
= 0; i
< str_nums
; i
++)
157 if (str_list
[i
] >= stream
->outcnt
)
161 for (i
= 0; i
< str_nums
; i
++)
162 if (str_list
[i
] >= stream
->incnt
)
165 for (i
= 0; i
< str_nums
; i
++)
166 str_list
[i
] = htons(str_list
[i
]);
168 chunk
= sctp_make_strreset_req(asoc
, str_nums
, str_list
, out
, in
);
170 for (i
= 0; i
< str_nums
; i
++)
171 str_list
[i
] = ntohs(str_list
[i
]);
180 for (i
= 0; i
< str_nums
; i
++)
181 stream
->out
[str_list
[i
]].state
=
184 for (i
= 0; i
< stream
->outcnt
; i
++)
185 stream
->out
[i
].state
= SCTP_STREAM_CLOSED
;
188 asoc
->strreset_chunk
= chunk
;
189 sctp_chunk_hold(asoc
->strreset_chunk
);
191 retval
= sctp_send_reconf(asoc
, chunk
);
193 sctp_chunk_put(asoc
->strreset_chunk
);
194 asoc
->strreset_chunk
= NULL
;
199 for (i
= 0; i
< str_nums
; i
++)
200 stream
->out
[str_list
[i
]].state
=
203 for (i
= 0; i
< stream
->outcnt
; i
++)
204 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
209 asoc
->strreset_outstanding
= out
+ in
;
215 int sctp_send_reset_assoc(struct sctp_association
*asoc
)
217 struct sctp_chunk
*chunk
= NULL
;
221 if (!asoc
->peer
.reconf_capable
||
222 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
225 if (asoc
->strreset_outstanding
)
228 chunk
= sctp_make_strreset_tsnreq(asoc
);
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
;
236 asoc
->strreset_chunk
= chunk
;
237 sctp_chunk_hold(asoc
->strreset_chunk
);
239 retval
= sctp_send_reconf(asoc
, chunk
);
241 sctp_chunk_put(asoc
->strreset_chunk
);
242 asoc
->strreset_chunk
= NULL
;
244 for (i
= 0; i
< asoc
->stream
->outcnt
; i
++)
245 asoc
->stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
250 asoc
->strreset_outstanding
= 1;
255 int sctp_send_add_streams(struct sctp_association
*asoc
,
256 struct sctp_add_streams
*params
)
258 struct sctp_stream
*stream
= asoc
->stream
;
259 struct sctp_chunk
*chunk
= NULL
;
260 int retval
= -ENOMEM
;
264 if (!asoc
->peer
.reconf_capable
||
265 !(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
)) {
266 retval
= -ENOPROTOOPT
;
270 if (asoc
->strreset_outstanding
) {
271 retval
= -EINPROGRESS
;
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
||
286 struct sctp_stream_out
*streamout
;
288 streamout
= krealloc(stream
->out
, outcnt
* sizeof(*streamout
),
293 memset(streamout
+ stream
->outcnt
, 0, out
* sizeof(*streamout
));
294 stream
->out
= streamout
;
297 chunk
= sctp_make_strreset_addstrm(asoc
, out
, in
);
301 asoc
->strreset_chunk
= chunk
;
302 sctp_chunk_hold(asoc
->strreset_chunk
);
304 retval
= sctp_send_reconf(asoc
, chunk
);
306 sctp_chunk_put(asoc
->strreset_chunk
);
307 asoc
->strreset_chunk
= NULL
;
311 stream
->incnt
= incnt
;
312 stream
->outcnt
= outcnt
;
314 asoc
->strreset_outstanding
= !!out
+ !!in
;
320 static sctp_paramhdr_t
*sctp_chunk_lookup_strreset_param(
321 struct sctp_association
*asoc
, __u32 resp_seq
,
324 struct sctp_chunk
*chunk
= asoc
->strreset_chunk
;
325 struct sctp_reconf_chunk
*hdr
;
326 union sctp_params param
;
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.
337 struct sctp_strreset_tsnreq
*req
= param
.v
;
339 if ((!resp_seq
|| req
->request_seq
== resp_seq
) &&
340 (!type
|| type
== req
->param_hdr
.type
))
347 static void sctp_update_strreset_result(struct sctp_association
*asoc
,
350 asoc
->strreset_result
[1] = asoc
->strreset_result
[0];
351 asoc
->strreset_result
[0] = result
;
354 struct sctp_chunk
*sctp_process_strreset_outreq(
355 struct sctp_association
*asoc
,
356 union sctp_params param
,
357 struct sctp_ulpevent
**evp
)
359 struct sctp_strreset_outreq
*outreq
= param
.v
;
360 struct sctp_stream
*stream
= asoc
->stream
;
361 __u16 i
, nums
, flags
= 0, *str_p
= NULL
;
362 __u32 result
= SCTP_STRRESET_DENIED
;
365 request_seq
= ntohl(outreq
->request_seq
);
367 if (ntohl(outreq
->send_reset_at_tsn
) >
368 sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
)) {
369 result
= SCTP_STRRESET_IN_PROGRESS
;
373 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
374 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
375 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
377 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
378 i
= asoc
->strreset_inseq
- request_seq
- 1;
379 result
= asoc
->strreset_result
[i
];
382 asoc
->strreset_inseq
++;
384 /* Check strreset_enable after inseq inc, as sender cannot tell
385 * the peer doesn't enable strreset after receiving response with
386 * result denied, as well as to keep consistent with bsd.
388 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
))
391 if (asoc
->strreset_chunk
) {
392 if (!sctp_chunk_lookup_strreset_param(
393 asoc
, outreq
->response_seq
,
394 SCTP_PARAM_RESET_IN_REQUEST
)) {
395 /* same process with outstanding isn't 0 */
396 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
400 asoc
->strreset_outstanding
--;
401 asoc
->strreset_outseq
++;
403 if (!asoc
->strreset_outstanding
) {
404 struct sctp_transport
*t
;
406 t
= asoc
->strreset_chunk
->transport
;
407 if (del_timer(&t
->reconf_timer
))
408 sctp_transport_put(t
);
410 sctp_chunk_put(asoc
->strreset_chunk
);
411 asoc
->strreset_chunk
= NULL
;
414 flags
= SCTP_STREAM_RESET_INCOMING_SSN
;
417 nums
= (ntohs(param
.p
->length
) - sizeof(*outreq
)) / 2;
419 str_p
= outreq
->list_of_streams
;
420 for (i
= 0; i
< nums
; i
++) {
421 if (ntohs(str_p
[i
]) >= stream
->incnt
) {
422 result
= SCTP_STRRESET_ERR_WRONG_SSN
;
427 for (i
= 0; i
< nums
; i
++)
428 stream
->in
[ntohs(str_p
[i
])].ssn
= 0;
430 for (i
= 0; i
< stream
->incnt
; i
++)
431 stream
->in
[i
].ssn
= 0;
434 result
= SCTP_STRRESET_PERFORMED
;
436 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
,
437 flags
| SCTP_STREAM_RESET_OUTGOING_SSN
, nums
, str_p
,
441 sctp_update_strreset_result(asoc
, result
);
443 return sctp_make_strreset_resp(asoc
, result
, request_seq
);
446 struct sctp_chunk
*sctp_process_strreset_inreq(
447 struct sctp_association
*asoc
,
448 union sctp_params param
,
449 struct sctp_ulpevent
**evp
)
451 struct sctp_strreset_inreq
*inreq
= param
.v
;
452 struct sctp_stream
*stream
= asoc
->stream
;
453 __u32 result
= SCTP_STRRESET_DENIED
;
454 struct sctp_chunk
*chunk
= NULL
;
455 __u16 i
, nums
, *str_p
;
458 request_seq
= ntohl(inreq
->request_seq
);
459 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
460 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
461 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
463 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
464 i
= asoc
->strreset_inseq
- request_seq
- 1;
465 result
= asoc
->strreset_result
[i
];
466 if (result
== SCTP_STRRESET_PERFORMED
)
470 asoc
->strreset_inseq
++;
472 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
))
475 if (asoc
->strreset_outstanding
) {
476 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
480 nums
= (ntohs(param
.p
->length
) - sizeof(*inreq
)) / 2;
481 str_p
= inreq
->list_of_streams
;
482 for (i
= 0; i
< nums
; i
++) {
483 if (ntohs(str_p
[i
]) >= stream
->outcnt
) {
484 result
= SCTP_STRRESET_ERR_WRONG_SSN
;
489 chunk
= sctp_make_strreset_req(asoc
, nums
, str_p
, 1, 0);
494 for (i
= 0; i
< nums
; i
++)
495 stream
->out
[ntohs(str_p
[i
])].state
=
498 for (i
= 0; i
< stream
->outcnt
; i
++)
499 stream
->out
[i
].state
= SCTP_STREAM_CLOSED
;
501 asoc
->strreset_chunk
= chunk
;
502 asoc
->strreset_outstanding
= 1;
503 sctp_chunk_hold(asoc
->strreset_chunk
);
505 result
= SCTP_STRRESET_PERFORMED
;
507 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
,
508 SCTP_STREAM_RESET_INCOMING_SSN
, nums
, str_p
, GFP_ATOMIC
);
511 sctp_update_strreset_result(asoc
, result
);
514 chunk
= sctp_make_strreset_resp(asoc
, result
, request_seq
);
519 struct sctp_chunk
*sctp_process_strreset_tsnreq(
520 struct sctp_association
*asoc
,
521 union sctp_params param
,
522 struct sctp_ulpevent
**evp
)
524 __u32 init_tsn
= 0, next_tsn
= 0, max_tsn_seen
;
525 struct sctp_strreset_tsnreq
*tsnreq
= param
.v
;
526 struct sctp_stream
*stream
= asoc
->stream
;
527 __u32 result
= SCTP_STRRESET_DENIED
;
531 request_seq
= ntohl(tsnreq
->request_seq
);
532 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
533 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
534 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
536 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
537 i
= asoc
->strreset_inseq
- request_seq
- 1;
538 result
= asoc
->strreset_result
[i
];
539 if (result
== SCTP_STRRESET_PERFORMED
) {
540 next_tsn
= asoc
->next_tsn
;
542 sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
) + 1;
546 asoc
->strreset_inseq
++;
548 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
551 if (asoc
->strreset_outstanding
) {
552 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
556 /* G3: The same processing as though a SACK chunk with no gap report
557 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
558 * received MUST be performed.
560 max_tsn_seen
= sctp_tsnmap_get_max_tsn_seen(&asoc
->peer
.tsn_map
);
561 sctp_ulpq_reasm_flushtsn(&asoc
->ulpq
, max_tsn_seen
);
562 sctp_ulpq_abort_pd(&asoc
->ulpq
, GFP_ATOMIC
);
564 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
565 * TSN that the peer should use to send the next DATA chunk. The
566 * value SHOULD be the smallest TSN not acknowledged by the
567 * receiver of the request plus 2^31.
569 init_tsn
= sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
) + (1 << 31);
570 sctp_tsnmap_init(&asoc
->peer
.tsn_map
, SCTP_TSN_MAP_INITIAL
,
571 init_tsn
, GFP_ATOMIC
);
573 /* G4: The same processing as though a FWD-TSN chunk (as defined in
574 * [RFC3758]) with all streams affected and a new cumulative TSN
575 * ACK of the Receiver's Next TSN minus 1 were received MUST be
578 sctp_outq_free(&asoc
->outqueue
);
580 /* G2: Compute an appropriate value for the local endpoint's next TSN,
581 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
582 * chunk. The value SHOULD be the highest TSN sent by the receiver
583 * of the request plus 1.
585 next_tsn
= asoc
->next_tsn
;
586 asoc
->ctsn_ack_point
= next_tsn
- 1;
587 asoc
->adv_peer_ack_point
= asoc
->ctsn_ack_point
;
589 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
590 * incoming and outgoing streams.
592 for (i
= 0; i
< stream
->outcnt
; i
++)
593 stream
->out
[i
].ssn
= 0;
594 for (i
= 0; i
< stream
->incnt
; i
++)
595 stream
->in
[i
].ssn
= 0;
597 result
= SCTP_STRRESET_PERFORMED
;
599 *evp
= sctp_ulpevent_make_assoc_reset_event(asoc
, 0, init_tsn
,
600 next_tsn
, GFP_ATOMIC
);
603 sctp_update_strreset_result(asoc
, result
);
605 return sctp_make_strreset_tsnresp(asoc
, result
, request_seq
,
609 struct sctp_chunk
*sctp_process_strreset_addstrm_out(
610 struct sctp_association
*asoc
,
611 union sctp_params param
,
612 struct sctp_ulpevent
**evp
)
614 struct sctp_strreset_addstrm
*addstrm
= param
.v
;
615 struct sctp_stream
*stream
= asoc
->stream
;
616 __u32 result
= SCTP_STRRESET_DENIED
;
617 struct sctp_stream_in
*streamin
;
618 __u32 request_seq
, incnt
;
621 request_seq
= ntohl(addstrm
->request_seq
);
622 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
623 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
624 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
626 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
627 i
= asoc
->strreset_inseq
- request_seq
- 1;
628 result
= asoc
->strreset_result
[i
];
631 asoc
->strreset_inseq
++;
633 if (!(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
))
636 if (asoc
->strreset_chunk
) {
637 if (!sctp_chunk_lookup_strreset_param(
638 asoc
, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS
)) {
639 /* same process with outstanding isn't 0 */
640 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
644 asoc
->strreset_outstanding
--;
645 asoc
->strreset_outseq
++;
647 if (!asoc
->strreset_outstanding
) {
648 struct sctp_transport
*t
;
650 t
= asoc
->strreset_chunk
->transport
;
651 if (del_timer(&t
->reconf_timer
))
652 sctp_transport_put(t
);
654 sctp_chunk_put(asoc
->strreset_chunk
);
655 asoc
->strreset_chunk
= NULL
;
659 in
= ntohs(addstrm
->number_of_streams
);
660 incnt
= stream
->incnt
+ in
;
661 if (!in
|| incnt
> SCTP_MAX_STREAM
)
664 streamin
= krealloc(stream
->in
, incnt
* sizeof(*streamin
),
669 memset(streamin
+ stream
->incnt
, 0, in
* sizeof(*streamin
));
670 stream
->in
= streamin
;
671 stream
->incnt
= incnt
;
673 result
= SCTP_STRRESET_PERFORMED
;
675 *evp
= sctp_ulpevent_make_stream_change_event(asoc
,
676 0, ntohs(addstrm
->number_of_streams
), 0, GFP_ATOMIC
);
679 sctp_update_strreset_result(asoc
, result
);
681 return sctp_make_strreset_resp(asoc
, result
, request_seq
);
684 struct sctp_chunk
*sctp_process_strreset_addstrm_in(
685 struct sctp_association
*asoc
,
686 union sctp_params param
,
687 struct sctp_ulpevent
**evp
)
689 struct sctp_strreset_addstrm
*addstrm
= param
.v
;
690 struct sctp_stream
*stream
= asoc
->stream
;
691 __u32 result
= SCTP_STRRESET_DENIED
;
692 struct sctp_stream_out
*streamout
;
693 struct sctp_chunk
*chunk
= NULL
;
694 __u32 request_seq
, outcnt
;
697 request_seq
= ntohl(addstrm
->request_seq
);
698 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
699 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
700 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
702 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
703 i
= asoc
->strreset_inseq
- request_seq
- 1;
704 result
= asoc
->strreset_result
[i
];
705 if (result
== SCTP_STRRESET_PERFORMED
)
709 asoc
->strreset_inseq
++;
711 if (!(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
))
714 if (asoc
->strreset_outstanding
) {
715 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
719 out
= ntohs(addstrm
->number_of_streams
);
720 outcnt
= stream
->outcnt
+ out
;
721 if (!out
|| outcnt
> SCTP_MAX_STREAM
)
724 streamout
= krealloc(stream
->out
, outcnt
* sizeof(*streamout
),
729 memset(streamout
+ stream
->outcnt
, 0, out
* sizeof(*streamout
));
730 stream
->out
= streamout
;
732 chunk
= sctp_make_strreset_addstrm(asoc
, out
, 0);
736 asoc
->strreset_chunk
= chunk
;
737 asoc
->strreset_outstanding
= 1;
738 sctp_chunk_hold(asoc
->strreset_chunk
);
740 stream
->outcnt
= outcnt
;
742 result
= SCTP_STRRESET_PERFORMED
;
744 *evp
= sctp_ulpevent_make_stream_change_event(asoc
,
745 0, 0, ntohs(addstrm
->number_of_streams
), GFP_ATOMIC
);
748 sctp_update_strreset_result(asoc
, result
);
751 chunk
= sctp_make_strreset_resp(asoc
, result
, request_seq
);
756 struct sctp_chunk
*sctp_process_strreset_resp(
757 struct sctp_association
*asoc
,
758 union sctp_params param
,
759 struct sctp_ulpevent
**evp
)
761 struct sctp_strreset_resp
*resp
= param
.v
;
762 struct sctp_stream
*stream
= asoc
->stream
;
763 struct sctp_transport
*t
;
764 __u16 i
, nums
, flags
= 0;
765 sctp_paramhdr_t
*req
;
768 req
= sctp_chunk_lookup_strreset_param(asoc
, resp
->response_seq
, 0);
772 result
= ntohl(resp
->result
);
773 if (result
!= SCTP_STRRESET_PERFORMED
) {
774 /* if in progress, do nothing but retransmit */
775 if (result
== SCTP_STRRESET_IN_PROGRESS
)
777 else if (result
== SCTP_STRRESET_DENIED
)
778 flags
= SCTP_STREAM_RESET_DENIED
;
780 flags
= SCTP_STREAM_RESET_FAILED
;
783 if (req
->type
== SCTP_PARAM_RESET_OUT_REQUEST
) {
784 struct sctp_strreset_outreq
*outreq
;
787 outreq
= (struct sctp_strreset_outreq
*)req
;
788 str_p
= outreq
->list_of_streams
;
789 nums
= (ntohs(outreq
->param_hdr
.length
) - sizeof(*outreq
)) / 2;
791 if (result
== SCTP_STRRESET_PERFORMED
) {
793 for (i
= 0; i
< nums
; i
++)
794 stream
->out
[ntohs(str_p
[i
])].ssn
= 0;
796 for (i
= 0; i
< stream
->outcnt
; i
++)
797 stream
->out
[i
].ssn
= 0;
800 flags
= SCTP_STREAM_RESET_OUTGOING_SSN
;
803 for (i
= 0; i
< stream
->outcnt
; i
++)
804 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
806 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
, flags
,
807 nums
, str_p
, GFP_ATOMIC
);
808 } else if (req
->type
== SCTP_PARAM_RESET_IN_REQUEST
) {
809 struct sctp_strreset_inreq
*inreq
;
812 /* if the result is performed, it's impossible for inreq */
813 if (result
== SCTP_STRRESET_PERFORMED
)
816 inreq
= (struct sctp_strreset_inreq
*)req
;
817 str_p
= inreq
->list_of_streams
;
818 nums
= (ntohs(inreq
->param_hdr
.length
) - sizeof(*inreq
)) / 2;
820 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
, flags
,
821 nums
, str_p
, GFP_ATOMIC
);
822 } else if (req
->type
== SCTP_PARAM_RESET_TSN_REQUEST
) {
823 struct sctp_strreset_resptsn
*resptsn
;
826 /* check for resptsn, as sctp_verify_reconf didn't do it*/
827 if (ntohs(param
.p
->length
) != sizeof(*resptsn
))
830 resptsn
= (struct sctp_strreset_resptsn
*)resp
;
831 stsn
= ntohl(resptsn
->senders_next_tsn
);
832 rtsn
= ntohl(resptsn
->receivers_next_tsn
);
834 if (result
== SCTP_STRRESET_PERFORMED
) {
835 __u32 mtsn
= sctp_tsnmap_get_max_tsn_seen(
836 &asoc
->peer
.tsn_map
);
838 sctp_ulpq_reasm_flushtsn(&asoc
->ulpq
, mtsn
);
839 sctp_ulpq_abort_pd(&asoc
->ulpq
, GFP_ATOMIC
);
841 sctp_tsnmap_init(&asoc
->peer
.tsn_map
,
842 SCTP_TSN_MAP_INITIAL
,
845 sctp_outq_free(&asoc
->outqueue
);
847 asoc
->next_tsn
= rtsn
;
848 asoc
->ctsn_ack_point
= asoc
->next_tsn
- 1;
849 asoc
->adv_peer_ack_point
= asoc
->ctsn_ack_point
;
851 for (i
= 0; i
< stream
->outcnt
; i
++)
852 stream
->out
[i
].ssn
= 0;
853 for (i
= 0; i
< stream
->incnt
; i
++)
854 stream
->in
[i
].ssn
= 0;
857 for (i
= 0; i
< stream
->outcnt
; i
++)
858 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
860 *evp
= sctp_ulpevent_make_assoc_reset_event(asoc
, flags
,
861 stsn
, rtsn
, GFP_ATOMIC
);
862 } else if (req
->type
== SCTP_PARAM_RESET_ADD_OUT_STREAMS
) {
863 struct sctp_strreset_addstrm
*addstrm
;
866 addstrm
= (struct sctp_strreset_addstrm
*)req
;
867 nums
= ntohs(addstrm
->number_of_streams
);
868 number
= stream
->outcnt
- nums
;
870 if (result
== SCTP_STRRESET_PERFORMED
)
871 for (i
= number
; i
< stream
->outcnt
; i
++)
872 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
874 stream
->outcnt
= number
;
876 *evp
= sctp_ulpevent_make_stream_change_event(asoc
, flags
,
877 0, nums
, GFP_ATOMIC
);
878 } else if (req
->type
== SCTP_PARAM_RESET_ADD_IN_STREAMS
) {
879 struct sctp_strreset_addstrm
*addstrm
;
881 /* if the result is performed, it's impossible for addstrm in
884 if (result
== SCTP_STRRESET_PERFORMED
)
887 addstrm
= (struct sctp_strreset_addstrm
*)req
;
888 nums
= ntohs(addstrm
->number_of_streams
);
890 *evp
= sctp_ulpevent_make_stream_change_event(asoc
, flags
,
891 nums
, 0, GFP_ATOMIC
);
894 asoc
->strreset_outstanding
--;
895 asoc
->strreset_outseq
++;
897 /* remove everything for this reconf request */
898 if (!asoc
->strreset_outstanding
) {
899 t
= asoc
->strreset_chunk
->transport
;
900 if (del_timer(&t
->reconf_timer
))
901 sctp_transport_put(t
);
903 sctp_chunk_put(asoc
->strreset_chunk
);
904 asoc
->strreset_chunk
= NULL
;