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_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt, 39 gfp_t gfp) 40 { 41 int i; 42 43 /* Initial stream->out size may be very big, so free it and alloc 44 * a new one with new outcnt to save memory. 45 */ 46 kfree(stream->out); 47 48 stream->out = kcalloc(outcnt, sizeof(*stream->out), gfp); 49 if (!stream->out) 50 return -ENOMEM; 51 52 stream->outcnt = outcnt; 53 for (i = 0; i < stream->outcnt; i++) 54 stream->out[i].state = SCTP_STREAM_OPEN; 55 56 if (!incnt) 57 return 0; 58 59 stream->in = kcalloc(incnt, sizeof(*stream->in), gfp); 60 if (!stream->in) { 61 kfree(stream->out); 62 stream->out = NULL; 63 return -ENOMEM; 64 } 65 66 stream->incnt = incnt; 67 68 return 0; 69 } 70 71 void sctp_stream_free(struct sctp_stream *stream) 72 { 73 kfree(stream->out); 74 kfree(stream->in); 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 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new) 89 { 90 sctp_stream_free(stream); 91 92 stream->out = new->out; 93 stream->in = new->in; 94 stream->outcnt = new->outcnt; 95 stream->incnt = new->incnt; 96 97 new->out = NULL; 98 new->in = NULL; 99 } 100 101 static int sctp_send_reconf(struct sctp_association *asoc, 102 struct sctp_chunk *chunk) 103 { 104 struct net *net = sock_net(asoc->base.sk); 105 int retval = 0; 106 107 retval = sctp_primitive_RECONF(net, asoc, chunk); 108 if (retval) 109 sctp_chunk_free(chunk); 110 111 return retval; 112 } 113 114 int sctp_send_reset_streams(struct sctp_association *asoc, 115 struct sctp_reset_streams *params) 116 { 117 struct sctp_stream *stream = &asoc->stream; 118 __u16 i, str_nums, *str_list; 119 struct sctp_chunk *chunk; 120 int retval = -EINVAL; 121 __be16 *nstr_list; 122 bool out, in; 123 124 if (!asoc->peer.reconf_capable || 125 !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) { 126 retval = -ENOPROTOOPT; 127 goto out; 128 } 129 130 if (asoc->strreset_outstanding) { 131 retval = -EINPROGRESS; 132 goto out; 133 } 134 135 out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING; 136 in = params->srs_flags & SCTP_STREAM_RESET_INCOMING; 137 if (!out && !in) 138 goto out; 139 140 str_nums = params->srs_number_streams; 141 str_list = params->srs_stream_list; 142 if (out && str_nums) 143 for (i = 0; i < str_nums; i++) 144 if (str_list[i] >= stream->outcnt) 145 goto out; 146 147 if (in && str_nums) 148 for (i = 0; i < str_nums; i++) 149 if (str_list[i] >= stream->incnt) 150 goto out; 151 152 nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL); 153 if (!nstr_list) { 154 retval = -ENOMEM; 155 goto out; 156 } 157 158 for (i = 0; i < str_nums; i++) 159 nstr_list[i] = htons(str_list[i]); 160 161 chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in); 162 163 kfree(nstr_list); 164 165 if (!chunk) { 166 retval = -ENOMEM; 167 goto out; 168 } 169 170 if (out) { 171 if (str_nums) 172 for (i = 0; i < str_nums; i++) 173 stream->out[str_list[i]].state = 174 SCTP_STREAM_CLOSED; 175 else 176 for (i = 0; i < stream->outcnt; i++) 177 stream->out[i].state = SCTP_STREAM_CLOSED; 178 } 179 180 asoc->strreset_chunk = chunk; 181 sctp_chunk_hold(asoc->strreset_chunk); 182 183 retval = sctp_send_reconf(asoc, chunk); 184 if (retval) { 185 sctp_chunk_put(asoc->strreset_chunk); 186 asoc->strreset_chunk = NULL; 187 if (!out) 188 goto out; 189 190 if (str_nums) 191 for (i = 0; i < str_nums; i++) 192 stream->out[str_list[i]].state = 193 SCTP_STREAM_OPEN; 194 else 195 for (i = 0; i < stream->outcnt; i++) 196 stream->out[i].state = SCTP_STREAM_OPEN; 197 198 goto out; 199 } 200 201 asoc->strreset_outstanding = out + in; 202 203 out: 204 return retval; 205 } 206 207 int sctp_send_reset_assoc(struct sctp_association *asoc) 208 { 209 struct sctp_stream *stream = &asoc->stream; 210 struct sctp_chunk *chunk = NULL; 211 int retval; 212 __u16 i; 213 214 if (!asoc->peer.reconf_capable || 215 !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) 216 return -ENOPROTOOPT; 217 218 if (asoc->strreset_outstanding) 219 return -EINPROGRESS; 220 221 chunk = sctp_make_strreset_tsnreq(asoc); 222 if (!chunk) 223 return -ENOMEM; 224 225 /* Block further xmit of data until this request is completed */ 226 for (i = 0; i < stream->outcnt; i++) 227 stream->out[i].state = SCTP_STREAM_CLOSED; 228 229 asoc->strreset_chunk = chunk; 230 sctp_chunk_hold(asoc->strreset_chunk); 231 232 retval = sctp_send_reconf(asoc, chunk); 233 if (retval) { 234 sctp_chunk_put(asoc->strreset_chunk); 235 asoc->strreset_chunk = NULL; 236 237 for (i = 0; i < stream->outcnt; i++) 238 stream->out[i].state = SCTP_STREAM_OPEN; 239 240 return retval; 241 } 242 243 asoc->strreset_outstanding = 1; 244 245 return 0; 246 } 247 248 int sctp_send_add_streams(struct sctp_association *asoc, 249 struct sctp_add_streams *params) 250 { 251 struct sctp_stream *stream = &asoc->stream; 252 struct sctp_chunk *chunk = NULL; 253 int retval = -ENOMEM; 254 __u32 outcnt, incnt; 255 __u16 out, in; 256 257 if (!asoc->peer.reconf_capable || 258 !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) { 259 retval = -ENOPROTOOPT; 260 goto out; 261 } 262 263 if (asoc->strreset_outstanding) { 264 retval = -EINPROGRESS; 265 goto out; 266 } 267 268 out = params->sas_outstrms; 269 in = params->sas_instrms; 270 outcnt = stream->outcnt + out; 271 incnt = stream->incnt + in; 272 if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM || 273 (!out && !in)) { 274 retval = -EINVAL; 275 goto out; 276 } 277 278 if (out) { 279 struct sctp_stream_out *streamout; 280 281 streamout = krealloc(stream->out, outcnt * sizeof(*streamout), 282 GFP_KERNEL); 283 if (!streamout) 284 goto out; 285 286 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout)); 287 stream->out = streamout; 288 } 289 290 chunk = sctp_make_strreset_addstrm(asoc, out, in); 291 if (!chunk) 292 goto out; 293 294 asoc->strreset_chunk = chunk; 295 sctp_chunk_hold(asoc->strreset_chunk); 296 297 retval = sctp_send_reconf(asoc, chunk); 298 if (retval) { 299 sctp_chunk_put(asoc->strreset_chunk); 300 asoc->strreset_chunk = NULL; 301 goto out; 302 } 303 304 stream->incnt = incnt; 305 stream->outcnt = outcnt; 306 307 asoc->strreset_outstanding = !!out + !!in; 308 309 out: 310 return retval; 311 } 312 313 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param( 314 struct sctp_association *asoc, __be32 resp_seq, 315 __be16 type) 316 { 317 struct sctp_chunk *chunk = asoc->strreset_chunk; 318 struct sctp_reconf_chunk *hdr; 319 union sctp_params param; 320 321 if (!chunk) 322 return NULL; 323 324 hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; 325 sctp_walk_params(param, hdr, params) { 326 /* sctp_strreset_tsnreq is actually the basic structure 327 * of all stream reconf params, so it's safe to use it 328 * to access request_seq. 329 */ 330 struct sctp_strreset_tsnreq *req = param.v; 331 332 if ((!resp_seq || req->request_seq == resp_seq) && 333 (!type || type == req->param_hdr.type)) 334 return param.v; 335 } 336 337 return NULL; 338 } 339 340 static void sctp_update_strreset_result(struct sctp_association *asoc, 341 __u32 result) 342 { 343 asoc->strreset_result[1] = asoc->strreset_result[0]; 344 asoc->strreset_result[0] = result; 345 } 346 347 struct sctp_chunk *sctp_process_strreset_outreq( 348 struct sctp_association *asoc, 349 union sctp_params param, 350 struct sctp_ulpevent **evp) 351 { 352 struct sctp_strreset_outreq *outreq = param.v; 353 struct sctp_stream *stream = &asoc->stream; 354 __u32 result = SCTP_STRRESET_DENIED; 355 __u16 i, nums, flags = 0; 356 __be16 *str_p = NULL; 357 __u32 request_seq; 358 359 request_seq = ntohl(outreq->request_seq); 360 361 if (ntohl(outreq->send_reset_at_tsn) > 362 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) { 363 result = SCTP_STRRESET_IN_PROGRESS; 364 goto err; 365 } 366 367 if (TSN_lt(asoc->strreset_inseq, request_seq) || 368 TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 369 result = SCTP_STRRESET_ERR_BAD_SEQNO; 370 goto err; 371 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 372 i = asoc->strreset_inseq - request_seq - 1; 373 result = asoc->strreset_result[i]; 374 goto err; 375 } 376 asoc->strreset_inseq++; 377 378 /* Check strreset_enable after inseq inc, as sender cannot tell 379 * the peer doesn't enable strreset after receiving response with 380 * result denied, as well as to keep consistent with bsd. 381 */ 382 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 383 goto out; 384 385 if (asoc->strreset_chunk) { 386 if (!sctp_chunk_lookup_strreset_param( 387 asoc, outreq->response_seq, 388 SCTP_PARAM_RESET_IN_REQUEST)) { 389 /* same process with outstanding isn't 0 */ 390 result = SCTP_STRRESET_ERR_IN_PROGRESS; 391 goto out; 392 } 393 394 asoc->strreset_outstanding--; 395 asoc->strreset_outseq++; 396 397 if (!asoc->strreset_outstanding) { 398 struct sctp_transport *t; 399 400 t = asoc->strreset_chunk->transport; 401 if (del_timer(&t->reconf_timer)) 402 sctp_transport_put(t); 403 404 sctp_chunk_put(asoc->strreset_chunk); 405 asoc->strreset_chunk = NULL; 406 } 407 408 flags = SCTP_STREAM_RESET_INCOMING_SSN; 409 } 410 411 nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2; 412 if (nums) { 413 str_p = outreq->list_of_streams; 414 for (i = 0; i < nums; i++) { 415 if (ntohs(str_p[i]) >= stream->incnt) { 416 result = SCTP_STRRESET_ERR_WRONG_SSN; 417 goto out; 418 } 419 } 420 421 for (i = 0; i < nums; i++) 422 stream->in[ntohs(str_p[i])].ssn = 0; 423 } else { 424 for (i = 0; i < stream->incnt; i++) 425 stream->in[i].ssn = 0; 426 } 427 428 result = SCTP_STRRESET_PERFORMED; 429 430 *evp = sctp_ulpevent_make_stream_reset_event(asoc, 431 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p, 432 GFP_ATOMIC); 433 434 out: 435 sctp_update_strreset_result(asoc, result); 436 err: 437 return sctp_make_strreset_resp(asoc, result, request_seq); 438 } 439 440 struct sctp_chunk *sctp_process_strreset_inreq( 441 struct sctp_association *asoc, 442 union sctp_params param, 443 struct sctp_ulpevent **evp) 444 { 445 struct sctp_strreset_inreq *inreq = param.v; 446 struct sctp_stream *stream = &asoc->stream; 447 __u32 result = SCTP_STRRESET_DENIED; 448 struct sctp_chunk *chunk = NULL; 449 __u32 request_seq; 450 __u16 i, nums; 451 __be16 *str_p; 452 453 request_seq = ntohl(inreq->request_seq); 454 if (TSN_lt(asoc->strreset_inseq, request_seq) || 455 TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 456 result = SCTP_STRRESET_ERR_BAD_SEQNO; 457 goto err; 458 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 459 i = asoc->strreset_inseq - request_seq - 1; 460 result = asoc->strreset_result[i]; 461 if (result == SCTP_STRRESET_PERFORMED) 462 return NULL; 463 goto err; 464 } 465 asoc->strreset_inseq++; 466 467 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 468 goto out; 469 470 if (asoc->strreset_outstanding) { 471 result = SCTP_STRRESET_ERR_IN_PROGRESS; 472 goto out; 473 } 474 475 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2; 476 str_p = inreq->list_of_streams; 477 for (i = 0; i < nums; i++) { 478 if (ntohs(str_p[i]) >= stream->outcnt) { 479 result = SCTP_STRRESET_ERR_WRONG_SSN; 480 goto out; 481 } 482 } 483 484 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0); 485 if (!chunk) 486 goto out; 487 488 if (nums) 489 for (i = 0; i < nums; i++) 490 stream->out[ntohs(str_p[i])].state = 491 SCTP_STREAM_CLOSED; 492 else 493 for (i = 0; i < stream->outcnt; i++) 494 stream->out[i].state = SCTP_STREAM_CLOSED; 495 496 asoc->strreset_chunk = chunk; 497 asoc->strreset_outstanding = 1; 498 sctp_chunk_hold(asoc->strreset_chunk); 499 500 result = SCTP_STRRESET_PERFORMED; 501 502 *evp = sctp_ulpevent_make_stream_reset_event(asoc, 503 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); 504 505 out: 506 sctp_update_strreset_result(asoc, result); 507 err: 508 if (!chunk) 509 chunk = sctp_make_strreset_resp(asoc, result, request_seq); 510 511 return chunk; 512 } 513 514 struct sctp_chunk *sctp_process_strreset_tsnreq( 515 struct sctp_association *asoc, 516 union sctp_params param, 517 struct sctp_ulpevent **evp) 518 { 519 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen; 520 struct sctp_strreset_tsnreq *tsnreq = param.v; 521 struct sctp_stream *stream = &asoc->stream; 522 __u32 result = SCTP_STRRESET_DENIED; 523 __u32 request_seq; 524 __u16 i; 525 526 request_seq = ntohl(tsnreq->request_seq); 527 if (TSN_lt(asoc->strreset_inseq, request_seq) || 528 TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 529 result = SCTP_STRRESET_ERR_BAD_SEQNO; 530 goto err; 531 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 532 i = asoc->strreset_inseq - request_seq - 1; 533 result = asoc->strreset_result[i]; 534 if (result == SCTP_STRRESET_PERFORMED) { 535 next_tsn = asoc->next_tsn; 536 init_tsn = 537 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1; 538 } 539 goto err; 540 } 541 asoc->strreset_inseq++; 542 543 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) 544 goto out; 545 546 if (asoc->strreset_outstanding) { 547 result = SCTP_STRRESET_ERR_IN_PROGRESS; 548 goto out; 549 } 550 551 /* G3: The same processing as though a SACK chunk with no gap report 552 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were 553 * received MUST be performed. 554 */ 555 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map); 556 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen); 557 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); 558 559 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the 560 * TSN that the peer should use to send the next DATA chunk. The 561 * value SHOULD be the smallest TSN not acknowledged by the 562 * receiver of the request plus 2^31. 563 */ 564 init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31); 565 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, 566 init_tsn, GFP_ATOMIC); 567 568 /* G4: The same processing as though a FWD-TSN chunk (as defined in 569 * [RFC3758]) with all streams affected and a new cumulative TSN 570 * ACK of the Receiver's Next TSN minus 1 were received MUST be 571 * performed. 572 */ 573 sctp_outq_free(&asoc->outqueue); 574 575 /* G2: Compute an appropriate value for the local endpoint's next TSN, 576 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset 577 * chunk. The value SHOULD be the highest TSN sent by the receiver 578 * of the request plus 1. 579 */ 580 next_tsn = asoc->next_tsn; 581 asoc->ctsn_ack_point = next_tsn - 1; 582 asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 583 584 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all 585 * incoming and outgoing streams. 586 */ 587 for (i = 0; i < stream->outcnt; i++) 588 stream->out[i].ssn = 0; 589 for (i = 0; i < stream->incnt; i++) 590 stream->in[i].ssn = 0; 591 592 result = SCTP_STRRESET_PERFORMED; 593 594 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn, 595 next_tsn, GFP_ATOMIC); 596 597 out: 598 sctp_update_strreset_result(asoc, result); 599 err: 600 return sctp_make_strreset_tsnresp(asoc, result, request_seq, 601 next_tsn, init_tsn); 602 } 603 604 struct sctp_chunk *sctp_process_strreset_addstrm_out( 605 struct sctp_association *asoc, 606 union sctp_params param, 607 struct sctp_ulpevent **evp) 608 { 609 struct sctp_strreset_addstrm *addstrm = param.v; 610 struct sctp_stream *stream = &asoc->stream; 611 __u32 result = SCTP_STRRESET_DENIED; 612 struct sctp_stream_in *streamin; 613 __u32 request_seq, incnt; 614 __u16 in, i; 615 616 request_seq = ntohl(addstrm->request_seq); 617 if (TSN_lt(asoc->strreset_inseq, request_seq) || 618 TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 619 result = SCTP_STRRESET_ERR_BAD_SEQNO; 620 goto err; 621 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 622 i = asoc->strreset_inseq - request_seq - 1; 623 result = asoc->strreset_result[i]; 624 goto err; 625 } 626 asoc->strreset_inseq++; 627 628 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) 629 goto out; 630 631 if (asoc->strreset_chunk) { 632 if (!sctp_chunk_lookup_strreset_param( 633 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { 634 /* same process with outstanding isn't 0 */ 635 result = SCTP_STRRESET_ERR_IN_PROGRESS; 636 goto out; 637 } 638 639 asoc->strreset_outstanding--; 640 asoc->strreset_outseq++; 641 642 if (!asoc->strreset_outstanding) { 643 struct sctp_transport *t; 644 645 t = asoc->strreset_chunk->transport; 646 if (del_timer(&t->reconf_timer)) 647 sctp_transport_put(t); 648 649 sctp_chunk_put(asoc->strreset_chunk); 650 asoc->strreset_chunk = NULL; 651 } 652 } 653 654 in = ntohs(addstrm->number_of_streams); 655 incnt = stream->incnt + in; 656 if (!in || incnt > SCTP_MAX_STREAM) 657 goto out; 658 659 streamin = krealloc(stream->in, incnt * sizeof(*streamin), 660 GFP_ATOMIC); 661 if (!streamin) 662 goto out; 663 664 memset(streamin + stream->incnt, 0, in * sizeof(*streamin)); 665 stream->in = streamin; 666 stream->incnt = incnt; 667 668 result = SCTP_STRRESET_PERFORMED; 669 670 *evp = sctp_ulpevent_make_stream_change_event(asoc, 671 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC); 672 673 out: 674 sctp_update_strreset_result(asoc, result); 675 err: 676 return sctp_make_strreset_resp(asoc, result, request_seq); 677 } 678 679 struct sctp_chunk *sctp_process_strreset_addstrm_in( 680 struct sctp_association *asoc, 681 union sctp_params param, 682 struct sctp_ulpevent **evp) 683 { 684 struct sctp_strreset_addstrm *addstrm = param.v; 685 struct sctp_stream *stream = &asoc->stream; 686 __u32 result = SCTP_STRRESET_DENIED; 687 struct sctp_stream_out *streamout; 688 struct sctp_chunk *chunk = NULL; 689 __u32 request_seq, outcnt; 690 __u16 out, i; 691 692 request_seq = ntohl(addstrm->request_seq); 693 if (TSN_lt(asoc->strreset_inseq, request_seq) || 694 TSN_lt(request_seq, asoc->strreset_inseq - 2)) { 695 result = SCTP_STRRESET_ERR_BAD_SEQNO; 696 goto err; 697 } else if (TSN_lt(request_seq, asoc->strreset_inseq)) { 698 i = asoc->strreset_inseq - request_seq - 1; 699 result = asoc->strreset_result[i]; 700 if (result == SCTP_STRRESET_PERFORMED) 701 return NULL; 702 goto err; 703 } 704 asoc->strreset_inseq++; 705 706 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) 707 goto out; 708 709 if (asoc->strreset_outstanding) { 710 result = SCTP_STRRESET_ERR_IN_PROGRESS; 711 goto out; 712 } 713 714 out = ntohs(addstrm->number_of_streams); 715 outcnt = stream->outcnt + out; 716 if (!out || outcnt > SCTP_MAX_STREAM) 717 goto out; 718 719 streamout = krealloc(stream->out, outcnt * sizeof(*streamout), 720 GFP_ATOMIC); 721 if (!streamout) 722 goto out; 723 724 memset(streamout + stream->outcnt, 0, out * sizeof(*streamout)); 725 stream->out = streamout; 726 727 chunk = sctp_make_strreset_addstrm(asoc, out, 0); 728 if (!chunk) 729 goto out; 730 731 asoc->strreset_chunk = chunk; 732 asoc->strreset_outstanding = 1; 733 sctp_chunk_hold(asoc->strreset_chunk); 734 735 stream->outcnt = outcnt; 736 737 result = SCTP_STRRESET_PERFORMED; 738 739 *evp = sctp_ulpevent_make_stream_change_event(asoc, 740 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC); 741 742 out: 743 sctp_update_strreset_result(asoc, result); 744 err: 745 if (!chunk) 746 chunk = sctp_make_strreset_resp(asoc, result, request_seq); 747 748 return chunk; 749 } 750 751 struct sctp_chunk *sctp_process_strreset_resp( 752 struct sctp_association *asoc, 753 union sctp_params param, 754 struct sctp_ulpevent **evp) 755 { 756 struct sctp_stream *stream = &asoc->stream; 757 struct sctp_strreset_resp *resp = param.v; 758 struct sctp_transport *t; 759 __u16 i, nums, flags = 0; 760 struct sctp_paramhdr *req; 761 __u32 result; 762 763 req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0); 764 if (!req) 765 return NULL; 766 767 result = ntohl(resp->result); 768 if (result != SCTP_STRRESET_PERFORMED) { 769 /* if in progress, do nothing but retransmit */ 770 if (result == SCTP_STRRESET_IN_PROGRESS) 771 return NULL; 772 else if (result == SCTP_STRRESET_DENIED) 773 flags = SCTP_STREAM_RESET_DENIED; 774 else 775 flags = SCTP_STREAM_RESET_FAILED; 776 } 777 778 if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) { 779 struct sctp_strreset_outreq *outreq; 780 __be16 *str_p; 781 782 outreq = (struct sctp_strreset_outreq *)req; 783 str_p = outreq->list_of_streams; 784 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2; 785 786 if (result == SCTP_STRRESET_PERFORMED) { 787 if (nums) { 788 for (i = 0; i < nums; i++) 789 stream->out[ntohs(str_p[i])].ssn = 0; 790 } else { 791 for (i = 0; i < stream->outcnt; i++) 792 stream->out[i].ssn = 0; 793 } 794 795 flags = SCTP_STREAM_RESET_OUTGOING_SSN; 796 } 797 798 for (i = 0; i < stream->outcnt; i++) 799 stream->out[i].state = SCTP_STREAM_OPEN; 800 801 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, 802 nums, str_p, GFP_ATOMIC); 803 } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) { 804 struct sctp_strreset_inreq *inreq; 805 __be16 *str_p; 806 807 /* if the result is performed, it's impossible for inreq */ 808 if (result == SCTP_STRRESET_PERFORMED) 809 return NULL; 810 811 inreq = (struct sctp_strreset_inreq *)req; 812 str_p = inreq->list_of_streams; 813 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2; 814 815 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, 816 nums, str_p, GFP_ATOMIC); 817 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) { 818 struct sctp_strreset_resptsn *resptsn; 819 __u32 stsn, rtsn; 820 821 /* check for resptsn, as sctp_verify_reconf didn't do it*/ 822 if (ntohs(param.p->length) != sizeof(*resptsn)) 823 return NULL; 824 825 resptsn = (struct sctp_strreset_resptsn *)resp; 826 stsn = ntohl(resptsn->senders_next_tsn); 827 rtsn = ntohl(resptsn->receivers_next_tsn); 828 829 if (result == SCTP_STRRESET_PERFORMED) { 830 __u32 mtsn = sctp_tsnmap_get_max_tsn_seen( 831 &asoc->peer.tsn_map); 832 833 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn); 834 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC); 835 836 sctp_tsnmap_init(&asoc->peer.tsn_map, 837 SCTP_TSN_MAP_INITIAL, 838 stsn, GFP_ATOMIC); 839 840 sctp_outq_free(&asoc->outqueue); 841 842 asoc->next_tsn = rtsn; 843 asoc->ctsn_ack_point = asoc->next_tsn - 1; 844 asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 845 846 for (i = 0; i < stream->outcnt; i++) 847 stream->out[i].ssn = 0; 848 for (i = 0; i < stream->incnt; i++) 849 stream->in[i].ssn = 0; 850 } 851 852 for (i = 0; i < stream->outcnt; i++) 853 stream->out[i].state = SCTP_STREAM_OPEN; 854 855 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags, 856 stsn, rtsn, GFP_ATOMIC); 857 } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) { 858 struct sctp_strreset_addstrm *addstrm; 859 __u16 number; 860 861 addstrm = (struct sctp_strreset_addstrm *)req; 862 nums = ntohs(addstrm->number_of_streams); 863 number = stream->outcnt - nums; 864 865 if (result == SCTP_STRRESET_PERFORMED) 866 for (i = number; i < stream->outcnt; i++) 867 stream->out[i].state = SCTP_STREAM_OPEN; 868 else 869 stream->outcnt = number; 870 871 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags, 872 0, nums, GFP_ATOMIC); 873 } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) { 874 struct sctp_strreset_addstrm *addstrm; 875 876 /* if the result is performed, it's impossible for addstrm in 877 * request. 878 */ 879 if (result == SCTP_STRRESET_PERFORMED) 880 return NULL; 881 882 addstrm = (struct sctp_strreset_addstrm *)req; 883 nums = ntohs(addstrm->number_of_streams); 884 885 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags, 886 nums, 0, GFP_ATOMIC); 887 } 888 889 asoc->strreset_outstanding--; 890 asoc->strreset_outseq++; 891 892 /* remove everything for this reconf request */ 893 if (!asoc->strreset_outstanding) { 894 t = asoc->strreset_chunk->transport; 895 if (del_timer(&t->reconf_timer)) 896 sctp_transport_put(t); 897 898 sctp_chunk_put(asoc->strreset_chunk); 899 asoc->strreset_chunk = NULL; 900 } 901 902 return NULL; 903 } 904