summaryrefslogtreecommitdiffstats
path: root/net/mptcp/options.c
diff options
context:
space:
mode:
authorPeter Krystad <peter.krystad@linux.intel.com>2020-03-27 22:48:38 +0100
committerDavid S. Miller <davem@davemloft.net>2020-03-30 07:14:48 +0200
commit1b1c7a0ef7f323f37281b134ade17baa94779787 (patch)
tree8fddc2a7ad56b081558cf89950a646ec9c4afab5 /net/mptcp/options.c
parentmptcp: Add ADD_ADDR handling (diff)
downloadlinux-1b1c7a0ef7f323f37281b134ade17baa94779787.tar.xz
linux-1b1c7a0ef7f323f37281b134ade17baa94779787.zip
mptcp: Add path manager interface
Add enough of a path manager interface to allow sending of ADD_ADDR when an incoming MPTCP connection is created. Capable of sending only a single IPv4 ADD_ADDR option. The 'pm_data' element of the connection sock will need to be expanded to handle multiple interfaces and IPv6. Partial processing of the incoming ADD_ADDR is included so the path manager notification of that event happens at the proper time, which involves validating the incoming address information. This is a skeleton interface definition for events generated by MPTCP. Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> Co-developed-by: Florian Westphal <fw@strlen.de> Signed-off-by: Florian Westphal <fw@strlen.de> Co-developed-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Co-developed-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mptcp/options.c')
-rw-r--r--net/mptcp/options.c80
1 files changed, 64 insertions, 16 deletions
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 6c6c18a09a40..a3661318a7af 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -492,36 +492,35 @@ static bool mptcp_established_options_addr(struct sock *sk,
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
- struct sockaddr_storage saddr;
- u8 id;
+ struct mptcp_addr_info saddr;
+ int len;
- id = 0;
- memset(&saddr, 0, sizeof(saddr));
+ if (!mptcp_pm_should_signal(msk) ||
+ !(mptcp_pm_addr_signal(msk, remaining, &saddr)))
+ return false;
+
+ len = mptcp_add_addr_len(saddr.family);
+ if (remaining < len)
+ return false;
- if (saddr.ss_family == AF_INET) {
- if (remaining < TCPOLEN_MPTCP_ADD_ADDR)
- return false;
+ *size = len;
+ opts->addr_id = saddr.id;
+ if (saddr.family == AF_INET) {
opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
- opts->addr_id = id;
- opts->addr = ((struct sockaddr_in *)&saddr)->sin_addr;
+ opts->addr = saddr.addr;
opts->ahmac = add_addr_generate_hmac(msk->local_key,
msk->remote_key,
opts->addr_id,
&opts->addr);
- *size = TCPOLEN_MPTCP_ADD_ADDR;
}
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
- else if (saddr.ss_family == AF_INET6) {
- if (remaining < TCPOLEN_MPTCP_ADD_ADDR6)
- return false;
+ else if (saddr.family == AF_INET6) {
opts->suboptions |= OPTION_MPTCP_ADD_ADDR6;
- opts->addr_id = id;
+ opts->addr6 = saddr.addr6;
opts->ahmac = add_addr6_generate_hmac(msk->local_key,
msk->remote_key,
opts->addr_id,
&opts->addr6);
- opts->addr6 = ((struct sockaddr_in6 *)&saddr)->sin6_addr;
- *size = TCPOLEN_MPTCP_ADD_ADDR6;
}
#endif
pr_debug("addr_id=%d, ahmac=%llu", opts->addr_id, opts->ahmac);
@@ -607,10 +606,37 @@ static bool check_fully_established(struct mptcp_subflow_context *subflow,
return true;
}
+static bool add_addr_hmac_valid(struct mptcp_sock *msk,
+ struct mptcp_options_received *mp_opt)
+{
+ u64 hmac = 0;
+
+ if (mp_opt->echo)
+ return true;
+
+ if (mp_opt->family == MPTCP_ADDR_IPVERSION_4)
+ hmac = add_addr_generate_hmac(msk->remote_key,
+ msk->local_key,
+ mp_opt->addr_id, &mp_opt->addr);
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+ else
+ hmac = add_addr6_generate_hmac(msk->remote_key,
+ msk->local_key,
+ mp_opt->addr_id, &mp_opt->addr6);
+#endif
+
+ pr_debug("msk=%p, ahmac=%llu, mp_opt->ahmac=%llu\n",
+ msk, (unsigned long long)hmac,
+ (unsigned long long)mp_opt->ahmac);
+
+ return hmac == mp_opt->ahmac;
+}
+
void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
struct tcp_options_received *opt_rx)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+ struct mptcp_sock *msk = mptcp_sk(subflow->conn);
struct mptcp_options_received *mp_opt;
struct mptcp_ext *mpext;
@@ -618,6 +644,26 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
if (!check_fully_established(subflow, skb, mp_opt))
return;
+ if (mp_opt->add_addr && add_addr_hmac_valid(msk, mp_opt)) {
+ struct mptcp_addr_info addr;
+
+ addr.port = htons(mp_opt->port);
+ addr.id = mp_opt->addr_id;
+ if (mp_opt->family == MPTCP_ADDR_IPVERSION_4) {
+ addr.family = AF_INET;
+ addr.addr = mp_opt->addr;
+ }
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+ else if (mp_opt->family == MPTCP_ADDR_IPVERSION_6) {
+ addr.family = AF_INET6;
+ addr.addr6 = mp_opt->addr6;
+ }
+#endif
+ if (!mp_opt->echo)
+ mptcp_pm_add_addr_received(msk, &addr);
+ mp_opt->add_addr = 0;
+ }
+
if (!mp_opt->dss)
return;
@@ -654,6 +700,8 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
}
mpext->data_fin = mp_opt->data_fin;
+
+ mptcp_pm_fully_established(msk);
}
void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)