1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* SCTP kernel implementation
3 * (C) Copyright IBM Corp. 2001, 2004
4 * Copyright (c) 1999-2000 Cisco, Inc.
5 * Copyright (c) 1999-2001 Motorola, Inc.
6 * Copyright (c) 2001 Intel Corp.
8 * This file is part of the SCTP kernel implementation
10 * This file contains sctp stream maniuplation primitives and helpers.
12 * Please send any bug reports or fixes you make to the
14 * lksctp developers <linux-sctp@vger.kernel.org>
16 * Written or modified by:
17 * Xin Long <lucien.xin@gmail.com>
20 #include <linux/list.h>
21 #include <net/sctp/sctp.h>
22 #include <net/sctp/sm.h>
23 #include <net/sctp/stream_sched.h>
25 /* Migrates chunks from stream queues to new stream queues if needed,
26 * but not across associations. Also, removes those chunks to streams
27 * higher than the new max.
29 static void sctp_stream_outq_migrate(struct sctp_stream
*stream
,
30 struct sctp_stream
*new, __u16 outcnt
)
32 struct sctp_association
*asoc
;
33 struct sctp_chunk
*ch
, *temp
;
34 struct sctp_outq
*outq
;
37 asoc
= container_of(stream
, struct sctp_association
, stream
);
38 outq
= &asoc
->outqueue
;
40 list_for_each_entry_safe(ch
, temp
, &outq
->out_chunk_list
, list
) {
41 __u16 sid
= sctp_chunk_stream_no(ch
);
46 sctp_sched_dequeue_common(outq
, ch
);
47 /* No need to call dequeue_done here because
48 * the chunks are not scheduled by now.
51 /* Mark as failed send. */
52 sctp_chunk_fail(ch
, (__force __u32
)SCTP_ERROR_INV_STRM
);
53 if (asoc
->peer
.prsctp_capable
&&
54 SCTP_PR_PRIO_ENABLED(ch
->sinfo
.sinfo_flags
))
55 asoc
->sent_cnt_removable
--;
61 /* Here we actually move the old ext stuff into the new
62 * buffer, because we want to keep it. Then
63 * sctp_stream_update will swap ->out pointers.
65 for (i
= 0; i
< outcnt
; i
++) {
66 kfree(SCTP_SO(new, i
)->ext
);
67 SCTP_SO(new, i
)->ext
= SCTP_SO(stream
, i
)->ext
;
68 SCTP_SO(stream
, i
)->ext
= NULL
;
72 for (i
= outcnt
; i
< stream
->outcnt
; i
++) {
73 kfree(SCTP_SO(stream
, i
)->ext
);
74 SCTP_SO(stream
, i
)->ext
= NULL
;
78 static int sctp_stream_alloc_out(struct sctp_stream
*stream
, __u16 outcnt
,
83 if (outcnt
<= stream
->outcnt
)
86 ret
= genradix_prealloc(&stream
->out
, outcnt
, gfp
);
90 stream
->outcnt
= outcnt
;
94 static int sctp_stream_alloc_in(struct sctp_stream
*stream
, __u16 incnt
,
99 if (incnt
<= stream
->incnt
)
102 ret
= genradix_prealloc(&stream
->in
, incnt
, gfp
);
106 stream
->incnt
= incnt
;
110 int sctp_stream_init(struct sctp_stream
*stream
, __u16 outcnt
, __u16 incnt
,
113 struct sctp_sched_ops
*sched
= sctp_sched_ops_from_stream(stream
);
118 /* Initial stream->out size may be very big, so free it and alloc
119 * a new one with new outcnt to save memory if needed.
121 if (outcnt
== stream
->outcnt
)
124 /* Filter out chunks queued on streams that won't exist anymore */
125 sched
->unsched_all(stream
);
126 sctp_stream_outq_migrate(stream
, NULL
, outcnt
);
127 sched
->sched_all(stream
);
129 ret
= sctp_stream_alloc_out(stream
, outcnt
, gfp
);
133 for (i
= 0; i
< stream
->outcnt
; i
++)
134 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_OPEN
;
137 sctp_stream_interleave_init(stream
);
141 ret
= sctp_stream_alloc_in(stream
, incnt
, gfp
);
144 genradix_free(&stream
->out
);
153 int sctp_stream_init_ext(struct sctp_stream
*stream
, __u16 sid
)
155 struct sctp_stream_out_ext
*soute
;
157 soute
= kzalloc(sizeof(*soute
), GFP_KERNEL
);
160 SCTP_SO(stream
, sid
)->ext
= soute
;
162 return sctp_sched_init_sid(stream
, sid
, GFP_KERNEL
);
165 void sctp_stream_free(struct sctp_stream
*stream
)
167 struct sctp_sched_ops
*sched
= sctp_sched_ops_from_stream(stream
);
171 for (i
= 0; i
< stream
->outcnt
; i
++)
172 kfree(SCTP_SO(stream
, i
)->ext
);
173 genradix_free(&stream
->out
);
174 genradix_free(&stream
->in
);
177 void sctp_stream_clear(struct sctp_stream
*stream
)
181 for (i
= 0; i
< stream
->outcnt
; i
++) {
182 SCTP_SO(stream
, i
)->mid
= 0;
183 SCTP_SO(stream
, i
)->mid_uo
= 0;
186 for (i
= 0; i
< stream
->incnt
; i
++)
187 SCTP_SI(stream
, i
)->mid
= 0;
190 void sctp_stream_update(struct sctp_stream
*stream
, struct sctp_stream
*new)
192 struct sctp_sched_ops
*sched
= sctp_sched_ops_from_stream(stream
);
194 sched
->unsched_all(stream
);
195 sctp_stream_outq_migrate(stream
, new, new->outcnt
);
196 sctp_stream_free(stream
);
198 stream
->out
= new->out
;
199 stream
->in
= new->in
;
200 stream
->outcnt
= new->outcnt
;
201 stream
->incnt
= new->incnt
;
203 sched
->sched_all(stream
);
205 new->out
.tree
.root
= NULL
;
206 new->in
.tree
.root
= NULL
;
211 static int sctp_send_reconf(struct sctp_association
*asoc
,
212 struct sctp_chunk
*chunk
)
214 struct net
*net
= sock_net(asoc
->base
.sk
);
217 retval
= sctp_primitive_RECONF(net
, asoc
, chunk
);
219 sctp_chunk_free(chunk
);
224 static bool sctp_stream_outq_is_empty(struct sctp_stream
*stream
,
225 __u16 str_nums
, __be16
*str_list
)
227 struct sctp_association
*asoc
;
230 asoc
= container_of(stream
, struct sctp_association
, stream
);
231 if (!asoc
->outqueue
.out_qlen
)
237 for (i
= 0; i
< str_nums
; i
++) {
238 __u16 sid
= ntohs(str_list
[i
]);
240 if (SCTP_SO(stream
, sid
)->ext
&&
241 !list_empty(&SCTP_SO(stream
, sid
)->ext
->outq
))
248 int sctp_send_reset_streams(struct sctp_association
*asoc
,
249 struct sctp_reset_streams
*params
)
251 struct sctp_stream
*stream
= &asoc
->stream
;
252 __u16 i
, str_nums
, *str_list
;
253 struct sctp_chunk
*chunk
;
254 int retval
= -EINVAL
;
258 if (!asoc
->peer
.reconf_capable
||
259 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
)) {
260 retval
= -ENOPROTOOPT
;
264 if (asoc
->strreset_outstanding
) {
265 retval
= -EINPROGRESS
;
269 out
= params
->srs_flags
& SCTP_STREAM_RESET_OUTGOING
;
270 in
= params
->srs_flags
& SCTP_STREAM_RESET_INCOMING
;
274 str_nums
= params
->srs_number_streams
;
275 str_list
= params
->srs_stream_list
;
280 for (i
= 0; i
< str_nums
; i
++)
281 if (str_list
[i
] >= stream
->outcnt
)
284 param_len
= str_nums
* sizeof(__u16
) +
285 sizeof(struct sctp_strreset_outreq
);
289 for (i
= 0; i
< str_nums
; i
++)
290 if (str_list
[i
] >= stream
->incnt
)
293 param_len
+= str_nums
* sizeof(__u16
) +
294 sizeof(struct sctp_strreset_inreq
);
297 if (param_len
> SCTP_MAX_CHUNK_LEN
-
298 sizeof(struct sctp_reconf_chunk
))
302 nstr_list
= kcalloc(str_nums
, sizeof(__be16
), GFP_KERNEL
);
308 for (i
= 0; i
< str_nums
; i
++)
309 nstr_list
[i
] = htons(str_list
[i
]);
311 if (out
&& !sctp_stream_outq_is_empty(stream
, str_nums
, nstr_list
)) {
316 chunk
= sctp_make_strreset_req(asoc
, str_nums
, nstr_list
, out
, in
);
327 for (i
= 0; i
< str_nums
; i
++)
328 SCTP_SO(stream
, str_list
[i
])->state
=
331 for (i
= 0; i
< stream
->outcnt
; i
++)
332 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_CLOSED
;
335 asoc
->strreset_chunk
= chunk
;
336 sctp_chunk_hold(asoc
->strreset_chunk
);
338 retval
= sctp_send_reconf(asoc
, chunk
);
340 sctp_chunk_put(asoc
->strreset_chunk
);
341 asoc
->strreset_chunk
= NULL
;
346 for (i
= 0; i
< str_nums
; i
++)
347 SCTP_SO(stream
, str_list
[i
])->state
=
350 for (i
= 0; i
< stream
->outcnt
; i
++)
351 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_OPEN
;
356 asoc
->strreset_outstanding
= out
+ in
;
362 int sctp_send_reset_assoc(struct sctp_association
*asoc
)
364 struct sctp_stream
*stream
= &asoc
->stream
;
365 struct sctp_chunk
*chunk
= NULL
;
369 if (!asoc
->peer
.reconf_capable
||
370 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
373 if (asoc
->strreset_outstanding
)
376 if (!sctp_outq_is_empty(&asoc
->outqueue
))
379 chunk
= sctp_make_strreset_tsnreq(asoc
);
383 /* Block further xmit of data until this request is completed */
384 for (i
= 0; i
< stream
->outcnt
; i
++)
385 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_CLOSED
;
387 asoc
->strreset_chunk
= chunk
;
388 sctp_chunk_hold(asoc
->strreset_chunk
);
390 retval
= sctp_send_reconf(asoc
, chunk
);
392 sctp_chunk_put(asoc
->strreset_chunk
);
393 asoc
->strreset_chunk
= NULL
;
395 for (i
= 0; i
< stream
->outcnt
; i
++)
396 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_OPEN
;
401 asoc
->strreset_outstanding
= 1;
406 int sctp_send_add_streams(struct sctp_association
*asoc
,
407 struct sctp_add_streams
*params
)
409 struct sctp_stream
*stream
= &asoc
->stream
;
410 struct sctp_chunk
*chunk
= NULL
;
415 if (!asoc
->peer
.reconf_capable
||
416 !(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
)) {
417 retval
= -ENOPROTOOPT
;
421 if (asoc
->strreset_outstanding
) {
422 retval
= -EINPROGRESS
;
426 out
= params
->sas_outstrms
;
427 in
= params
->sas_instrms
;
428 outcnt
= stream
->outcnt
+ out
;
429 incnt
= stream
->incnt
+ in
;
430 if (outcnt
> SCTP_MAX_STREAM
|| incnt
> SCTP_MAX_STREAM
||
437 retval
= sctp_stream_alloc_out(stream
, outcnt
, GFP_KERNEL
);
442 chunk
= sctp_make_strreset_addstrm(asoc
, out
, in
);
448 asoc
->strreset_chunk
= chunk
;
449 sctp_chunk_hold(asoc
->strreset_chunk
);
451 retval
= sctp_send_reconf(asoc
, chunk
);
453 sctp_chunk_put(asoc
->strreset_chunk
);
454 asoc
->strreset_chunk
= NULL
;
458 asoc
->strreset_outstanding
= !!out
+ !!in
;
464 static struct sctp_paramhdr
*sctp_chunk_lookup_strreset_param(
465 struct sctp_association
*asoc
, __be32 resp_seq
,
468 struct sctp_chunk
*chunk
= asoc
->strreset_chunk
;
469 struct sctp_reconf_chunk
*hdr
;
470 union sctp_params param
;
475 hdr
= (struct sctp_reconf_chunk
*)chunk
->chunk_hdr
;
476 sctp_walk_params(param
, hdr
, params
) {
477 /* sctp_strreset_tsnreq is actually the basic structure
478 * of all stream reconf params, so it's safe to use it
479 * to access request_seq.
481 struct sctp_strreset_tsnreq
*req
= param
.v
;
483 if ((!resp_seq
|| req
->request_seq
== resp_seq
) &&
484 (!type
|| type
== req
->param_hdr
.type
))
491 static void sctp_update_strreset_result(struct sctp_association
*asoc
,
494 asoc
->strreset_result
[1] = asoc
->strreset_result
[0];
495 asoc
->strreset_result
[0] = result
;
498 struct sctp_chunk
*sctp_process_strreset_outreq(
499 struct sctp_association
*asoc
,
500 union sctp_params param
,
501 struct sctp_ulpevent
**evp
)
503 struct sctp_strreset_outreq
*outreq
= param
.v
;
504 struct sctp_stream
*stream
= &asoc
->stream
;
505 __u32 result
= SCTP_STRRESET_DENIED
;
506 __be16
*str_p
= NULL
;
510 request_seq
= ntohl(outreq
->request_seq
);
512 if (ntohl(outreq
->send_reset_at_tsn
) >
513 sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
)) {
514 result
= SCTP_STRRESET_IN_PROGRESS
;
518 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
519 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
520 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
522 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
523 i
= asoc
->strreset_inseq
- request_seq
- 1;
524 result
= asoc
->strreset_result
[i
];
527 asoc
->strreset_inseq
++;
529 /* Check strreset_enable after inseq inc, as sender cannot tell
530 * the peer doesn't enable strreset after receiving response with
531 * result denied, as well as to keep consistent with bsd.
533 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
))
536 nums
= (ntohs(param
.p
->length
) - sizeof(*outreq
)) / sizeof(__u16
);
537 str_p
= outreq
->list_of_streams
;
538 for (i
= 0; i
< nums
; i
++) {
539 if (ntohs(str_p
[i
]) >= stream
->incnt
) {
540 result
= SCTP_STRRESET_ERR_WRONG_SSN
;
545 if (asoc
->strreset_chunk
) {
546 if (!sctp_chunk_lookup_strreset_param(
547 asoc
, outreq
->response_seq
,
548 SCTP_PARAM_RESET_IN_REQUEST
)) {
549 /* same process with outstanding isn't 0 */
550 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
554 asoc
->strreset_outstanding
--;
555 asoc
->strreset_outseq
++;
557 if (!asoc
->strreset_outstanding
) {
558 struct sctp_transport
*t
;
560 t
= asoc
->strreset_chunk
->transport
;
561 if (del_timer(&t
->reconf_timer
))
562 sctp_transport_put(t
);
564 sctp_chunk_put(asoc
->strreset_chunk
);
565 asoc
->strreset_chunk
= NULL
;
570 for (i
= 0; i
< nums
; i
++)
571 SCTP_SI(stream
, ntohs(str_p
[i
]))->mid
= 0;
573 for (i
= 0; i
< stream
->incnt
; i
++)
574 SCTP_SI(stream
, i
)->mid
= 0;
576 result
= SCTP_STRRESET_PERFORMED
;
578 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
,
579 SCTP_STREAM_RESET_INCOMING_SSN
, nums
, str_p
, GFP_ATOMIC
);
582 sctp_update_strreset_result(asoc
, result
);
584 return sctp_make_strreset_resp(asoc
, result
, request_seq
);
587 struct sctp_chunk
*sctp_process_strreset_inreq(
588 struct sctp_association
*asoc
,
589 union sctp_params param
,
590 struct sctp_ulpevent
**evp
)
592 struct sctp_strreset_inreq
*inreq
= param
.v
;
593 struct sctp_stream
*stream
= &asoc
->stream
;
594 __u32 result
= SCTP_STRRESET_DENIED
;
595 struct sctp_chunk
*chunk
= NULL
;
600 request_seq
= ntohl(inreq
->request_seq
);
601 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
602 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
603 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
605 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
606 i
= asoc
->strreset_inseq
- request_seq
- 1;
607 result
= asoc
->strreset_result
[i
];
608 if (result
== SCTP_STRRESET_PERFORMED
)
612 asoc
->strreset_inseq
++;
614 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
))
617 if (asoc
->strreset_outstanding
) {
618 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
622 nums
= (ntohs(param
.p
->length
) - sizeof(*inreq
)) / sizeof(__u16
);
623 str_p
= inreq
->list_of_streams
;
624 for (i
= 0; i
< nums
; i
++) {
625 if (ntohs(str_p
[i
]) >= stream
->outcnt
) {
626 result
= SCTP_STRRESET_ERR_WRONG_SSN
;
631 if (!sctp_stream_outq_is_empty(stream
, nums
, str_p
)) {
632 result
= SCTP_STRRESET_IN_PROGRESS
;
633 asoc
->strreset_inseq
--;
637 chunk
= sctp_make_strreset_req(asoc
, nums
, str_p
, 1, 0);
642 for (i
= 0; i
< nums
; i
++)
643 SCTP_SO(stream
, ntohs(str_p
[i
]))->state
=
646 for (i
= 0; i
< stream
->outcnt
; i
++)
647 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_CLOSED
;
649 asoc
->strreset_chunk
= chunk
;
650 asoc
->strreset_outstanding
= 1;
651 sctp_chunk_hold(asoc
->strreset_chunk
);
653 result
= SCTP_STRRESET_PERFORMED
;
656 sctp_update_strreset_result(asoc
, result
);
659 chunk
= sctp_make_strreset_resp(asoc
, result
, request_seq
);
664 struct sctp_chunk
*sctp_process_strreset_tsnreq(
665 struct sctp_association
*asoc
,
666 union sctp_params param
,
667 struct sctp_ulpevent
**evp
)
669 __u32 init_tsn
= 0, next_tsn
= 0, max_tsn_seen
;
670 struct sctp_strreset_tsnreq
*tsnreq
= param
.v
;
671 struct sctp_stream
*stream
= &asoc
->stream
;
672 __u32 result
= SCTP_STRRESET_DENIED
;
676 request_seq
= ntohl(tsnreq
->request_seq
);
677 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
678 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
679 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
681 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
682 i
= asoc
->strreset_inseq
- request_seq
- 1;
683 result
= asoc
->strreset_result
[i
];
684 if (result
== SCTP_STRRESET_PERFORMED
) {
685 next_tsn
= asoc
->ctsn_ack_point
+ 1;
687 sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
) + 1;
692 if (!sctp_outq_is_empty(&asoc
->outqueue
)) {
693 result
= SCTP_STRRESET_IN_PROGRESS
;
697 asoc
->strreset_inseq
++;
699 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
702 if (asoc
->strreset_outstanding
) {
703 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
707 /* G4: The same processing as though a FWD-TSN chunk (as defined in
708 * [RFC3758]) with all streams affected and a new cumulative TSN
709 * ACK of the Receiver's Next TSN minus 1 were received MUST be
712 max_tsn_seen
= sctp_tsnmap_get_max_tsn_seen(&asoc
->peer
.tsn_map
);
713 asoc
->stream
.si
->report_ftsn(&asoc
->ulpq
, max_tsn_seen
);
715 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
716 * TSN that the peer should use to send the next DATA chunk. The
717 * value SHOULD be the smallest TSN not acknowledged by the
718 * receiver of the request plus 2^31.
720 init_tsn
= sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
) + (1 << 31);
721 sctp_tsnmap_init(&asoc
->peer
.tsn_map
, SCTP_TSN_MAP_INITIAL
,
722 init_tsn
, GFP_ATOMIC
);
724 /* G3: The same processing as though a SACK chunk with no gap report
725 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
726 * received MUST be performed.
728 sctp_outq_free(&asoc
->outqueue
);
730 /* G2: Compute an appropriate value for the local endpoint's next TSN,
731 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
732 * chunk. The value SHOULD be the highest TSN sent by the receiver
733 * of the request plus 1.
735 next_tsn
= asoc
->next_tsn
;
736 asoc
->ctsn_ack_point
= next_tsn
- 1;
737 asoc
->adv_peer_ack_point
= asoc
->ctsn_ack_point
;
739 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
740 * incoming and outgoing streams.
742 for (i
= 0; i
< stream
->outcnt
; i
++) {
743 SCTP_SO(stream
, i
)->mid
= 0;
744 SCTP_SO(stream
, i
)->mid_uo
= 0;
746 for (i
= 0; i
< stream
->incnt
; i
++)
747 SCTP_SI(stream
, i
)->mid
= 0;
749 result
= SCTP_STRRESET_PERFORMED
;
751 *evp
= sctp_ulpevent_make_assoc_reset_event(asoc
, 0, init_tsn
,
752 next_tsn
, GFP_ATOMIC
);
755 sctp_update_strreset_result(asoc
, result
);
757 return sctp_make_strreset_tsnresp(asoc
, result
, request_seq
,
761 struct sctp_chunk
*sctp_process_strreset_addstrm_out(
762 struct sctp_association
*asoc
,
763 union sctp_params param
,
764 struct sctp_ulpevent
**evp
)
766 struct sctp_strreset_addstrm
*addstrm
= param
.v
;
767 struct sctp_stream
*stream
= &asoc
->stream
;
768 __u32 result
= SCTP_STRRESET_DENIED
;
769 __u32 request_seq
, incnt
;
772 request_seq
= ntohl(addstrm
->request_seq
);
773 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
774 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
775 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
777 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
778 i
= asoc
->strreset_inseq
- request_seq
- 1;
779 result
= asoc
->strreset_result
[i
];
782 asoc
->strreset_inseq
++;
784 if (!(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
))
787 in
= ntohs(addstrm
->number_of_streams
);
788 incnt
= stream
->incnt
+ in
;
789 if (!in
|| incnt
> SCTP_MAX_STREAM
)
792 if (sctp_stream_alloc_in(stream
, incnt
, GFP_ATOMIC
))
795 if (asoc
->strreset_chunk
) {
796 if (!sctp_chunk_lookup_strreset_param(
797 asoc
, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS
)) {
798 /* same process with outstanding isn't 0 */
799 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
803 asoc
->strreset_outstanding
--;
804 asoc
->strreset_outseq
++;
806 if (!asoc
->strreset_outstanding
) {
807 struct sctp_transport
*t
;
809 t
= asoc
->strreset_chunk
->transport
;
810 if (del_timer(&t
->reconf_timer
))
811 sctp_transport_put(t
);
813 sctp_chunk_put(asoc
->strreset_chunk
);
814 asoc
->strreset_chunk
= NULL
;
818 stream
->incnt
= incnt
;
820 result
= SCTP_STRRESET_PERFORMED
;
822 *evp
= sctp_ulpevent_make_stream_change_event(asoc
,
823 0, ntohs(addstrm
->number_of_streams
), 0, GFP_ATOMIC
);
826 sctp_update_strreset_result(asoc
, result
);
828 return sctp_make_strreset_resp(asoc
, result
, request_seq
);
831 struct sctp_chunk
*sctp_process_strreset_addstrm_in(
832 struct sctp_association
*asoc
,
833 union sctp_params param
,
834 struct sctp_ulpevent
**evp
)
836 struct sctp_strreset_addstrm
*addstrm
= param
.v
;
837 struct sctp_stream
*stream
= &asoc
->stream
;
838 __u32 result
= SCTP_STRRESET_DENIED
;
839 struct sctp_chunk
*chunk
= NULL
;
840 __u32 request_seq
, outcnt
;
844 request_seq
= ntohl(addstrm
->request_seq
);
845 if (TSN_lt(asoc
->strreset_inseq
, request_seq
) ||
846 TSN_lt(request_seq
, asoc
->strreset_inseq
- 2)) {
847 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
849 } else if (TSN_lt(request_seq
, asoc
->strreset_inseq
)) {
850 i
= asoc
->strreset_inseq
- request_seq
- 1;
851 result
= asoc
->strreset_result
[i
];
852 if (result
== SCTP_STRRESET_PERFORMED
)
856 asoc
->strreset_inseq
++;
858 if (!(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
))
861 if (asoc
->strreset_outstanding
) {
862 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
866 out
= ntohs(addstrm
->number_of_streams
);
867 outcnt
= stream
->outcnt
+ out
;
868 if (!out
|| outcnt
> SCTP_MAX_STREAM
)
871 ret
= sctp_stream_alloc_out(stream
, outcnt
, GFP_ATOMIC
);
875 chunk
= sctp_make_strreset_addstrm(asoc
, out
, 0);
879 asoc
->strreset_chunk
= chunk
;
880 asoc
->strreset_outstanding
= 1;
881 sctp_chunk_hold(asoc
->strreset_chunk
);
883 stream
->outcnt
= outcnt
;
885 result
= SCTP_STRRESET_PERFORMED
;
888 sctp_update_strreset_result(asoc
, result
);
891 chunk
= sctp_make_strreset_resp(asoc
, result
, request_seq
);
896 struct sctp_chunk
*sctp_process_strreset_resp(
897 struct sctp_association
*asoc
,
898 union sctp_params param
,
899 struct sctp_ulpevent
**evp
)
901 struct sctp_stream
*stream
= &asoc
->stream
;
902 struct sctp_strreset_resp
*resp
= param
.v
;
903 struct sctp_transport
*t
;
904 __u16 i
, nums
, flags
= 0;
905 struct sctp_paramhdr
*req
;
908 req
= sctp_chunk_lookup_strreset_param(asoc
, resp
->response_seq
, 0);
912 result
= ntohl(resp
->result
);
913 if (result
!= SCTP_STRRESET_PERFORMED
) {
914 /* if in progress, do nothing but retransmit */
915 if (result
== SCTP_STRRESET_IN_PROGRESS
)
917 else if (result
== SCTP_STRRESET_DENIED
)
918 flags
= SCTP_STREAM_RESET_DENIED
;
920 flags
= SCTP_STREAM_RESET_FAILED
;
923 if (req
->type
== SCTP_PARAM_RESET_OUT_REQUEST
) {
924 struct sctp_strreset_outreq
*outreq
;
927 outreq
= (struct sctp_strreset_outreq
*)req
;
928 str_p
= outreq
->list_of_streams
;
929 nums
= (ntohs(outreq
->param_hdr
.length
) - sizeof(*outreq
)) /
932 if (result
== SCTP_STRRESET_PERFORMED
) {
933 struct sctp_stream_out
*sout
;
935 for (i
= 0; i
< nums
; i
++) {
936 sout
= SCTP_SO(stream
, ntohs(str_p
[i
]));
941 for (i
= 0; i
< stream
->outcnt
; i
++) {
942 sout
= SCTP_SO(stream
, i
);
949 flags
|= SCTP_STREAM_RESET_OUTGOING_SSN
;
951 for (i
= 0; i
< stream
->outcnt
; i
++)
952 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_OPEN
;
954 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
, flags
,
955 nums
, str_p
, GFP_ATOMIC
);
956 } else if (req
->type
== SCTP_PARAM_RESET_IN_REQUEST
) {
957 struct sctp_strreset_inreq
*inreq
;
960 /* if the result is performed, it's impossible for inreq */
961 if (result
== SCTP_STRRESET_PERFORMED
)
964 inreq
= (struct sctp_strreset_inreq
*)req
;
965 str_p
= inreq
->list_of_streams
;
966 nums
= (ntohs(inreq
->param_hdr
.length
) - sizeof(*inreq
)) /
969 flags
|= SCTP_STREAM_RESET_INCOMING_SSN
;
971 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
, flags
,
972 nums
, str_p
, GFP_ATOMIC
);
973 } else if (req
->type
== SCTP_PARAM_RESET_TSN_REQUEST
) {
974 struct sctp_strreset_resptsn
*resptsn
;
977 /* check for resptsn, as sctp_verify_reconf didn't do it*/
978 if (ntohs(param
.p
->length
) != sizeof(*resptsn
))
981 resptsn
= (struct sctp_strreset_resptsn
*)resp
;
982 stsn
= ntohl(resptsn
->senders_next_tsn
);
983 rtsn
= ntohl(resptsn
->receivers_next_tsn
);
985 if (result
== SCTP_STRRESET_PERFORMED
) {
986 __u32 mtsn
= sctp_tsnmap_get_max_tsn_seen(
987 &asoc
->peer
.tsn_map
);
990 asoc
->stream
.si
->report_ftsn(&asoc
->ulpq
, mtsn
);
992 sctp_tsnmap_init(&asoc
->peer
.tsn_map
,
993 SCTP_TSN_MAP_INITIAL
,
996 /* Clean up sacked and abandoned queues only. As the
997 * out_chunk_list may not be empty, splice it to temp,
998 * then get it back after sctp_outq_free is done.
1000 list_splice_init(&asoc
->outqueue
.out_chunk_list
, &temp
);
1001 sctp_outq_free(&asoc
->outqueue
);
1002 list_splice_init(&temp
, &asoc
->outqueue
.out_chunk_list
);
1004 asoc
->next_tsn
= rtsn
;
1005 asoc
->ctsn_ack_point
= asoc
->next_tsn
- 1;
1006 asoc
->adv_peer_ack_point
= asoc
->ctsn_ack_point
;
1008 for (i
= 0; i
< stream
->outcnt
; i
++) {
1009 SCTP_SO(stream
, i
)->mid
= 0;
1010 SCTP_SO(stream
, i
)->mid_uo
= 0;
1012 for (i
= 0; i
< stream
->incnt
; i
++)
1013 SCTP_SI(stream
, i
)->mid
= 0;
1016 for (i
= 0; i
< stream
->outcnt
; i
++)
1017 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_OPEN
;
1019 *evp
= sctp_ulpevent_make_assoc_reset_event(asoc
, flags
,
1020 stsn
, rtsn
, GFP_ATOMIC
);
1021 } else if (req
->type
== SCTP_PARAM_RESET_ADD_OUT_STREAMS
) {
1022 struct sctp_strreset_addstrm
*addstrm
;
1025 addstrm
= (struct sctp_strreset_addstrm
*)req
;
1026 nums
= ntohs(addstrm
->number_of_streams
);
1027 number
= stream
->outcnt
- nums
;
1029 if (result
== SCTP_STRRESET_PERFORMED
)
1030 for (i
= number
; i
< stream
->outcnt
; i
++)
1031 SCTP_SO(stream
, i
)->state
= SCTP_STREAM_OPEN
;
1033 stream
->outcnt
= number
;
1035 *evp
= sctp_ulpevent_make_stream_change_event(asoc
, flags
,
1036 0, nums
, GFP_ATOMIC
);
1037 } else if (req
->type
== SCTP_PARAM_RESET_ADD_IN_STREAMS
) {
1038 struct sctp_strreset_addstrm
*addstrm
;
1040 /* if the result is performed, it's impossible for addstrm in
1043 if (result
== SCTP_STRRESET_PERFORMED
)
1046 addstrm
= (struct sctp_strreset_addstrm
*)req
;
1047 nums
= ntohs(addstrm
->number_of_streams
);
1049 *evp
= sctp_ulpevent_make_stream_change_event(asoc
, flags
,
1050 nums
, 0, GFP_ATOMIC
);
1053 asoc
->strreset_outstanding
--;
1054 asoc
->strreset_outseq
++;
1056 /* remove everything for this reconf request */
1057 if (!asoc
->strreset_outstanding
) {
1058 t
= asoc
->strreset_chunk
->transport
;
1059 if (del_timer(&t
->reconf_timer
))
1060 sctp_transport_put(t
);
1062 sctp_chunk_put(asoc
->strreset_chunk
);
1063 asoc
->strreset_chunk
= NULL
;