Commit 50a13bc3 authored by Matthieu Baerts's avatar Matthieu Baerts Committed by Jakub Kicinski

mptcp: support MPJoin with IPv4 mapped in v6 sk

With an IPv4 mapped in v6 socket, we were trying to call inet6_bind()
with an IPv4 address resulting in a -EINVAL error because the given
addr_len -- size of the address structure -- was too short.

We now make sure to use address structures for the same family as the
MPTCP socket for both the bind() and the connect(). It means we convert
v4 addresses to v4 mapped in v6 or the opposite if needed.

Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/122Co-developed-by: default avatarGeliang Tang <geliangtang@gmail.com>
Signed-off-by: default avatarGeliang Tang <geliangtang@gmail.com>
Signed-off-by: default avatarMatthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 17ce76c4
...@@ -1085,21 +1085,31 @@ void mptcpv6_handle_mapped(struct sock *sk, bool mapped) ...@@ -1085,21 +1085,31 @@ void mptcpv6_handle_mapped(struct sock *sk, bool mapped)
#endif #endif
static void mptcp_info2sockaddr(const struct mptcp_addr_info *info, static void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
struct sockaddr_storage *addr) struct sockaddr_storage *addr,
unsigned short family)
{ {
memset(addr, 0, sizeof(*addr)); memset(addr, 0, sizeof(*addr));
addr->ss_family = info->family; addr->ss_family = family;
if (addr->ss_family == AF_INET) { if (addr->ss_family == AF_INET) {
struct sockaddr_in *in_addr = (struct sockaddr_in *)addr; struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
in_addr->sin_addr = info->addr; if (info->family == AF_INET)
in_addr->sin_addr = info->addr;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
else if (ipv6_addr_v4mapped(&info->addr6))
in_addr->sin_addr.s_addr = info->addr6.s6_addr32[3];
#endif
in_addr->sin_port = info->port; in_addr->sin_port = info->port;
} }
#if IS_ENABLED(CONFIG_MPTCP_IPV6) #if IS_ENABLED(CONFIG_MPTCP_IPV6)
else if (addr->ss_family == AF_INET6) { else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)addr; struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)addr;
in6_addr->sin6_addr = info->addr6; if (info->family == AF_INET)
ipv6_addr_set_v4mapped(info->addr.s_addr,
&in6_addr->sin6_addr);
else
in6_addr->sin6_addr = info->addr6;
in6_addr->sin6_port = info->port; in6_addr->sin6_port = info->port;
} }
#endif #endif
...@@ -1143,11 +1153,11 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc, ...@@ -1143,11 +1153,11 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
subflow->remote_key = msk->remote_key; subflow->remote_key = msk->remote_key;
subflow->local_key = msk->local_key; subflow->local_key = msk->local_key;
subflow->token = msk->token; subflow->token = msk->token;
mptcp_info2sockaddr(loc, &addr); mptcp_info2sockaddr(loc, &addr, ssk->sk_family);
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
#if IS_ENABLED(CONFIG_MPTCP_IPV6) #if IS_ENABLED(CONFIG_MPTCP_IPV6)
if (loc->family == AF_INET6) if (addr.ss_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6); addrlen = sizeof(struct sockaddr_in6);
#endif #endif
ssk->sk_bound_dev_if = loc->ifindex; ssk->sk_bound_dev_if = loc->ifindex;
...@@ -1163,7 +1173,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc, ...@@ -1163,7 +1173,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
subflow->remote_id = remote_id; subflow->remote_id = remote_id;
subflow->request_join = 1; subflow->request_join = 1;
subflow->request_bkup = !!(loc->flags & MPTCP_PM_ADDR_FLAG_BACKUP); subflow->request_bkup = !!(loc->flags & MPTCP_PM_ADDR_FLAG_BACKUP);
mptcp_info2sockaddr(remote, &addr); mptcp_info2sockaddr(remote, &addr, ssk->sk_family);
mptcp_add_pending_subflow(msk, subflow); mptcp_add_pending_subflow(msk, subflow);
err = kernel_connect(sf, (struct sockaddr *)&addr, addrlen, O_NONBLOCK); err = kernel_connect(sf, (struct sockaddr *)&addr, addrlen, O_NONBLOCK);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment