diff mbox series

[v3,3/4] mptcp: build ADD_ADDR/echo-ADD_ADDR option according pm.add_signal

Message ID 1623921276-97178-4-git-send-email-liyonglong@chinatelecom.cn (mailing list archive)
State Superseded, archived
Headers show
Series mptcp: fix conflicts when using pm.add_signal in ADD_ADDR/echo and RM_ADDR process | expand

Commit Message

YonglongLi June 17, 2021, 9:14 a.m. UTC
according MPTCP_ADD_ADDR_SIGNAL and MPTCP_ADD_ADDR_ECHO flag build
ADD_ADDR/echo-ADD_ADDR option

add a suboptions type OPTION_MPTCP_ADD_ECHO to mark as echo option

Signed-off-by: Yonglong Li <liyonglong@chinatelecom.cn>
---
 net/mptcp/options.c  | 161 +++++++++++++++++++++++++++++++++------------------
 net/mptcp/pm.c       |  30 +++-------
 net/mptcp/protocol.h |  13 +++--
 3 files changed, 122 insertions(+), 82 deletions(-)

Comments

Geliang Tang June 17, 2021, 12:37 p.m. UTC | #1
Hi Yonglong,

Thanks for this patch set.

Yonglong Li <liyonglong@chinatelecom.cn> 于2021年6月17日周四 下午5:15写道:
>
> according MPTCP_ADD_ADDR_SIGNAL and MPTCP_ADD_ADDR_ECHO flag build
> ADD_ADDR/echo-ADD_ADDR option
>
> add a suboptions type OPTION_MPTCP_ADD_ECHO to mark as echo option
>
> Signed-off-by: Yonglong Li <liyonglong@chinatelecom.cn>
> ---
>  net/mptcp/options.c  | 161 +++++++++++++++++++++++++++++++++------------------
>  net/mptcp/pm.c       |  30 +++-------
>  net/mptcp/protocol.h |  13 +++--
>  3 files changed, 122 insertions(+), 82 deletions(-)
>
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index 1aec016..3ecf2c6 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -655,43 +655,72 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
>         struct mptcp_sock *msk = mptcp_sk(subflow->conn);
>         bool drop_other_suboptions = false;
>         unsigned int opt_size = *size;
> -       bool echo;
> -       bool port;
> +       struct mptcp_addr_info remote;
> +       struct mptcp_addr_info local;
> +       int ret = false;
> +       u8 add_addr, flags;
>         int len;
>
> -       if ((mptcp_pm_should_add_signal_ipv6(msk) ||
> -            mptcp_pm_should_add_signal_port(msk) ||
> -            mptcp_pm_should_add_signal_echo(msk)) &&
> -           skb && skb_is_tcp_pure_ack(skb)) {
> -               pr_debug("drop other suboptions");
> -               opts->suboptions = 0;
> -               opts->ext_copy.use_ack = 0;
> -               opts->ext_copy.use_map = 0;
> -               remaining += opt_size;
> -               drop_other_suboptions = true;
> -       }
> -
> -       if (!mptcp_pm_should_add_signal(msk) ||
> -           !(mptcp_pm_add_addr_signal(msk, remaining, &opts->addr, &echo, &port)))
> -               return false;
> -
> -       len = mptcp_add_addr_len(opts->addr.family, echo, port);
> -       if (remaining < len)
> -               return false;
> -
> -       *size = len;
> -       if (drop_other_suboptions)
> -               *size -= opt_size;
> -       opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
> -       if (!echo) {
> +       if (!mptcp_pm_should_add_signal(msk))
> +               goto out;
> +
> +       *size = 0;
> +       mptcp_pm_add_addr_signal(msk, &local, &remote, &add_addr);
> +       if (mptcp_pm_should_add_signal_echo(msk)) {
> +               if (skb && skb_is_tcp_pure_ack(skb)) {
> +                       pr_debug("drop other suboptions");
> +                       opts->suboptions = 0;
> +                       opts->ext_copy.use_ack = 0;
> +                       opts->ext_copy.use_map = 0;
> +                       remaining += opt_size;
> +                       drop_other_suboptions = true;
> +               }
> +               len = mptcp_add_addr_len(remote.family, true, !!remote.port);
> +               if (remaining < len && mptcp_pm_should_add_signal_addr(msk))
> +                       goto add_addr;
> +               else if (remaining < len)
> +                       goto out;
> +               remaining -= len;
> +               *size += len;
> +               opts->remote = remote;
> +               flags = (u8)~BIT(MPTCP_ADD_ADDR_ECHO);
> +               opts->suboptions |= OPTION_MPTCP_ADD_ECHO;
> +               pr_debug("addr_id=%d, echo=1, port=%d addr_signal:%x",
> +                        opts->remote.id, ntohs(opts->remote.port), add_addr);
> +       } else if (mptcp_pm_should_add_signal_addr(msk)) {
> +add_addr:
> +               if ((local.family == AF_INET6 || local.port) && skb &&
> +                   skb_is_tcp_pure_ack(skb)) {
> +                       pr_debug("drop other suboptions");
> +                       opts->suboptions = 0;
> +                       opts->ext_copy.use_ack = 0;
> +                       opts->ext_copy.use_map = 0;
> +                       remaining += opt_size;
> +                       drop_other_suboptions = true;
> +               }
> +               len = mptcp_add_addr_len(local.family, false, !!local.port);
> +               if (remaining < len)
> +                       goto out;
> +               *size += len;
> +               opts->addr = local;
>                 opts->ahmac = add_addr_generate_hmac(msk->local_key,
>                                                      msk->remote_key,
>                                                      &opts->addr);
> +               opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
> +               flags = (u8)~BIT(MPTCP_ADD_ADDR_SIGNAL);
> +               pr_debug("addr_id=%d, ahmac=%llu, echo=0, port=%d, addr_signal:%x",
> +                        opts->addr.id, opts->ahmac, ntohs(opts->addr.port), add_addr);
>         }

There are some duplicate codes here between the
mptcp_pm_should_add_signal_echo(msk) trunk and the
mptcp_pm_should_add_signal_addr(msk) trunk, could you please simply them
into one trunk?

> -       pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d",
> -                opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port));
>
> -       return true;
> +       if (drop_other_suboptions)
> +               *size -= opt_size;
> +       spin_lock_bh(&msk->pm.lock);
> +       WRITE_ONCE(msk->pm.addr_signal, flags | msk->pm.addr_signal);
> +       spin_unlock_bh(&msk->pm.lock);
> +       ret = true;
> +
> +out:
> +       return ret;
>  }
>
>  static bool mptcp_established_options_rm_addr(struct sock *sk,
> @@ -1230,21 +1259,18 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
>  mp_capable_done:
>         if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
>                 u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
> -               u8 echo = MPTCP_ADDR_ECHO;
> +               u8 echo = 0;
>
>  #if IS_ENABLED(CONFIG_MPTCP_IPV6)
>                 if (opts->addr.family == AF_INET6)
>                         len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
>  #endif
>
> +               len += sizeof(opts->ahmac);
> +
>                 if (opts->addr.port)
>                         len += TCPOLEN_MPTCP_PORT_LEN;
>
> -               if (opts->ahmac) {
> -                       len += sizeof(opts->ahmac);
> -                       echo = 0;
> -               }
> -
>                 *ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
>                                       len, echo, opts->addr.id);
>                 if (opts->addr.family == AF_INET) {
> @@ -1259,30 +1285,55 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
>  #endif
>
>                 if (!opts->addr.port) {
> -                       if (opts->ahmac) {
> -                               put_unaligned_be64(opts->ahmac, ptr);
> -                               ptr += 2;
> -                       }
> +                       put_unaligned_be64(opts->ahmac, ptr);
> +                       ptr += 2;
>                 } else {
>                         u16 port = ntohs(opts->addr.port);
> +                       u8 *bptr = (u8 *)ptr;
>
> -                       if (opts->ahmac) {
> -                               u8 *bptr = (u8 *)ptr;
> +                       put_unaligned_be16(port, bptr);
> +                       bptr += 2;
> +                       put_unaligned_be64(opts->ahmac, bptr);
> +                       bptr += 8;
> +                       put_unaligned_be16(TCPOPT_NOP << 8 |
> +                                          TCPOPT_NOP, bptr);
>
> -                               put_unaligned_be16(port, bptr);
> -                               bptr += 2;
> -                               put_unaligned_be64(opts->ahmac, bptr);
> -                               bptr += 8;
> -                               put_unaligned_be16(TCPOPT_NOP << 8 |
> -                                                  TCPOPT_NOP, bptr);
> +                       ptr += 3;
> +               }
> +       }
>
> -                               ptr += 3;
> -                       } else {
> -                               put_unaligned_be32(port << 16 |
> -                                                  TCPOPT_NOP << 8 |
> -                                                  TCPOPT_NOP, ptr);
> -                               ptr += 1;
> -                       }
> +       if (OPTION_MPTCP_ADD_ECHO & opts->suboptions) {
> +               u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
> +               u8 echo = MPTCP_ADDR_ECHO;
> +
> +#if IS_ENABLED(CONFIG_MPTCP_IPV6)
> +               if (opts->remote.family == AF_INET6)
> +                       len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
> +#endif
> +
> +               if (opts->remote.port)
> +                       len += TCPOLEN_MPTCP_PORT_LEN;
> +
> +               *ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
> +                                     len, echo, opts->remote.id);
> +               if (opts->remote.family == AF_INET) {
> +                       memcpy((u8 *)ptr, (u8 *)&opts->remote.addr.s_addr, 4);
> +                       ptr += 1;
> +               }
> +#if IS_ENABLED(CONFIG_MPTCP_IPV6)
> +               else if (opts->remote.family == AF_INET6) {
> +                       memcpy((u8 *)ptr, opts->remote.addr6.s6_addr, 16);
> +                       ptr += 4;
> +               }
> +#endif
> +
> +               if (opts->remote.port) {
> +                       u16 port = ntohs(opts->remote.port);
> +
> +                       put_unaligned_be32(port << 16 |
> +                                          TCPOPT_NOP << 8 |
> +                                          TCPOPT_NOP, ptr);
> +                       ptr += 1;
>                 }
>         }

And the same here between the OPTION_MPTCP_ADD_ADDR trunk and the
OPTION_MPTCP_ADD_ECHO trunk.

Thanks.
-Geliang

>
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index 74be6d7..a62d4a5 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -22,7 +22,8 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk,
>
>         lockdep_assert_held(&msk->pm.lock);
>
> -       if (add_addr) {
> +       if (add_addr &
> +           (echo ? BIT(MPTCP_ADD_ADDR_ECHO) : BIT(MPTCP_ADD_ADDR_SIGNAL))) {
>                 pr_warn("addr_signal error, add_addr=%d", add_addr);
>                 return -EINVAL;
>         }
> @@ -252,32 +253,19 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup)
>
>  /* path manager helpers */
>
> -bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> -                             struct mptcp_addr_info *saddr, bool *echo, bool *port)
> +void mptcp_pm_add_addr_signal(struct mptcp_sock *msk, struct mptcp_addr_info *saddr,
> +                             struct mptcp_addr_info *daddr, u8 *add_addr)
>  {
> -       u8 add_addr;
> -       int ret = false;
> -
>         spin_lock_bh(&msk->pm.lock);
>
> -       /* double check after the lock is acquired */
> -       if (!mptcp_pm_should_add_signal(msk))
> -               goto out_unlock;
> -
> -       *echo = mptcp_pm_should_add_signal_echo(msk);
> -       *port = mptcp_pm_should_add_signal_port(msk);
> -
> -       if (remaining < mptcp_add_addr_len(msk->pm.local.family, *echo, *port))
> -               goto out_unlock;
> -
>         *saddr = msk->pm.local;
> -       add_addr = msk->pm.addr_signal & BIT(MPTCP_RM_ADDR_SIGNAL);
> -       WRITE_ONCE(msk->pm.addr_signal, add_addr);
> -       ret = true;
> +       *daddr = msk->pm.remote;
> +       *add_addr = msk->pm.addr_signal;
>
> -out_unlock:
>         spin_unlock_bh(&msk->pm.lock);
> -       return ret;
> +
> +       if ((mptcp_pm_should_add_signal_echo(msk)) && (mptcp_pm_should_add_signal_addr(msk)))
> +               mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_SEND_ACK);
>  }
>
>  bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index a0b0ec0..90fb532 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -22,10 +22,11 @@
>  #define OPTION_MPTCP_MPJ_SYNACK        BIT(4)
>  #define OPTION_MPTCP_MPJ_ACK   BIT(5)
>  #define OPTION_MPTCP_ADD_ADDR  BIT(6)
> -#define OPTION_MPTCP_RM_ADDR   BIT(7)
> -#define OPTION_MPTCP_FASTCLOSE BIT(8)
> -#define OPTION_MPTCP_PRIO      BIT(9)
> -#define OPTION_MPTCP_RST       BIT(10)
> +#define OPTION_MPTCP_ADD_ECHO  BIT(7)
> +#define OPTION_MPTCP_RM_ADDR   BIT(8)
> +#define OPTION_MPTCP_FASTCLOSE BIT(9)
> +#define OPTION_MPTCP_PRIO      BIT(10)
> +#define OPTION_MPTCP_RST       BIT(11)
>
>  /* MPTCP option subtypes */
>  #define MPTCPOPT_MP_CAPABLE    0
> @@ -760,8 +761,8 @@ static inline int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list)
>         return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1;
>  }
>
> -bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> -                             struct mptcp_addr_info *saddr, bool *echo, bool *port);
> +void mptcp_pm_add_addr_signal(struct mptcp_sock *msk, struct mptcp_addr_info *saddr,
> +                             struct mptcp_addr_info *daddr, u8 *add_addr);
>  bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
>                              struct mptcp_rm_list *rm_list);
>  int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
> --
> 1.8.3.1
>
kernel test robot June 17, 2021, 7:22 p.m. UTC | #2
Hi Yonglong,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mptcp/export]
[also build test WARNING on linus/master v5.13-rc6 next-20210617]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Yonglong-Li/mptcp-fix-conflicts-when-using-pm-add_signal-in-ADD_ADDR-echo-and-RM_ADDR-process/20210617-171559
base:   https://github.com/multipath-tcp/mptcp_net-next.git export
config: x86_64-randconfig-a015-20210617 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 64720f57bea6a6bf033feef4a5751ab9c0c3b401)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/dcb008513c667a57c48dd885599f2d760c8cf7eb
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Yonglong-Li/mptcp-fix-conflicts-when-using-pm-add_signal-in-ADD_ADDR-echo-and-RM_ADDR-process/20210617-171559
        git checkout dcb008513c667a57c48dd885599f2d760c8cf7eb
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   net/mptcp/options.c:567:21: warning: parameter 'remaining' set but not used [-Wunused-but-set-parameter]
                                             unsigned int remaining,
                                                          ^
>> net/mptcp/options.c:698:9: warning: variable 'flags' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
           } else if (mptcp_pm_should_add_signal_addr(msk)) {
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/compiler.h:56:28: note: expanded from macro 'if'
   #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/compiler.h:58:30: note: expanded from macro '__trace_if_var'
   #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   net/mptcp/options.c:726:34: note: uninitialized use occurs here
           WRITE_ONCE(msk->pm.addr_signal, flags | msk->pm.addr_signal);
                                           ^~~~~
   include/asm-generic/rwonce.h:61:18: note: expanded from macro 'WRITE_ONCE'
           __WRITE_ONCE(x, val);                                           \
                           ^~~
   include/asm-generic/rwonce.h:55:33: note: expanded from macro '__WRITE_ONCE'
           *(volatile typeof(x) *)&(x) = (val);                            \
                                          ^~~
   net/mptcp/options.c:698:9: note: remove the 'if' if its condition is always true
           } else if (mptcp_pm_should_add_signal_addr(msk)) {
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/compiler.h:56:23: note: expanded from macro 'if'
   #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
                         ^
   net/mptcp/options.c:669:20: note: initialize the variable 'flags' to silence this warning
           u8 add_addr, flags;
                             ^
                              = '\0'
   2 warnings generated.


vim +698 net/mptcp/options.c

   563	
   564	static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
   565						  bool snd_data_fin_enable,
   566						  unsigned int *size,
 > 567						  unsigned int remaining,
   568						  struct mptcp_out_options *opts)
   569	{
   570		struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
   571		struct mptcp_sock *msk = mptcp_sk(subflow->conn);
   572		unsigned int dss_size = 0;
   573		struct mptcp_ext *mpext;
   574		unsigned int ack_size;
   575		bool ret = false;
   576		u64 ack_seq;
   577	
   578		opts->csum_reqd = READ_ONCE(msk->csum_enabled);
   579		mpext = skb ? mptcp_get_ext(skb) : NULL;
   580	
   581		if (!skb || (mpext && mpext->use_map) || snd_data_fin_enable) {
   582			unsigned int map_size = TCPOLEN_MPTCP_DSS_BASE + TCPOLEN_MPTCP_DSS_MAP64;
   583	
   584			if (mpext) {
   585				if (opts->csum_reqd)
   586					map_size += TCPOLEN_MPTCP_DSS_CHECKSUM;
   587	
   588				opts->ext_copy = *mpext;
   589			}
   590	
   591			remaining -= map_size;
   592			dss_size = map_size;
   593			if (skb && snd_data_fin_enable)
   594				mptcp_write_data_fin(subflow, skb, &opts->ext_copy);
   595			ret = true;
   596		}
   597	
   598		/* passive sockets msk will set the 'can_ack' after accept(), even
   599		 * if the first subflow may have the already the remote key handy
   600		 */
   601		opts->ext_copy.use_ack = 0;
   602		if (!READ_ONCE(msk->can_ack)) {
   603			*size = ALIGN(dss_size, 4);
   604			return ret;
   605		}
   606	
   607		ack_seq = READ_ONCE(msk->ack_seq);
   608		if (READ_ONCE(msk->use_64bit_ack)) {
   609			ack_size = TCPOLEN_MPTCP_DSS_ACK64;
   610			opts->ext_copy.data_ack = ack_seq;
   611			opts->ext_copy.ack64 = 1;
   612		} else {
   613			ack_size = TCPOLEN_MPTCP_DSS_ACK32;
   614			opts->ext_copy.data_ack32 = (uint32_t)ack_seq;
   615			opts->ext_copy.ack64 = 0;
   616		}
   617		opts->ext_copy.use_ack = 1;
   618		WRITE_ONCE(msk->old_wspace, __mptcp_space((struct sock *)msk));
   619	
   620		/* Add kind/length/subtype/flag overhead if mapping is not populated */
   621		if (dss_size == 0)
   622			ack_size += TCPOLEN_MPTCP_DSS_BASE;
   623	
   624		dss_size += ack_size;
   625	
   626		*size = ALIGN(dss_size, 4);
   627		return true;
   628	}
   629	
   630	static u64 add_addr_generate_hmac(u64 key1, u64 key2,
   631					  struct mptcp_addr_info *addr)
   632	{
   633		u16 port = ntohs(addr->port);
   634		u8 hmac[SHA256_DIGEST_SIZE];
   635		u8 msg[19];
   636		int i = 0;
   637	
   638		msg[i++] = addr->id;
   639		if (addr->family == AF_INET) {
   640			memcpy(&msg[i], &addr->addr.s_addr, 4);
   641			i += 4;
   642		}
   643	#if IS_ENABLED(CONFIG_MPTCP_IPV6)
   644		else if (addr->family == AF_INET6) {
   645			memcpy(&msg[i], &addr->addr6.s6_addr, 16);
   646			i += 16;
   647		}
   648	#endif
   649		msg[i++] = port >> 8;
   650		msg[i++] = port & 0xFF;
   651	
   652		mptcp_crypto_hmac_sha(key1, key2, msg, i, hmac);
   653	
   654		return get_unaligned_be64(&hmac[SHA256_DIGEST_SIZE - sizeof(u64)]);
   655	}
   656	
   657	static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *skb,
   658						       unsigned int *size,
   659						       unsigned int remaining,
   660						       struct mptcp_out_options *opts)
   661	{
   662		struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
   663		struct mptcp_sock *msk = mptcp_sk(subflow->conn);
   664		bool drop_other_suboptions = false;
   665		unsigned int opt_size = *size;
   666		struct mptcp_addr_info remote;
   667		struct mptcp_addr_info local;
   668		int ret = false;
   669		u8 add_addr, flags;
   670		int len;
   671	
   672		if (!mptcp_pm_should_add_signal(msk))
   673			goto out;
   674	
   675		*size = 0;
   676		mptcp_pm_add_addr_signal(msk, &local, &remote, &add_addr);
   677		if (mptcp_pm_should_add_signal_echo(msk)) {
   678			if (skb && skb_is_tcp_pure_ack(skb)) {
   679				pr_debug("drop other suboptions");
   680				opts->suboptions = 0;
   681				opts->ext_copy.use_ack = 0;
   682				opts->ext_copy.use_map = 0;
   683				remaining += opt_size;
   684				drop_other_suboptions = true;
   685			}
   686			len = mptcp_add_addr_len(remote.family, true, !!remote.port);
   687			if (remaining < len && mptcp_pm_should_add_signal_addr(msk))
   688				goto add_addr;
   689			else if (remaining < len)
   690				goto out;
   691			remaining -= len;
   692			*size += len;
   693			opts->remote = remote;
   694			flags = (u8)~BIT(MPTCP_ADD_ADDR_ECHO);
   695			opts->suboptions |= OPTION_MPTCP_ADD_ECHO;
   696			pr_debug("addr_id=%d, echo=1, port=%d addr_signal:%x",
   697				 opts->remote.id, ntohs(opts->remote.port), add_addr);
 > 698		} else if (mptcp_pm_should_add_signal_addr(msk)) {
   699	add_addr:
   700			if ((local.family == AF_INET6 || local.port) && skb &&
   701			    skb_is_tcp_pure_ack(skb)) {
   702				pr_debug("drop other suboptions");
   703				opts->suboptions = 0;
   704				opts->ext_copy.use_ack = 0;
   705				opts->ext_copy.use_map = 0;
   706				remaining += opt_size;
   707				drop_other_suboptions = true;
   708			}
   709			len = mptcp_add_addr_len(local.family, false, !!local.port);
   710			if (remaining < len)
   711				goto out;
   712			*size += len;
   713			opts->addr = local;
   714			opts->ahmac = add_addr_generate_hmac(msk->local_key,
   715							     msk->remote_key,
   716							     &opts->addr);
   717			opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
   718			flags = (u8)~BIT(MPTCP_ADD_ADDR_SIGNAL);
   719			pr_debug("addr_id=%d, ahmac=%llu, echo=0, port=%d, addr_signal:%x",
   720				 opts->addr.id, opts->ahmac, ntohs(opts->addr.port), add_addr);
   721		}
   722	
   723		if (drop_other_suboptions)
   724			*size -= opt_size;
   725		spin_lock_bh(&msk->pm.lock);
   726		WRITE_ONCE(msk->pm.addr_signal, flags | msk->pm.addr_signal);
   727		spin_unlock_bh(&msk->pm.lock);
   728		ret = true;
   729	
   730	out:
   731		return ret;
   732	}
   733	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Mat Martineau June 18, 2021, 12:25 a.m. UTC | #3
On Thu, 17 Jun 2021, Yonglong Li wrote:

> according MPTCP_ADD_ADDR_SIGNAL and MPTCP_ADD_ADDR_ECHO flag build
> ADD_ADDR/echo-ADD_ADDR option
>
> add a suboptions type OPTION_MPTCP_ADD_ECHO to mark as echo option
>
> Signed-off-by: Yonglong Li <liyonglong@chinatelecom.cn>
> ---
> net/mptcp/options.c  | 161 +++++++++++++++++++++++++++++++++------------------
> net/mptcp/pm.c       |  30 +++-------
> net/mptcp/protocol.h |  13 +++--
> 3 files changed, 122 insertions(+), 82 deletions(-)
>
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index 1aec016..3ecf2c6 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -655,43 +655,72 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
> 	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
> 	bool drop_other_suboptions = false;
> 	unsigned int opt_size = *size;
> -	bool echo;
> -	bool port;
> +	struct mptcp_addr_info remote;
> +	struct mptcp_addr_info local;
> +	int ret = false;
> +	u8 add_addr, flags;
> 	int len;
>
> -	if ((mptcp_pm_should_add_signal_ipv6(msk) ||
> -	     mptcp_pm_should_add_signal_port(msk) ||
> -	     mptcp_pm_should_add_signal_echo(msk)) &&
> -	    skb && skb_is_tcp_pure_ack(skb)) {
> -		pr_debug("drop other suboptions");
> -		opts->suboptions = 0;
> -		opts->ext_copy.use_ack = 0;
> -		opts->ext_copy.use_map = 0;
> -		remaining += opt_size;
> -		drop_other_suboptions = true;
> -	}
> -
> -	if (!mptcp_pm_should_add_signal(msk) ||
> -	    !(mptcp_pm_add_addr_signal(msk, remaining, &opts->addr, &echo, &port)))
> -		return false;
> -
> -	len = mptcp_add_addr_len(opts->addr.family, echo, port);
> -	if (remaining < len)
> -		return false;
> -
> -	*size = len;
> -	if (drop_other_suboptions)
> -		*size -= opt_size;
> -	opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
> -	if (!echo) {
> +	if (!mptcp_pm_should_add_signal(msk))
> +		goto out;

Hi Yonglong, thanks for revising.

Instead of the goto here, just "return true;".

> +
> +	*size = 0;
> +	mptcp_pm_add_addr_signal(msk, &local, &remote, &add_addr);
> +	if (mptcp_pm_should_add_signal_echo(msk)) {
> +		if (skb && skb_is_tcp_pure_ack(skb)) {
> +			pr_debug("drop other suboptions");
> +			opts->suboptions = 0;
> +			opts->ext_copy.use_ack = 0;
> +			opts->ext_copy.use_map = 0;
> +			remaining += opt_size;
> +			drop_other_suboptions = true;
> +		}
> +		len = mptcp_add_addr_len(remote.family, true, !!remote.port);
> +		if (remaining < len && mptcp_pm_should_add_signal_addr(msk))
> +			goto add_addr;

This goto isn't quite right. It jumps below with opts and remaining 
already modified, and may end up modifying 'remaining' again.

Would be better to separate the logic for sending echo-vs-signal, so the 
goto isn't necessary.

> +		else if (remaining < len)
> +			goto out;
> +		remaining -= len;
> +		*size += len;
> +		opts->remote = remote;
> +		flags = (u8)~BIT(MPTCP_ADD_ADDR_ECHO);
> +		opts->suboptions |= OPTION_MPTCP_ADD_ECHO;
> +		pr_debug("addr_id=%d, echo=1, port=%d addr_signal:%x",
> +			 opts->remote.id, ntohs(opts->remote.port), add_addr);
> +	} else if (mptcp_pm_should_add_signal_addr(msk)) {
> +add_addr:
> +		if ((local.family == AF_INET6 || local.port) && skb &&
> +		    skb_is_tcp_pure_ack(skb)) {
> +			pr_debug("drop other suboptions");
> +			opts->suboptions = 0;
> +			opts->ext_copy.use_ack = 0;
> +			opts->ext_copy.use_map = 0;
> +			remaining += opt_size;
> +			drop_other_suboptions = true;
> +		}
> +		len = mptcp_add_addr_len(local.family, false, !!local.port);
> +		if (remaining < len)
> +			goto out;
> +		*size += len;
> +		opts->addr = local;
> 		opts->ahmac = add_addr_generate_hmac(msk->local_key,
> 						     msk->remote_key,
> 						     &opts->addr);
> +		opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
> +		flags = (u8)~BIT(MPTCP_ADD_ADDR_SIGNAL);
> +		pr_debug("addr_id=%d, ahmac=%llu, echo=0, port=%d, addr_signal:%x",
> +			 opts->addr.id, opts->ahmac, ntohs(opts->addr.port), add_addr);
> 	}
> -	pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d",
> -		 opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port));
>
> -	return true;
> +	if (drop_other_suboptions)
> +		*size -= opt_size;
> +	spin_lock_bh(&msk->pm.lock);
> +	WRITE_ONCE(msk->pm.addr_signal, flags | msk->pm.addr_signal);
> +	spin_unlock_bh(&msk->pm.lock);

This would set bits in msk->pm.addr_signal rather than clear them. Did you 
intend '&' instead of '|'?

As the kbuild bot noted, 'flags' can be uninitialized. That code path is 
not expected and shouldn't happen, but since the pm lock is not held the 
whole time the code should handle concurrent changes to 
msk->pm.addr_signal. Could initialize flags to 0 and only 
lock/write/unlock if flags is nonzero.

> +	ret = true;
> +
> +out:
> +	return ret;

Since the return is the only thing after the label, better to not use 
'goto' and use return statements where needed in the code above.

-Mat


> }
>
> static bool mptcp_established_options_rm_addr(struct sock *sk,
> @@ -1230,21 +1259,18 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
> mp_capable_done:
> 	if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
> 		u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
> -		u8 echo = MPTCP_ADDR_ECHO;
> +		u8 echo = 0;
>
> #if IS_ENABLED(CONFIG_MPTCP_IPV6)
> 		if (opts->addr.family == AF_INET6)
> 			len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
> #endif
>
> +		len += sizeof(opts->ahmac);
> +
> 		if (opts->addr.port)
> 			len += TCPOLEN_MPTCP_PORT_LEN;
>
> -		if (opts->ahmac) {
> -			len += sizeof(opts->ahmac);
> -			echo = 0;
> -		}
> -
> 		*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
> 				      len, echo, opts->addr.id);
> 		if (opts->addr.family == AF_INET) {
> @@ -1259,30 +1285,55 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
> #endif
>
> 		if (!opts->addr.port) {
> -			if (opts->ahmac) {
> -				put_unaligned_be64(opts->ahmac, ptr);
> -				ptr += 2;
> -			}
> +			put_unaligned_be64(opts->ahmac, ptr);
> +			ptr += 2;
> 		} else {
> 			u16 port = ntohs(opts->addr.port);
> +			u8 *bptr = (u8 *)ptr;
>
> -			if (opts->ahmac) {
> -				u8 *bptr = (u8 *)ptr;
> +			put_unaligned_be16(port, bptr);
> +			bptr += 2;
> +			put_unaligned_be64(opts->ahmac, bptr);
> +			bptr += 8;
> +			put_unaligned_be16(TCPOPT_NOP << 8 |
> +					   TCPOPT_NOP, bptr);
>
> -				put_unaligned_be16(port, bptr);
> -				bptr += 2;
> -				put_unaligned_be64(opts->ahmac, bptr);
> -				bptr += 8;
> -				put_unaligned_be16(TCPOPT_NOP << 8 |
> -						   TCPOPT_NOP, bptr);
> +			ptr += 3;
> +		}
> +	}
>
> -				ptr += 3;
> -			} else {
> -				put_unaligned_be32(port << 16 |
> -						   TCPOPT_NOP << 8 |
> -						   TCPOPT_NOP, ptr);
> -				ptr += 1;
> -			}
> +	if (OPTION_MPTCP_ADD_ECHO & opts->suboptions) {
> +		u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
> +		u8 echo = MPTCP_ADDR_ECHO;
> +
> +#if IS_ENABLED(CONFIG_MPTCP_IPV6)
> +		if (opts->remote.family == AF_INET6)
> +			len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
> +#endif
> +
> +		if (opts->remote.port)
> +			len += TCPOLEN_MPTCP_PORT_LEN;
> +
> +		*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
> +				      len, echo, opts->remote.id);
> +		if (opts->remote.family == AF_INET) {
> +			memcpy((u8 *)ptr, (u8 *)&opts->remote.addr.s_addr, 4);
> +			ptr += 1;
> +		}
> +#if IS_ENABLED(CONFIG_MPTCP_IPV6)
> +		else if (opts->remote.family == AF_INET6) {
> +			memcpy((u8 *)ptr, opts->remote.addr6.s6_addr, 16);
> +			ptr += 4;
> +		}
> +#endif
> +
> +		if (opts->remote.port) {
> +			u16 port = ntohs(opts->remote.port);
> +
> +			put_unaligned_be32(port << 16 |
> +					   TCPOPT_NOP << 8 |
> +					   TCPOPT_NOP, ptr);
> +			ptr += 1;
> 		}
> 	}
>
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index 74be6d7..a62d4a5 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -22,7 +22,8 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk,
>
> 	lockdep_assert_held(&msk->pm.lock);
>
> -	if (add_addr) {
> +	if (add_addr &
> +	    (echo ? BIT(MPTCP_ADD_ADDR_ECHO) : BIT(MPTCP_ADD_ADDR_SIGNAL))) {
> 		pr_warn("addr_signal error, add_addr=%d", add_addr);
> 		return -EINVAL;
> 	}
> @@ -252,32 +253,19 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup)
>
> /* path manager helpers */
>
> -bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> -			      struct mptcp_addr_info *saddr, bool *echo, bool *port)
> +void mptcp_pm_add_addr_signal(struct mptcp_sock *msk, struct mptcp_addr_info *saddr,
> +			      struct mptcp_addr_info *daddr, u8 *add_addr)
> {
> -	u8 add_addr;
> -	int ret = false;
> -
> 	spin_lock_bh(&msk->pm.lock);
>
> -	/* double check after the lock is acquired */
> -	if (!mptcp_pm_should_add_signal(msk))
> -		goto out_unlock;
> -
> -	*echo = mptcp_pm_should_add_signal_echo(msk);
> -	*port = mptcp_pm_should_add_signal_port(msk);
> -
> -	if (remaining < mptcp_add_addr_len(msk->pm.local.family, *echo, *port))
> -		goto out_unlock;
> -
> 	*saddr = msk->pm.local;
> -	add_addr = msk->pm.addr_signal & BIT(MPTCP_RM_ADDR_SIGNAL);
> -	WRITE_ONCE(msk->pm.addr_signal, add_addr);
> -	ret = true;
> +	*daddr = msk->pm.remote;
> +	*add_addr = msk->pm.addr_signal;
>
> -out_unlock:
> 	spin_unlock_bh(&msk->pm.lock);
> -	return ret;
> +
> +	if ((mptcp_pm_should_add_signal_echo(msk)) && (mptcp_pm_should_add_signal_addr(msk)))
> +		mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_SEND_ACK);
> }
>
> bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index a0b0ec0..90fb532 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -22,10 +22,11 @@
> #define OPTION_MPTCP_MPJ_SYNACK	BIT(4)
> #define OPTION_MPTCP_MPJ_ACK	BIT(5)
> #define OPTION_MPTCP_ADD_ADDR	BIT(6)
> -#define OPTION_MPTCP_RM_ADDR	BIT(7)
> -#define OPTION_MPTCP_FASTCLOSE	BIT(8)
> -#define OPTION_MPTCP_PRIO	BIT(9)
> -#define OPTION_MPTCP_RST	BIT(10)
> +#define OPTION_MPTCP_ADD_ECHO	BIT(7)
> +#define OPTION_MPTCP_RM_ADDR	BIT(8)
> +#define OPTION_MPTCP_FASTCLOSE	BIT(9)
> +#define OPTION_MPTCP_PRIO	BIT(10)
> +#define OPTION_MPTCP_RST	BIT(11)
>
> /* MPTCP option subtypes */
> #define MPTCPOPT_MP_CAPABLE	0
> @@ -760,8 +761,8 @@ static inline int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list)
> 	return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1;
> }
>
> -bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> -			      struct mptcp_addr_info *saddr, bool *echo, bool *port);
> +void mptcp_pm_add_addr_signal(struct mptcp_sock *msk, struct mptcp_addr_info *saddr,
> +			      struct mptcp_addr_info *daddr, u8 *add_addr);
> bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> 			     struct mptcp_rm_list *rm_list);
> int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
> -- 
> 1.8.3.1
>
>
>

--
Mat Martineau
Intel
YonglongLi June 18, 2021, 1:10 a.m. UTC | #4
Hi Geliang,

Thanks for your review. I will simply the code and send v4 patch.

On 2021/6/17 20:37, Geliang Tang wrote:
>>                                                      &opts->addr);
>> +               opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
>> +               flags = (u8)~BIT(MPTCP_ADD_ADDR_SIGNAL);
>> +               pr_debug("addr_id=%d, ahmac=%llu, echo=0, port=%d, addr_signal:%x",
>> +                        opts->addr.id, opts->ahmac, ntohs(opts->addr.port), add_addr);
>>         }
> There are some duplicate codes here between the
> mptcp_pm_should_add_signal_echo(msk) trunk and the
> mptcp_pm_should_add_signal_addr(msk) trunk, could you please simply them
> into one trunk?
>
YonglongLi June 18, 2021, 1:24 a.m. UTC | #5
On 2021/6/18 8:25, Mat Martineau wrote:
> 
> This goto isn't quite right. It jumps below with opts and remaining already modified, and may end up modifying 'remaining' again.
> 
> Would be better to separate the logic for sending echo-vs-signal, so the goto isn't necessary.

Thanks for your review. The goto logic is not right indeed. I will separate the logic for sending echo-vs-signal

> 
>> +        else if (remaining < len)
>> +            goto out;
>> +        remaining -= len;
>> +        *size += len;
>> +        opts->remote = remote;
>> +        flags = (u8)~BIT(MPTCP_ADD_ADDR_ECHO);
>> +        opts->suboptions |= OPTION_MPTCP_ADD_ECHO;
>> +        pr_debug("addr_id=%d, echo=1, port=%d addr_signal:%x",
>> +             opts->remote.id, ntohs(opts->remote.port), add_addr);
>> +    } else if (mptcp_pm_should_add_signal_addr(msk)) {
>> +add_addr:
>> +        if ((local.family == AF_INET6 || local.port) && skb &&
>> +            skb_is_tcp_pure_ack(skb)) {
>> +            pr_debug("drop other suboptions");
>> +            opts->suboptions = 0;
>> +            opts->ext_copy.use_ack = 0;
>> +            opts->ext_copy.use_map = 0;
>> +            remaining += opt_size;
>> +            drop_other_suboptions = true;
>> +        }
>> +        len = mptcp_add_addr_len(local.family, false, !!local.port);
>> +        if (remaining < len)
>> +            goto out;
>> +        *size += len;
>> +        opts->addr = local;
>>         opts->ahmac = add_addr_generate_hmac(msk->local_key,
>>                              msk->remote_key,
>>                              &opts->addr);
>> +        opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
>> +        flags = (u8)~BIT(MPTCP_ADD_ADDR_SIGNAL);
>> +        pr_debug("addr_id=%d, ahmac=%llu, echo=0, port=%d, addr_signal:%x",
>> +             opts->addr.id, opts->ahmac, ntohs(opts->addr.port), add_addr);
>>     }
>> -    pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d",
>> -         opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port));
>>
>> -    return true;
>> +    if (drop_other_suboptions)
>> +        *size -= opt_size;
>> +    spin_lock_bh(&msk->pm.lock);
>> +    WRITE_ONCE(msk->pm.addr_signal, flags | msk->pm.addr_signal);
>> +    spin_unlock_bh(&msk->pm.lock);
> 
> This would set bits in msk->pm.addr_signal rather than clear them. Did you intend '&' instead of '|'?

Sorry for this mistake. :(
diff mbox series

Patch

diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 1aec016..3ecf2c6 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -655,43 +655,72 @@  static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
 	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
 	bool drop_other_suboptions = false;
 	unsigned int opt_size = *size;
-	bool echo;
-	bool port;
+	struct mptcp_addr_info remote;
+	struct mptcp_addr_info local;
+	int ret = false;
+	u8 add_addr, flags;
 	int len;
 
-	if ((mptcp_pm_should_add_signal_ipv6(msk) ||
-	     mptcp_pm_should_add_signal_port(msk) ||
-	     mptcp_pm_should_add_signal_echo(msk)) &&
-	    skb && skb_is_tcp_pure_ack(skb)) {
-		pr_debug("drop other suboptions");
-		opts->suboptions = 0;
-		opts->ext_copy.use_ack = 0;
-		opts->ext_copy.use_map = 0;
-		remaining += opt_size;
-		drop_other_suboptions = true;
-	}
-
-	if (!mptcp_pm_should_add_signal(msk) ||
-	    !(mptcp_pm_add_addr_signal(msk, remaining, &opts->addr, &echo, &port)))
-		return false;
-
-	len = mptcp_add_addr_len(opts->addr.family, echo, port);
-	if (remaining < len)
-		return false;
-
-	*size = len;
-	if (drop_other_suboptions)
-		*size -= opt_size;
-	opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
-	if (!echo) {
+	if (!mptcp_pm_should_add_signal(msk))
+		goto out;
+
+	*size = 0;
+	mptcp_pm_add_addr_signal(msk, &local, &remote, &add_addr);
+	if (mptcp_pm_should_add_signal_echo(msk)) {
+		if (skb && skb_is_tcp_pure_ack(skb)) {
+			pr_debug("drop other suboptions");
+			opts->suboptions = 0;
+			opts->ext_copy.use_ack = 0;
+			opts->ext_copy.use_map = 0;
+			remaining += opt_size;
+			drop_other_suboptions = true;
+		}
+		len = mptcp_add_addr_len(remote.family, true, !!remote.port);
+		if (remaining < len && mptcp_pm_should_add_signal_addr(msk))
+			goto add_addr;
+		else if (remaining < len)
+			goto out;
+		remaining -= len;
+		*size += len;
+		opts->remote = remote;
+		flags = (u8)~BIT(MPTCP_ADD_ADDR_ECHO);
+		opts->suboptions |= OPTION_MPTCP_ADD_ECHO;
+		pr_debug("addr_id=%d, echo=1, port=%d addr_signal:%x",
+			 opts->remote.id, ntohs(opts->remote.port), add_addr);
+	} else if (mptcp_pm_should_add_signal_addr(msk)) {
+add_addr:
+		if ((local.family == AF_INET6 || local.port) && skb &&
+		    skb_is_tcp_pure_ack(skb)) {
+			pr_debug("drop other suboptions");
+			opts->suboptions = 0;
+			opts->ext_copy.use_ack = 0;
+			opts->ext_copy.use_map = 0;
+			remaining += opt_size;
+			drop_other_suboptions = true;
+		}
+		len = mptcp_add_addr_len(local.family, false, !!local.port);
+		if (remaining < len)
+			goto out;
+		*size += len;
+		opts->addr = local;
 		opts->ahmac = add_addr_generate_hmac(msk->local_key,
 						     msk->remote_key,
 						     &opts->addr);
+		opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
+		flags = (u8)~BIT(MPTCP_ADD_ADDR_SIGNAL);
+		pr_debug("addr_id=%d, ahmac=%llu, echo=0, port=%d, addr_signal:%x",
+			 opts->addr.id, opts->ahmac, ntohs(opts->addr.port), add_addr);
 	}
-	pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d",
-		 opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port));
 
-	return true;
+	if (drop_other_suboptions)
+		*size -= opt_size;
+	spin_lock_bh(&msk->pm.lock);
+	WRITE_ONCE(msk->pm.addr_signal, flags | msk->pm.addr_signal);
+	spin_unlock_bh(&msk->pm.lock);
+	ret = true;
+
+out:
+	return ret;
 }
 
 static bool mptcp_established_options_rm_addr(struct sock *sk,
@@ -1230,21 +1259,18 @@  void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
 mp_capable_done:
 	if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
 		u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
-		u8 echo = MPTCP_ADDR_ECHO;
+		u8 echo = 0;
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 		if (opts->addr.family == AF_INET6)
 			len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
 #endif
 
+		len += sizeof(opts->ahmac);
+
 		if (opts->addr.port)
 			len += TCPOLEN_MPTCP_PORT_LEN;
 
-		if (opts->ahmac) {
-			len += sizeof(opts->ahmac);
-			echo = 0;
-		}
-
 		*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
 				      len, echo, opts->addr.id);
 		if (opts->addr.family == AF_INET) {
@@ -1259,30 +1285,55 @@  void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
 #endif
 
 		if (!opts->addr.port) {
-			if (opts->ahmac) {
-				put_unaligned_be64(opts->ahmac, ptr);
-				ptr += 2;
-			}
+			put_unaligned_be64(opts->ahmac, ptr);
+			ptr += 2;
 		} else {
 			u16 port = ntohs(opts->addr.port);
+			u8 *bptr = (u8 *)ptr;
 
-			if (opts->ahmac) {
-				u8 *bptr = (u8 *)ptr;
+			put_unaligned_be16(port, bptr);
+			bptr += 2;
+			put_unaligned_be64(opts->ahmac, bptr);
+			bptr += 8;
+			put_unaligned_be16(TCPOPT_NOP << 8 |
+					   TCPOPT_NOP, bptr);
 
-				put_unaligned_be16(port, bptr);
-				bptr += 2;
-				put_unaligned_be64(opts->ahmac, bptr);
-				bptr += 8;
-				put_unaligned_be16(TCPOPT_NOP << 8 |
-						   TCPOPT_NOP, bptr);
+			ptr += 3;
+		}
+	}
 
-				ptr += 3;
-			} else {
-				put_unaligned_be32(port << 16 |
-						   TCPOPT_NOP << 8 |
-						   TCPOPT_NOP, ptr);
-				ptr += 1;
-			}
+	if (OPTION_MPTCP_ADD_ECHO & opts->suboptions) {
+		u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
+		u8 echo = MPTCP_ADDR_ECHO;
+
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+		if (opts->remote.family == AF_INET6)
+			len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
+#endif
+
+		if (opts->remote.port)
+			len += TCPOLEN_MPTCP_PORT_LEN;
+
+		*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
+				      len, echo, opts->remote.id);
+		if (opts->remote.family == AF_INET) {
+			memcpy((u8 *)ptr, (u8 *)&opts->remote.addr.s_addr, 4);
+			ptr += 1;
+		}
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+		else if (opts->remote.family == AF_INET6) {
+			memcpy((u8 *)ptr, opts->remote.addr6.s6_addr, 16);
+			ptr += 4;
+		}
+#endif
+
+		if (opts->remote.port) {
+			u16 port = ntohs(opts->remote.port);
+
+			put_unaligned_be32(port << 16 |
+					   TCPOPT_NOP << 8 |
+					   TCPOPT_NOP, ptr);
+			ptr += 1;
 		}
 	}
 
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 74be6d7..a62d4a5 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -22,7 +22,8 @@  int mptcp_pm_announce_addr(struct mptcp_sock *msk,
 
 	lockdep_assert_held(&msk->pm.lock);
 
-	if (add_addr) {
+	if (add_addr &
+	    (echo ? BIT(MPTCP_ADD_ADDR_ECHO) : BIT(MPTCP_ADD_ADDR_SIGNAL))) {
 		pr_warn("addr_signal error, add_addr=%d", add_addr);
 		return -EINVAL;
 	}
@@ -252,32 +253,19 @@  void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup)
 
 /* path manager helpers */
 
-bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
-			      struct mptcp_addr_info *saddr, bool *echo, bool *port)
+void mptcp_pm_add_addr_signal(struct mptcp_sock *msk, struct mptcp_addr_info *saddr,
+			      struct mptcp_addr_info *daddr, u8 *add_addr)
 {
-	u8 add_addr;
-	int ret = false;
-
 	spin_lock_bh(&msk->pm.lock);
 
-	/* double check after the lock is acquired */
-	if (!mptcp_pm_should_add_signal(msk))
-		goto out_unlock;
-
-	*echo = mptcp_pm_should_add_signal_echo(msk);
-	*port = mptcp_pm_should_add_signal_port(msk);
-
-	if (remaining < mptcp_add_addr_len(msk->pm.local.family, *echo, *port))
-		goto out_unlock;
-
 	*saddr = msk->pm.local;
-	add_addr = msk->pm.addr_signal & BIT(MPTCP_RM_ADDR_SIGNAL);
-	WRITE_ONCE(msk->pm.addr_signal, add_addr);
-	ret = true;
+	*daddr = msk->pm.remote;
+	*add_addr = msk->pm.addr_signal;
 
-out_unlock:
 	spin_unlock_bh(&msk->pm.lock);
-	return ret;
+
+	if ((mptcp_pm_should_add_signal_echo(msk)) && (mptcp_pm_should_add_signal_addr(msk)))
+		mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_SEND_ACK);
 }
 
 bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index a0b0ec0..90fb532 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -22,10 +22,11 @@ 
 #define OPTION_MPTCP_MPJ_SYNACK	BIT(4)
 #define OPTION_MPTCP_MPJ_ACK	BIT(5)
 #define OPTION_MPTCP_ADD_ADDR	BIT(6)
-#define OPTION_MPTCP_RM_ADDR	BIT(7)
-#define OPTION_MPTCP_FASTCLOSE	BIT(8)
-#define OPTION_MPTCP_PRIO	BIT(9)
-#define OPTION_MPTCP_RST	BIT(10)
+#define OPTION_MPTCP_ADD_ECHO	BIT(7)
+#define OPTION_MPTCP_RM_ADDR	BIT(8)
+#define OPTION_MPTCP_FASTCLOSE	BIT(9)
+#define OPTION_MPTCP_PRIO	BIT(10)
+#define OPTION_MPTCP_RST	BIT(11)
 
 /* MPTCP option subtypes */
 #define MPTCPOPT_MP_CAPABLE	0
@@ -760,8 +761,8 @@  static inline int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list)
 	return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1;
 }
 
-bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
-			      struct mptcp_addr_info *saddr, bool *echo, bool *port);
+void mptcp_pm_add_addr_signal(struct mptcp_sock *msk, struct mptcp_addr_info *saddr,
+			      struct mptcp_addr_info *daddr, u8 *add_addr);
 bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
 			     struct mptcp_rm_list *rm_list);
 int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);