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

The process is kind of complicate, it's wonth having some comments
from section 6.2.4 in the codes.

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 b6f682ec184a62a1e7b9d2a0ea159293cca12a76..2629d6670a27661714ad1d553fb7671a2a97bca8 100644 (file)
@@ -293,6 +293,10 @@ struct sctp_chunk *sctp_process_strreset_inreq(
                                struct sctp_association *asoc,
                                union sctp_params param,
                                struct sctp_ulpevent **evp);
+struct sctp_chunk *sctp_process_strreset_tsnreq(
+                               struct sctp_association *asoc,
+                               union sctp_params param,
+                               struct sctp_ulpevent **evp);
 
 /* Prototypes for statetable processing. */
 
index e03bb1aab4d095b65259c33f4fba6990e90f586b..6982064957a76494ceff3f950b03296e2a8ca215 100644 (file)
@@ -3872,6 +3872,9 @@ sctp_disposition_t sctp_sf_do_reconf(struct net *net,
                else if (param.p->type == SCTP_PARAM_RESET_IN_REQUEST)
                        reply = sctp_process_strreset_inreq(
                                (struct sctp_association *)asoc, param, &ev);
+               else if (param.p->type == SCTP_PARAM_RESET_TSN_REQUEST)
+                       reply = sctp_process_strreset_tsnreq(
+                               (struct sctp_association *)asoc, param, &ev);
                /* More handles for other types will be added here, by now it
                 * just ignores other types.
                 */
index 1c6cc04fa3a41f7266597f9cd80420c228094a2b..7e993b0c1412092964c936c4ecdc1e66022b0375 100644 (file)
@@ -477,3 +477,82 @@ out:
 
        return chunk;
 }
+
+struct sctp_chunk *sctp_process_strreset_tsnreq(
+                               struct sctp_association *asoc,
+                               union sctp_params param,
+                               struct sctp_ulpevent **evp)
+{
+       __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
+       struct sctp_strreset_tsnreq *tsnreq = param.v;
+       struct sctp_stream *stream = asoc->stream;
+       __u32 result = SCTP_STRRESET_DENIED;
+       __u32 request_seq;
+       __u16 i;
+
+       request_seq = ntohl(tsnreq->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_RESET_ASSOC_REQ))
+               goto out;
+
+       if (asoc->strreset_outstanding) {
+               result = SCTP_STRRESET_ERR_IN_PROGRESS;
+               goto out;
+       }
+
+       /* G3: The same processing as though a SACK chunk with no gap report
+        *     and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
+        *     received MUST be performed.
+        */
+       max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
+       sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
+       sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
+
+       /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
+        *     TSN that the peer should use to send the next DATA chunk.  The
+        *     value SHOULD be the smallest TSN not acknowledged by the
+        *     receiver of the request plus 2^31.
+        */
+       init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
+       sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
+                        init_tsn, GFP_ATOMIC);
+
+       /* G4: The same processing as though a FWD-TSN chunk (as defined in
+        *     [RFC3758]) with all streams affected and a new cumulative TSN
+        *     ACK of the Receiver's Next TSN minus 1 were received MUST be
+        *     performed.
+        */
+       sctp_outq_free(&asoc->outqueue);
+
+       /* G2: Compute an appropriate value for the local endpoint's next TSN,
+        *     i.e., the next TSN assigned by the receiver of the SSN/TSN reset
+        *     chunk.  The value SHOULD be the highest TSN sent by the receiver
+        *     of the request plus 1.
+        */
+       next_tsn = asoc->next_tsn;
+       asoc->ctsn_ack_point = next_tsn - 1;
+       asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
+
+       /* G5:  The next expected and outgoing SSNs MUST be reset to 0 for all
+        *      incoming and outgoing streams.
+        */
+       for (i = 0; i < stream->outcnt; i++)
+               stream->out[i].ssn = 0;
+       for (i = 0; i < stream->incnt; i++)
+               stream->in[i].ssn = 0;
+
+       result = SCTP_STRRESET_PERFORMED;
+
+       *evp = sctp_ulpevent_make_assoc_reset_event(asoc, 0, init_tsn,
+                                                   next_tsn, GFP_ATOMIC);
+
+out:
+       return sctp_make_strreset_tsnresp(asoc, result, request_seq,
+                                         next_tsn, init_tsn);
+}