else
                                expected_opsize = TCPOLEN_MPTCP_MPC_SYN;
                }
-               if (opsize != expected_opsize)
+
+               /* Cfr RFC 8684 Section 3.3.0:
+                * If a checksum is present but its use had
+                * not been negotiated in the MP_CAPABLE handshake, the receiver MUST
+                * close the subflow with a RST, as it is not behaving as negotiated.
+                * If a checksum is not present when its use has been negotiated, the
+                * receiver MUST close the subflow with a RST, as it is considered
+                * broken
+                * We parse even option with mismatching csum presence, so that
+                * later in subflow_data_ready we can trigger the reset.
+                */
+               if (opsize != expected_opsize &&
+                   (expected_opsize != TCPOLEN_MPTCP_MPC_ACK_DATA ||
+                    opsize != TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM))
                        break;
 
                /* try to be gentle vs future versions on the initial syn */
                 * host requires the use of checksums, checksums MUST be used.
                 * In other words, the only way for checksums not to be used
                 * is if both hosts in their SYNs set A=0."
-                *
-                * Section 3.3.0:
-                * "If a checksum is not present when its use has been
-                * negotiated, the receiver MUST close the subflow with a RST as
-                * it is considered broken."
                 */
                if (flags & MPTCP_CAP_CHECKSUM_REQD)
                        mp_opt->csum_reqd = 1;
                        mp_opt->rcvr_key = get_unaligned_be64(ptr);
                        ptr += 8;
                }
-               if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA) {
+               if (opsize >= TCPOLEN_MPTCP_MPC_ACK_DATA) {
                        /* Section 3.1.:
                         * "the data parameters in a MP_CAPABLE are semantically
                         * equivalent to those in a DSS option and can be used
                        mp_opt->data_len = get_unaligned_be16(ptr);
                        ptr += 2;
                }
-               pr_debug("MP_CAPABLE version=%x, flags=%x, optlen=%d sndr=%llu, rcvr=%llu len=%d",
+               if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM) {
+                       mp_opt->csum = (__force __sum16)get_unaligned_be16(ptr);
+                       mp_opt->csum_reqd = 1;
+                       ptr += 2;
+               }
+               pr_debug("MP_CAPABLE version=%x, flags=%x, optlen=%d sndr=%llu, rcvr=%llu len=%d csum=%u",
                         version, flags, opsize, mp_opt->sndr_key,
-                        mp_opt->rcvr_key, mp_opt->data_len);
+                        mp_opt->rcvr_key, mp_opt->data_len, mp_opt->csum);
                break;
 
        case MPTCPOPT_MP_JOIN:
                }
                mpext->data_len = mp_opt.data_len;
                mpext->use_map = 1;
+               mpext->csum_reqd = mp_opt.csum_reqd;
+
+               if (mpext->csum_reqd)
+                       mpext->csum = mp_opt.csum;
        }
 }