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. 6 * 7 * This file is part of the SCTP kernel implementation 8 * 9 * These functions manipulate sctp tsn mapping array. 10 * 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) 15 * any later version. 16 * 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. 22 * 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/>. 26 * 27 * Please send any bug reports or fixes you make to the 28 * email address(es): 29 * lksctp developers <linux-sctp@vger.kernel.org> 30 * 31 * Written or modified by: 32 * Xin Long <lucien.xin@gmail.com> 33 */ 34 35 #include <net/sctp/sctp.h> 36 #include <net/sctp/sm.h> 37 38 struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp) 39 { 40 struct sctp_stream *stream; 41 int i; 42 43 stream = kzalloc(sizeof(*stream), gfp); 44 if (!stream) 45 return NULL; 46 47 stream->outcnt = outcnt; 48 stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); 49 if (!stream->out) { 50 kfree(stream); 51 return NULL; 52 } 53 for (i = 0; i < stream->outcnt; i++) 54 stream->out[i].state = SCTP_STREAM_OPEN; 55 56 stream->incnt = incnt; 57 stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); 58 if (!stream->in) { 59 kfree(stream->out); 60 kfree(stream); 61 return NULL; 62 } 63 64 return stream; 65 } 66 67 void sctp_stream_free(struct sctp_stream *stream) 68 { 69 if (unlikely(!stream)) 70 return; 71 72 kfree(stream->out); 73 kfree(stream->in); 74 kfree(stream); 75 } 76 77 void sctp_stream_clear(struct sctp_stream *stream) 78 { 79 int i; 80 81 for (i = 0; i < stream->outcnt; i++) 82 stream->out[i].ssn = 0; 83 84 for (i = 0; i < stream->incnt; i++) 85 stream->in[i].ssn = 0; 86 } 87 88 static int sctp_send_reconf(struct sctp_association *asoc, 89 struct sctp_chunk *chunk) 90 { 91 struct net *net = sock_net(asoc->base.sk); 92 int retval = 0; 93 94 retval = sctp_primitive_RECONF(net, asoc, chunk); 95 if (retval) 96 sctp_chunk_free(chunk); 97 98 return retval; 99 } 100 101 int sctp_send_reset_streams(struct sctp_association *asoc, 102 struct sctp_reset_streams *params) 103 { 104 struct sctp_stream *stream = asoc->stream; 105 __u16 i, str_nums, *str_list; 106 struct sctp_chunk *chunk; 107 int retval = -EINVAL; 108 bool out, in; 109 110 if (!asoc->peer.reconf_capable || 111 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) { 112 retval = -ENOPROTOOPT; 113 goto out; 114 } 115 116 if (asoc->strreset_outstanding) { 117 retval = -EINPROGRESS; 118 goto out; 119 } 120 121 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING; 122 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING; 123 if (!out && !in) 124 goto out; 125 126 str_nums = params->srs_number_streams; 127 str_list = params->srs_stream_list; 128 if (out && str_nums) 129 for (i = 0; i < str_nums; i++) 130 if (str_list[i] >= stream->outcnt) 131 goto out; 132 133 if (in && str_nums) 134 for (i = 0; i < str_nums; i++) 135 if (str_list[i] >= stream->incnt) 136 goto out; 137 138 for (i = 0; i < str_nums; i++) 139 str_list[i] = htons(str_list[i]); 140 141 chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in); 142 143 for (i = 0; i < str_nums; i++) 144 str_list[i] = ntohs(str_list[i]); 145 146 if (!chunk) { 147 retval = -ENOMEM; 148 goto out; 149 } 150 151 if (out) { 152 if (str_nums) 153 for (i = 0; i < str_nums; i++) 154 stream->out[str_list[i]].state = 155 SCTP_STREAM_CLOSED; 156 else 157 for (i = 0; i < stream->outcnt; i++) 158 stream->out[i].state = SCTP_STREAM_CLOSED; 159 } 160 161 asoc->strreset_chunk = chunk; 162 sctp_chunk_hold(asoc->strreset_chunk); 163 164 retval = sctp_send_reconf(asoc, chunk); 165 if (retval) { 166 sctp_chunk_put(asoc->strreset_chunk); 167 asoc->strreset_chunk = NULL; 168 if (!out) 169 goto out; 170 171 if (str_nums) 172 for (i = 0; i < str_nums; i++) 173 stream->out[str_list[i]].state = 174 SCTP_STREAM_OPEN; 175 else 176 for (i = 0; i < stream->outcnt; i++) 177 stream->out[i].state = SCTP_STREAM_OPEN; 178 179 goto out; 180 } 181 182 asoc->strreset_outstanding = out + in; 183 184 out: 185 return retval; 186 } 187 188 int sctp_send_reset_assoc(struct sctp_association *asoc) 189 { 190 struct sctp_chunk *chunk = NULL; 191 int retval; 192 __u16 i; 193 194 if (!asoc->peer.reconf_capable || 195 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) 196 return -ENOPROTOOPT; 197 198 if (asoc->strreset_outstanding) 199 return -EINPROGRESS; 200 201 chunk = sctp_make_strreset_tsnreq(asoc); 202 if (!chunk) 203 return -ENOMEM; 204 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; 208 209 asoc->strreset_chunk = chunk; 210 sctp_chunk_hold(asoc->strreset_chunk); 211 212 retval = sctp_send_reconf(asoc, chunk); 213 if (retval) { 214 sctp_chunk_put(asoc->strreset_chunk); 215 asoc->strreset_chunk = NULL; 216 217 for (i = 0; i < asoc->stream->outcnt; i++) 218 asoc->stream->out[i].state = SCTP_STREAM_OPEN; 219 220 return retval; 221 } 222 223 asoc->strreset_outstanding = 1; 224 225 return 0; 226 } 227 228 int sctp_send_add_streams(struct sctp_association *asoc, 229 struct sctp_add_streams *params) 230 { 231 struct sctp_stream *stream = asoc->stream; 232 struct sctp_chunk *chunk = NULL; 233 int retval = -ENOMEM; 234 __u32 outcnt, incnt; 235 __u16 out, in; 236 237 if (!asoc->peer.reconf_capable || 238 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { 239 retval = -ENOPROTOOPT; 240 goto out; 241 } 242 243 if (asoc->strreset_outstanding) { 244 retval = -EINPROGRESS; 245 goto out; 246 } 247 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 || 253 (!out && !in)) { 254 retval = -EINVAL; 255 goto out; 256 } 257 258 if (out) { 259 struct sctp_stream_out *streamout; 260 261 streamout = krealloc(stream->out, outcnt * sizeof(*streamout), 262 GFP_KERNEL); 263 if (!streamout) 264 goto out; 265 266 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout)); 267 stream->out = streamout; 268 } 269 270 if (in) { 271 struct sctp_stream_in *streamin; 272 273 streamin = krealloc(stream->in, incnt * sizeof(*streamin), 274 GFP_KERNEL); 275 if (!streamin) 276 goto out; 277 278 memset(streamin + stream->incnt, 0, in * sizeof(*streamin)); 279 stream->in = streamin; 280 } 281 282 chunk = sctp_make_strreset_addstrm(asoc, out, in); 283 if (!chunk) 284 goto out; 285 286 asoc->strreset_chunk = chunk; 287 sctp_chunk_hold(asoc->strreset_chunk); 288 289 retval = sctp_send_reconf(asoc, chunk); 290 if (retval) { 291 sctp_chunk_put(asoc->strreset_chunk); 292 asoc->strreset_chunk = NULL; 293 goto out; 294 } 295 296 stream->incnt = incnt; 297 stream->outcnt = outcnt; 298 299 asoc->strreset_outstanding = !!out + !!in; 300 301 out: 302 return retval; 303 } 304 305 static sctp_paramhdr_t *sctp_chunk_lookup_strreset_param( 306 struct sctp_association *asoc, __u32 resp_seq) 307 { 308 struct sctp_chunk *chunk = asoc->strreset_chunk; 309 struct sctp_reconf_chunk *hdr; 310 union sctp_params param; 311 312 if (ntohl(resp_seq) != asoc->strreset_outseq || !chunk) 313 return NULL; 314 315 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; 316 sctp_walk_params(param, hdr, params) { 317 /* sctp_strreset_tsnreq is actually the basic structure 318 * of all stream reconf params, so it's safe to use it 319 * to access request_seq. 320 */ 321 struct sctp_strreset_tsnreq *req = param.v; 322 323 if (req->request_seq == resp_seq) 324 return param.v; 325 } 326 327 return NULL; 328 } 329 330 struct sctp_chunk *sctp_process_strreset_outreq( 331 struct sctp_association *asoc, 332 union sctp_params param, 333 struct sctp_ulpevent **evp) 334 { 335 struct sctp_strreset_outreq *outreq = param.v; 336 struct sctp_stream *stream = asoc->stream; 337 __u16 i, nums, flags = 0, *str_p = NULL; 338 __u32 result = SCTP_STRRESET_DENIED; 339 __u32 request_seq; 340 341 request_seq = ntohl(outreq->request_seq); 342 343 if (ntohl(outreq->send_reset_at_tsn) > 344 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) { 345 result = SCTP_STRRESET_IN_PROGRESS; 346 goto out; 347 } 348 349 if (request_seq > asoc->strreset_inseq) { 350 result = SCTP_STRRESET_ERR_BAD_SEQNO; 351 goto out; 352 } else if (request_seq == asoc->strreset_inseq) { 353 asoc->strreset_inseq++; 354 } 355 356 /* Check strreset_enable after inseq inc, as sender cannot tell 357 * the peer doesn't enable strreset after receiving response with 358 * result denied, as well as to keep consistent with bsd. 359 */ 360 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 361 goto out; 362 363 if (asoc->strreset_chunk) { 364 sctp_paramhdr_t *param_hdr; 365 struct sctp_transport *t; 366 367 param_hdr = sctp_chunk_lookup_strreset_param( 368 asoc, outreq->response_seq); 369 if (!param_hdr || param_hdr->type != 370 SCTP_PARAM_RESET_IN_REQUEST) { 371 /* same process with outstanding isn't 0 */ 372 result = SCTP_STRRESET_ERR_IN_PROGRESS; 373 goto out; 374 } 375 376 asoc->strreset_outstanding--; 377 asoc->strreset_outseq++; 378 379 if (!asoc->strreset_outstanding) { 380 t = asoc->strreset_chunk->transport; 381 if (del_timer(&t->reconf_timer)) 382 sctp_transport_put(t); 383 384 sctp_chunk_put(asoc->strreset_chunk); 385 asoc->strreset_chunk = NULL; 386 } 387 388 flags = SCTP_STREAM_RESET_INCOMING_SSN; 389 } 390 391 nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2; 392 if (nums) { 393 str_p = outreq->list_of_streams; 394 for (i = 0; i < nums; i++) { 395 if (ntohs(str_p[i]) >= stream->incnt) { 396 result = SCTP_STRRESET_ERR_WRONG_SSN; 397 goto out; 398 } 399 } 400 401 for (i = 0; i < nums; i++) 402 stream->in[ntohs(str_p[i])].ssn = 0; 403 } else { 404 for (i = 0; i < stream->incnt; i++) 405 stream->in[i].ssn = 0; 406 } 407 408 result = SCTP_STRRESET_PERFORMED; 409 410 *evp = sctp_ulpevent_make_stream_reset_event(asoc, 411 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p, 412 GFP_ATOMIC); 413 414 out: 415 return sctp_make_strreset_resp(asoc, result, request_seq); 416 } 417 418 struct sctp_chunk *sctp_process_strreset_inreq( 419 struct sctp_association *asoc, 420 union sctp_params param, 421 struct sctp_ulpevent **evp) 422 { 423 struct sctp_strreset_inreq *inreq = param.v; 424 struct sctp_stream *stream = asoc->stream; 425 __u32 result = SCTP_STRRESET_DENIED; 426 struct sctp_chunk *chunk = NULL; 427 __u16 i, nums, *str_p; 428 __u32 request_seq; 429 430 request_seq = ntohl(inreq->request_seq); 431 if (request_seq > asoc->strreset_inseq) { 432 result = SCTP_STRRESET_ERR_BAD_SEQNO; 433 goto out; 434 } else if (request_seq == asoc->strreset_inseq) { 435 asoc->strreset_inseq++; 436 } 437 438 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 439 goto out; 440 441 if (asoc->strreset_outstanding) { 442 result = SCTP_STRRESET_ERR_IN_PROGRESS; 443 goto out; 444 } 445 446 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2; 447 str_p = inreq->list_of_streams; 448 for (i = 0; i < nums; i++) { 449 if (ntohs(str_p[i]) >= stream->outcnt) { 450 result = SCTP_STRRESET_ERR_WRONG_SSN; 451 goto out; 452 } 453 } 454 455 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0); 456 if (!chunk) 457 goto out; 458 459 if (nums) 460 for (i = 0; i < nums; i++) 461 stream->out[ntohs(str_p[i])].state = 462 SCTP_STREAM_CLOSED; 463 else 464 for (i = 0; i < stream->outcnt; i++) 465 stream->out[i].state = SCTP_STREAM_CLOSED; 466 467 asoc->strreset_chunk = chunk; 468 asoc->strreset_outstanding = 1; 469 sctp_chunk_hold(asoc->strreset_chunk); 470 471 *evp = sctp_ulpevent_make_stream_reset_event(asoc, 472 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); 473 474 out: 475 if (!chunk) 476 chunk = sctp_make_strreset_resp(asoc, result, request_seq); 477 478 return chunk; 479 } 480