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