root/net/sctp/stream.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sctp_stream_outq_migrate
  2. sctp_stream_alloc_out
  3. sctp_stream_alloc_in
  4. sctp_stream_init
  5. sctp_stream_init_ext
  6. sctp_stream_free
  7. sctp_stream_clear
  8. sctp_stream_update
  9. sctp_send_reconf
  10. sctp_stream_outq_is_empty
  11. sctp_send_reset_streams
  12. sctp_send_reset_assoc
  13. sctp_send_add_streams
  14. sctp_chunk_lookup_strreset_param
  15. sctp_update_strreset_result
  16. sctp_process_strreset_outreq
  17. sctp_process_strreset_inreq
  18. sctp_process_strreset_tsnreq
  19. sctp_process_strreset_addstrm_out
  20. sctp_process_strreset_addstrm_in
  21. sctp_process_strreset_resp

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* SCTP kernel implementation
   3  * (C) Copyright IBM Corp. 2001, 2004
   4  * Copyright (c) 1999-2000 Cisco, Inc.
   5  * Copyright (c) 1999-2001 Motorola, Inc.
   6  * Copyright (c) 2001 Intel Corp.
   7  *
   8  * This file is part of the SCTP kernel implementation
   9  *
  10  * This file contains sctp stream maniuplation primitives and helpers.
  11  *
  12  * Please send any bug reports or fixes you make to the
  13  * email address(es):
  14  *    lksctp developers <linux-sctp@vger.kernel.org>
  15  *
  16  * Written or modified by:
  17  *    Xin Long <lucien.xin@gmail.com>
  18  */
  19 
  20 #include <linux/list.h>
  21 #include <net/sctp/sctp.h>
  22 #include <net/sctp/sm.h>
  23 #include <net/sctp/stream_sched.h>
  24 
  25 /* Migrates chunks from stream queues to new stream queues if needed,
  26  * but not across associations. Also, removes those chunks to streams
  27  * higher than the new max.
  28  */
  29 static void sctp_stream_outq_migrate(struct sctp_stream *stream,
  30                                      struct sctp_stream *new, __u16 outcnt)
  31 {
  32         struct sctp_association *asoc;
  33         struct sctp_chunk *ch, *temp;
  34         struct sctp_outq *outq;
  35         int i;
  36 
  37         asoc = container_of(stream, struct sctp_association, stream);
  38         outq = &asoc->outqueue;
  39 
  40         list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
  41                 __u16 sid = sctp_chunk_stream_no(ch);
  42 
  43                 if (sid < outcnt)
  44                         continue;
  45 
  46                 sctp_sched_dequeue_common(outq, ch);
  47                 /* No need to call dequeue_done here because
  48                  * the chunks are not scheduled by now.
  49                  */
  50 
  51                 /* Mark as failed send. */
  52                 sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
  53                 if (asoc->peer.prsctp_capable &&
  54                     SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
  55                         asoc->sent_cnt_removable--;
  56 
  57                 sctp_chunk_free(ch);
  58         }
  59 
  60         if (new) {
  61                 /* Here we actually move the old ext stuff into the new
  62                  * buffer, because we want to keep it. Then
  63                  * sctp_stream_update will swap ->out pointers.
  64                  */
  65                 for (i = 0; i < outcnt; i++) {
  66                         kfree(SCTP_SO(new, i)->ext);
  67                         SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
  68                         SCTP_SO(stream, i)->ext = NULL;
  69                 }
  70         }
  71 
  72         for (i = outcnt; i < stream->outcnt; i++) {
  73                 kfree(SCTP_SO(stream, i)->ext);
  74                 SCTP_SO(stream, i)->ext = NULL;
  75         }
  76 }
  77 
  78 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
  79                                  gfp_t gfp)
  80 {
  81         int ret;
  82 
  83         if (outcnt <= stream->outcnt)
  84                 return 0;
  85 
  86         ret = genradix_prealloc(&stream->out, outcnt, gfp);
  87         if (ret)
  88                 return ret;
  89 
  90         stream->outcnt = outcnt;
  91         return 0;
  92 }
  93 
  94 static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
  95                                 gfp_t gfp)
  96 {
  97         int ret;
  98 
  99         if (incnt <= stream->incnt)
 100                 return 0;
 101 
 102         ret = genradix_prealloc(&stream->in, incnt, gfp);
 103         if (ret)
 104                 return ret;
 105 
 106         stream->incnt = incnt;
 107         return 0;
 108 }
 109 
 110 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
 111                      gfp_t gfp)
 112 {
 113         struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 114         int i, ret = 0;
 115 
 116         gfp |= __GFP_NOWARN;
 117 
 118         /* Initial stream->out size may be very big, so free it and alloc
 119          * a new one with new outcnt to save memory if needed.
 120          */
 121         if (outcnt == stream->outcnt)
 122                 goto handle_in;
 123 
 124         /* Filter out chunks queued on streams that won't exist anymore */
 125         sched->unsched_all(stream);
 126         sctp_stream_outq_migrate(stream, NULL, outcnt);
 127         sched->sched_all(stream);
 128 
 129         ret = sctp_stream_alloc_out(stream, outcnt, gfp);
 130         if (ret)
 131                 goto out_err;
 132 
 133         for (i = 0; i < stream->outcnt; i++)
 134                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 135 
 136 handle_in:
 137         sctp_stream_interleave_init(stream);
 138         if (!incnt)
 139                 goto out;
 140 
 141         ret = sctp_stream_alloc_in(stream, incnt, gfp);
 142         if (ret)
 143                 goto in_err;
 144 
 145         goto out;
 146 
 147 in_err:
 148         sched->free(stream);
 149         genradix_free(&stream->in);
 150 out_err:
 151         genradix_free(&stream->out);
 152         stream->outcnt = 0;
 153 out:
 154         return ret;
 155 }
 156 
 157 int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
 158 {
 159         struct sctp_stream_out_ext *soute;
 160         int ret;
 161 
 162         soute = kzalloc(sizeof(*soute), GFP_KERNEL);
 163         if (!soute)
 164                 return -ENOMEM;
 165         SCTP_SO(stream, sid)->ext = soute;
 166 
 167         ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
 168         if (ret) {
 169                 kfree(SCTP_SO(stream, sid)->ext);
 170                 SCTP_SO(stream, sid)->ext = NULL;
 171         }
 172 
 173         return ret;
 174 }
 175 
 176 void sctp_stream_free(struct sctp_stream *stream)
 177 {
 178         struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 179         int i;
 180 
 181         sched->free(stream);
 182         for (i = 0; i < stream->outcnt; i++)
 183                 kfree(SCTP_SO(stream, i)->ext);
 184         genradix_free(&stream->out);
 185         genradix_free(&stream->in);
 186 }
 187 
 188 void sctp_stream_clear(struct sctp_stream *stream)
 189 {
 190         int i;
 191 
 192         for (i = 0; i < stream->outcnt; i++) {
 193                 SCTP_SO(stream, i)->mid = 0;
 194                 SCTP_SO(stream, i)->mid_uo = 0;
 195         }
 196 
 197         for (i = 0; i < stream->incnt; i++)
 198                 SCTP_SI(stream, i)->mid = 0;
 199 }
 200 
 201 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
 202 {
 203         struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
 204 
 205         sched->unsched_all(stream);
 206         sctp_stream_outq_migrate(stream, new, new->outcnt);
 207         sctp_stream_free(stream);
 208 
 209         stream->out = new->out;
 210         stream->in  = new->in;
 211         stream->outcnt = new->outcnt;
 212         stream->incnt  = new->incnt;
 213 
 214         sched->sched_all(stream);
 215 
 216         new->out.tree.root = NULL;
 217         new->in.tree.root  = NULL;
 218         new->outcnt = 0;
 219         new->incnt  = 0;
 220 }
 221 
 222 static int sctp_send_reconf(struct sctp_association *asoc,
 223                             struct sctp_chunk *chunk)
 224 {
 225         struct net *net = sock_net(asoc->base.sk);
 226         int retval = 0;
 227 
 228         retval = sctp_primitive_RECONF(net, asoc, chunk);
 229         if (retval)
 230                 sctp_chunk_free(chunk);
 231 
 232         return retval;
 233 }
 234 
 235 static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
 236                                       __u16 str_nums, __be16 *str_list)
 237 {
 238         struct sctp_association *asoc;
 239         __u16 i;
 240 
 241         asoc = container_of(stream, struct sctp_association, stream);
 242         if (!asoc->outqueue.out_qlen)
 243                 return true;
 244 
 245         if (!str_nums)
 246                 return false;
 247 
 248         for (i = 0; i < str_nums; i++) {
 249                 __u16 sid = ntohs(str_list[i]);
 250 
 251                 if (SCTP_SO(stream, sid)->ext &&
 252                     !list_empty(&SCTP_SO(stream, sid)->ext->outq))
 253                         return false;
 254         }
 255 
 256         return true;
 257 }
 258 
 259 int sctp_send_reset_streams(struct sctp_association *asoc,
 260                             struct sctp_reset_streams *params)
 261 {
 262         struct sctp_stream *stream = &asoc->stream;
 263         __u16 i, str_nums, *str_list;
 264         struct sctp_chunk *chunk;
 265         int retval = -EINVAL;
 266         __be16 *nstr_list;
 267         bool out, in;
 268 
 269         if (!asoc->peer.reconf_capable ||
 270             !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
 271                 retval = -ENOPROTOOPT;
 272                 goto out;
 273         }
 274 
 275         if (asoc->strreset_outstanding) {
 276                 retval = -EINPROGRESS;
 277                 goto out;
 278         }
 279 
 280         out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
 281         in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
 282         if (!out && !in)
 283                 goto out;
 284 
 285         str_nums = params->srs_number_streams;
 286         str_list = params->srs_stream_list;
 287         if (str_nums) {
 288                 int param_len = 0;
 289 
 290                 if (out) {
 291                         for (i = 0; i < str_nums; i++)
 292                                 if (str_list[i] >= stream->outcnt)
 293                                         goto out;
 294 
 295                         param_len = str_nums * sizeof(__u16) +
 296                                     sizeof(struct sctp_strreset_outreq);
 297                 }
 298 
 299                 if (in) {
 300                         for (i = 0; i < str_nums; i++)
 301                                 if (str_list[i] >= stream->incnt)
 302                                         goto out;
 303 
 304                         param_len += str_nums * sizeof(__u16) +
 305                                      sizeof(struct sctp_strreset_inreq);
 306                 }
 307 
 308                 if (param_len > SCTP_MAX_CHUNK_LEN -
 309                                 sizeof(struct sctp_reconf_chunk))
 310                         goto out;
 311         }
 312 
 313         nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
 314         if (!nstr_list) {
 315                 retval = -ENOMEM;
 316                 goto out;
 317         }
 318 
 319         for (i = 0; i < str_nums; i++)
 320                 nstr_list[i] = htons(str_list[i]);
 321 
 322         if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
 323                 kfree(nstr_list);
 324                 retval = -EAGAIN;
 325                 goto out;
 326         }
 327 
 328         chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
 329 
 330         kfree(nstr_list);
 331 
 332         if (!chunk) {
 333                 retval = -ENOMEM;
 334                 goto out;
 335         }
 336 
 337         if (out) {
 338                 if (str_nums)
 339                         for (i = 0; i < str_nums; i++)
 340                                 SCTP_SO(stream, str_list[i])->state =
 341                                                        SCTP_STREAM_CLOSED;
 342                 else
 343                         for (i = 0; i < stream->outcnt; i++)
 344                                 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 345         }
 346 
 347         asoc->strreset_chunk = chunk;
 348         sctp_chunk_hold(asoc->strreset_chunk);
 349 
 350         retval = sctp_send_reconf(asoc, chunk);
 351         if (retval) {
 352                 sctp_chunk_put(asoc->strreset_chunk);
 353                 asoc->strreset_chunk = NULL;
 354                 if (!out)
 355                         goto out;
 356 
 357                 if (str_nums)
 358                         for (i = 0; i < str_nums; i++)
 359                                 SCTP_SO(stream, str_list[i])->state =
 360                                                        SCTP_STREAM_OPEN;
 361                 else
 362                         for (i = 0; i < stream->outcnt; i++)
 363                                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 364 
 365                 goto out;
 366         }
 367 
 368         asoc->strreset_outstanding = out + in;
 369 
 370 out:
 371         return retval;
 372 }
 373 
 374 int sctp_send_reset_assoc(struct sctp_association *asoc)
 375 {
 376         struct sctp_stream *stream = &asoc->stream;
 377         struct sctp_chunk *chunk = NULL;
 378         int retval;
 379         __u16 i;
 380 
 381         if (!asoc->peer.reconf_capable ||
 382             !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
 383                 return -ENOPROTOOPT;
 384 
 385         if (asoc->strreset_outstanding)
 386                 return -EINPROGRESS;
 387 
 388         if (!sctp_outq_is_empty(&asoc->outqueue))
 389                 return -EAGAIN;
 390 
 391         chunk = sctp_make_strreset_tsnreq(asoc);
 392         if (!chunk)
 393                 return -ENOMEM;
 394 
 395         /* Block further xmit of data until this request is completed */
 396         for (i = 0; i < stream->outcnt; i++)
 397                 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 398 
 399         asoc->strreset_chunk = chunk;
 400         sctp_chunk_hold(asoc->strreset_chunk);
 401 
 402         retval = sctp_send_reconf(asoc, chunk);
 403         if (retval) {
 404                 sctp_chunk_put(asoc->strreset_chunk);
 405                 asoc->strreset_chunk = NULL;
 406 
 407                 for (i = 0; i < stream->outcnt; i++)
 408                         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 409 
 410                 return retval;
 411         }
 412 
 413         asoc->strreset_outstanding = 1;
 414 
 415         return 0;
 416 }
 417 
 418 int sctp_send_add_streams(struct sctp_association *asoc,
 419                           struct sctp_add_streams *params)
 420 {
 421         struct sctp_stream *stream = &asoc->stream;
 422         struct sctp_chunk *chunk = NULL;
 423         int retval;
 424         __u32 outcnt, incnt;
 425         __u16 out, in;
 426 
 427         if (!asoc->peer.reconf_capable ||
 428             !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
 429                 retval = -ENOPROTOOPT;
 430                 goto out;
 431         }
 432 
 433         if (asoc->strreset_outstanding) {
 434                 retval = -EINPROGRESS;
 435                 goto out;
 436         }
 437 
 438         out = params->sas_outstrms;
 439         in  = params->sas_instrms;
 440         outcnt = stream->outcnt + out;
 441         incnt = stream->incnt + in;
 442         if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
 443             (!out && !in)) {
 444                 retval = -EINVAL;
 445                 goto out;
 446         }
 447 
 448         if (out) {
 449                 retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
 450                 if (retval)
 451                         goto out;
 452         }
 453 
 454         chunk = sctp_make_strreset_addstrm(asoc, out, in);
 455         if (!chunk) {
 456                 retval = -ENOMEM;
 457                 goto out;
 458         }
 459 
 460         asoc->strreset_chunk = chunk;
 461         sctp_chunk_hold(asoc->strreset_chunk);
 462 
 463         retval = sctp_send_reconf(asoc, chunk);
 464         if (retval) {
 465                 sctp_chunk_put(asoc->strreset_chunk);
 466                 asoc->strreset_chunk = NULL;
 467                 goto out;
 468         }
 469 
 470         asoc->strreset_outstanding = !!out + !!in;
 471 
 472 out:
 473         return retval;
 474 }
 475 
 476 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
 477                         struct sctp_association *asoc, __be32 resp_seq,
 478                         __be16 type)
 479 {
 480         struct sctp_chunk *chunk = asoc->strreset_chunk;
 481         struct sctp_reconf_chunk *hdr;
 482         union sctp_params param;
 483 
 484         if (!chunk)
 485                 return NULL;
 486 
 487         hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
 488         sctp_walk_params(param, hdr, params) {
 489                 /* sctp_strreset_tsnreq is actually the basic structure
 490                  * of all stream reconf params, so it's safe to use it
 491                  * to access request_seq.
 492                  */
 493                 struct sctp_strreset_tsnreq *req = param.v;
 494 
 495                 if ((!resp_seq || req->request_seq == resp_seq) &&
 496                     (!type || type == req->param_hdr.type))
 497                         return param.v;
 498         }
 499 
 500         return NULL;
 501 }
 502 
 503 static void sctp_update_strreset_result(struct sctp_association *asoc,
 504                                         __u32 result)
 505 {
 506         asoc->strreset_result[1] = asoc->strreset_result[0];
 507         asoc->strreset_result[0] = result;
 508 }
 509 
 510 struct sctp_chunk *sctp_process_strreset_outreq(
 511                                 struct sctp_association *asoc,
 512                                 union sctp_params param,
 513                                 struct sctp_ulpevent **evp)
 514 {
 515         struct sctp_strreset_outreq *outreq = param.v;
 516         struct sctp_stream *stream = &asoc->stream;
 517         __u32 result = SCTP_STRRESET_DENIED;
 518         __be16 *str_p = NULL;
 519         __u32 request_seq;
 520         __u16 i, nums;
 521 
 522         request_seq = ntohl(outreq->request_seq);
 523 
 524         if (ntohl(outreq->send_reset_at_tsn) >
 525             sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
 526                 result = SCTP_STRRESET_IN_PROGRESS;
 527                 goto err;
 528         }
 529 
 530         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 531             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 532                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
 533                 goto err;
 534         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 535                 i = asoc->strreset_inseq - request_seq - 1;
 536                 result = asoc->strreset_result[i];
 537                 goto err;
 538         }
 539         asoc->strreset_inseq++;
 540 
 541         /* Check strreset_enable after inseq inc, as sender cannot tell
 542          * the peer doesn't enable strreset after receiving response with
 543          * result denied, as well as to keep consistent with bsd.
 544          */
 545         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
 546                 goto out;
 547 
 548         nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
 549         str_p = outreq->list_of_streams;
 550         for (i = 0; i < nums; i++) {
 551                 if (ntohs(str_p[i]) >= stream->incnt) {
 552                         result = SCTP_STRRESET_ERR_WRONG_SSN;
 553                         goto out;
 554                 }
 555         }
 556 
 557         if (asoc->strreset_chunk) {
 558                 if (!sctp_chunk_lookup_strreset_param(
 559                                 asoc, outreq->response_seq,
 560                                 SCTP_PARAM_RESET_IN_REQUEST)) {
 561                         /* same process with outstanding isn't 0 */
 562                         result = SCTP_STRRESET_ERR_IN_PROGRESS;
 563                         goto out;
 564                 }
 565 
 566                 asoc->strreset_outstanding--;
 567                 asoc->strreset_outseq++;
 568 
 569                 if (!asoc->strreset_outstanding) {
 570                         struct sctp_transport *t;
 571 
 572                         t = asoc->strreset_chunk->transport;
 573                         if (del_timer(&t->reconf_timer))
 574                                 sctp_transport_put(t);
 575 
 576                         sctp_chunk_put(asoc->strreset_chunk);
 577                         asoc->strreset_chunk = NULL;
 578                 }
 579         }
 580 
 581         if (nums)
 582                 for (i = 0; i < nums; i++)
 583                         SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
 584         else
 585                 for (i = 0; i < stream->incnt; i++)
 586                         SCTP_SI(stream, i)->mid = 0;
 587 
 588         result = SCTP_STRRESET_PERFORMED;
 589 
 590         *evp = sctp_ulpevent_make_stream_reset_event(asoc,
 591                 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
 592 
 593 out:
 594         sctp_update_strreset_result(asoc, result);
 595 err:
 596         return sctp_make_strreset_resp(asoc, result, request_seq);
 597 }
 598 
 599 struct sctp_chunk *sctp_process_strreset_inreq(
 600                                 struct sctp_association *asoc,
 601                                 union sctp_params param,
 602                                 struct sctp_ulpevent **evp)
 603 {
 604         struct sctp_strreset_inreq *inreq = param.v;
 605         struct sctp_stream *stream = &asoc->stream;
 606         __u32 result = SCTP_STRRESET_DENIED;
 607         struct sctp_chunk *chunk = NULL;
 608         __u32 request_seq;
 609         __u16 i, nums;
 610         __be16 *str_p;
 611 
 612         request_seq = ntohl(inreq->request_seq);
 613         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 614             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 615                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
 616                 goto err;
 617         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 618                 i = asoc->strreset_inseq - request_seq - 1;
 619                 result = asoc->strreset_result[i];
 620                 if (result == SCTP_STRRESET_PERFORMED)
 621                         return NULL;
 622                 goto err;
 623         }
 624         asoc->strreset_inseq++;
 625 
 626         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
 627                 goto out;
 628 
 629         if (asoc->strreset_outstanding) {
 630                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
 631                 goto out;
 632         }
 633 
 634         nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
 635         str_p = inreq->list_of_streams;
 636         for (i = 0; i < nums; i++) {
 637                 if (ntohs(str_p[i]) >= stream->outcnt) {
 638                         result = SCTP_STRRESET_ERR_WRONG_SSN;
 639                         goto out;
 640                 }
 641         }
 642 
 643         if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
 644                 result = SCTP_STRRESET_IN_PROGRESS;
 645                 asoc->strreset_inseq--;
 646                 goto err;
 647         }
 648 
 649         chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
 650         if (!chunk)
 651                 goto out;
 652 
 653         if (nums)
 654                 for (i = 0; i < nums; i++)
 655                         SCTP_SO(stream, ntohs(str_p[i]))->state =
 656                                                SCTP_STREAM_CLOSED;
 657         else
 658                 for (i = 0; i < stream->outcnt; i++)
 659                         SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
 660 
 661         asoc->strreset_chunk = chunk;
 662         asoc->strreset_outstanding = 1;
 663         sctp_chunk_hold(asoc->strreset_chunk);
 664 
 665         result = SCTP_STRRESET_PERFORMED;
 666 
 667 out:
 668         sctp_update_strreset_result(asoc, result);
 669 err:
 670         if (!chunk)
 671                 chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
 672 
 673         return chunk;
 674 }
 675 
 676 struct sctp_chunk *sctp_process_strreset_tsnreq(
 677                                 struct sctp_association *asoc,
 678                                 union sctp_params param,
 679                                 struct sctp_ulpevent **evp)
 680 {
 681         __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
 682         struct sctp_strreset_tsnreq *tsnreq = param.v;
 683         struct sctp_stream *stream = &asoc->stream;
 684         __u32 result = SCTP_STRRESET_DENIED;
 685         __u32 request_seq;
 686         __u16 i;
 687 
 688         request_seq = ntohl(tsnreq->request_seq);
 689         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 690             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 691                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
 692                 goto err;
 693         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 694                 i = asoc->strreset_inseq - request_seq - 1;
 695                 result = asoc->strreset_result[i];
 696                 if (result == SCTP_STRRESET_PERFORMED) {
 697                         next_tsn = asoc->ctsn_ack_point + 1;
 698                         init_tsn =
 699                                 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
 700                 }
 701                 goto err;
 702         }
 703 
 704         if (!sctp_outq_is_empty(&asoc->outqueue)) {
 705                 result = SCTP_STRRESET_IN_PROGRESS;
 706                 goto err;
 707         }
 708 
 709         asoc->strreset_inseq++;
 710 
 711         if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
 712                 goto out;
 713 
 714         if (asoc->strreset_outstanding) {
 715                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
 716                 goto out;
 717         }
 718 
 719         /* G4: The same processing as though a FWD-TSN chunk (as defined in
 720          *     [RFC3758]) with all streams affected and a new cumulative TSN
 721          *     ACK of the Receiver's Next TSN minus 1 were received MUST be
 722          *     performed.
 723          */
 724         max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
 725         asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
 726 
 727         /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
 728          *     TSN that the peer should use to send the next DATA chunk.  The
 729          *     value SHOULD be the smallest TSN not acknowledged by the
 730          *     receiver of the request plus 2^31.
 731          */
 732         init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
 733         sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
 734                          init_tsn, GFP_ATOMIC);
 735 
 736         /* G3: The same processing as though a SACK chunk with no gap report
 737          *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
 738          *     received MUST be performed.
 739          */
 740         sctp_outq_free(&asoc->outqueue);
 741 
 742         /* G2: Compute an appropriate value for the local endpoint's next TSN,
 743          *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
 744          *     chunk.  The value SHOULD be the highest TSN sent by the receiver
 745          *     of the request plus 1.
 746          */
 747         next_tsn = asoc->next_tsn;
 748         asoc->ctsn_ack_point = next_tsn - 1;
 749         asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 750 
 751         /* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
 752          *      incoming and outgoing streams.
 753          */
 754         for (i = 0; i < stream->outcnt; i++) {
 755                 SCTP_SO(stream, i)->mid = 0;
 756                 SCTP_SO(stream, i)->mid_uo = 0;
 757         }
 758         for (i = 0; i < stream->incnt; i++)
 759                 SCTP_SI(stream, i)->mid = 0;
 760 
 761         result = SCTP_STRRESET_PERFORMED;
 762 
 763         *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
 764                                                     next_tsn, GFP_ATOMIC);
 765 
 766 out:
 767         sctp_update_strreset_result(asoc, result);
 768 err:
 769         return sctp_make_strreset_tsnresp(asoc, result, request_seq,
 770                                           next_tsn, init_tsn);
 771 }
 772 
 773 struct sctp_chunk *sctp_process_strreset_addstrm_out(
 774                                 struct sctp_association *asoc,
 775                                 union sctp_params param,
 776                                 struct sctp_ulpevent **evp)
 777 {
 778         struct sctp_strreset_addstrm *addstrm = param.v;
 779         struct sctp_stream *stream = &asoc->stream;
 780         __u32 result = SCTP_STRRESET_DENIED;
 781         __u32 request_seq, incnt;
 782         __u16 in, i;
 783 
 784         request_seq = ntohl(addstrm->request_seq);
 785         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 786             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 787                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
 788                 goto err;
 789         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 790                 i = asoc->strreset_inseq - request_seq - 1;
 791                 result = asoc->strreset_result[i];
 792                 goto err;
 793         }
 794         asoc->strreset_inseq++;
 795 
 796         if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
 797                 goto out;
 798 
 799         in = ntohs(addstrm->number_of_streams);
 800         incnt = stream->incnt + in;
 801         if (!in || incnt > SCTP_MAX_STREAM)
 802                 goto out;
 803 
 804         if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
 805                 goto out;
 806 
 807         if (asoc->strreset_chunk) {
 808                 if (!sctp_chunk_lookup_strreset_param(
 809                         asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
 810                         /* same process with outstanding isn't 0 */
 811                         result = SCTP_STRRESET_ERR_IN_PROGRESS;
 812                         goto out;
 813                 }
 814 
 815                 asoc->strreset_outstanding--;
 816                 asoc->strreset_outseq++;
 817 
 818                 if (!asoc->strreset_outstanding) {
 819                         struct sctp_transport *t;
 820 
 821                         t = asoc->strreset_chunk->transport;
 822                         if (del_timer(&t->reconf_timer))
 823                                 sctp_transport_put(t);
 824 
 825                         sctp_chunk_put(asoc->strreset_chunk);
 826                         asoc->strreset_chunk = NULL;
 827                 }
 828         }
 829 
 830         stream->incnt = incnt;
 831 
 832         result = SCTP_STRRESET_PERFORMED;
 833 
 834         *evp = sctp_ulpevent_make_stream_change_event(asoc,
 835                 0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
 836 
 837 out:
 838         sctp_update_strreset_result(asoc, result);
 839 err:
 840         return sctp_make_strreset_resp(asoc, result, request_seq);
 841 }
 842 
 843 struct sctp_chunk *sctp_process_strreset_addstrm_in(
 844                                 struct sctp_association *asoc,
 845                                 union sctp_params param,
 846                                 struct sctp_ulpevent **evp)
 847 {
 848         struct sctp_strreset_addstrm *addstrm = param.v;
 849         struct sctp_stream *stream = &asoc->stream;
 850         __u32 result = SCTP_STRRESET_DENIED;
 851         struct sctp_chunk *chunk = NULL;
 852         __u32 request_seq, outcnt;
 853         __u16 out, i;
 854         int ret;
 855 
 856         request_seq = ntohl(addstrm->request_seq);
 857         if (TSN_lt(asoc->strreset_inseq, request_seq) ||
 858             TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
 859                 result = SCTP_STRRESET_ERR_BAD_SEQNO;
 860                 goto err;
 861         } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
 862                 i = asoc->strreset_inseq - request_seq - 1;
 863                 result = asoc->strreset_result[i];
 864                 if (result == SCTP_STRRESET_PERFORMED)
 865                         return NULL;
 866                 goto err;
 867         }
 868         asoc->strreset_inseq++;
 869 
 870         if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
 871                 goto out;
 872 
 873         if (asoc->strreset_outstanding) {
 874                 result = SCTP_STRRESET_ERR_IN_PROGRESS;
 875                 goto out;
 876         }
 877 
 878         out = ntohs(addstrm->number_of_streams);
 879         outcnt = stream->outcnt + out;
 880         if (!out || outcnt > SCTP_MAX_STREAM)
 881                 goto out;
 882 
 883         ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
 884         if (ret)
 885                 goto out;
 886 
 887         chunk = sctp_make_strreset_addstrm(asoc, out, 0);
 888         if (!chunk)
 889                 goto out;
 890 
 891         asoc->strreset_chunk = chunk;
 892         asoc->strreset_outstanding = 1;
 893         sctp_chunk_hold(asoc->strreset_chunk);
 894 
 895         stream->outcnt = outcnt;
 896 
 897         result = SCTP_STRRESET_PERFORMED;
 898 
 899 out:
 900         sctp_update_strreset_result(asoc, result);
 901 err:
 902         if (!chunk)
 903                 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
 904 
 905         return chunk;
 906 }
 907 
 908 struct sctp_chunk *sctp_process_strreset_resp(
 909                                 struct sctp_association *asoc,
 910                                 union sctp_params param,
 911                                 struct sctp_ulpevent **evp)
 912 {
 913         struct sctp_stream *stream = &asoc->stream;
 914         struct sctp_strreset_resp *resp = param.v;
 915         struct sctp_transport *t;
 916         __u16 i, nums, flags = 0;
 917         struct sctp_paramhdr *req;
 918         __u32 result;
 919 
 920         req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
 921         if (!req)
 922                 return NULL;
 923 
 924         result = ntohl(resp->result);
 925         if (result != SCTP_STRRESET_PERFORMED) {
 926                 /* if in progress, do nothing but retransmit */
 927                 if (result == SCTP_STRRESET_IN_PROGRESS)
 928                         return NULL;
 929                 else if (result == SCTP_STRRESET_DENIED)
 930                         flags = SCTP_STREAM_RESET_DENIED;
 931                 else
 932                         flags = SCTP_STREAM_RESET_FAILED;
 933         }
 934 
 935         if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
 936                 struct sctp_strreset_outreq *outreq;
 937                 __be16 *str_p;
 938 
 939                 outreq = (struct sctp_strreset_outreq *)req;
 940                 str_p = outreq->list_of_streams;
 941                 nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
 942                        sizeof(__u16);
 943 
 944                 if (result == SCTP_STRRESET_PERFORMED) {
 945                         struct sctp_stream_out *sout;
 946                         if (nums) {
 947                                 for (i = 0; i < nums; i++) {
 948                                         sout = SCTP_SO(stream, ntohs(str_p[i]));
 949                                         sout->mid = 0;
 950                                         sout->mid_uo = 0;
 951                                 }
 952                         } else {
 953                                 for (i = 0; i < stream->outcnt; i++) {
 954                                         sout = SCTP_SO(stream, i);
 955                                         sout->mid = 0;
 956                                         sout->mid_uo = 0;
 957                                 }
 958                         }
 959                 }
 960 
 961                 flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
 962 
 963                 for (i = 0; i < stream->outcnt; i++)
 964                         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
 965 
 966                 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 967                         nums, str_p, GFP_ATOMIC);
 968         } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
 969                 struct sctp_strreset_inreq *inreq;
 970                 __be16 *str_p;
 971 
 972                 /* if the result is performed, it's impossible for inreq */
 973                 if (result == SCTP_STRRESET_PERFORMED)
 974                         return NULL;
 975 
 976                 inreq = (struct sctp_strreset_inreq *)req;
 977                 str_p = inreq->list_of_streams;
 978                 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
 979                        sizeof(__u16);
 980 
 981                 flags |= SCTP_STREAM_RESET_INCOMING_SSN;
 982 
 983                 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 984                         nums, str_p, GFP_ATOMIC);
 985         } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
 986                 struct sctp_strreset_resptsn *resptsn;
 987                 __u32 stsn, rtsn;
 988 
 989                 /* check for resptsn, as sctp_verify_reconf didn't do it*/
 990                 if (ntohs(param.p->length) != sizeof(*resptsn))
 991                         return NULL;
 992 
 993                 resptsn = (struct sctp_strreset_resptsn *)resp;
 994                 stsn = ntohl(resptsn->senders_next_tsn);
 995                 rtsn = ntohl(resptsn->receivers_next_tsn);
 996 
 997                 if (result == SCTP_STRRESET_PERFORMED) {
 998                         __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
 999                                                 &asoc->peer.tsn_map);
1000                         LIST_HEAD(temp);
1001 
1002                         asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
1003 
1004                         sctp_tsnmap_init(&asoc->peer.tsn_map,
1005                                          SCTP_TSN_MAP_INITIAL,
1006                                          stsn, GFP_ATOMIC);
1007 
1008                         /* Clean up sacked and abandoned queues only. As the
1009                          * out_chunk_list may not be empty, splice it to temp,
1010                          * then get it back after sctp_outq_free is done.
1011                          */
1012                         list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
1013                         sctp_outq_free(&asoc->outqueue);
1014                         list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
1015 
1016                         asoc->next_tsn = rtsn;
1017                         asoc->ctsn_ack_point = asoc->next_tsn - 1;
1018                         asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1019 
1020                         for (i = 0; i < stream->outcnt; i++) {
1021                                 SCTP_SO(stream, i)->mid = 0;
1022                                 SCTP_SO(stream, i)->mid_uo = 0;
1023                         }
1024                         for (i = 0; i < stream->incnt; i++)
1025                                 SCTP_SI(stream, i)->mid = 0;
1026                 }
1027 
1028                 for (i = 0; i < stream->outcnt; i++)
1029                         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1030 
1031                 *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
1032                         stsn, rtsn, GFP_ATOMIC);
1033         } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
1034                 struct sctp_strreset_addstrm *addstrm;
1035                 __u16 number;
1036 
1037                 addstrm = (struct sctp_strreset_addstrm *)req;
1038                 nums = ntohs(addstrm->number_of_streams);
1039                 number = stream->outcnt - nums;
1040 
1041                 if (result == SCTP_STRRESET_PERFORMED)
1042                         for (i = number; i < stream->outcnt; i++)
1043                                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1044                 else
1045                         stream->outcnt = number;
1046 
1047                 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1048                         0, nums, GFP_ATOMIC);
1049         } else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
1050                 struct sctp_strreset_addstrm *addstrm;
1051 
1052                 /* if the result is performed, it's impossible for addstrm in
1053                  * request.
1054                  */
1055                 if (result == SCTP_STRRESET_PERFORMED)
1056                         return NULL;
1057 
1058                 addstrm = (struct sctp_strreset_addstrm *)req;
1059                 nums = ntohs(addstrm->number_of_streams);
1060 
1061                 *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
1062                         nums, 0, GFP_ATOMIC);
1063         }
1064 
1065         asoc->strreset_outstanding--;
1066         asoc->strreset_outseq++;
1067 
1068         /* remove everything for this reconf request */
1069         if (!asoc->strreset_outstanding) {
1070                 t = asoc->strreset_chunk->transport;
1071                 if (del_timer(&t->reconf_timer))
1072                         sctp_transport_put(t);
1073 
1074                 sctp_chunk_put(asoc->strreset_chunk);
1075                 asoc->strreset_chunk = NULL;
1076         }
1077 
1078         return NULL;
1079 }

/* [<][>][^][v][top][bottom][index][help] */