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 struct sctp_stream
*sctp_stream_new(__u16 incnt
, __u16 outcnt
, gfp_t gfp
)
40 struct sctp_stream
*stream
;
43 stream
= kzalloc(sizeof(*stream
), gfp
);
47 stream
->outcnt
= outcnt
;
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 stream
->incnt
= incnt
;
57 stream
->in
= kcalloc(stream
->incnt
, sizeof(*stream
->in
), gfp
);
67 void sctp_stream_free(struct sctp_stream
*stream
)
69 if (unlikely(!stream
))
77 void sctp_stream_clear(struct sctp_stream
*stream
)
81 for (i
= 0; i
< stream
->outcnt
; i
++)
82 stream
->out
[i
].ssn
= 0;
84 for (i
= 0; i
< stream
->incnt
; i
++)
85 stream
->in
[i
].ssn
= 0;
88 static int sctp_send_reconf(struct sctp_association
*asoc
,
89 struct sctp_chunk
*chunk
)
91 struct net
*net
= sock_net(asoc
->base
.sk
);
94 retval
= sctp_primitive_RECONF(net
, asoc
, chunk
);
96 sctp_chunk_free(chunk
);
101 int sctp_send_reset_streams(struct sctp_association
*asoc
,
102 struct sctp_reset_streams
*params
)
104 struct sctp_stream
*stream
= asoc
->stream
;
105 __u16 i
, str_nums
, *str_list
;
106 struct sctp_chunk
*chunk
;
107 int retval
= -EINVAL
;
110 if (!asoc
->peer
.reconf_capable
||
111 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
)) {
112 retval
= -ENOPROTOOPT
;
116 if (asoc
->strreset_outstanding
) {
117 retval
= -EINPROGRESS
;
121 out
= params
->srs_flags
& SCTP_STREAM_RESET_OUTGOING
;
122 in
= params
->srs_flags
& SCTP_STREAM_RESET_INCOMING
;
126 str_nums
= params
->srs_number_streams
;
127 str_list
= params
->srs_stream_list
;
129 for (i
= 0; i
< str_nums
; i
++)
130 if (str_list
[i
] >= stream
->outcnt
)
134 for (i
= 0; i
< str_nums
; i
++)
135 if (str_list
[i
] >= stream
->incnt
)
138 for (i
= 0; i
< str_nums
; i
++)
139 str_list
[i
] = htons(str_list
[i
]);
141 chunk
= sctp_make_strreset_req(asoc
, str_nums
, str_list
, out
, in
);
143 for (i
= 0; i
< str_nums
; i
++)
144 str_list
[i
] = ntohs(str_list
[i
]);
153 for (i
= 0; i
< str_nums
; i
++)
154 stream
->out
[str_list
[i
]].state
=
157 for (i
= 0; i
< stream
->outcnt
; i
++)
158 stream
->out
[i
].state
= SCTP_STREAM_CLOSED
;
161 asoc
->strreset_chunk
= chunk
;
162 sctp_chunk_hold(asoc
->strreset_chunk
);
164 retval
= sctp_send_reconf(asoc
, chunk
);
166 sctp_chunk_put(asoc
->strreset_chunk
);
167 asoc
->strreset_chunk
= NULL
;
172 for (i
= 0; i
< str_nums
; i
++)
173 stream
->out
[str_list
[i
]].state
=
176 for (i
= 0; i
< stream
->outcnt
; i
++)
177 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
182 asoc
->strreset_outstanding
= out
+ in
;
188 int sctp_send_reset_assoc(struct sctp_association
*asoc
)
190 struct sctp_chunk
*chunk
= NULL
;
194 if (!asoc
->peer
.reconf_capable
||
195 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
198 if (asoc
->strreset_outstanding
)
201 chunk
= sctp_make_strreset_tsnreq(asoc
);
205 /* Block further xmit of data until this request is completed */
206 for (i
= 0; i
< asoc
->stream
->outcnt
; i
++)
207 asoc
->stream
->out
[i
].state
= SCTP_STREAM_CLOSED
;
209 asoc
->strreset_chunk
= chunk
;
210 sctp_chunk_hold(asoc
->strreset_chunk
);
212 retval
= sctp_send_reconf(asoc
, chunk
);
214 sctp_chunk_put(asoc
->strreset_chunk
);
215 asoc
->strreset_chunk
= NULL
;
217 for (i
= 0; i
< asoc
->stream
->outcnt
; i
++)
218 asoc
->stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
223 asoc
->strreset_outstanding
= 1;
228 int sctp_send_add_streams(struct sctp_association
*asoc
,
229 struct sctp_add_streams
*params
)
231 struct sctp_stream
*stream
= asoc
->stream
;
232 struct sctp_chunk
*chunk
= NULL
;
233 int retval
= -ENOMEM
;
237 if (!asoc
->peer
.reconf_capable
||
238 !(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
)) {
239 retval
= -ENOPROTOOPT
;
243 if (asoc
->strreset_outstanding
) {
244 retval
= -EINPROGRESS
;
248 out
= params
->sas_outstrms
;
249 in
= params
->sas_instrms
;
250 outcnt
= stream
->outcnt
+ out
;
251 incnt
= stream
->incnt
+ in
;
252 if (outcnt
> SCTP_MAX_STREAM
|| incnt
> SCTP_MAX_STREAM
||
259 struct sctp_stream_out
*streamout
;
261 streamout
= krealloc(stream
->out
, outcnt
* sizeof(*streamout
),
266 memset(streamout
+ stream
->outcnt
, 0, out
* sizeof(*streamout
));
267 stream
->out
= streamout
;
270 chunk
= sctp_make_strreset_addstrm(asoc
, out
, in
);
274 asoc
->strreset_chunk
= chunk
;
275 sctp_chunk_hold(asoc
->strreset_chunk
);
277 retval
= sctp_send_reconf(asoc
, chunk
);
279 sctp_chunk_put(asoc
->strreset_chunk
);
280 asoc
->strreset_chunk
= NULL
;
284 stream
->incnt
= incnt
;
285 stream
->outcnt
= outcnt
;
287 asoc
->strreset_outstanding
= !!out
+ !!in
;
293 static sctp_paramhdr_t
*sctp_chunk_lookup_strreset_param(
294 struct sctp_association
*asoc
, __u32 resp_seq
,
297 struct sctp_chunk
*chunk
= asoc
->strreset_chunk
;
298 struct sctp_reconf_chunk
*hdr
;
299 union sctp_params param
;
304 hdr
= (struct sctp_reconf_chunk
*)chunk
->chunk_hdr
;
305 sctp_walk_params(param
, hdr
, params
) {
306 /* sctp_strreset_tsnreq is actually the basic structure
307 * of all stream reconf params, so it's safe to use it
308 * to access request_seq.
310 struct sctp_strreset_tsnreq
*req
= param
.v
;
312 if ((!resp_seq
|| req
->request_seq
== resp_seq
) &&
313 (!type
|| type
== req
->param_hdr
.type
))
320 struct sctp_chunk
*sctp_process_strreset_outreq(
321 struct sctp_association
*asoc
,
322 union sctp_params param
,
323 struct sctp_ulpevent
**evp
)
325 struct sctp_strreset_outreq
*outreq
= param
.v
;
326 struct sctp_stream
*stream
= asoc
->stream
;
327 __u16 i
, nums
, flags
= 0, *str_p
= NULL
;
328 __u32 result
= SCTP_STRRESET_DENIED
;
331 request_seq
= ntohl(outreq
->request_seq
);
333 if (ntohl(outreq
->send_reset_at_tsn
) >
334 sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
)) {
335 result
= SCTP_STRRESET_IN_PROGRESS
;
339 if (request_seq
> asoc
->strreset_inseq
) {
340 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
342 } else if (request_seq
== asoc
->strreset_inseq
) {
343 asoc
->strreset_inseq
++;
346 /* Check strreset_enable after inseq inc, as sender cannot tell
347 * the peer doesn't enable strreset after receiving response with
348 * result denied, as well as to keep consistent with bsd.
350 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
))
353 if (asoc
->strreset_chunk
) {
354 if (!sctp_chunk_lookup_strreset_param(
355 asoc
, outreq
->response_seq
,
356 SCTP_PARAM_RESET_IN_REQUEST
)) {
357 /* same process with outstanding isn't 0 */
358 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
362 asoc
->strreset_outstanding
--;
363 asoc
->strreset_outseq
++;
365 if (!asoc
->strreset_outstanding
) {
366 struct sctp_transport
*t
;
368 t
= asoc
->strreset_chunk
->transport
;
369 if (del_timer(&t
->reconf_timer
))
370 sctp_transport_put(t
);
372 sctp_chunk_put(asoc
->strreset_chunk
);
373 asoc
->strreset_chunk
= NULL
;
376 flags
= SCTP_STREAM_RESET_INCOMING_SSN
;
379 nums
= (ntohs(param
.p
->length
) - sizeof(*outreq
)) / 2;
381 str_p
= outreq
->list_of_streams
;
382 for (i
= 0; i
< nums
; i
++) {
383 if (ntohs(str_p
[i
]) >= stream
->incnt
) {
384 result
= SCTP_STRRESET_ERR_WRONG_SSN
;
389 for (i
= 0; i
< nums
; i
++)
390 stream
->in
[ntohs(str_p
[i
])].ssn
= 0;
392 for (i
= 0; i
< stream
->incnt
; i
++)
393 stream
->in
[i
].ssn
= 0;
396 result
= SCTP_STRRESET_PERFORMED
;
398 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
,
399 flags
| SCTP_STREAM_RESET_OUTGOING_SSN
, nums
, str_p
,
403 return sctp_make_strreset_resp(asoc
, result
, request_seq
);
406 struct sctp_chunk
*sctp_process_strreset_inreq(
407 struct sctp_association
*asoc
,
408 union sctp_params param
,
409 struct sctp_ulpevent
**evp
)
411 struct sctp_strreset_inreq
*inreq
= param
.v
;
412 struct sctp_stream
*stream
= asoc
->stream
;
413 __u32 result
= SCTP_STRRESET_DENIED
;
414 struct sctp_chunk
*chunk
= NULL
;
415 __u16 i
, nums
, *str_p
;
418 request_seq
= ntohl(inreq
->request_seq
);
419 if (request_seq
> asoc
->strreset_inseq
) {
420 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
422 } else if (request_seq
== asoc
->strreset_inseq
) {
423 asoc
->strreset_inseq
++;
426 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_STREAM_REQ
))
429 if (asoc
->strreset_outstanding
) {
430 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
434 nums
= (ntohs(param
.p
->length
) - sizeof(*inreq
)) / 2;
435 str_p
= inreq
->list_of_streams
;
436 for (i
= 0; i
< nums
; i
++) {
437 if (ntohs(str_p
[i
]) >= stream
->outcnt
) {
438 result
= SCTP_STRRESET_ERR_WRONG_SSN
;
443 chunk
= sctp_make_strreset_req(asoc
, nums
, str_p
, 1, 0);
448 for (i
= 0; i
< nums
; i
++)
449 stream
->out
[ntohs(str_p
[i
])].state
=
452 for (i
= 0; i
< stream
->outcnt
; i
++)
453 stream
->out
[i
].state
= SCTP_STREAM_CLOSED
;
455 asoc
->strreset_chunk
= chunk
;
456 asoc
->strreset_outstanding
= 1;
457 sctp_chunk_hold(asoc
->strreset_chunk
);
459 *evp
= sctp_ulpevent_make_stream_reset_event(asoc
,
460 SCTP_STREAM_RESET_INCOMING_SSN
, nums
, str_p
, GFP_ATOMIC
);
464 chunk
= sctp_make_strreset_resp(asoc
, result
, request_seq
);
469 struct sctp_chunk
*sctp_process_strreset_tsnreq(
470 struct sctp_association
*asoc
,
471 union sctp_params param
,
472 struct sctp_ulpevent
**evp
)
474 __u32 init_tsn
= 0, next_tsn
= 0, max_tsn_seen
;
475 struct sctp_strreset_tsnreq
*tsnreq
= param
.v
;
476 struct sctp_stream
*stream
= asoc
->stream
;
477 __u32 result
= SCTP_STRRESET_DENIED
;
481 request_seq
= ntohl(tsnreq
->request_seq
);
482 if (request_seq
> asoc
->strreset_inseq
) {
483 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
485 } else if (request_seq
== asoc
->strreset_inseq
) {
486 asoc
->strreset_inseq
++;
489 if (!(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
492 if (asoc
->strreset_outstanding
) {
493 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
497 /* G3: The same processing as though a SACK chunk with no gap report
498 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
499 * received MUST be performed.
501 max_tsn_seen
= sctp_tsnmap_get_max_tsn_seen(&asoc
->peer
.tsn_map
);
502 sctp_ulpq_reasm_flushtsn(&asoc
->ulpq
, max_tsn_seen
);
503 sctp_ulpq_abort_pd(&asoc
->ulpq
, GFP_ATOMIC
);
505 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
506 * TSN that the peer should use to send the next DATA chunk. The
507 * value SHOULD be the smallest TSN not acknowledged by the
508 * receiver of the request plus 2^31.
510 init_tsn
= sctp_tsnmap_get_ctsn(&asoc
->peer
.tsn_map
) + (1 << 31);
511 sctp_tsnmap_init(&asoc
->peer
.tsn_map
, SCTP_TSN_MAP_INITIAL
,
512 init_tsn
, GFP_ATOMIC
);
514 /* G4: The same processing as though a FWD-TSN chunk (as defined in
515 * [RFC3758]) with all streams affected and a new cumulative TSN
516 * ACK of the Receiver's Next TSN minus 1 were received MUST be
519 sctp_outq_free(&asoc
->outqueue
);
521 /* G2: Compute an appropriate value for the local endpoint's next TSN,
522 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
523 * chunk. The value SHOULD be the highest TSN sent by the receiver
524 * of the request plus 1.
526 next_tsn
= asoc
->next_tsn
;
527 asoc
->ctsn_ack_point
= next_tsn
- 1;
528 asoc
->adv_peer_ack_point
= asoc
->ctsn_ack_point
;
530 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
531 * incoming and outgoing streams.
533 for (i
= 0; i
< stream
->outcnt
; i
++)
534 stream
->out
[i
].ssn
= 0;
535 for (i
= 0; i
< stream
->incnt
; i
++)
536 stream
->in
[i
].ssn
= 0;
538 result
= SCTP_STRRESET_PERFORMED
;
540 *evp
= sctp_ulpevent_make_assoc_reset_event(asoc
, 0, init_tsn
,
541 next_tsn
, GFP_ATOMIC
);
544 return sctp_make_strreset_tsnresp(asoc
, result
, request_seq
,
548 struct sctp_chunk
*sctp_process_strreset_addstrm_out(
549 struct sctp_association
*asoc
,
550 union sctp_params param
,
551 struct sctp_ulpevent
**evp
)
553 struct sctp_strreset_addstrm
*addstrm
= param
.v
;
554 struct sctp_stream
*stream
= asoc
->stream
;
555 __u32 result
= SCTP_STRRESET_DENIED
;
556 struct sctp_stream_in
*streamin
;
557 __u32 request_seq
, incnt
;
560 request_seq
= ntohl(addstrm
->request_seq
);
561 if (request_seq
> asoc
->strreset_inseq
) {
562 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
564 } else if (request_seq
== asoc
->strreset_inseq
) {
565 asoc
->strreset_inseq
++;
568 if (!(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
))
571 if (asoc
->strreset_chunk
) {
572 if (!sctp_chunk_lookup_strreset_param(
573 asoc
, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS
)) {
574 /* same process with outstanding isn't 0 */
575 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
579 asoc
->strreset_outstanding
--;
580 asoc
->strreset_outseq
++;
582 if (!asoc
->strreset_outstanding
) {
583 struct sctp_transport
*t
;
585 t
= asoc
->strreset_chunk
->transport
;
586 if (del_timer(&t
->reconf_timer
))
587 sctp_transport_put(t
);
589 sctp_chunk_put(asoc
->strreset_chunk
);
590 asoc
->strreset_chunk
= NULL
;
594 in
= ntohs(addstrm
->number_of_streams
);
595 incnt
= stream
->incnt
+ in
;
596 if (!in
|| incnt
> SCTP_MAX_STREAM
)
599 streamin
= krealloc(stream
->in
, incnt
* sizeof(*streamin
),
604 memset(streamin
+ stream
->incnt
, 0, in
* sizeof(*streamin
));
605 stream
->in
= streamin
;
606 stream
->incnt
= incnt
;
608 result
= SCTP_STRRESET_PERFORMED
;
610 *evp
= sctp_ulpevent_make_stream_change_event(asoc
,
611 0, ntohs(addstrm
->number_of_streams
), 0, GFP_ATOMIC
);
614 return sctp_make_strreset_resp(asoc
, result
, request_seq
);
617 struct sctp_chunk
*sctp_process_strreset_addstrm_in(
618 struct sctp_association
*asoc
,
619 union sctp_params param
,
620 struct sctp_ulpevent
**evp
)
622 struct sctp_strreset_addstrm
*addstrm
= param
.v
;
623 struct sctp_stream
*stream
= asoc
->stream
;
624 __u32 result
= SCTP_STRRESET_DENIED
;
625 struct sctp_stream_out
*streamout
;
626 struct sctp_chunk
*chunk
= NULL
;
627 __u32 request_seq
, outcnt
;
630 request_seq
= ntohl(addstrm
->request_seq
);
631 if (request_seq
> asoc
->strreset_inseq
) {
632 result
= SCTP_STRRESET_ERR_BAD_SEQNO
;
634 } else if (request_seq
== asoc
->strreset_inseq
) {
635 asoc
->strreset_inseq
++;
638 if (!(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
))
641 if (asoc
->strreset_outstanding
) {
642 result
= SCTP_STRRESET_ERR_IN_PROGRESS
;
646 out
= ntohs(addstrm
->number_of_streams
);
647 outcnt
= stream
->outcnt
+ out
;
648 if (!out
|| outcnt
> SCTP_MAX_STREAM
)
651 streamout
= krealloc(stream
->out
, outcnt
* sizeof(*streamout
),
656 memset(streamout
+ stream
->outcnt
, 0, out
* sizeof(*streamout
));
657 stream
->out
= streamout
;
659 chunk
= sctp_make_strreset_addstrm(asoc
, out
, 0);
663 asoc
->strreset_chunk
= chunk
;
664 asoc
->strreset_outstanding
= 1;
665 sctp_chunk_hold(asoc
->strreset_chunk
);
667 stream
->outcnt
= outcnt
;
669 *evp
= sctp_ulpevent_make_stream_change_event(asoc
,
670 0, 0, ntohs(addstrm
->number_of_streams
), GFP_ATOMIC
);
674 chunk
= sctp_make_strreset_resp(asoc
, result
, request_seq
);