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