Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / net / mptcp / options.c
index 888bbbb..4d35fa9 100644 (file)
@@ -11,6 +11,7 @@
 #include <net/tcp.h>
 #include <net/mptcp.h>
 #include "protocol.h"
+#include "mib.h"
 
 static bool mptcp_cap_flag_sha256(u8 flags)
 {
@@ -242,7 +243,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
                mp_opt->add_addr = 1;
                mp_opt->port = 0;
                mp_opt->addr_id = *ptr++;
-               pr_debug("ADD_ADDR: id=%d", mp_opt->addr_id);
+               pr_debug("ADD_ADDR: id=%d, echo=%d", mp_opt->addr_id, mp_opt->echo);
                if (mp_opt->family == MPTCP_ADDR_IPVERSION_4) {
                        memcpy((u8 *)&mp_opt->addr.s_addr, (u8 *)ptr, 4);
                        ptr += 4;
@@ -571,21 +572,22 @@ static u64 add_addr6_generate_hmac(u64 key1, u64 key2, u8 addr_id,
 }
 #endif
 
-static bool mptcp_established_options_addr(struct sock *sk,
-                                          unsigned int *size,
-                                          unsigned int remaining,
-                                          struct mptcp_out_options *opts)
+static bool mptcp_established_options_add_addr(struct sock *sk,
+                                              unsigned int *size,
+                                              unsigned int remaining,
+                                              struct mptcp_out_options *opts)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
        struct mptcp_sock *msk = mptcp_sk(subflow->conn);
        struct mptcp_addr_info saddr;
+       bool echo;
        int len;
 
-       if (!mptcp_pm_should_signal(msk) ||
-           !(mptcp_pm_addr_signal(msk, remaining, &saddr)))
+       if (!mptcp_pm_should_add_signal(msk) ||
+           !(mptcp_pm_add_addr_signal(msk, remaining, &saddr, &echo)))
                return false;
 
-       len = mptcp_add_addr_len(saddr.family);
+       len = mptcp_add_addr_len(saddr.family, echo);
        if (remaining < len)
                return false;
 
@@ -594,22 +596,51 @@ static bool mptcp_established_options_addr(struct sock *sk,
        if (saddr.family == AF_INET) {
                opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
                opts->addr = saddr.addr;
-               opts->ahmac = add_addr_generate_hmac(msk->local_key,
-                                                    msk->remote_key,
-                                                    opts->addr_id,
-                                                    &opts->addr);
+               if (!echo) {
+                       opts->ahmac = add_addr_generate_hmac(msk->local_key,
+                                                            msk->remote_key,
+                                                            opts->addr_id,
+                                                            &opts->addr);
+               }
        }
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
        else if (saddr.family == AF_INET6) {
                opts->suboptions |= OPTION_MPTCP_ADD_ADDR6;
                opts->addr6 = saddr.addr6;
-               opts->ahmac = add_addr6_generate_hmac(msk->local_key,
-                                                     msk->remote_key,
-                                                     opts->addr_id,
-                                                     &opts->addr6);
+               if (!echo) {
+                       opts->ahmac = add_addr6_generate_hmac(msk->local_key,
+                                                             msk->remote_key,
+                                                             opts->addr_id,
+                                                             &opts->addr6);
+               }
        }
 #endif
-       pr_debug("addr_id=%d, ahmac=%llu", opts->addr_id, opts->ahmac);
+       pr_debug("addr_id=%d, ahmac=%llu, echo=%d", opts->addr_id, opts->ahmac, echo);
+
+       return true;
+}
+
+static bool mptcp_established_options_rm_addr(struct sock *sk,
+                                             unsigned int *size,
+                                             unsigned int remaining,
+                                             struct mptcp_out_options *opts)
+{
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+       struct mptcp_sock *msk = mptcp_sk(subflow->conn);
+       u8 rm_id;
+
+       if (!mptcp_pm_should_rm_signal(msk) ||
+           !(mptcp_pm_rm_addr_signal(msk, remaining, &rm_id)))
+               return false;
+
+       if (remaining < TCPOLEN_MPTCP_RM_ADDR_BASE)
+               return false;
+
+       *size = TCPOLEN_MPTCP_RM_ADDR_BASE;
+       opts->suboptions |= OPTION_MPTCP_RM_ADDR;
+       opts->rm_id = rm_id;
+
+       pr_debug("rm_id=%d", opts->rm_id);
 
        return true;
 }
@@ -640,7 +671,11 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
 
        *size += opt_size;
        remaining -= opt_size;
-       if (mptcp_established_options_addr(sk, &opt_size, remaining, opts)) {
+       if (mptcp_established_options_add_addr(sk, &opt_size, remaining, opts)) {
+               *size += opt_size;
+               remaining -= opt_size;
+               ret = true;
+       } else if (mptcp_established_options_rm_addr(sk, &opt_size, remaining, opts)) {
                *size += opt_size;
                remaining -= opt_size;
                ret = true;
@@ -825,8 +860,7 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk,
        return hmac == mp_opt->ahmac;
 }
 
-void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
-                           struct tcp_options_received *opt_rx)
+void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
 {
        struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
        struct mptcp_sock *msk = mptcp_sk(subflow->conn);
@@ -855,11 +889,21 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
                        addr.addr6 = mp_opt.addr6;
                }
 #endif
-               if (!mp_opt.echo)
+               if (!mp_opt.echo) {
                        mptcp_pm_add_addr_received(msk, &addr);
+                       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR);
+               } else {
+                       mptcp_pm_del_add_timer(msk, &addr);
+                       MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD);
+               }
                mp_opt.add_addr = 0;
        }
 
+       if (mp_opt.rm_addr) {
+               mptcp_pm_rm_addr_received(msk, mp_opt.rm_id);
+               mp_opt.rm_addr = 0;
+       }
+
        if (!mp_opt.dss)
                return;