This allows to call inet(6)_getname on the parent socket
and it will return the right result.
At this time it only works because the first incoming subflow has a
'struct socket' allocated.
This will change in followup patch, passive subflows will not have
a socket struct anymore.
Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
net/mptcp/pm.c | 18 ++++----
net/mptcp/protocol.c | 98 ++++++++++++++++++++++++--------------------
net/mptcp/protocol.h | 1 -
3 files changed, 63 insertions(+), 54 deletions(-)
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 7e493d81afef..e474bd9dc05d 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -81,6 +81,7 @@ int mptcp_pm_create_subflow(u32 token, u8 remote_id, struct in_addr
*addr)
struct mptcp_sock *msk = mptcp_token_get_sock(token);
struct sockaddr_in remote;
struct sockaddr_in local;
+ struct sock *sk;
int err;
if (!msk)
@@ -88,6 +89,7 @@ int mptcp_pm_create_subflow(u32 token, u8 remote_id, struct in_addr
*addr)
pr_debug("msk=%p", msk);
+ sk = (struct sock *)msk;
if (!msk->pm.remote_valid || remote_id != msk->pm.remote_id) {
err = -EBADR;
goto create_put;
@@ -101,15 +103,14 @@ int mptcp_pm_create_subflow(u32 token, u8 remote_id, struct in_addr
*addr)
local.sin_addr.s_addr = htonl(INADDR_ANY);
remote.sin_family = msk->pm.remote_family;
- remote.sin_port = htons(msk->dport);
+ remote.sin_port = inet_sk(sk)->inet_dport;
remote.sin_addr = msk->pm.remote_addr;
- err = mptcp_subflow_connect((struct sock *)msk,
- (struct sockaddr *)&local,
+ err = mptcp_subflow_connect(sk, (struct sockaddr *)&local,
(struct sockaddr *)&remote, remote_id);
create_put:
- sock_put((struct sock *)msk);
+ sock_put(sk);
return err;
}
@@ -119,12 +120,14 @@ int mptcp_pm_create_subflow6(u32 token, u8 remote_id, struct
in6_addr *addr)
struct mptcp_sock *msk = mptcp_token_get_sock(token);
struct sockaddr_in6 remote;
struct sockaddr_in6 local;
+ struct sock *sk;
int err;
if (!msk)
return -EINVAL;
pr_debug("msk=%p", msk);
+ sk = (struct sock *)msk;
if (!msk->pm.remote_valid || remote_id != msk->pm.remote_id) {
err = -EBADR;
@@ -139,15 +142,14 @@ int mptcp_pm_create_subflow6(u32 token, u8 remote_id, struct
in6_addr *addr)
local.sin6_addr = in6addr_any;
remote.sin6_family = msk->pm.remote_family;
- remote.sin6_port = htons(msk->dport);
+ remote.sin6_port = inet_sk(sk)->inet_dport;
remote.sin6_addr = msk->pm.remote_addr6;
- err = mptcp_subflow_connect((struct sock *)msk,
- (struct sockaddr *)&local,
+ err = mptcp_subflow_connect(sk, (struct sockaddr *)&local,
(struct sockaddr *)&remote, remote_id);
create_put:
- sock_put((struct sock *)msk);
+ sock_put(sk);
return err;
}
#endif
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 529a08095512..7e16e5878fa5 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -91,19 +91,6 @@ static struct socket *mptcp_fallback_get_ref(const struct mptcp_sock
*msk)
return ssock;
}
-static struct sock *mptcp_subflow_get(const struct mptcp_sock *msk)
-{
- struct mptcp_subflow_context *subflow;
-
- sock_owned_by_me((const struct sock *)msk);
-
- mptcp_for_each_subflow(msk, subflow) {
- return mptcp_subflow_tcp_socket(subflow)->sk;
- }
-
- return NULL;
-}
-
static struct sock *mptcp_subflow_recv_lookup(const struct mptcp_sock *msk)
{
struct sock *sk = (struct sock *)msk;
@@ -934,6 +921,29 @@ static int mptcp_disconnect(struct sock *sk, int flags)
return tcp_disconnect(sk, flags);
}
+static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
+{
+ const struct ipv6_pinfo *ssk6 = inet6_sk(ssk);
+ struct ipv6_pinfo *msk6 = inet6_sk(msk);
+
+ inet_sk(msk)->inet_num = inet_sk(ssk)->inet_num;
+ inet_sk(msk)->inet_dport = inet_sk(ssk)->inet_dport;
+ inet_sk(msk)->inet_sport = inet_sk(ssk)->inet_sport;
+ inet_sk(msk)->inet_daddr = inet_sk(ssk)->inet_daddr;
+ inet_sk(msk)->inet_saddr = inet_sk(ssk)->inet_saddr;
+ inet_sk(msk)->inet_rcv_saddr = inet_sk(ssk)->inet_rcv_saddr;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ msk->sk_v6_daddr = ssk->sk_v6_daddr;
+ msk->sk_v6_rcv_saddr = ssk->sk_v6_rcv_saddr;
+
+ if (msk6 && ssk6) {
+ msk6->saddr = ssk6->saddr;
+ msk6->flow_label = ssk6->flow_label;
+ }
+#endif
+}
+
static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
bool kern)
{
@@ -954,6 +964,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int
*err,
pr_debug("msk=%p, new subflow=%p, ", msk, subflow);
if (subflow->mp_capable) {
+ struct sock *ssk = new_sock->sk;
struct sock *new_mptcp_sock;
u64 ack_seq;
@@ -988,6 +999,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int
*err,
ack_seq++;
msk->ack_seq = ack_seq;
newsk = new_mptcp_sock;
+ mptcp_copy_inaddrs(newsk, ssk);
list_add(&subflow->node, &msk->conn_list);
bh_unlock_sock(new_mptcp_sock);
@@ -999,7 +1011,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int
*err,
/* the subflow can already receive packet, avoid racing with
* the receive path and process the pending ones
*/
- lock_sock(new_sock->sk);
+ lock_sock(ssk);
subflow->map_seq = ack_seq;
subflow->map_subflow_seq = 1;
subflow->rel_write_seq = 1;
@@ -1007,7 +1019,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int
*err,
subflow->conn = new_mptcp_sock;
if (unlikely(!skb_queue_empty(&new_sock->sk->sk_receive_queue)))
mptcp_subflow_data_available(new_sock->sk);
- release_sock(new_sock->sk);
+ release_sock(ssk);
} else {
newsk = new_sock->sk;
tcp_sk(newsk)->is_mptcp = 0;
@@ -1122,6 +1134,7 @@ void mptcp_finish_connect(struct sock *sk, int mp_capable)
subflow = mptcp_subflow_ctx(msk->subflow->sk);
if (mp_capable) {
+ struct sock *ssk = msk->subflow->sk;
u64 ack_seq;
/* sk (new subflow socket) is already locked, but we need
@@ -1151,7 +1164,7 @@ void mptcp_finish_connect(struct sock *sk, int mp_capable)
msk->local_key = subflow->local_key;
msk->token = subflow->token;
pr_debug("msk=%p, token=%u", msk, msk->token);
- msk->dport = ntohs(inet_sk(msk->subflow->sk)->inet_dport);
+ mptcp_copy_inaddrs(sk, ssk);
mptcp_pm_new_connection(msk, 0);
@@ -1309,43 +1322,44 @@ static int mptcp_stream_connect(struct socket *sock, struct
sockaddr *uaddr,
}
static int mptcp_getname(struct socket *sock, struct sockaddr *uaddr,
- int peer)
+ int peer, int af)
{
struct mptcp_sock *msk = mptcp_sk(sock->sk);
struct socket *ssock;
- struct sock *ssk;
int ret;
- lock_sock(sock->sk);
- ssock = __mptcp_fallback_get_ref(msk);
- if (ssock) {
+ if (msk->subflow) {
+ lock_sock(sock->sk);
+ ssock = __mptcp_fallback_get_ref(msk);
release_sock(sock->sk);
- pr_debug("subflow=%p", ssock->sk);
- ret = ssock->ops->getname(ssock, uaddr, peer);
- sock_put(ssock->sk);
- return ret;
+ if (ssock) {
+ pr_debug("subflow=%p", ssock->sk);
+ ret = ssock->ops->getname(ssock, uaddr, peer);
+ sock_put(ssock->sk);
+ return ret;
+ }
}
- /* @@ the meaning of getname() for the remote peer when the socket
- * is connected and there are multiple subflows is not defined.
- * For now just use the first subflow on the list.
- */
- ssk = mptcp_subflow_get(msk);
- if (!ssk) {
- release_sock(sock->sk);
- return -ENOTCONN;
+ switch (af) {
+ case AF_INET:
+ ret = inet_getname(sock, uaddr, peer);
+ break;
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+ case AF_INET6:
+ ret = inet6_getname(sock, uaddr, peer);
+ break;
+#endif
+ default:
+ ret = -ENOPROTOOPT;
+ WARN_ON_ONCE(1);
}
- ret = ssk->sk_socket->ops->getname(ssk->sk_socket, uaddr, peer);
- release_sock(sock->sk);
return ret;
}
static int mptcp_v4_getname(struct socket *sock, struct sockaddr *uaddr,
int peer)
{
- int ret;
-
if (sock->sk->sk_prot == &tcp_prot) {
/* we are being invoked from __sys_accept4, after
* mptcp_accept() has just accepted a non-mp-capable
@@ -1358,17 +1372,13 @@ static int mptcp_v4_getname(struct socket *sock, struct sockaddr
*uaddr,
return sock->ops->getname(sock, uaddr, peer);
}
- ret = mptcp_getname(sock, uaddr, peer);
-
- return ret;
+ return mptcp_getname(sock, uaddr, peer, AF_INET);
}
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
static int mptcp_v6_getname(struct socket *sock, struct sockaddr *uaddr,
int peer)
{
- int ret;
-
if (sock->sk->sk_prot == &tcpv6_prot) {
/* we are being invoked from __sys_accept4 after
* mptcp_accept() has accepted a non-mp-capable
@@ -1381,9 +1391,7 @@ static int mptcp_v6_getname(struct socket *sock, struct sockaddr
*uaddr,
return sock->ops->getname(sock, uaddr, peer);
}
- ret = mptcp_getname(sock, uaddr, peer);
-
- return ret;
+ return mptcp_getname(sock, uaddr, peer, AF_INET6);
}
#endif
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index ac18dd38618e..61c77616482c 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -134,7 +134,6 @@ struct mptcp_sock {
unsigned long timer_ival;
u32 token;
unsigned long flags;
- u16 dport;
struct work_struct rtx_work;
struct list_head conn_list;
struct list_head rtx_queue;
--
2.23.0