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