dss_size = map_size;
                if (skb && snd_data_fin_enable)
                        mptcp_write_data_fin(subflow, skb, &opts->ext_copy);
+               opts->suboptions = OPTION_MPTCP_DSS;
                ret = true;
        }
 
                opts->ext_copy.ack64 = 0;
        }
        opts->ext_copy.use_ack = 1;
+       opts->suboptions = OPTION_MPTCP_DSS;
        WRITE_ONCE(msk->old_wspace, __mptcp_space((struct sock *)msk));
 
        /* Add kind/length/subtype/flag overhead if mapping is not populated */
        if (drop_other_suboptions) {
                pr_debug("drop other suboptions");
                opts->suboptions = 0;
-               opts->ext_copy.use_ack = 0;
-               opts->ext_copy.use_map = 0;
+
+               /* note that e.g. DSS could have written into the memory
+                * aliased by ahmac, we must reset the field here
+                * to avoid appending the hmac even for ADD_ADDR echo
+                * options
+                */
+               opts->ahmac = 0;
                *size -= opt_size;
        }
        opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
 
-       if (!subflow->send_mp_prio)
+       /* can't send MP_PRIO with MPC, as they share the same option space:
+        * 'backup'. Also it makes no sense at all
+        */
+       if (!subflow->send_mp_prio ||
+           ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK |
+             OPTION_MPTCP_MPC_ACK) & opts->suboptions))
                return false;
 
        /* account for the trailing 'nop' option */
 void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
                         struct mptcp_out_options *opts)
 {
-       if ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK |
-            OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
+       /* RST is mutually exclusive with everything else */
+       if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) {
+               *ptr++ = mptcp_option(MPTCPOPT_RST,
+                                     TCPOLEN_MPTCP_RST,
+                                     opts->reset_transient,
+                                     opts->reset_reason);
+               return;
+       }
+
+       /* DSS, MPC, MPJ and ADD_ADDR are mutually exclusive, see
+        * mptcp_established_options*()
+        */
+       if (likely(OPTION_MPTCP_DSS & opts->suboptions)) {
+               struct mptcp_ext *mpext = &opts->ext_copy;
+               u8 len = TCPOLEN_MPTCP_DSS_BASE;
+               u8 flags = 0;
+
+               if (mpext->use_ack) {
+                       flags = MPTCP_DSS_HAS_ACK;
+                       if (mpext->ack64) {
+                               len += TCPOLEN_MPTCP_DSS_ACK64;
+                               flags |= MPTCP_DSS_ACK64;
+                       } else {
+                               len += TCPOLEN_MPTCP_DSS_ACK32;
+                       }
+               }
+
+               if (mpext->use_map) {
+                       len += TCPOLEN_MPTCP_DSS_MAP64;
+
+                       /* Use only 64-bit mapping flags for now, add
+                        * support for optional 32-bit mappings later.
+                        */
+                       flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64;
+                       if (mpext->data_fin)
+                               flags |= MPTCP_DSS_DATA_FIN;
+
+                       if (opts->csum_reqd)
+                               len += TCPOLEN_MPTCP_DSS_CHECKSUM;
+               }
+
+               *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);
+
+               if (mpext->use_ack) {
+                       if (mpext->ack64) {
+                               put_unaligned_be64(mpext->data_ack, ptr);
+                               ptr += 2;
+                       } else {
+                               put_unaligned_be32(mpext->data_ack32, ptr);
+                               ptr += 1;
+                       }
+               }
+
+               if (mpext->use_map) {
+                       put_unaligned_be64(mpext->data_seq, ptr);
+                       ptr += 2;
+                       put_unaligned_be32(mpext->subflow_seq, ptr);
+                       ptr += 1;
+                       if (opts->csum_reqd) {
+                               put_unaligned_be32(mpext->data_len << 16 |
+                                                  mptcp_make_csum(mpext), ptr);
+                       } else {
+                               put_unaligned_be32(mpext->data_len << 16 |
+                                                  TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
+                       }
+               }
+       } else if ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK |
+                   OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
                u8 len, flag = MPTCP_CAP_HMAC_SHA256;
 
                if (OPTION_MPTCP_MPC_SYN & opts->suboptions) {
                                           TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
                }
                ptr += 1;
-       }
 
-mp_capable_done:
-       if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
+               /* MPC is additionally mutually exclusive with MP_PRIO */
+               goto mp_capable_done;
+       } else if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
+               *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
+                                     TCPOLEN_MPTCP_MPJ_SYN,
+                                     opts->backup, opts->join_id);
+               put_unaligned_be32(opts->token, ptr);
+               ptr += 1;
+               put_unaligned_be32(opts->nonce, ptr);
+               ptr += 1;
+       } else if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) {
+               *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
+                                     TCPOLEN_MPTCP_MPJ_SYNACK,
+                                     opts->backup, opts->join_id);
+               put_unaligned_be64(opts->thmac, ptr);
+               ptr += 2;
+               put_unaligned_be32(opts->nonce, ptr);
+               ptr += 1;
+       } else if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) {
+               *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
+                                     TCPOLEN_MPTCP_MPJ_ACK, 0, 0);
+               memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN);
+               ptr += 5;
+       } else if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
                u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
                u8 echo = MPTCP_ADDR_ECHO;
 
                }
        }
 
+       if (OPTION_MPTCP_PRIO & opts->suboptions) {
+               const struct sock *ssk = (const struct sock *)tp;
+               struct mptcp_subflow_context *subflow;
+
+               subflow = mptcp_subflow_ctx(ssk);
+               subflow->send_mp_prio = 0;
+
+               *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
+                                     TCPOLEN_MPTCP_PRIO,
+                                     opts->backup, TCPOPT_NOP);
+       }
+
+mp_capable_done:
        if (OPTION_MPTCP_RM_ADDR & opts->suboptions) {
                u8 i = 1;
 
                }
        }
 
-       if (OPTION_MPTCP_PRIO & opts->suboptions) {
-               const struct sock *ssk = (const struct sock *)tp;
-               struct mptcp_subflow_context *subflow;
-
-               subflow = mptcp_subflow_ctx(ssk);
-               subflow->send_mp_prio = 0;
-
-               *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
-                                     TCPOLEN_MPTCP_PRIO,
-                                     opts->backup, TCPOPT_NOP);
-       }
-
-       if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
-               *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
-                                     TCPOLEN_MPTCP_MPJ_SYN,
-                                     opts->backup, opts->join_id);
-               put_unaligned_be32(opts->token, ptr);
-               ptr += 1;
-               put_unaligned_be32(opts->nonce, ptr);
-               ptr += 1;
-       }
-
-       if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) {
-               *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
-                                     TCPOLEN_MPTCP_MPJ_SYNACK,
-                                     opts->backup, opts->join_id);
-               put_unaligned_be64(opts->thmac, ptr);
-               ptr += 2;
-               put_unaligned_be32(opts->nonce, ptr);
-               ptr += 1;
-       }
-
-       if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) {
-               *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
-                                     TCPOLEN_MPTCP_MPJ_ACK, 0, 0);
-               memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN);
-               ptr += 5;
-       }
-
-       if (OPTION_MPTCP_RST & opts->suboptions)
-               *ptr++ = mptcp_option(MPTCPOPT_RST,
-                                     TCPOLEN_MPTCP_RST,
-                                     opts->reset_transient,
-                                     opts->reset_reason);
-
-       if (opts->ext_copy.use_ack || opts->ext_copy.use_map) {
-               struct mptcp_ext *mpext = &opts->ext_copy;
-               u8 len = TCPOLEN_MPTCP_DSS_BASE;
-               u8 flags = 0;
-
-               if (mpext->use_ack) {
-                       flags = MPTCP_DSS_HAS_ACK;
-                       if (mpext->ack64) {
-                               len += TCPOLEN_MPTCP_DSS_ACK64;
-                               flags |= MPTCP_DSS_ACK64;
-                       } else {
-                               len += TCPOLEN_MPTCP_DSS_ACK32;
-                       }
-               }
-
-               if (mpext->use_map) {
-                       len += TCPOLEN_MPTCP_DSS_MAP64;
-
-                       /* Use only 64-bit mapping flags for now, add
-                        * support for optional 32-bit mappings later.
-                        */
-                       flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64;
-                       if (mpext->data_fin)
-                               flags |= MPTCP_DSS_DATA_FIN;
-
-                       if (opts->csum_reqd)
-                               len += TCPOLEN_MPTCP_DSS_CHECKSUM;
-               }
-
-               *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);
-
-               if (mpext->use_ack) {
-                       if (mpext->ack64) {
-                               put_unaligned_be64(mpext->data_ack, ptr);
-                               ptr += 2;
-                       } else {
-                               put_unaligned_be32(mpext->data_ack32, ptr);
-                               ptr += 1;
-                       }
-               }
-
-               if (mpext->use_map) {
-                       put_unaligned_be64(mpext->data_seq, ptr);
-                       ptr += 2;
-                       put_unaligned_be32(mpext->subflow_seq, ptr);
-                       ptr += 1;
-                       if (opts->csum_reqd) {
-                               put_unaligned_be32(mpext->data_len << 16 |
-                                                  mptcp_make_csum(mpext), ptr);
-                       } else {
-                               put_unaligned_be32(mpext->data_len << 16 |
-                                                  TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
-                       }
-               }
-       }
-
        if (tp)
                mptcp_set_rwin(tp);
 }