Blame SOURCES/wireshark-0026-mptcp.patch

6f145f
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
6f145f
index 36e8afb2a3..73f4a2647a 100644
6f145f
--- a/epan/dissectors/packet-tcp.c
6f145f
+++ b/epan/dissectors/packet-tcp.c
6f145f
@@ -285,7 +285,9 @@ static int hf_mptcp_analysis_subflows_stream_id = -1;
6f145f
 static int hf_mptcp_analysis_subflows = -1;
6f145f
 static int hf_mptcp_number_of_removed_addresses = -1;
6f145f
 static int hf_mptcp_related_mapping = -1;
6f145f
-static int hf_mptcp_duplicated_data = -1;
6f145f
+static int hf_mptcp_reinjection_of = -1;
6f145f
+static int hf_mptcp_reinjected_in = -1;
6f145f
+
6f145f
 
6f145f
 static int hf_tcp_option_fast_open_cookie_request = -1;
6f145f
 static int hf_tcp_option_fast_open_cookie = -1;
6f145f
@@ -1455,8 +1457,8 @@ mptcp_init_subflow(tcp_flow_t *flow)
6f145f
 
6f145f
     DISSECTOR_ASSERT(flow->mptcp_subflow == 0);
6f145f
     flow->mptcp_subflow = sf;
6f145f
-    sf->mappings        = wmem_itree_new(wmem_file_scope());
6f145f
-    sf->dsn_map         = wmem_itree_new(wmem_file_scope());
6f145f
+    sf->ssn2dsn_mappings        = wmem_itree_new(wmem_file_scope());
6f145f
+    sf->dsn2packet_map         = wmem_itree_new(wmem_file_scope());
6f145f
 }
6f145f
 
6f145f
 
6f145f
@@ -2607,13 +2609,13 @@ guint64 rawdsn64low, guint64 rawdsn64high
6f145f
     mptcp_dsn2packet_mapping_t *packet = NULL;
6f145f
     proto_item *item = NULL;
6f145f
 
6f145f
-    results = wmem_itree_find_intervals(subflow->mappings,
6f145f
+    results = wmem_itree_find_intervals(subflow->dsn2packet_map,
6f145f
                     wmem_packet_scope(),
6f145f
                     rawdsn64low,
6f145f
                     rawdsn64high
6f145f
                     );
6f145f
 
6f145f
-    for(packet_it=wmem_list_head(results);
6f145f
+    for(packet_it = wmem_list_head(results);
6f145f
         packet_it != NULL;
6f145f
         packet_it = wmem_list_frame_next(packet_it))
6f145f
     {
6f145f
@@ -2621,43 +2623,18 @@ guint64 rawdsn64low, guint64 rawdsn64high
6f145f
         packet = (mptcp_dsn2packet_mapping_t *) wmem_list_frame_data(packet_it);
6f145f
         DISSECTOR_ASSERT(packet);
6f145f
 
6f145f
-        item = proto_tree_add_uint(tree, hf_mptcp_duplicated_data, tvb, 0, 0, packet->frame);
6f145f
+        if(pinfo->num > packet->frame) {
6f145f
+            item = proto_tree_add_uint(tree, hf_mptcp_reinjection_of, tvb, 0, 0, packet->frame);
6f145f
+        }
6f145f
+        else {
6f145f
+            item = proto_tree_add_uint(tree, hf_mptcp_reinjected_in, tvb, 0, 0, packet->frame);
6f145f
+        }
6f145f
         PROTO_ITEM_SET_GENERATED(item);
6f145f
     }
6f145f
 
6f145f
     return packet;
6f145f
 }
6f145f
 
6f145f
-/* Finds mappings that cover the sent data */
6f145f
-static mptcp_dss_mapping_t *
6f145f
-mptcp_add_matching_dss_on_subflow(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, struct mptcp_subflow *subflow,
6f145f
-guint32 relseq, guint32 seglen
6f145f
-)
6f145f
-{
6f145f
-    wmem_list_t *results = NULL;
6f145f
-    wmem_list_frame_t *dss_it = NULL;
6f145f
-    mptcp_dss_mapping_t *mapping = NULL;
6f145f
-    proto_item *item = NULL;
6f145f
-
6f145f
-    results = wmem_itree_find_intervals(subflow->mappings,
6f145f
-                    wmem_packet_scope(),
6f145f
-                    relseq,
6f145f
-                    (seglen) ? relseq + seglen - 1 : relseq
6f145f
-                    );
6f145f
-
6f145f
-    for(dss_it=wmem_list_head(results);
6f145f
-        dss_it!= NULL;
6f145f
-        dss_it= wmem_list_frame_next(dss_it))
6f145f
-    {
6f145f
-        mapping = (mptcp_dss_mapping_t *) wmem_list_frame_data(dss_it);
6f145f
-        DISSECTOR_ASSERT(mapping);
6f145f
-
6f145f
-        item = proto_tree_add_uint(tree, hf_mptcp_related_mapping, tvb, 0, 0, mapping->frame);
6f145f
-        PROTO_ITEM_SET_GENERATED(item);
6f145f
-    }
6f145f
-
6f145f
-    return mapping;
6f145f
-}
6f145f
 
6f145f
 /* Lookup mappings that describe the packet and then converts the tcp seq number
6f145f
  * into the MPTCP Data Sequence Number (DSN)
6f145f
@@ -2698,13 +2675,29 @@ mptcp_analysis_dsn_lookup(packet_info *pinfo , tvbuff_t *tvb,
6f145f
         rawdsn = tcpd->fwd->mptcp_subflow->meta->base_dsn;
6f145f
         convert = DSN_CONV_NONE;
6f145f
     }
6f145f
+    /* if it's a non-syn packet without data (just used to convey TCP options)
6f145f
+     * then there would be no mappings */
6f145f
+    else if(relseq == 1 && tcph->th_seglen == 0) {
6f145f
+        rawdsn = tcpd->fwd->mptcp_subflow->meta->base_dsn + 1;
6f145f
+        convert = DSN_CONV_NONE;
6f145f
+    }
6f145f
     else {
6f145f
-        /* display packets that conveyed the mappings covering the data range */
6f145f
-        mapping = mptcp_add_matching_dss_on_subflow(pinfo, parent_tree, tvb,
6f145f
-                            tcpd->fwd->mptcp_subflow, relseq,
6f145f
-                            (tcph->th_have_seglen) ? tcph->th_seglen : 0
6f145f
-                                                    );
6f145f
-        if(mapping == NULL) {
6f145f
+
6f145f
+        wmem_list_frame_t *dss_it = NULL;
6f145f
+        wmem_list_t *results = NULL;
6f145f
+        guint32 ssn_low = relseq;
6f145f
+        guint32 seglen = tcph->th_seglen;
6f145f
+
6f145f
+        results = wmem_itree_find_intervals(tcpd->fwd->mptcp_subflow->ssn2dsn_mappings,
6f145f
+                    wmem_packet_scope(),
6f145f
+                    ssn_low,
6f145f
+                    (seglen) ? ssn_low + seglen - 1 : ssn_low
6f145f
+                    );
6f145f
+        dss_it = wmem_list_head(results); /* assume it's always ok */
6f145f
+        if(dss_it) {
6f145f
+            mapping = (mptcp_dss_mapping_t *) wmem_list_frame_data(dss_it);
6f145f
+        }
6f145f
+        if(dss_it == NULL || mapping == NULL) {
6f145f
             expert_add_info(pinfo, parent_tree, &ei_mptcp_mapping_missing);
6f145f
             return;
6f145f
         }
6f145f
@@ -2713,6 +2706,19 @@ mptcp_analysis_dsn_lookup(packet_info *pinfo , tvbuff_t *tvb,
6f145f
         }
6f145f
 
6f145f
         DISSECTOR_ASSERT(mapping);
6f145f
+        if(seglen) {
6f145f
+            /* Finds mappings that cover the sent data and adds them to the dissection tree */
6f145f
+            for(dss_it = wmem_list_head(results);
6f145f
+                dss_it != NULL;
6f145f
+                dss_it = wmem_list_frame_next(dss_it))
6f145f
+            {
6f145f
+                mapping = (mptcp_dss_mapping_t *) wmem_list_frame_data(dss_it);
6f145f
+                DISSECTOR_ASSERT(mapping);
6f145f
+
6f145f
+                item = proto_tree_add_uint(parent_tree, hf_mptcp_related_mapping, tvb, 0, 0, mapping->frame);
6f145f
+                PROTO_ITEM_SET_GENERATED(item);
6f145f
+            }
6f145f
+        }
6f145f
 
6f145f
         convert = (mapping->extended_dsn) ? DSN_CONV_NONE : DSN_CONV_32_TO_64;
6f145f
         DISSECTOR_ASSERT(mptcp_map_relssn_to_rawdsn(mapping, relseq, &rawdsn));
6f145f
@@ -2732,39 +2738,40 @@ mptcp_analysis_dsn_lookup(packet_info *pinfo , tvbuff_t *tvb,
6f145f
             proto_item_append_text(item, " (Relative)");
6f145f
         }
6f145f
 
6f145f
-        /* register */
6f145f
-        if (!PINFO_FD_VISITED(pinfo))
6f145f
-        {
6f145f
-            mptcp_dsn2packet_mapping_t *packet;
6f145f
-            packet = wmem_new0(wmem_file_scope(), mptcp_dsn2packet_mapping_t);
6f145f
-            packet->frame = pinfo->fd->num;
6f145f
-            packet->subflow = tcpd;
6f145f
-
6f145f
-            /* tcph->th_mptcp->mh_rawdsn64 */
6f145f
-            if (tcph->th_have_seglen) {
6f145f
-                wmem_itree_insert(tcpd->fwd->mptcp_subflow->dsn_map,
6f145f
+        /* register dsn->packet mapping */
6f145f
+        if(mptcp_intersubflows_retransmission
6f145f
+            && !PINFO_FD_VISITED(pinfo)
6f145f
+            && tcph->th_seglen > 0
6f145f
+          ) {
6f145f
+                mptcp_dsn2packet_mapping_t *packet = 0;
6f145f
+                packet = wmem_new0(wmem_file_scope(), mptcp_dsn2packet_mapping_t);
6f145f
+                packet->frame = pinfo->fd->num;
6f145f
+                packet->subflow = tcpd;
6f145f
+
6f145f
+                wmem_itree_insert(tcpd->fwd->mptcp_subflow->dsn2packet_map,
6f145f
                         tcph->th_mptcp->mh_rawdsn64,
6f145f
                         tcph->th_mptcp->mh_rawdsn64 + (tcph->th_seglen - 1 ),
6f145f
                         packet
6f145f
                         );
6f145f
-            }
6f145f
         }
6f145f
         PROTO_ITEM_SET_GENERATED(item);
6f145f
 
6f145f
         /* We can do this only if rawdsn64 is valid !
6f145f
         if enabled, look for overlapping mappings on other subflows */
6f145f
-        if(mptcp_intersubflows_retransmission) {
6f145f
+        if(mptcp_intersubflows_retransmission
6f145f
+            && tcph->th_have_seglen
6f145f
+            && tcph->th_seglen) {
6f145f
 
6f145f
             wmem_list_frame_t *subflow_it = NULL;
6f145f
 
6f145f
-            /* results should be some kind of  in case 2 DSS are needed to cover this packet */
6f145f
+            /* results should be some kind of list in case 2 DSS are needed to cover this packet */
6f145f
             for(subflow_it = wmem_list_head(mptcpd->subflows); subflow_it != NULL; subflow_it = wmem_list_frame_next(subflow_it)) {
6f145f
                 struct tcp_analysis *sf_tcpd = (struct tcp_analysis *)wmem_list_frame_data(subflow_it);
6f145f
                 struct mptcp_subflow *sf = mptcp_select_subflow_from_meta(sf_tcpd, tcpd->fwd->mptcp_subflow->meta);
6f145f
 
6f145f
                 /* for current subflow */
6f145f
                 if (sf == tcpd->fwd->mptcp_subflow) {
6f145f
-                    /* skip, was done just before */
6f145f
+                    /* skip, this is the current subflow */
6f145f
                 }
6f145f
                 /* in case there were retransmissions on other subflows */
6f145f
                 else  {
6f145f
@@ -2776,7 +2783,7 @@ mptcp_analysis_dsn_lookup(packet_info *pinfo , tvbuff_t *tvb,
6f145f
         }
6f145f
     }
6f145f
     else {
6f145f
-        /* ignore and continue */
6f145f
+        /* could not get the rawdsn64, ignore and continue */
6f145f
     }
6f145f
 
6f145f
 }
6f145f
@@ -4590,7 +4597,6 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
 
6f145f
                     if (!PINFO_FD_VISITED(pinfo))
6f145f
                     {
6f145f
-
6f145f
                         /* register SSN range described by the mapping into a subflow interval_tree */
6f145f
                         mptcp_dss_mapping_t *mapping = NULL;
6f145f
                         mapping = wmem_new0(wmem_file_scope(), mptcp_dss_mapping_t);
6f145f
@@ -4601,7 +4607,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                         mapping->ssn_low = mph->mh_dss_ssn;
6f145f
                         mapping->ssn_high = mph->mh_dss_ssn + mph->mh_dss_length-1;
6f145f
 
6f145f
-                        wmem_itree_insert(tcpd->fwd->mptcp_subflow->mappings,
6f145f
+                        wmem_itree_insert(tcpd->fwd->mptcp_subflow->ssn2dsn_mappings,
6f145f
                             mph->mh_dss_ssn,
6f145f
                             mapping->ssn_high,
6f145f
                             mapping
6f145f
@@ -7564,15 +7570,19 @@ proto_register_tcp(void)
6f145f
             "This frame has some of the MPTCP analysis shown", HFILL }},
6f145f
 
6f145f
         { &hf_mptcp_related_mapping,
6f145f
-          { "Related mapping",   "mptcp.related_mapping", FT_FRAMENUM , BASE_NONE, NULL, 0x0,
6f145f
-            "Packet in which mapping describing current packet was sent", HFILL }},
6f145f
+          { "Related mapping", "mptcp.related_mapping", FT_FRAMENUM , BASE_NONE, NULL, 0x0,
6f145f
+            "Packet in which current packet DSS mapping was sent", HFILL }},
6f145f
+
6f145f
+        { &hf_mptcp_reinjection_of,
6f145f
+          { "Reinjection of", "mptcp.reinjection_of", FT_FRAMENUM , BASE_NONE, NULL, 0x0,
6f145f
+            "This is a retransmission of data sent on another subflow", HFILL }},
6f145f
 
6f145f
-        { &hf_mptcp_duplicated_data,
6f145f
-          { "Was data duplicated",   "mptcp.duplicated_dsn", FT_FRAMENUM , BASE_NONE, NULL, 0x0,
6f145f
+        { &hf_mptcp_reinjected_in,
6f145f
+          { "Data reinjected in", "mptcp.reinjected_in", FT_FRAMENUM , BASE_NONE, NULL, 0x0,
6f145f
             "This was retransmitted on another subflow", HFILL }},
6f145f
 
6f145f
         { &hf_mptcp_analysis_subflows,
6f145f
-          { "TCP subflow stream id(s):",   "mptcp.analysis.subflows", FT_NONE, BASE_NONE, NULL, 0x0,
6f145f
+          { "TCP subflow stream id(s):", "mptcp.analysis.subflows", FT_NONE, BASE_NONE, NULL, 0x0,
6f145f
             "List all TCP connections mapped to this MPTCP connection", HFILL }},
6f145f
 
6f145f
         { &hf_mptcp_stream,
6f145f
@@ -7752,13 +7762,16 @@ proto_register_tcp(void)
6f145f
         &mptcp_relative_seq);
6f145f
 
6f145f
     prefs_register_bool_preference(mptcp_module, "analyze_mappings",
6f145f
-        "In depth analysis of Data Sequence Signal (DSS) mappings.",
6f145f
+        "Deeper analysis of Data Sequence Signal (DSS)",
6f145f
+        "Scales logarithmically with the number of packets"
6f145f
         "You need to capture the handshake for this to work."
6f145f
         "\"Map TCP subflows to their respective MPTCP connections\"",
6f145f
         &mptcp_analyze_mappings);
6f145f
 
6f145f
     prefs_register_bool_preference(mptcp_module, "intersubflows_retransmission",
6f145f
         "Check for data duplication across subflows",
6f145f
+        "(Greedy algorithm: Scales linearly with number of subflows and"
6f145f
+        " logarithmic scaling with number of packets)"
6f145f
         "You need to enable DSS mapping analysis for this option to work",
6f145f
         &mptcp_intersubflows_retransmission);
6f145f
 
6f145f
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
6f145f
index 7f84351ade..c1811fa049 100644
6f145f
--- a/epan/dissectors/packet-tcp.h
6f145f
+++ b/epan/dissectors/packet-tcp.h
6f145f
@@ -257,15 +257,16 @@ struct mptcp_subflow {
6f145f
 	guint8 address_id;   /* sent during an MP_JOIN */
6f145f
 
6f145f
 
6f145f
-	/* Attempt to map DSN to packets
6f145f
-	 * Ideally this was to generate application latency
6f145f
-	 * each node contains a GSList * ?
6f145f
-	 * this should be done in tap or 3rd party tools
6f145f
+	/* map DSN to packets
6f145f
+	 * Used when looking for reinjections across subflows
6f145f
 	 */
6f145f
-	wmem_itree_t *dsn_map;
6f145f
+	wmem_itree_t *dsn2packet_map;
6f145f
 
6f145f
-	/* Map SSN to a DSS mappings, each node registers a mptcp_dss_mapping_t */
6f145f
-	wmem_itree_t *mappings;
6f145f
+	/* Map SSN to a DSS mappings
6f145f
+	 * a DSS can map DSN to SSNs possibily over several packets,
6f145f
+	 * hence some packets may have been mapped by previous DSS,
6f145f
+	 * whence the necessity to be able to look for SSN -> DSN */
6f145f
+	wmem_itree_t *ssn2dsn_mappings;
6f145f
 	/* meta flow to which it is attached. Helps setting forward and backward meta flow */
6f145f
 	mptcp_meta_flow_t *meta;
6f145f
 };
6f145f
diff --git a/epan/wmem/wmem_interval_tree.c b/epan/wmem/wmem_interval_tree.c
6f145f
index d52267de18..48888996b7 100644
6f145f
--- a/epan/wmem/wmem_interval_tree.c
6f145f
+++ b/epan/wmem/wmem_interval_tree.c
6f145f
@@ -121,7 +121,7 @@ wmem_itree_insert(wmem_itree_t *tree, const guint64 low, const guint64 high, voi
6f145f
     node = wmem_tree_insert(tree, range, data, (compare_func)wmem_tree_compare_ranges);
6f145f
 
6f145f
     /* Even If no rotations, still a need to update max_edge */
6f145f
-    update_max_edge(node);
6f145f
+    update_max_edge(node->parent);
6f145f
 }
6f145f
 
6f145f
 
6f145f
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
6f145f
index 74e9b6b10c..efcfa005af 100644
6f145f
--- a/epan/dissectors/packet-tcp.c
6f145f
+++ b/epan/dissectors/packet-tcp.c
6f145f
@@ -4361,6 +4361,35 @@ get_or_create_mptcpd_from_key(struct tcp_analysis* tcpd, tcp_flow_t *fwd, guint6
6f145f
     return mptcpd;
6f145f
 }
6f145f
 
6f145f
+/* record this mapping */
6f145f
+static
6f145f
+void analyze_mapping(struct tcp_analysis *tcpd, packet_info *pinfo, guint16 len, guint64 dsn, gboolean extended, guint32 ssn) {
6f145f
+
6f145f
+    /* store mapping only if analysis is enabled and mapping is not unlimited */
6f145f
+    if (!mptcp_analyze_mappings || !len) {
6f145f
+        return;
6f145f
+    }
6f145f
+
6f145f
+    if (PINFO_FD_VISITED(pinfo)) {
6f145f
+        return;
6f145f
+    }
6f145f
+
6f145f
+    /* register SSN range described by the mapping into a subflow interval_tree */
6f145f
+    mptcp_dss_mapping_t *mapping = NULL;
6f145f
+    mapping = wmem_new0(wmem_file_scope(), mptcp_dss_mapping_t);
6f145f
+
6f145f
+    mapping->rawdsn  = dsn;
6f145f
+    mapping->extended_dsn = extended;
6f145f
+    mapping->frame = pinfo->fd->num;
6f145f
+    mapping->ssn_low = ssn;
6f145f
+    mapping->ssn_high = ssn + len - 1;
6f145f
+
6f145f
+    wmem_itree_insert(tcpd->fwd->mptcp_subflow->ssn2dsn_mappings,
6f145f
+        mapping->ssn_low,
6f145f
+        mapping->ssn_high,
6f145f
+        mapping
6f145f
+        );
6f145f
+}
6f145f
 
6f145f
 /*
6f145f
  * The TCP Extensions for Multipath Operation with Multiple Addresses
6f145f
@@ -4449,8 +4478,11 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
             }
6f145f
             offset += 1;
6f145f
 
6f145f
-            /* optlen == 12 => SYN or SYN/ACK; optlen == 20 => ACK */
6f145f
-            if (optlen == 12 || optlen == 20) {
6f145f
+            /* optlen == 12 => SYN or SYN/ACK; optlen == 20 => ACK;
6f145f
+             * optlen == 22 => ACK + data (v1 only);
6f145f
+             * optlen == 24 => ACK + data + csum (v1 only)
6f145f
+             */
6f145f
+            if (optlen == 12 || optlen == 20 || optlen == 22 || optlen == 24) {
6f145f
 
6f145f
                 mph->mh_key = tvb_get_ntoh64(tvb,offset);
6f145f
                 proto_tree_add_uint64(mptcp_tree, hf_tcp_option_mptcp_sender_key, tvb, offset, 8, mph->mh_key);
6f145f
@@ -4468,9 +4500,10 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                 PROTO_ITEM_SET_GENERATED(item);
6f145f
 
6f145f
                 /* last ACK of 3WHS, repeats both keys */
6f145f
-                if (optlen == 20) {
6f145f
+                if (optlen >= 20) {
6f145f
                     guint64 recv_key = tvb_get_ntoh64(tvb,offset);
6f145f
                     proto_tree_add_uint64(mptcp_tree, hf_tcp_option_mptcp_recv_key, tvb, offset, 8, recv_key);
6f145f
+                    offset += 8;
6f145f
 
6f145f
                     if(tcpd->rev->mptcp_subflow->meta
6f145f
                         && (tcpd->rev->mptcp_subflow->meta->static_flags & MPTCP_META_HAS_KEY)) {
6f145f
@@ -4484,6 +4517,26 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                         mptcpd = get_or_create_mptcpd_from_key(tcpd, tcpd->rev, recv_key, mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK);
6f145f
                     }
6f145f
                 }
6f145f
+
6f145f
+                /* MPTCP v1 ACK + data, contains data_len and optional checksum */
6f145f
+                if (optlen >= 22) {
6f145f
+                    proto_tree_add_item(mptcp_tree, hf_tcp_option_mptcp_data_lvl_len, tvb, offset, 2, ENC_BIG_ENDIAN);
6f145f
+                    mph->mh_dss_length = tvb_get_ntohs(tvb,offset);
6f145f
+                    offset += 2;
6f145f
+
6f145f
+                    if (mph->mh_dss_length == 0) {
6f145f
+                        expert_add_info(pinfo, mptcp_tree, &ei_mptcp_infinite_mapping);
6f145f
+                    }
6f145f
+
6f145f
+                    /* when data len is present, this MP_CAPABLE also carries an implicit mapping ... */
6f145f
+                    analyze_mapping(tcpd, pinfo, mph->mh_dss_length, tcpd->fwd->mptcp_subflow->meta->base_dsn + 1, TRUE, tcph->th_seq);
6f145f
+
6f145f
+                    /* ... with optional checksum */
6f145f
+                    if (optlen == 24)
6f145f
+                    {
6f145f
+                        proto_tree_add_checksum(mptcp_tree, tvb, offset, hf_tcp_option_mptcp_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
6f145f
+                    }
6f145f
+                }
6f145f
             }
6f145f
             break;
6f145f
 
6f145f
@@ -4650,29 +4703,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                     /* ignore and continue */
6f145f
                 }
6f145f
 
6f145f
-                /* if mapping analysis enabled and not a */
6f145f
-                if(mptcp_analyze_mappings && mph->mh_dss_length)
6f145f
-                {
6f145f
-
6f145f
-                    if (!PINFO_FD_VISITED(pinfo))
6f145f
-                    {
6f145f
-                        /* register SSN range described by the mapping into a subflow interval_tree */
6f145f
-                        mptcp_dss_mapping_t *mapping = NULL;
6f145f
-                        mapping = wmem_new0(wmem_file_scope(), mptcp_dss_mapping_t);
6f145f
-
6f145f
-                        mapping->rawdsn  = mph->mh_dss_rawdsn;
6f145f
-                        mapping->extended_dsn = (mph->mh_dss_flags & MPTCP_DSS_FLAG_DATA_ACK_8BYTES);
6f145f
-                        mapping->frame = pinfo->fd->num;
6f145f
-                        mapping->ssn_low = mph->mh_dss_ssn;
6f145f
-                        mapping->ssn_high = mph->mh_dss_ssn + mph->mh_dss_length-1;
6f145f
-
6f145f
-                        wmem_itree_insert(tcpd->fwd->mptcp_subflow->ssn2dsn_mappings,
6f145f
-                            mph->mh_dss_ssn,
6f145f
-                            mapping->ssn_high,
6f145f
-                            mapping
6f145f
-                            );
6f145f
-                    }
6f145f
-                }
6f145f
+                analyze_mapping(tcpd, pinfo, mph->mh_dss_length, mph->mh_dss_rawdsn, mph->mh_dss_flags & MPTCP_DSS_FLAG_DATA_ACK_8BYTES, mph->mh_dss_ssn);
6f145f
 
6f145f
                 if ((int)optlen >= offset-start_offset+4)
6f145f
                 {
6f145f
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
6f145f
index efcfa005af..238b592927 100644
6f145f
--- a/epan/dissectors/packet-tcp.c
6f145f
+++ b/epan/dissectors/packet-tcp.c
6f145f
@@ -246,7 +246,8 @@ static int hf_tcp_option_mptcp_flags = -1;
6f145f
 static int hf_tcp_option_mptcp_backup_flag = -1;
6f145f
 static int hf_tcp_option_mptcp_checksum_flag = -1;
6f145f
 static int hf_tcp_option_mptcp_B_flag = -1;
6f145f
-static int hf_tcp_option_mptcp_H_flag = -1;
6f145f
+static int hf_tcp_option_mptcp_H_v0_flag = -1;
6f145f
+static int hf_tcp_option_mptcp_H_v1_flag = -1;
6f145f
 static int hf_tcp_option_mptcp_F_flag = -1;
6f145f
 static int hf_tcp_option_mptcp_m_flag = -1;
6f145f
 static int hf_tcp_option_mptcp_M_flag = -1;
6f145f
@@ -593,10 +594,18 @@ static guint32 mptcp_stream_count;
6f145f
  */
6f145f
 static wmem_tree_t *mptcp_tokens = NULL;
6f145f
 
6f145f
-static const int *tcp_option_mptcp_capable_flags[] = {
6f145f
+static const int *tcp_option_mptcp_capable_v0_flags[] = {
6f145f
   &hf_tcp_option_mptcp_checksum_flag,
6f145f
   &hf_tcp_option_mptcp_B_flag,
6f145f
-  &hf_tcp_option_mptcp_H_flag,
6f145f
+  &hf_tcp_option_mptcp_H_v0_flag,
6f145f
+  &hf_tcp_option_mptcp_reserved_flag,
6f145f
+  NULL
6f145f
+};
6f145f
+
6f145f
+static const int *tcp_option_mptcp_capable_v1_flags[] = {
6f145f
+  &hf_tcp_option_mptcp_checksum_flag,
6f145f
+  &hf_tcp_option_mptcp_B_flag,
6f145f
+  &hf_tcp_option_mptcp_H_v1_flag,
6f145f
   &hf_tcp_option_mptcp_reserved_flag,
6f145f
   NULL
6f145f
 };
6f145f
@@ -2574,6 +2583,24 @@ mptcp_cryptodata_sha1(const guint64 key, guint32 *token, guint64 *idsn)
6f145f
     *idsn = GUINT64_FROM_BE(_isdn);
6f145f
 }
6f145f
 
6f145f
+/* Generate the initial data sequence number and MPTCP connection token from the key. */
6f145f
+static void
6f145f
+mptcp_cryptodata_sha256(const guint64 key, guint32 *token, guint64 *idsn)
6f145f
+{
6f145f
+    guint8 digest_buf[HASH_SHA2_256_LENGTH];
6f145f
+    guint64 pseudokey = GUINT64_TO_BE(key);
6f145f
+    guint32 _token;
6f145f
+    guint64 _isdn;
6f145f
+
6f145f
+    gcry_md_hash_buffer(GCRY_MD_SHA256, digest_buf, (const guint8 *)&pseudokey, 8);
6f145f
+
6f145f
+    /* memcpy to prevent -Wstrict-aliasing errors with GCC 4 */
6f145f
+    memcpy(&_token, digest_buf, sizeof(_token));
6f145f
+    *token = GUINT32_FROM_BE(_token);
6f145f
+    memcpy(&_isdn, digest_buf + HASH_SHA2_256_LENGTH - sizeof(_isdn), sizeof(_isdn));
6f145f
+    *idsn = GUINT64_FROM_BE(_isdn);
6f145f
+}
6f145f
+
6f145f
 
6f145f
 /* Print formatted list of tcp stream ids that are part of the connection */
6f145f
 static void
6f145f
@@ -4338,7 +4365,7 @@ mptcp_get_meta_from_token(struct tcp_analysis* tcpd, tcp_flow_t *tcp_flow, guint
6f145f
 /* setup from_key */
6f145f
 static
6f145f
 struct mptcp_analysis*
6f145f
-get_or_create_mptcpd_from_key(struct tcp_analysis* tcpd, tcp_flow_t *fwd, guint64 key, guint8 hmac_algo _U_) {
6f145f
+get_or_create_mptcpd_from_key(struct tcp_analysis* tcpd, tcp_flow_t *fwd, guint8 version, guint64 key, guint8 hmac_algo _U_) {
6f145f
 
6f145f
     guint32 token = 0;
6f145f
     guint64 expected_idsn= 0;
6f145f
@@ -4348,8 +4375,11 @@ get_or_create_mptcpd_from_key(struct tcp_analysis* tcpd, tcp_flow_t *fwd, guint6
6f145f
         return mptcpd;
6f145f
     }
6f145f
 
6f145f
-    /* MPTCP only standardizes SHA1 for now. */
6f145f
-    mptcp_cryptodata_sha1(key, &token, &expected_idsn);
6f145f
+    /* MPTCP v0 only standardizes SHA1, and v1 SHA256. */
6f145f
+    if (version == 0)
6f145f
+        mptcp_cryptodata_sha1(key, &token, &expected_idsn);
6f145f
+    else if (version == 1)
6f145f
+        mptcp_cryptodata_sha256(key, &token, &expected_idsn);
6f145f
 
6f145f
     mptcpd = mptcp_get_meta_from_token(tcpd, fwd, token);
6f145f
 
6f145f
@@ -4409,6 +4439,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
     proto_item *item,*main_item;
6f145f
     proto_tree *mptcp_tree;
6f145f
 
6f145f
+    guint32 version;
6f145f
     guint8 subtype;
6f145f
     guint8 ipver;
6f145f
     int offset = 0;
6f145f
@@ -4462,18 +4493,19 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
         case TCPOPT_MPTCP_MP_CAPABLE:
6f145f
             mph->mh_mpc = TRUE;
6f145f
 
6f145f
-            proto_tree_add_item(mptcp_tree, hf_tcp_option_mptcp_version, tvb,
6f145f
-                        offset, 1, ENC_BIG_ENDIAN);
6f145f
+            proto_tree_add_item_ret_uint(mptcp_tree, hf_tcp_option_mptcp_version, tvb,
6f145f
+                        offset, 1, ENC_BIG_ENDIAN, &version);
6f145f
             offset += 1;
6f145f
 
6f145f
             item = proto_tree_add_bitmask(mptcp_tree, tvb, offset, hf_tcp_option_mptcp_flags,
6f145f
-                         ett_tcp_option_mptcp, tcp_option_mptcp_capable_flags,
6f145f
+                         ett_tcp_option_mptcp,
6f145f
+                         version == 1 ? tcp_option_mptcp_capable_v1_flags : tcp_option_mptcp_capable_v0_flags,
6f145f
                          ENC_BIG_ENDIAN);
6f145f
             mph->mh_capable_flags = tvb_get_guint8(tvb, offset);
6f145f
             if ((mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK) == 0) {
6f145f
                 expert_add_info(pinfo, item, &ei_mptcp_analysis_missing_algorithm);
6f145f
             }
6f145f
-            if ((mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK) != MPTCP_HMAC_SHA1) {
6f145f
+            if ((mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK) != MPTCP_HMAC_SHA) {
6f145f
                 expert_add_info(pinfo, item, &ei_mptcp_analysis_unsupported_algorithm);
6f145f
             }
6f145f
             offset += 1;
6f145f
@@ -4488,7 +4520,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                 proto_tree_add_uint64(mptcp_tree, hf_tcp_option_mptcp_sender_key, tvb, offset, 8, mph->mh_key);
6f145f
                 offset += 8;
6f145f
 
6f145f
-                mptcpd = get_or_create_mptcpd_from_key(tcpd, tcpd->fwd, mph->mh_key, mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK);
6f145f
+                mptcpd = get_or_create_mptcpd_from_key(tcpd, tcpd->fwd, version, mph->mh_key, mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK);
6f145f
                 mptcpd->master = tcpd;
6f145f
 
6f145f
                 item = proto_tree_add_uint(mptcp_tree,
6f145f
@@ -4514,7 +4546,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                         }
6f145f
                     }
6f145f
                     else {
6f145f
-                        mptcpd = get_or_create_mptcpd_from_key(tcpd, tcpd->rev, recv_key, mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK);
6f145f
+                        mptcpd = get_or_create_mptcpd_from_key(tcpd, tcpd->rev, version, recv_key, mph->mh_capable_flags & MPTCP_CAPABLE_CRYPTO_MASK);
6f145f
                     }
6f145f
                 }
6f145f
 
6f145f
@@ -7147,10 +7179,14 @@ proto_register_tcp(void)
6f145f
           { "Extensibility", "tcp.options.mptcp.extensibility.flag", FT_UINT8,
6f145f
             BASE_DEC, NULL, 0x40, NULL, HFILL}},
6f145f
 
6f145f
-        { &hf_tcp_option_mptcp_H_flag,
6f145f
+        { &hf_tcp_option_mptcp_H_v0_flag,
6f145f
           { "Use HMAC-SHA1", "tcp.options.mptcp.sha1.flag", FT_UINT8,
6f145f
             BASE_DEC, NULL, 0x01, NULL, HFILL}},
6f145f
 
6f145f
+        { &hf_tcp_option_mptcp_H_v1_flag,
6f145f
+          { "Use HMAC-SHA256", "tcp.options.mptcp.sha256.flag", FT_UINT8,
6f145f
+            BASE_DEC, NULL, 0x01, NULL, HFILL}},
6f145f
+
6f145f
         { &hf_tcp_option_mptcp_F_flag,
6f145f
           { "DATA_FIN", "tcp.options.mptcp.datafin.flag", FT_UINT8,
6f145f
             BASE_DEC, NULL, MPTCP_DSS_FLAG_DATA_FIN_PRESENT, NULL, HFILL}},
6f145f
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
6f145f
index dfee9cdeb4..38630d3a51 100644
6f145f
--- a/epan/dissectors/packet-tcp.h
6f145f
+++ b/epan/dissectors/packet-tcp.h
6f145f
@@ -277,7 +277,8 @@ struct mptcp_subflow {
6f145f
 
6f145f
 typedef enum {
6f145f
 	MPTCP_HMAC_NOT_SET = 0,
6f145f
-	MPTCP_HMAC_SHA1 = 1,
6f145f
+	/* this is either SHA1 for MPTCP v0 or sha256 for MPTCP v1 */
6f145f
+	MPTCP_HMAC_SHA = 1,
6f145f
 	MPTCP_HMAC_LAST
6f145f
 } mptcp_hmac_algorithm_t;
6f145f
 
6f145f
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
6f145f
index c4a9a6eb15..ca284604ed 100644
6f145f
--- a/epan/dissectors/packet-tcp.c
6f145f
+++ b/epan/dissectors/packet-tcp.c
6f145f
@@ -271,6 +271,7 @@ static int hf_tcp_option_mptcp_subflow_seq_no = -1;
6f145f
 static int hf_tcp_option_mptcp_data_lvl_len = -1;
6f145f
 static int hf_tcp_option_mptcp_checksum = -1;
6f145f
 static int hf_tcp_option_mptcp_ipver = -1;
6f145f
+static int hf_tcp_option_mptcp_echo = -1;
6f145f
 static int hf_tcp_option_mptcp_ipv4 = -1;
6f145f
 static int hf_tcp_option_mptcp_ipv6 = -1;
6f145f
 static int hf_tcp_option_mptcp_port = -1;
6f145f
@@ -4776,33 +4777,32 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
             break;
6f145f
 
6f145f
         case TCPOPT_MPTCP_ADD_ADDR:
6f145f
-            proto_tree_add_item(mptcp_tree,
6f145f
-                            hf_tcp_option_mptcp_ipver, tvb, offset, 1, ENC_BIG_ENDIAN);
6f145f
             ipver = tvb_get_guint8(tvb, offset) & 0x0F;
6f145f
+            if (ipver == 4 || ipver == 6)
6f145f
+                proto_tree_add_item(mptcp_tree,
6f145f
+                            hf_tcp_option_mptcp_ipver, tvb, offset, 1, ENC_BIG_ENDIAN);
6f145f
+            else
6f145f
+                proto_tree_add_item(mptcp_tree,
6f145f
+                            hf_tcp_option_mptcp_echo, tvb, offset, 1, ENC_BIG_ENDIAN);
6f145f
             offset += 1;
6f145f
 
6f145f
             proto_tree_add_item(mptcp_tree,
6f145f
                     hf_tcp_option_mptcp_address_id, tvb, offset, 1, ENC_BIG_ENDIAN);
6f145f
             offset += 1;
6f145f
 
6f145f
-            switch (ipver) {
6f145f
-                case 4:
6f145f
-                    proto_tree_add_item(mptcp_tree,
6f145f
+            if (optlen == 8 || optlen == 10 || optlen == 16 || optlen == 18) {
6f145f
+                proto_tree_add_item(mptcp_tree,
6f145f
                             hf_tcp_option_mptcp_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
6f145f
-                    offset += 4;
6f145f
-                    break;
6f145f
+                offset += 4;
6f145f
+            }
6f145f
 
6f145f
-                case 6:
6f145f
-                    proto_tree_add_item(mptcp_tree,
6f145f
+            if (optlen == 20 || optlen == 22 || optlen == 28 || optlen == 30) {
6f145f
+                proto_tree_add_item(mptcp_tree,
6f145f
                             hf_tcp_option_mptcp_ipv6, tvb, offset, 16, ENC_NA);
6f145f
-                    offset += 16;
6f145f
-                    break;
6f145f
-
6f145f
-                default:
6f145f
-                    break;
6f145f
+                offset += 16;
6f145f
             }
6f145f
 
6f145f
-            if (optlen % 4 == 2) {
6f145f
+            if (optlen == 10 || optlen == 18 || optlen == 22 || optlen == 30) {
6f145f
                 proto_tree_add_item(mptcp_tree,
6f145f
                             hf_tcp_option_mptcp_port, tvb, offset, 2, ENC_BIG_ENDIAN);
6f145f
                 offset += 2;
6f145f
@@ -7303,6 +7303,10 @@ proto_register_tcp(void)
6f145f
           { "IP version", "tcp.options.mptcp.ipver", FT_UINT8,
6f145f
             BASE_DEC, NULL, 0x0F, NULL, HFILL}},
6f145f
 
6f145f
+        { &hf_tcp_option_mptcp_echo,
6f145f
+          { "Echo", "tcp.options.mptcp.echo", FT_UINT8,
6f145f
+            BASE_DEC, NULL, 0x01, NULL, HFILL}},
6f145f
+
6f145f
         { &hf_tcp_option_mptcp_ipv4,
6f145f
           { "Advertised IPv4 Address", "tcp.options.mptcp.ipv4", FT_IPv4,
6f145f
             BASE_NONE, NULL, 0x0, NULL, HFILL}},
6f145f
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
6f145f
index 6bc1915e82..b0ed652215 100644
6f145f
--- a/epan/dissectors/packet-tcp.c
6f145f
+++ b/epan/dissectors/packet-tcp.c
6f145f
@@ -2152,13 +2152,19 @@ tcp_analyze_sequence_number(packet_info *pinfo, guint32 seq, guint32 ack, guint3
6f145f
     &&  seq==tcpd->fwd->tcp_analyze_seq_info->nextseq
6f145f
     &&  ack==tcpd->fwd->tcp_analyze_seq_info->lastack
6f145f
     &&  (flags&(TH_SYN|TH_FIN|TH_RST))==0 ) {
6f145f
-        tcpd->fwd->tcp_analyze_seq_info->dupacknum++;
6f145f
-        if(!tcpd->ta) {
6f145f
-            tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
6f145f
-        }
6f145f
-        tcpd->ta->flags|=TCP_A_DUPLICATE_ACK;
6f145f
-        tcpd->ta->dupack_num=tcpd->fwd->tcp_analyze_seq_info->dupacknum;
6f145f
-        tcpd->ta->dupack_frame=tcpd->fwd->tcp_analyze_seq_info->lastnondupack;
6f145f
+
6f145f
+        /* MPTCP tolerates duplicate acks in some circumstances, see RFC 8684 4. */
6f145f
+        if(tcpd->mptcp_analysis && (tcpd->mptcp_analysis->mp_operations!=tcpd->fwd->mp_operations)) {
6f145f
+            /* just ignore this DUPLICATE ACK */
6f145f
+        } else {
6f145f
+            tcpd->fwd->tcp_analyze_seq_info->dupacknum++;
6f145f
+            if(!tcpd->ta) {
6f145f
+                tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);
6f145f
+            }
6f145f
+            tcpd->ta->flags|=TCP_A_DUPLICATE_ACK;
6f145f
+            tcpd->ta->dupack_num=tcpd->fwd->tcp_analyze_seq_info->dupacknum;
6f145f
+            tcpd->ta->dupack_frame=tcpd->fwd->tcp_analyze_seq_info->lastnondupack;
6f145f
+       }
6f145f
     }
6f145f
 
6f145f
 
6f145f
@@ -2343,6 +2349,10 @@ finished_checking_retransmission_type:
6f145f
     tcpd->fwd->tcp_analyze_seq_info->lastacktime.secs=pinfo->abs_ts.secs;
6f145f
     tcpd->fwd->tcp_analyze_seq_info->lastacktime.nsecs=pinfo->abs_ts.nsecs;
6f145f
 
6f145f
+    /* remember the MPTCP operations if any */
6f145f
+    if( tcpd->mptcp_analysis ) {
6f145f
+        tcpd->fwd->mp_operations=tcpd->mptcp_analysis->mp_operations;
6f145f
+    }
6f145f
 
6f145f
     /* if there were any flags set for this segment we need to remember them
6f145f
      * we only remember the flags for the very last segment though.
6f145f
@@ -2702,24 +2712,17 @@ mptcp_analysis_add_subflows(packet_info *pinfo _U_,  tvbuff_t *tvb,
6f145f
     proto_tree *parent_tree, struct mptcp_analysis* mptcpd)
6f145f
 {
6f145f
     wmem_list_frame_t *it;
6f145f
-    proto_tree *tree;
6f145f
     proto_item *item;
6f145f
 
6f145f
-    item=proto_tree_add_item(parent_tree, hf_mptcp_analysis_subflows, tvb, 0, 0, ENC_NA);
6f145f
-    PROTO_ITEM_SET_GENERATED(item);
6f145f
-
6f145f
-    tree=proto_item_add_subtree(item, ett_mptcp_analysis_subflows);
6f145f
+    wmem_strbuf_t *val = wmem_strbuf_new(wmem_packet_scope(), "");
6f145f
 
6f145f
     /* for the analysis, we set each subflow tcp stream id */
6f145f
     for(it = wmem_list_head(mptcpd->subflows); it != NULL; it = wmem_list_frame_next(it)) {
6f145f
         struct tcp_analysis *sf = (struct tcp_analysis *)wmem_list_frame_data(it);
6f145f
-        proto_item *subflow_item;
6f145f
-        subflow_item=proto_tree_add_uint(tree, hf_mptcp_analysis_subflows_stream_id, tvb, 0, 0, sf->stream);
6f145f
-        PROTO_ITEM_SET_HIDDEN(subflow_item);
6f145f
-
6f145f
-        proto_item_append_text(item, " %d", sf->stream);
6f145f
+        wmem_strbuf_append_printf(val, "%u ", sf->stream);
6f145f
     }
6f145f
 
6f145f
+    item = proto_tree_add_string(parent_tree, hf_mptcp_analysis_subflows, tvb, 0, 0, wmem_strbuf_get_str(val));
6f145f
     PROTO_ITEM_SET_GENERATED(item);
6f145f
 }
6f145f
 
6f145f
@@ -2962,6 +2965,42 @@ mptcp_add_analysis_subtree(packet_info *pinfo, tvbuff_t *tvb, proto_tree *parent
6f145f
 
6f145f
     PROTO_ITEM_SET_GENERATED(item);
6f145f
 
6f145f
+    /* store the TCP Options related to MPTCP then we will avoid false DUP ACKs later */
6f145f
+    guint8 nbOptionsChanged = 0;
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x01))!=tcph->th_mptcp->mh_mpc) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x01;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x02))!=tcph->th_mptcp->mh_join) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x02;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x04))!=tcph->th_mptcp->mh_dss) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x04;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x08))!=tcph->th_mptcp->mh_add) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x08;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x10))!=tcph->th_mptcp->mh_remove) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x10;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x20))!=tcph->th_mptcp->mh_prio) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x20;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x40))!=tcph->th_mptcp->mh_fail) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x40;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    if((tcpd->mptcp_analysis->mp_operations&(0x80))!=tcph->th_mptcp->mh_fastclose) {
6f145f
+        tcpd->mptcp_analysis->mp_operations |= 0x80;
6f145f
+        nbOptionsChanged++;
6f145f
+    }
6f145f
+    /* we could track MPTCP option changes here, with nbOptionsChanged */
6f145f
+
6f145f
     item = proto_tree_add_uint(tree, hf_mptcp_stream, tvb, 0, 0, mptcpd->stream);
6f145f
     PROTO_ITEM_SET_GENERATED(item);
6f145f
 
6f145f
@@ -4537,6 +4576,7 @@ get_or_create_mptcpd_from_key(struct tcp_analysis* tcpd, tcp_flow_t *fwd, guint8
6f145f
 
6f145f
     DISSECTOR_ASSERT(fwd->mptcp_subflow->meta);
6f145f
 
6f145f
+    fwd->mptcp_subflow->meta->version = version;
6f145f
     fwd->mptcp_subflow->meta->key = key;
6f145f
     fwd->mptcp_subflow->meta->static_flags |= MPTCP_META_HAS_KEY;
6f145f
     fwd->mptcp_subflow->meta->base_dsn = expected_idsn;
6f145f
@@ -4747,6 +4787,13 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
                     offset += 4;
6f145f
 
6f145f
                     mptcpd = mptcp_get_meta_from_token(tcpd, tcpd->rev, mph->mh_token);
6f145f
+                    if (tcpd->fwd->mptcp_subflow->meta->version == 1) {
6f145f
+                        mptcp_meta_flow_t *tmp = tcpd->fwd->mptcp_subflow->meta;
6f145f
+
6f145f
+                        /* if the negotiated version is v1 the first key was exchanged on SYN/ACK packet: we must swap the meta */
6f145f
+                        tcpd->fwd->mptcp_subflow->meta = tcpd->rev->mptcp_subflow->meta;
6f145f
+                        tcpd->rev->mptcp_subflow->meta = tmp;
6f145f
+                    }
6f145f
 
6f145f
                     proto_tree_add_item_ret_uint(mptcp_tree, hf_tcp_option_mptcp_sender_rand, tvb, offset,
6f145f
                             4, ENC_BIG_ENDIAN, &tcpd->fwd->mptcp_subflow->nonce);
6f145f
@@ -4897,6 +4944,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
             break;
6f145f
 
6f145f
         case TCPOPT_MPTCP_ADD_ADDR:
6f145f
+            mph->mh_add = TRUE;
6f145f
             ipver = tvb_get_guint8(tvb, offset) & 0x0F;
6f145f
             if (ipver == 4 || ipver == 6)
6f145f
                 proto_tree_add_item(mptcp_tree,
6f145f
@@ -4935,6 +4983,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
             break;
6f145f
 
6f145f
         case TCPOPT_MPTCP_REMOVE_ADDR:
6f145f
+            mph->mh_remove = TRUE;
6f145f
             item = proto_tree_add_uint(mptcp_tree, hf_mptcp_number_of_removed_addresses, tvb, start_offset+2,
6f145f
                 1, optlen - 3);
6f145f
             PROTO_ITEM_SET_GENERATED(item);
6f145f
@@ -4947,6 +4996,7 @@ dissect_tcpopt_mptcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
6f145f
             break;
6f145f
 
6f145f
         case TCPOPT_MPTCP_MP_PRIO:
6f145f
+            mph->mh_prio = TRUE;
6f145f
             proto_tree_add_bitmask(mptcp_tree, tvb, offset, hf_tcp_option_mptcp_flags,
6f145f
                          ett_tcp_option_mptcp, tcp_option_mptcp_join_flags,
6f145f
                          ENC_BIG_ENDIAN);
6f145f
@@ -8040,7 +8090,7 @@ proto_register_tcp(void)
6f145f
             "This was retransmitted on another subflow", HFILL }},
6f145f
 
6f145f
         { &hf_mptcp_analysis_subflows,
6f145f
-          { "TCP subflow stream id(s):", "mptcp.analysis.subflows", FT_NONE, BASE_NONE, NULL, 0x0,
6f145f
+          { "TCP subflow stream id(s)", "mptcp.analysis.subflows", FT_STRING, BASE_NONE, NULL, 0x0,
6f145f
             "List all TCP connections mapped to this MPTCP connection", HFILL }},
6f145f
 
6f145f
         { &hf_mptcp_stream,
6f145f
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
6f145f
index ac250d948e..21e6a61086 100644
6f145f
--- a/epan/dissectors/packet-tcp.h
6f145f
+++ b/epan/dissectors/packet-tcp.h
6f145f
@@ -49,8 +49,11 @@ struct mptcpheader {
6f145f
 	gboolean mh_mpc;         /* true if seen an mp_capable option */
6f145f
 	gboolean mh_join;        /* true if seen an mp_join option */
6f145f
 	gboolean mh_dss;         /* true if seen a dss */
6f145f
-	gboolean mh_fastclose;   /* true if seen a fastclose */
6f145f
+	gboolean mh_add;         /* true if seen an MP_ADD */
6f145f
+	gboolean mh_remove;      /* true if seen an MP_REMOVE */
6f145f
+	gboolean mh_prio;        /* true if seen an MP_PRIO */
6f145f
 	gboolean mh_fail;        /* true if seen an MP_FAIL */
6f145f
+	gboolean mh_fastclose;   /* true if seen a fastclose */
6f145f
 
6f145f
 	guint8  mh_capable_flags; /* to get hmac version for instance */
6f145f
 	guint8  mh_dss_flags; /* data sequence signal flag */
6f145f
@@ -332,6 +335,7 @@ typedef struct _tcp_flow_t {
6f145f
 	gboolean valid_bif;     /* if lost pkts, disable BiF until ACK is recvd */
6f145f
 	guint32 push_bytes_sent; /* bytes since the last PSH flag */
6f145f
 	gboolean push_set_last; /* tracking last time PSH flag was set */
6f145f
+	guint8 mp_operations; /* tracking of the MPTCP operations */
6f145f
 
6f145f
 	tcp_analyze_seq_flow_info_t* tcp_analyze_seq_info;
6f145f
 
6f145f
@@ -378,6 +382,9 @@ struct mptcp_analysis {
6f145f
 
6f145f
 	/* identifier of the tcp stream that saw the initial 3WHS with MP_CAPABLE option */
6f145f
 	struct tcp_analysis *master;
6f145f
+
6f145f
+	/* Keep track of the last TCP operations seen in order to avoid false DUP ACKs */
6f145f
+	guint8 mp_operations;
6f145f
 };
6f145f
 
6f145f
 struct tcp_analysis {