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 chunk
= sctp_make_strreset_req(asoc
, str_nums
, str_list
, out
, in
);
146 for (i
= 0; i
< str_nums
; i
++)
147 stream
->out
[str_list
[i
]].state
=
150 for (i
= 0; i
< stream
->outcnt
; i
++)
151 stream
->out
[i
].state
= SCTP_STREAM_CLOSED
;
154 asoc
->strreset_chunk
= chunk
;
155 sctp_chunk_hold(asoc
->strreset_chunk
);
157 retval
= sctp_send_reconf(asoc
, chunk
);
159 sctp_chunk_put(asoc
->strreset_chunk
);
160 asoc
->strreset_chunk
= NULL
;
165 for (i
= 0; i
< str_nums
; i
++)
166 stream
->out
[str_list
[i
]].state
=
169 for (i
= 0; i
< stream
->outcnt
; i
++)
170 stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
175 asoc
->strreset_outstanding
= out
+ in
;
181 int sctp_send_reset_assoc(struct sctp_association
*asoc
)
183 struct sctp_chunk
*chunk
= NULL
;
187 if (!asoc
->peer
.reconf_capable
||
188 !(asoc
->strreset_enable
& SCTP_ENABLE_RESET_ASSOC_REQ
))
191 if (asoc
->strreset_outstanding
)
194 chunk
= sctp_make_strreset_tsnreq(asoc
);
198 /* Block further xmit of data until this request is completed */
199 for (i
= 0; i
< asoc
->stream
->outcnt
; i
++)
200 asoc
->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
;
210 for (i
= 0; i
< asoc
->stream
->outcnt
; i
++)
211 asoc
->stream
->out
[i
].state
= SCTP_STREAM_OPEN
;
216 asoc
->strreset_outstanding
= 1;
221 int sctp_send_add_streams(struct sctp_association
*asoc
,
222 struct sctp_add_streams
*params
)
224 struct sctp_stream
*stream
= asoc
->stream
;
225 struct sctp_chunk
*chunk
= NULL
;
226 int retval
= -ENOMEM
;
230 if (!asoc
->peer
.reconf_capable
||
231 !(asoc
->strreset_enable
& SCTP_ENABLE_CHANGE_ASSOC_REQ
)) {
232 retval
= -ENOPROTOOPT
;
236 if (asoc
->strreset_outstanding
) {
237 retval
= -EINPROGRESS
;
241 out
= params
->sas_outstrms
;
242 in
= params
->sas_instrms
;
243 outcnt
= stream
->outcnt
+ out
;
244 incnt
= stream
->incnt
+ in
;
245 if (outcnt
> SCTP_MAX_STREAM
|| incnt
> SCTP_MAX_STREAM
||
252 struct sctp_stream_out
*streamout
;
254 streamout
= krealloc(stream
->out
, outcnt
* sizeof(*streamout
),
259 memset(streamout
+ stream
->outcnt
, 0, out
* sizeof(*streamout
));
260 stream
->out
= streamout
;
264 struct sctp_stream_in
*streamin
;
266 streamin
= krealloc(stream
->in
, incnt
* sizeof(*streamin
),
271 memset(streamin
+ stream
->incnt
, 0, in
* sizeof(*streamin
));
272 stream
->in
= streamin
;
275 chunk
= sctp_make_strreset_addstrm(asoc
, out
, in
);
279 asoc
->strreset_chunk
= chunk
;
280 sctp_chunk_hold(asoc
->strreset_chunk
);
282 retval
= sctp_send_reconf(asoc
, chunk
);
284 sctp_chunk_put(asoc
->strreset_chunk
);
285 asoc
->strreset_chunk
= NULL
;
289 stream
->incnt
= incnt
;
290 stream
->outcnt
= outcnt
;
292 asoc
->strreset_outstanding
= !!out
+ !!in
;