sctp: implement receiver-side procedures for the Add Incoming Streams Request Parameter
authorXin Long <lucien.xin@gmail.com>
Fri, 10 Mar 2017 04:11:10 +0000 (12:11 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Mar 2017 06:22:24 +0000 (23:22 -0700)
This patch is to implement Receiver-Side Procedures for the Add Incoming
Streams Request Parameter described in rfc6525 section 5.2.6.

It is also to fix that it shouldn't have add streams when sending addstrm
in request, as the process in peer will handle it by sending a addstrm out
request back.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sctp/sm.h
net/sctp/sm_statefuns.c
net/sctp/stream.c

index 93ae50bbfa99a4200affcc24ce1b8a33b5d11100..e0d9825886420f71bbae04c9762862b70eb00b01 100644 (file)
@@ -301,6 +301,10 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out(
                                struct sctp_association *asoc,
                                union sctp_params param,
                                struct sctp_ulpevent **evp);
+struct sctp_chunk *sctp_process_strreset_addstrm_in(
+                               struct sctp_association *asoc,
+                               union sctp_params param,
+                               struct sctp_ulpevent **evp);
 
 /* Prototypes for statetable processing. */
 
index 881122b8c3707e4a99f17219da84eaaf0964c300..a8687a78ed41d66d99fb8980fd767337e538e778 100644 (file)
@@ -3878,6 +3878,9 @@ sctp_disposition_t sctp_sf_do_reconf(struct net *net,
                else if (param.p->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS)
                        reply = sctp_process_strreset_addstrm_out(
                                (struct sctp_association *)asoc, param, &ev);
+               else if (param.p->type == SCTP_PARAM_RESET_ADD_IN_STREAMS)
+                       reply = sctp_process_strreset_addstrm_in(
+                               (struct sctp_association *)asoc, param, &ev);
                /* More handles for other types will be added here, by now it
                 * just ignores other types.
                 */
index df2794db05d3cd36b09fc041c44a717a4f440e5c..1c925db2e914168b5f4b89a600977fd260fc6f99 100644 (file)
@@ -267,18 +267,6 @@ int sctp_send_add_streams(struct sctp_association *asoc,
                stream->out = streamout;
        }
 
-       if (in) {
-               struct sctp_stream_in *streamin;
-
-               streamin = krealloc(stream->in, incnt * sizeof(*streamin),
-                                   GFP_KERNEL);
-               if (!streamin)
-                       goto out;
-
-               memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
-               stream->in = streamin;
-       }
-
        chunk = sctp_make_strreset_addstrm(asoc, out, in);
        if (!chunk)
                goto out;
@@ -625,3 +613,65 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out(
 out:
        return sctp_make_strreset_resp(asoc, result, request_seq);
 }
+
+struct sctp_chunk *sctp_process_strreset_addstrm_in(
+                               struct sctp_association *asoc,
+                               union sctp_params param,
+                               struct sctp_ulpevent **evp)
+{
+       struct sctp_strreset_addstrm *addstrm = param.v;
+       struct sctp_stream *stream = asoc->stream;
+       __u32 result = SCTP_STRRESET_DENIED;
+       struct sctp_stream_out *streamout;
+       struct sctp_chunk *chunk = NULL;
+       __u32 request_seq, outcnt;
+       __u16 out;
+
+       request_seq = ntohl(addstrm->request_seq);
+       if (request_seq > asoc->strreset_inseq) {
+               result = SCTP_STRRESET_ERR_BAD_SEQNO;
+               goto out;
+       } else if (request_seq == asoc->strreset_inseq) {
+               asoc->strreset_inseq++;
+       }
+
+       if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
+               goto out;
+
+       if (asoc->strreset_outstanding) {
+               result = SCTP_STRRESET_ERR_IN_PROGRESS;
+               goto out;
+       }
+
+       out = ntohs(addstrm->number_of_streams);
+       outcnt = stream->outcnt + out;
+       if (!out || outcnt > SCTP_MAX_STREAM)
+               goto out;
+
+       streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
+                            GFP_ATOMIC);
+       if (!streamout)
+               goto out;
+
+       memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
+       stream->out = streamout;
+
+       chunk = sctp_make_strreset_addstrm(asoc, out, 0);
+       if (!chunk)
+               goto out;
+
+       asoc->strreset_chunk = chunk;
+       asoc->strreset_outstanding = 1;
+       sctp_chunk_hold(asoc->strreset_chunk);
+
+       stream->outcnt = outcnt;
+
+       *evp = sctp_ulpevent_make_stream_change_event(asoc,
+               0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
+
+out:
+       if (!chunk)
+               chunk = sctp_make_strreset_resp(asoc, result, request_seq);
+
+       return chunk;
+}