sctp: implement handle_ftsn for sctp_stream_interleave
authorXin Long <lucien.xin@gmail.com>
Thu, 14 Dec 2017 16:41:29 +0000 (00:41 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 15 Dec 2017 18:52:22 +0000 (13:52 -0500)
handle_ftsn is added as a member of sctp_stream_interleave, used to skip
ssn for data or mid for idata, called for SCTP_CMD_PROCESS_FWDTSN cmd.

sctp_handle_iftsn works for ifwdtsn, and sctp_handle_fwdtsn works for
fwdtsn. Note that different from sctp_handle_fwdtsn, sctp_handle_iftsn
could do stream abort pd.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo R. Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sctp/stream_interleave.h
net/sctp/sm_sideeffect.c
net/sctp/stream_interleave.c

index 0b55c70ac5af1fd23b5676d76f4a6ead970cd46b..6657711c8bc4383aab312e0e9dad28cb587c14d9 100644 (file)
@@ -52,6 +52,8 @@ struct sctp_stream_interleave {
        void    (*generate_ftsn)(struct sctp_outq *q, __u32 ctsn);
        bool    (*validate_ftsn)(struct sctp_chunk *chunk);
        void    (*report_ftsn)(struct sctp_ulpq *ulpq, __u32 ftsn);
+       void    (*handle_ftsn)(struct sctp_ulpq *ulpq,
+                              struct sctp_chunk *chunk);
 };
 
 void sctp_stream_interleave_init(struct sctp_stream *stream);
index be7c6dbdb2830de8fc7b7190a24acb0c5b14e024..16ddf2ca14386d9c3d893d7d81677fb51fa4ffbb 100644 (file)
@@ -1007,18 +1007,6 @@ static void sctp_cmd_process_operr(struct sctp_cmd_seq *cmds,
        }
 }
 
-/* Process variable FWDTSN chunk information. */
-static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq,
-                                   struct sctp_chunk *chunk)
-{
-       struct sctp_fwdtsn_skip *skip;
-
-       /* Walk through all the skipped SSNs */
-       sctp_walk_fwdtsn(skip, chunk) {
-               sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));
-       }
-}
-
 /* Helper function to remove the association non-primary peer
  * transports.
  */
@@ -1372,7 +1360,8 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
                        break;
 
                case SCTP_CMD_PROCESS_FWDTSN:
-                       sctp_cmd_process_fwdtsn(&asoc->ulpq, cmd->obj.chunk);
+                       asoc->stream.si->handle_ftsn(&asoc->ulpq,
+                                                    cmd->obj.chunk);
                        break;
 
                case SCTP_CMD_GEN_SACK:
index f62771ccaf5d1a8534be0d1abd885b564d2c8d3e..8c7cf8f08711f93a460354faa220d3d564dcbe75 100644 (file)
@@ -1239,6 +1239,53 @@ static void sctp_report_iftsn(struct sctp_ulpq *ulpq, __u32 ftsn)
                sctp_intl_abort_pd(ulpq, GFP_ATOMIC);
 }
 
+static void sctp_handle_fwdtsn(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk)
+{
+       struct sctp_fwdtsn_skip *skip;
+
+       /* Walk through all the skipped SSNs */
+       sctp_walk_fwdtsn(skip, chunk)
+               sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));
+}
+
+static void sctp_intl_skip(struct sctp_ulpq *ulpq, __u16 sid, __u32 mid,
+                          __u8 flags)
+{
+       struct sctp_stream_in *sin = sctp_stream_in(ulpq->asoc, sid);
+       struct sctp_stream *stream  = &ulpq->asoc->stream;
+
+       if (flags & SCTP_FTSN_U_BIT) {
+               if (sin->pd_mode_uo && MID_lt(sin->mid_uo, mid)) {
+                       sin->pd_mode_uo = 0;
+                       sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x1,
+                                                 GFP_ATOMIC);
+               }
+               return;
+       }
+
+       if (MID_lt(mid, sctp_mid_peek(stream, in, sid)))
+               return;
+
+       if (sin->pd_mode) {
+               sin->pd_mode = 0;
+               sctp_intl_stream_abort_pd(ulpq, sid, mid, 0x0, GFP_ATOMIC);
+       }
+
+       sctp_mid_skip(stream, in, sid, mid);
+
+       sctp_intl_reap_ordered(ulpq, sid);
+}
+
+static void sctp_handle_iftsn(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk)
+{
+       struct sctp_ifwdtsn_skip *skip;
+
+       /* Walk through all the skipped MIDs and abort stream pd if possible */
+       sctp_walk_ifwdtsn(skip, chunk)
+               sctp_intl_skip(ulpq, ntohs(skip->stream),
+                              ntohl(skip->mid), skip->flags);
+}
+
 static struct sctp_stream_interleave sctp_stream_interleave_0 = {
        .data_chunk_len         = sizeof(struct sctp_data_chunk),
        .ftsn_chunk_len         = sizeof(struct sctp_fwdtsn_chunk),
@@ -1255,6 +1302,7 @@ static struct sctp_stream_interleave sctp_stream_interleave_0 = {
        .generate_ftsn          = sctp_generate_fwdtsn,
        .validate_ftsn          = sctp_validate_fwdtsn,
        .report_ftsn            = sctp_report_fwdtsn,
+       .handle_ftsn            = sctp_handle_fwdtsn,
 };
 
 static struct sctp_stream_interleave sctp_stream_interleave_1 = {
@@ -1273,6 +1321,7 @@ static struct sctp_stream_interleave sctp_stream_interleave_1 = {
        .generate_ftsn          = sctp_generate_iftsn,
        .validate_ftsn          = sctp_validate_iftsn,
        .report_ftsn            = sctp_report_iftsn,
+       .handle_ftsn            = sctp_handle_iftsn,
 };
 
 void sctp_stream_interleave_init(struct sctp_stream *stream)