Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* SCTP kernel implementation
0003  * (C) Copyright IBM Corp. 2001, 2004
0004  * Copyright (c) 1999-2000 Cisco, Inc.
0005  * Copyright (c) 1999-2001 Motorola, Inc.
0006  * Copyright (c) 2001 Intel Corp.
0007  *
0008  * This file is part of the SCTP kernel implementation
0009  *
0010  * This file contains sctp stream maniuplation primitives and helpers.
0011  *
0012  * Please send any bug reports or fixes you make to the
0013  * email address(es):
0014  *    lksctp developers <linux-sctp@vger.kernel.org>
0015  *
0016  * Written or modified by:
0017  *    Xin Long <lucien.xin@gmail.com>
0018  */
0019 
0020 #include <linux/list.h>
0021 #include <net/sctp/sctp.h>
0022 #include <net/sctp/sm.h>
0023 #include <net/sctp/stream_sched.h>
0024 
0025 static void sctp_stream_shrink_out(struct sctp_stream *stream, __u16 outcnt)
0026 {
0027     struct sctp_association *asoc;
0028     struct sctp_chunk *ch, *temp;
0029     struct sctp_outq *outq;
0030 
0031     asoc = container_of(stream, struct sctp_association, stream);
0032     outq = &asoc->outqueue;
0033 
0034     list_for_each_entry_safe(ch, temp, &outq->out_chunk_list, list) {
0035         __u16 sid = sctp_chunk_stream_no(ch);
0036 
0037         if (sid < outcnt)
0038             continue;
0039 
0040         sctp_sched_dequeue_common(outq, ch);
0041         /* No need to call dequeue_done here because
0042          * the chunks are not scheduled by now.
0043          */
0044 
0045         /* Mark as failed send. */
0046         sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM);
0047         if (asoc->peer.prsctp_capable &&
0048             SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
0049             asoc->sent_cnt_removable--;
0050 
0051         sctp_chunk_free(ch);
0052     }
0053 }
0054 
0055 /* Migrates chunks from stream queues to new stream queues if needed,
0056  * but not across associations. Also, removes those chunks to streams
0057  * higher than the new max.
0058  */
0059 static void sctp_stream_outq_migrate(struct sctp_stream *stream,
0060                      struct sctp_stream *new, __u16 outcnt)
0061 {
0062     int i;
0063 
0064     if (stream->outcnt > outcnt)
0065         sctp_stream_shrink_out(stream, outcnt);
0066 
0067     if (new) {
0068         /* Here we actually move the old ext stuff into the new
0069          * buffer, because we want to keep it. Then
0070          * sctp_stream_update will swap ->out pointers.
0071          */
0072         for (i = 0; i < outcnt; i++) {
0073             kfree(SCTP_SO(new, i)->ext);
0074             SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
0075             SCTP_SO(stream, i)->ext = NULL;
0076         }
0077     }
0078 
0079     for (i = outcnt; i < stream->outcnt; i++) {
0080         kfree(SCTP_SO(stream, i)->ext);
0081         SCTP_SO(stream, i)->ext = NULL;
0082     }
0083 }
0084 
0085 static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
0086                  gfp_t gfp)
0087 {
0088     int ret;
0089 
0090     if (outcnt <= stream->outcnt)
0091         goto out;
0092 
0093     ret = genradix_prealloc(&stream->out, outcnt, gfp);
0094     if (ret)
0095         return ret;
0096 
0097 out:
0098     stream->outcnt = outcnt;
0099     return 0;
0100 }
0101 
0102 static int sctp_stream_alloc_in(struct sctp_stream *stream, __u16 incnt,
0103                 gfp_t gfp)
0104 {
0105     int ret;
0106 
0107     if (incnt <= stream->incnt)
0108         goto out;
0109 
0110     ret = genradix_prealloc(&stream->in, incnt, gfp);
0111     if (ret)
0112         return ret;
0113 
0114 out:
0115     stream->incnt = incnt;
0116     return 0;
0117 }
0118 
0119 int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
0120              gfp_t gfp)
0121 {
0122     struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
0123     int i, ret = 0;
0124 
0125     gfp |= __GFP_NOWARN;
0126 
0127     /* Initial stream->out size may be very big, so free it and alloc
0128      * a new one with new outcnt to save memory if needed.
0129      */
0130     if (outcnt == stream->outcnt)
0131         goto handle_in;
0132 
0133     /* Filter out chunks queued on streams that won't exist anymore */
0134     sched->unsched_all(stream);
0135     sctp_stream_outq_migrate(stream, NULL, outcnt);
0136     sched->sched_all(stream);
0137 
0138     ret = sctp_stream_alloc_out(stream, outcnt, gfp);
0139     if (ret)
0140         return ret;
0141 
0142     for (i = 0; i < stream->outcnt; i++)
0143         SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
0144 
0145 handle_in:
0146     sctp_stream_interleave_init(stream);
0147     if (!incnt)
0148         return 0;
0149 
0150     return sctp_stream_alloc_in(stream, incnt, gfp);
0151 }
0152 
0153 int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
0154 {
0155     struct sctp_stream_out_ext *soute;
0156     int ret;
0157 
0158     soute = kzalloc(sizeof(*soute), GFP_KERNEL);
0159     if (!soute)
0160         return -ENOMEM;
0161     SCTP_SO(stream, sid)->ext = soute;
0162 
0163     ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
0164     if (ret) {
0165         kfree(SCTP_SO(stream, sid)->ext);
0166         SCTP_SO(stream, sid)->ext = NULL;
0167     }
0168 
0169     return ret;
0170 }
0171 
0172 void sctp_stream_free(struct sctp_stream *stream)
0173 {
0174     struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
0175     int i;
0176 
0177     sched->free(stream);
0178     for (i = 0; i < stream->outcnt; i++)
0179         kfree(SCTP_SO(stream, i)->ext);
0180     genradix_free(&stream->out);
0181     genradix_free(&stream->in);
0182 }
0183 
0184 void sctp_stream_clear(struct sctp_stream *stream)
0185 {
0186     int i;
0187 
0188     for (i = 0; i < stream->outcnt; i++) {
0189         SCTP_SO(stream, i)->mid = 0;
0190         SCTP_SO(stream, i)->mid_uo = 0;
0191     }
0192 
0193     for (i = 0; i < stream->incnt; i++)
0194         SCTP_SI(stream, i)->mid = 0;
0195 }
0196 
0197 void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
0198 {
0199     struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
0200 
0201     sched->unsched_all(stream);
0202     sctp_stream_outq_migrate(stream, new, new->outcnt);
0203     sctp_stream_free(stream);
0204 
0205     stream->out = new->out;
0206     stream->in  = new->in;
0207     stream->outcnt = new->outcnt;
0208     stream->incnt  = new->incnt;
0209 
0210     sched->sched_all(stream);
0211 
0212     new->out.tree.root = NULL;
0213     new->in.tree.root  = NULL;
0214     new->outcnt = 0;
0215     new->incnt  = 0;
0216 }
0217 
0218 static int sctp_send_reconf(struct sctp_association *asoc,
0219                 struct sctp_chunk *chunk)
0220 {
0221     int retval = 0;
0222 
0223     retval = sctp_primitive_RECONF(asoc->base.net, asoc, chunk);
0224     if (retval)
0225         sctp_chunk_free(chunk);
0226 
0227     return retval;
0228 }
0229 
0230 static bool sctp_stream_outq_is_empty(struct sctp_stream *stream,
0231                       __u16 str_nums, __be16 *str_list)
0232 {
0233     struct sctp_association *asoc;
0234     __u16 i;
0235 
0236     asoc = container_of(stream, struct sctp_association, stream);
0237     if (!asoc->outqueue.out_qlen)
0238         return true;
0239 
0240     if (!str_nums)
0241         return false;
0242 
0243     for (i = 0; i < str_nums; i++) {
0244         __u16 sid = ntohs(str_list[i]);
0245 
0246         if (SCTP_SO(stream, sid)->ext &&
0247             !list_empty(&SCTP_SO(stream, sid)->ext->outq))
0248             return false;
0249     }
0250 
0251     return true;
0252 }
0253 
0254 int sctp_send_reset_streams(struct sctp_association *asoc,
0255                 struct sctp_reset_streams *params)
0256 {
0257     struct sctp_stream *stream = &asoc->stream;
0258     __u16 i, str_nums, *str_list;
0259     struct sctp_chunk *chunk;
0260     int retval = -EINVAL;
0261     __be16 *nstr_list;
0262     bool out, in;
0263 
0264     if (!asoc->peer.reconf_capable ||
0265         !(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
0266         retval = -ENOPROTOOPT;
0267         goto out;
0268     }
0269 
0270     if (asoc->strreset_outstanding) {
0271         retval = -EINPROGRESS;
0272         goto out;
0273     }
0274 
0275     out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
0276     in  = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
0277     if (!out && !in)
0278         goto out;
0279 
0280     str_nums = params->srs_number_streams;
0281     str_list = params->srs_stream_list;
0282     if (str_nums) {
0283         int param_len = 0;
0284 
0285         if (out) {
0286             for (i = 0; i < str_nums; i++)
0287                 if (str_list[i] >= stream->outcnt)
0288                     goto out;
0289 
0290             param_len = str_nums * sizeof(__u16) +
0291                     sizeof(struct sctp_strreset_outreq);
0292         }
0293 
0294         if (in) {
0295             for (i = 0; i < str_nums; i++)
0296                 if (str_list[i] >= stream->incnt)
0297                     goto out;
0298 
0299             param_len += str_nums * sizeof(__u16) +
0300                      sizeof(struct sctp_strreset_inreq);
0301         }
0302 
0303         if (param_len > SCTP_MAX_CHUNK_LEN -
0304                 sizeof(struct sctp_reconf_chunk))
0305             goto out;
0306     }
0307 
0308     nstr_list = kcalloc(str_nums, sizeof(__be16), GFP_KERNEL);
0309     if (!nstr_list) {
0310         retval = -ENOMEM;
0311         goto out;
0312     }
0313 
0314     for (i = 0; i < str_nums; i++)
0315         nstr_list[i] = htons(str_list[i]);
0316 
0317     if (out && !sctp_stream_outq_is_empty(stream, str_nums, nstr_list)) {
0318         kfree(nstr_list);
0319         retval = -EAGAIN;
0320         goto out;
0321     }
0322 
0323     chunk = sctp_make_strreset_req(asoc, str_nums, nstr_list, out, in);
0324 
0325     kfree(nstr_list);
0326 
0327     if (!chunk) {
0328         retval = -ENOMEM;
0329         goto out;
0330     }
0331 
0332     if (out) {
0333         if (str_nums)
0334             for (i = 0; i < str_nums; i++)
0335                 SCTP_SO(stream, str_list[i])->state =
0336                                SCTP_STREAM_CLOSED;
0337         else
0338             for (i = 0; i < stream->outcnt; i++)
0339                 SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
0340     }
0341 
0342     asoc->strreset_chunk = chunk;
0343     sctp_chunk_hold(asoc->strreset_chunk);
0344 
0345     retval = sctp_send_reconf(asoc, chunk);
0346     if (retval) {
0347         sctp_chunk_put(asoc->strreset_chunk);
0348         asoc->strreset_chunk = NULL;
0349         if (!out)
0350             goto out;
0351 
0352         if (str_nums)
0353             for (i = 0; i < str_nums; i++)
0354                 SCTP_SO(stream, str_list[i])->state =
0355                                SCTP_STREAM_OPEN;
0356         else
0357             for (i = 0; i < stream->outcnt; i++)
0358                 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
0359 
0360         goto out;
0361     }
0362 
0363     asoc->strreset_outstanding = out + in;
0364 
0365 out:
0366     return retval;
0367 }
0368 
0369 int sctp_send_reset_assoc(struct sctp_association *asoc)
0370 {
0371     struct sctp_stream *stream = &asoc->stream;
0372     struct sctp_chunk *chunk = NULL;
0373     int retval;
0374     __u16 i;
0375 
0376     if (!asoc->peer.reconf_capable ||
0377         !(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
0378         return -ENOPROTOOPT;
0379 
0380     if (asoc->strreset_outstanding)
0381         return -EINPROGRESS;
0382 
0383     if (!sctp_outq_is_empty(&asoc->outqueue))
0384         return -EAGAIN;
0385 
0386     chunk = sctp_make_strreset_tsnreq(asoc);
0387     if (!chunk)
0388         return -ENOMEM;
0389 
0390     /* Block further xmit of data until this request is completed */
0391     for (i = 0; i < stream->outcnt; i++)
0392         SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
0393 
0394     asoc->strreset_chunk = chunk;
0395     sctp_chunk_hold(asoc->strreset_chunk);
0396 
0397     retval = sctp_send_reconf(asoc, chunk);
0398     if (retval) {
0399         sctp_chunk_put(asoc->strreset_chunk);
0400         asoc->strreset_chunk = NULL;
0401 
0402         for (i = 0; i < stream->outcnt; i++)
0403             SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
0404 
0405         return retval;
0406     }
0407 
0408     asoc->strreset_outstanding = 1;
0409 
0410     return 0;
0411 }
0412 
0413 int sctp_send_add_streams(struct sctp_association *asoc,
0414               struct sctp_add_streams *params)
0415 {
0416     struct sctp_stream *stream = &asoc->stream;
0417     struct sctp_chunk *chunk = NULL;
0418     int retval;
0419     __u32 outcnt, incnt;
0420     __u16 out, in;
0421 
0422     if (!asoc->peer.reconf_capable ||
0423         !(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
0424         retval = -ENOPROTOOPT;
0425         goto out;
0426     }
0427 
0428     if (asoc->strreset_outstanding) {
0429         retval = -EINPROGRESS;
0430         goto out;
0431     }
0432 
0433     out = params->sas_outstrms;
0434     in  = params->sas_instrms;
0435     outcnt = stream->outcnt + out;
0436     incnt = stream->incnt + in;
0437     if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
0438         (!out && !in)) {
0439         retval = -EINVAL;
0440         goto out;
0441     }
0442 
0443     if (out) {
0444         retval = sctp_stream_alloc_out(stream, outcnt, GFP_KERNEL);
0445         if (retval)
0446             goto out;
0447     }
0448 
0449     chunk = sctp_make_strreset_addstrm(asoc, out, in);
0450     if (!chunk) {
0451         retval = -ENOMEM;
0452         goto out;
0453     }
0454 
0455     asoc->strreset_chunk = chunk;
0456     sctp_chunk_hold(asoc->strreset_chunk);
0457 
0458     retval = sctp_send_reconf(asoc, chunk);
0459     if (retval) {
0460         sctp_chunk_put(asoc->strreset_chunk);
0461         asoc->strreset_chunk = NULL;
0462         goto out;
0463     }
0464 
0465     asoc->strreset_outstanding = !!out + !!in;
0466 
0467 out:
0468     return retval;
0469 }
0470 
0471 static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param(
0472             struct sctp_association *asoc, __be32 resp_seq,
0473             __be16 type)
0474 {
0475     struct sctp_chunk *chunk = asoc->strreset_chunk;
0476     struct sctp_reconf_chunk *hdr;
0477     union sctp_params param;
0478 
0479     if (!chunk)
0480         return NULL;
0481 
0482     hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
0483     sctp_walk_params(param, hdr, params) {
0484         /* sctp_strreset_tsnreq is actually the basic structure
0485          * of all stream reconf params, so it's safe to use it
0486          * to access request_seq.
0487          */
0488         struct sctp_strreset_tsnreq *req = param.v;
0489 
0490         if ((!resp_seq || req->request_seq == resp_seq) &&
0491             (!type || type == req->param_hdr.type))
0492             return param.v;
0493     }
0494 
0495     return NULL;
0496 }
0497 
0498 static void sctp_update_strreset_result(struct sctp_association *asoc,
0499                     __u32 result)
0500 {
0501     asoc->strreset_result[1] = asoc->strreset_result[0];
0502     asoc->strreset_result[0] = result;
0503 }
0504 
0505 struct sctp_chunk *sctp_process_strreset_outreq(
0506                 struct sctp_association *asoc,
0507                 union sctp_params param,
0508                 struct sctp_ulpevent **evp)
0509 {
0510     struct sctp_strreset_outreq *outreq = param.v;
0511     struct sctp_stream *stream = &asoc->stream;
0512     __u32 result = SCTP_STRRESET_DENIED;
0513     __be16 *str_p = NULL;
0514     __u32 request_seq;
0515     __u16 i, nums;
0516 
0517     request_seq = ntohl(outreq->request_seq);
0518 
0519     if (ntohl(outreq->send_reset_at_tsn) >
0520         sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
0521         result = SCTP_STRRESET_IN_PROGRESS;
0522         goto err;
0523     }
0524 
0525     if (TSN_lt(asoc->strreset_inseq, request_seq) ||
0526         TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
0527         result = SCTP_STRRESET_ERR_BAD_SEQNO;
0528         goto err;
0529     } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
0530         i = asoc->strreset_inseq - request_seq - 1;
0531         result = asoc->strreset_result[i];
0532         goto err;
0533     }
0534     asoc->strreset_inseq++;
0535 
0536     /* Check strreset_enable after inseq inc, as sender cannot tell
0537      * the peer doesn't enable strreset after receiving response with
0538      * result denied, as well as to keep consistent with bsd.
0539      */
0540     if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
0541         goto out;
0542 
0543     nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
0544     str_p = outreq->list_of_streams;
0545     for (i = 0; i < nums; i++) {
0546         if (ntohs(str_p[i]) >= stream->incnt) {
0547             result = SCTP_STRRESET_ERR_WRONG_SSN;
0548             goto out;
0549         }
0550     }
0551 
0552     if (asoc->strreset_chunk) {
0553         if (!sctp_chunk_lookup_strreset_param(
0554                 asoc, outreq->response_seq,
0555                 SCTP_PARAM_RESET_IN_REQUEST)) {
0556             /* same process with outstanding isn't 0 */
0557             result = SCTP_STRRESET_ERR_IN_PROGRESS;
0558             goto out;
0559         }
0560 
0561         asoc->strreset_outstanding--;
0562         asoc->strreset_outseq++;
0563 
0564         if (!asoc->strreset_outstanding) {
0565             struct sctp_transport *t;
0566 
0567             t = asoc->strreset_chunk->transport;
0568             if (del_timer(&t->reconf_timer))
0569                 sctp_transport_put(t);
0570 
0571             sctp_chunk_put(asoc->strreset_chunk);
0572             asoc->strreset_chunk = NULL;
0573         }
0574     }
0575 
0576     if (nums)
0577         for (i = 0; i < nums; i++)
0578             SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
0579     else
0580         for (i = 0; i < stream->incnt; i++)
0581             SCTP_SI(stream, i)->mid = 0;
0582 
0583     result = SCTP_STRRESET_PERFORMED;
0584 
0585     *evp = sctp_ulpevent_make_stream_reset_event(asoc,
0586         SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
0587 
0588 out:
0589     sctp_update_strreset_result(asoc, result);
0590 err:
0591     return sctp_make_strreset_resp(asoc, result, request_seq);
0592 }
0593 
0594 struct sctp_chunk *sctp_process_strreset_inreq(
0595                 struct sctp_association *asoc,
0596                 union sctp_params param,
0597                 struct sctp_ulpevent **evp)
0598 {
0599     struct sctp_strreset_inreq *inreq = param.v;
0600     struct sctp_stream *stream = &asoc->stream;
0601     __u32 result = SCTP_STRRESET_DENIED;
0602     struct sctp_chunk *chunk = NULL;
0603     __u32 request_seq;
0604     __u16 i, nums;
0605     __be16 *str_p;
0606 
0607     request_seq = ntohl(inreq->request_seq);
0608     if (TSN_lt(asoc->strreset_inseq, request_seq) ||
0609         TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
0610         result = SCTP_STRRESET_ERR_BAD_SEQNO;
0611         goto err;
0612     } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
0613         i = asoc->strreset_inseq - request_seq - 1;
0614         result = asoc->strreset_result[i];
0615         if (result == SCTP_STRRESET_PERFORMED)
0616             return NULL;
0617         goto err;
0618     }
0619     asoc->strreset_inseq++;
0620 
0621     if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
0622         goto out;
0623 
0624     if (asoc->strreset_outstanding) {
0625         result = SCTP_STRRESET_ERR_IN_PROGRESS;
0626         goto out;
0627     }
0628 
0629     nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
0630     str_p = inreq->list_of_streams;
0631     for (i = 0; i < nums; i++) {
0632         if (ntohs(str_p[i]) >= stream->outcnt) {
0633             result = SCTP_STRRESET_ERR_WRONG_SSN;
0634             goto out;
0635         }
0636     }
0637 
0638     if (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
0639         result = SCTP_STRRESET_IN_PROGRESS;
0640         asoc->strreset_inseq--;
0641         goto err;
0642     }
0643 
0644     chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
0645     if (!chunk)
0646         goto out;
0647 
0648     if (nums)
0649         for (i = 0; i < nums; i++)
0650             SCTP_SO(stream, ntohs(str_p[i]))->state =
0651                            SCTP_STREAM_CLOSED;
0652     else
0653         for (i = 0; i < stream->outcnt; i++)
0654             SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
0655 
0656     asoc->strreset_chunk = chunk;
0657     asoc->strreset_outstanding = 1;
0658     sctp_chunk_hold(asoc->strreset_chunk);
0659 
0660     result = SCTP_STRRESET_PERFORMED;
0661 
0662 out:
0663     sctp_update_strreset_result(asoc, result);
0664 err:
0665     if (!chunk)
0666         chunk =  sctp_make_strreset_resp(asoc, result, request_seq);
0667 
0668     return chunk;
0669 }
0670 
0671 struct sctp_chunk *sctp_process_strreset_tsnreq(
0672                 struct sctp_association *asoc,
0673                 union sctp_params param,
0674                 struct sctp_ulpevent **evp)
0675 {
0676     __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
0677     struct sctp_strreset_tsnreq *tsnreq = param.v;
0678     struct sctp_stream *stream = &asoc->stream;
0679     __u32 result = SCTP_STRRESET_DENIED;
0680     __u32 request_seq;
0681     __u16 i;
0682 
0683     request_seq = ntohl(tsnreq->request_seq);
0684     if (TSN_lt(asoc->strreset_inseq, request_seq) ||
0685         TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
0686         result = SCTP_STRRESET_ERR_BAD_SEQNO;
0687         goto err;
0688     } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
0689         i = asoc->strreset_inseq - request_seq - 1;
0690         result = asoc->strreset_result[i];
0691         if (result == SCTP_STRRESET_PERFORMED) {
0692             next_tsn = asoc->ctsn_ack_point + 1;
0693             init_tsn =
0694                 sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1;
0695         }
0696         goto err;
0697     }
0698 
0699     if (!sctp_outq_is_empty(&asoc->outqueue)) {
0700         result = SCTP_STRRESET_IN_PROGRESS;
0701         goto err;
0702     }
0703 
0704     asoc->strreset_inseq++;
0705 
0706     if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
0707         goto out;
0708 
0709     if (asoc->strreset_outstanding) {
0710         result = SCTP_STRRESET_ERR_IN_PROGRESS;
0711         goto out;
0712     }
0713 
0714     /* G4: The same processing as though a FWD-TSN chunk (as defined in
0715      *     [RFC3758]) with all streams affected and a new cumulative TSN
0716      *     ACK of the Receiver's Next TSN minus 1 were received MUST be
0717      *     performed.
0718      */
0719     max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
0720     asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
0721 
0722     /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
0723      *     TSN that the peer should use to send the next DATA chunk.  The
0724      *     value SHOULD be the smallest TSN not acknowledged by the
0725      *     receiver of the request plus 2^31.
0726      */
0727     init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
0728     sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
0729              init_tsn, GFP_ATOMIC);
0730 
0731     /* G3: The same processing as though a SACK chunk with no gap report
0732      *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
0733      *     received MUST be performed.
0734      */
0735     sctp_outq_free(&asoc->outqueue);
0736 
0737     /* G2: Compute an appropriate value for the local endpoint's next TSN,
0738      *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
0739      *     chunk.  The value SHOULD be the highest TSN sent by the receiver
0740      *     of the request plus 1.
0741      */
0742     next_tsn = asoc->next_tsn;
0743     asoc->ctsn_ack_point = next_tsn - 1;
0744     asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
0745 
0746     /* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
0747      *      incoming and outgoing streams.
0748      */
0749     for (i = 0; i < stream->outcnt; i++) {
0750         SCTP_SO(stream, i)->mid = 0;
0751         SCTP_SO(stream, i)->mid_uo = 0;
0752     }
0753     for (i = 0; i < stream->incnt; i++)
0754         SCTP_SI(stream, i)->mid = 0;
0755 
0756     result = SCTP_STRRESET_PERFORMED;
0757 
0758     *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
0759                             next_tsn, GFP_ATOMIC);
0760 
0761 out:
0762     sctp_update_strreset_result(asoc, result);
0763 err:
0764     return sctp_make_strreset_tsnresp(asoc, result, request_seq,
0765                       next_tsn, init_tsn);
0766 }
0767 
0768 struct sctp_chunk *sctp_process_strreset_addstrm_out(
0769                 struct sctp_association *asoc,
0770                 union sctp_params param,
0771                 struct sctp_ulpevent **evp)
0772 {
0773     struct sctp_strreset_addstrm *addstrm = param.v;
0774     struct sctp_stream *stream = &asoc->stream;
0775     __u32 result = SCTP_STRRESET_DENIED;
0776     __u32 request_seq, incnt;
0777     __u16 in, i;
0778 
0779     request_seq = ntohl(addstrm->request_seq);
0780     if (TSN_lt(asoc->strreset_inseq, request_seq) ||
0781         TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
0782         result = SCTP_STRRESET_ERR_BAD_SEQNO;
0783         goto err;
0784     } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
0785         i = asoc->strreset_inseq - request_seq - 1;
0786         result = asoc->strreset_result[i];
0787         goto err;
0788     }
0789     asoc->strreset_inseq++;
0790 
0791     if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
0792         goto out;
0793 
0794     in = ntohs(addstrm->number_of_streams);
0795     incnt = stream->incnt + in;
0796     if (!in || incnt > SCTP_MAX_STREAM)
0797         goto out;
0798 
0799     if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
0800         goto out;
0801 
0802     if (asoc->strreset_chunk) {
0803         if (!sctp_chunk_lookup_strreset_param(
0804             asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
0805             /* same process with outstanding isn't 0 */
0806             result = SCTP_STRRESET_ERR_IN_PROGRESS;
0807             goto out;
0808         }
0809 
0810         asoc->strreset_outstanding--;
0811         asoc->strreset_outseq++;
0812 
0813         if (!asoc->strreset_outstanding) {
0814             struct sctp_transport *t;
0815 
0816             t = asoc->strreset_chunk->transport;
0817             if (del_timer(&t->reconf_timer))
0818                 sctp_transport_put(t);
0819 
0820             sctp_chunk_put(asoc->strreset_chunk);
0821             asoc->strreset_chunk = NULL;
0822         }
0823     }
0824 
0825     stream->incnt = incnt;
0826 
0827     result = SCTP_STRRESET_PERFORMED;
0828 
0829     *evp = sctp_ulpevent_make_stream_change_event(asoc,
0830         0, ntohs(addstrm->number_of_streams), 0, GFP_ATOMIC);
0831 
0832 out:
0833     sctp_update_strreset_result(asoc, result);
0834 err:
0835     return sctp_make_strreset_resp(asoc, result, request_seq);
0836 }
0837 
0838 struct sctp_chunk *sctp_process_strreset_addstrm_in(
0839                 struct sctp_association *asoc,
0840                 union sctp_params param,
0841                 struct sctp_ulpevent **evp)
0842 {
0843     struct sctp_strreset_addstrm *addstrm = param.v;
0844     struct sctp_stream *stream = &asoc->stream;
0845     __u32 result = SCTP_STRRESET_DENIED;
0846     struct sctp_chunk *chunk = NULL;
0847     __u32 request_seq, outcnt;
0848     __u16 out, i;
0849     int ret;
0850 
0851     request_seq = ntohl(addstrm->request_seq);
0852     if (TSN_lt(asoc->strreset_inseq, request_seq) ||
0853         TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
0854         result = SCTP_STRRESET_ERR_BAD_SEQNO;
0855         goto err;
0856     } else if (TSN_lt(request_seq, asoc->strreset_inseq)) {
0857         i = asoc->strreset_inseq - request_seq - 1;
0858         result = asoc->strreset_result[i];
0859         if (result == SCTP_STRRESET_PERFORMED)
0860             return NULL;
0861         goto err;
0862     }
0863     asoc->strreset_inseq++;
0864 
0865     if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
0866         goto out;
0867 
0868     if (asoc->strreset_outstanding) {
0869         result = SCTP_STRRESET_ERR_IN_PROGRESS;
0870         goto out;
0871     }
0872 
0873     out = ntohs(addstrm->number_of_streams);
0874     outcnt = stream->outcnt + out;
0875     if (!out || outcnt > SCTP_MAX_STREAM)
0876         goto out;
0877 
0878     ret = sctp_stream_alloc_out(stream, outcnt, GFP_ATOMIC);
0879     if (ret)
0880         goto out;
0881 
0882     chunk = sctp_make_strreset_addstrm(asoc, out, 0);
0883     if (!chunk)
0884         goto out;
0885 
0886     asoc->strreset_chunk = chunk;
0887     asoc->strreset_outstanding = 1;
0888     sctp_chunk_hold(asoc->strreset_chunk);
0889 
0890     stream->outcnt = outcnt;
0891 
0892     result = SCTP_STRRESET_PERFORMED;
0893 
0894 out:
0895     sctp_update_strreset_result(asoc, result);
0896 err:
0897     if (!chunk)
0898         chunk = sctp_make_strreset_resp(asoc, result, request_seq);
0899 
0900     return chunk;
0901 }
0902 
0903 struct sctp_chunk *sctp_process_strreset_resp(
0904                 struct sctp_association *asoc,
0905                 union sctp_params param,
0906                 struct sctp_ulpevent **evp)
0907 {
0908     struct sctp_stream *stream = &asoc->stream;
0909     struct sctp_strreset_resp *resp = param.v;
0910     struct sctp_transport *t;
0911     __u16 i, nums, flags = 0;
0912     struct sctp_paramhdr *req;
0913     __u32 result;
0914 
0915     req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
0916     if (!req)
0917         return NULL;
0918 
0919     result = ntohl(resp->result);
0920     if (result != SCTP_STRRESET_PERFORMED) {
0921         /* if in progress, do nothing but retransmit */
0922         if (result == SCTP_STRRESET_IN_PROGRESS)
0923             return NULL;
0924         else if (result == SCTP_STRRESET_DENIED)
0925             flags = SCTP_STREAM_RESET_DENIED;
0926         else
0927             flags = SCTP_STREAM_RESET_FAILED;
0928     }
0929 
0930     if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
0931         struct sctp_strreset_outreq *outreq;
0932         __be16 *str_p;
0933 
0934         outreq = (struct sctp_strreset_outreq *)req;
0935         str_p = outreq->list_of_streams;
0936         nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
0937                sizeof(__u16);
0938 
0939         if (result == SCTP_STRRESET_PERFORMED) {
0940             struct sctp_stream_out *sout;
0941             if (nums) {
0942                 for (i = 0; i < nums; i++) {
0943                     sout = SCTP_SO(stream, ntohs(str_p[i]));
0944                     sout->mid = 0;
0945                     sout->mid_uo = 0;
0946                 }
0947             } else {
0948                 for (i = 0; i < stream->outcnt; i++) {
0949                     sout = SCTP_SO(stream, i);
0950                     sout->mid = 0;
0951                     sout->mid_uo = 0;
0952                 }
0953             }
0954         }
0955 
0956         flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
0957 
0958         for (i = 0; i < stream->outcnt; i++)
0959             SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
0960 
0961         *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
0962             nums, str_p, GFP_ATOMIC);
0963     } else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
0964         struct sctp_strreset_inreq *inreq;
0965         __be16 *str_p;
0966 
0967         /* if the result is performed, it's impossible for inreq */
0968         if (result == SCTP_STRRESET_PERFORMED)
0969             return NULL;
0970 
0971         inreq = (struct sctp_strreset_inreq *)req;
0972         str_p = inreq->list_of_streams;
0973         nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
0974                sizeof(__u16);
0975 
0976         flags |= SCTP_STREAM_RESET_INCOMING_SSN;
0977 
0978         *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
0979             nums, str_p, GFP_ATOMIC);
0980     } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
0981         struct sctp_strreset_resptsn *resptsn;
0982         __u32 stsn, rtsn;
0983 
0984         /* check for resptsn, as sctp_verify_reconf didn't do it*/
0985         if (ntohs(param.p->length) != sizeof(*resptsn))
0986             return NULL;
0987 
0988         resptsn = (struct sctp_strreset_resptsn *)resp;
0989         stsn = ntohl(resptsn->senders_next_tsn);
0990         rtsn = ntohl(resptsn->receivers_next_tsn);
0991 
0992         if (result == SCTP_STRRESET_PERFORMED) {
0993             __u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
0994                         &asoc->peer.tsn_map);
0995             LIST_HEAD(temp);
0996 
0997             asoc->stream.si->report_ftsn(&asoc->ulpq, mtsn);
0998 
0999             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 }