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