mptcp: add MPTCP_INFO getsockopt
authorFlorian Westphal <fw@strlen.de>
Fri, 17 Sep 2021 23:33:19 +0000 (16:33 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 18 Sep 2021 13:20:01 +0000 (14:20 +0100)
Its not compatible with multipath-tcp.org kernel one.

1. The out-of-tree implementation defines a different 'struct mptcp_info',
   with embedded __user addresses for additional data such as
   endpoint addresses.

2. Mat Martineau points out that embedded __user addresses doesn't work
with BPF_CGROUP_RUN_PROG_GETSOCKOPT() which assumes that copying in
optsize bytes from optval provides all data that got copied to userspace.

This provides mptcp_info data for the given mptcp socket.

Userspace sets optlen to the size of the structure it expects.
The kernel updates it to contain the number of bytes that it copied.

This allows to append more information to the structure later.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/socket.h
include/uapi/linux/mptcp.h
net/mptcp/sockopt.c

index 041d6032a34899ddc96f9ac65a7e0158271230b6..7612d760b6a9bd1e025b6ea88c6016e1ddae7c6e 100644 (file)
@@ -364,6 +364,7 @@ struct ucred {
 #define SOL_KCM                281
 #define SOL_TLS                282
 #define SOL_XDP                283
+#define SOL_MPTCP      284
 
 /* IPX options */
 #define IPX_TYPE       1
index f66038b9551fa0a24529e891b50adca3616fcd36..3e9caeddda7e0e8011b5ed0bf79c3e9bcf891fbe 100644 (file)
@@ -193,4 +193,7 @@ enum mptcp_event_attr {
 #define MPTCP_RST_EBADPERF     5
 #define MPTCP_RST_EMIDDLEBOX   6
 
+/* MPTCP socket options */
+#define MPTCP_INFO 1
+
 #endif /* _UAPI_MPTCP_H */
index 54f0d521a3998e3b9dc8e3a053a1217daa2872cb..f7683c22911f0205a7c12509fbf28a818e6e6b64 100644 (file)
@@ -673,10 +673,14 @@ out:
 void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info)
 {
        struct sock *sk = &msk->sk.icsk_inet.sk;
-       bool slow = lock_sock_fast(sk);
        u32 flags = 0;
+       bool slow;
        u8 val;
 
+       memset(info, 0, sizeof(*info));
+
+       slow = lock_sock_fast(sk);
+
        info->mptcpi_subflows = READ_ONCE(msk->pm.subflows);
        info->mptcpi_add_addr_signal = READ_ONCE(msk->pm.add_addr_signaled);
        info->mptcpi_add_addr_accepted = READ_ONCE(msk->pm.add_addr_accepted);
@@ -702,6 +706,27 @@ void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info)
 }
 EXPORT_SYMBOL_GPL(mptcp_diag_fill_info);
 
+static int mptcp_getsockopt_info(struct mptcp_sock *msk, char __user *optval, int __user *optlen)
+{
+       struct mptcp_info m_info;
+       int len;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       len = min_t(unsigned int, len, sizeof(struct mptcp_info));
+
+       mptcp_diag_fill_info(msk, &m_info);
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+
+       if (copy_to_user(optval, &m_info, len))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
                                    char __user *optval, int __user *optlen)
 {
@@ -716,6 +741,17 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
        return -EOPNOTSUPP;
 }
 
+static int mptcp_getsockopt_sol_mptcp(struct mptcp_sock *msk, int optname,
+                                     char __user *optval, int __user *optlen)
+{
+       switch (optname) {
+       case MPTCP_INFO:
+               return mptcp_getsockopt_info(msk, optval, optlen);
+       }
+
+       return -EOPNOTSUPP;
+}
+
 int mptcp_getsockopt(struct sock *sk, int level, int optname,
                     char __user *optval, int __user *option)
 {
@@ -738,6 +774,8 @@ int mptcp_getsockopt(struct sock *sk, int level, int optname,
 
        if (level == SOL_TCP)
                return mptcp_getsockopt_sol_tcp(msk, optname, optval, option);
+       if (level == SOL_MPTCP)
+               return mptcp_getsockopt_sol_mptcp(msk, optname, optval, option);
        return -EOPNOTSUPP;
 }