From nobody Thu Sep 18 14:00:52 2025 Delivered-To: wpasupplicant.patchew@gmail.com Received: by 2002:a02:1d48:0:0:0:0:0 with SMTP id 69csp2535284jaj; Fri, 17 Sep 2021 16:33:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyxVfPMYV9gbaGMl1TjGyG0iRVZm9EzCWiWTbgTcVw5XoSbeE0XiHgVpPB5TweaIYY25Rja X-Received: by 2002:ac8:5912:: with SMTP id 18mr13002482qty.212.1631921617342; Fri, 17 Sep 2021 16:33:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1631921617; cv=none; d=google.com; s=arc-20160816; b=W4bjN5hXhJ980mElzhwLKnJ/SgISwrMjt5D4d50DCeuFYIzMGkNiyMwImwHJAWG7o0 dEavJR/VC9tuZp1ig86FI/9M4i6yGdULW+wAPA5qlf33rIYU3/7jisE2/Bm110AT7nza HiN+/ARTN3yMSYL9dpNEIvyQXdVuWJZnVNJTXbwSdp1lvV9P8rdYL3LGszHaQZk+vAUW T40lqYIv2zbOxginRDIOfHV9kCrhmLGNsAsdSTODcC93uerl1bbtetLCkdzNqitpZzBp Vkiu/LSFkl/WO7rrY/7rPWs/k/T82fhXEURRakGYxt8DuqEL1XijnE/UiHU4/mW6PMa6 NanA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from; bh=Q76kl/UKr7GWzBqlSwAOOVnYsMmgJcu+bob0lAoe/k8=; b=LEUmf1VL2Iodt/geoQCNgEEyU3715il03HVT5BtOIl+pYbRKysCB9rcyxwKdtYWS4x M4HJi2+WbrioiwOUsDc5zP7yy4C8RksmG27LFmZxDJGPwys9a6x69LHrzglEKjO33xtr Z08u185p5dL/MYVjANgtPd0r3/nUXL4uNHvpuQREnbgm1rOjymIcQ0PEq2/9oasNH4OH tXR/UXWSobOE2Gn4bEUTkxgjpdf7iU1pOaZ9Brwuq6ljXuJGEa6SYeXwdnaqSUOB4A7w cna33Xy5CPa9QU+8ma8Wy1A2KBWpkwnW8zTwnoM6g+aD0sE7JlAAQCSTv/2UMasM2IHp U+KQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of mptcp+bounces-1961-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) smtp.mailfrom="mptcp+bounces-1961-wpasupplicant.patchew=gmail.com@lists.linux.dev"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from ewr.edge.kernel.org (ewr.edge.kernel.org. [147.75.197.195]) by mx.google.com with ESMTPS id c6si3013406qtg.301.2021.09.17.16.33.37 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 17 Sep 2021 16:33:37 -0700 (PDT) Received-SPF: pass (google.com: domain of mptcp+bounces-1961-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) client-ip=147.75.197.195; Authentication-Results: mx.google.com; spf=pass (google.com: domain of mptcp+bounces-1961-wpasupplicant.patchew=gmail.com@lists.linux.dev designates 147.75.197.195 as permitted sender) smtp.mailfrom="mptcp+bounces-1961-wpasupplicant.patchew=gmail.com@lists.linux.dev"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ewr.edge.kernel.org (Postfix) with ESMTPS id 158FF1C0F96 for ; Fri, 17 Sep 2021 23:33:37 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5DE763FD4; Fri, 17 Sep 2021 23:33:34 +0000 (UTC) X-Original-To: mptcp@lists.linux.dev Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 236163FC9 for ; Fri, 17 Sep 2021 23:33:33 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6200,9189,10110"; a="209979873" X-IronPort-AV: E=Sophos;i="5.85,302,1624345200"; d="scan'208";a="209979873" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Sep 2021 16:33:30 -0700 X-IronPort-AV: E=Sophos;i="5.85,302,1624345200"; d="scan'208";a="483228559" Received: from mjmartin-desk2.amr.corp.intel.com (HELO mjmartin-desk2.intel.com) ([10.212.205.24]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Sep 2021 16:33:30 -0700 From: Mat Martineau To: netdev@vger.kernel.org Cc: Florian Westphal , davem@davemloft.net, kuba@kernel.org, matthieu.baerts@tessares.net, mptcp@lists.linux.dev, Mat Martineau Subject: [PATCH net-next 3/5] mptcp: add MPTCP_TCPINFO getsockopt support Date: Fri, 17 Sep 2021 16:33:20 -0700 Message-Id: <20210917233322.271789-4-mathew.j.martineau@linux.intel.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210917233322.271789-1-mathew.j.martineau@linux.intel.com> References: <20210917233322.271789-1-mathew.j.martineau@linux.intel.com> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Florian Westphal Allow users to retrieve TCP_INFO data of all subflows. Users need to pre-initialize a meta header that has to be prepended to the data buffer that will be filled with the tcp info data. The meta header looks like this: struct mptcp_subflow_data { __u32 size_subflow_data;/* size of this structure in userspace */ __u32 num_subflows; /* must be 0, set by kernel */ __u32 size_kernel; /* must be 0, set by kernel */ __u32 size_user; /* size of one element in data[] */ } __attribute__((aligned(8))); size_subflow_data has to be set to 'sizeof(struct mptcp_subflow_data)'. This allows to extend mptcp_subflow_data structure later on without breaking backwards compatibility. If the structure is extended later on, kernel knows where the userspace-provided meta header ends, even if userspace uses an older (smaller) version of the structure. num_subflows must be set to 0. If the getsockopt request succeeds (return value is 0), it will be updated to contain the number of active subflows for the given logical connection. size_kernel must be set to 0. If the getsockopt request is successful, it will contain the size of the 'struct tcp_info' as known by the kernel. This is informational only. size_user must be set to 'sizeof(struct tcp_info)'. This allows the kernel to only fill in the space reserved/expected by userspace. Example: struct my_tcp_info { struct mptcp_subflow_data d; struct tcp_info ti[2]; }; struct my_tcp_info ti; socklen_t olen; memset(&ti, 0, sizeof(ti)); ti.d.size_subflow_data =3D sizeof(struct mptcp_subflow_data); ti.d.size_user =3D sizeof(struct tcp_info); olen =3D sizeof(ti); ret =3D getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen); if (ret < 0) die_perror("getsockopt MPTCP_TCPINFO"); mptcp_subflow_data.num_subflows is populated with the number of subflows that exist on the kernel side for the logical mptcp connection. This allows userspace to re-try with a larger tcp_info array if the number of subflows was larger than the available space in the ti[] array. olen has to be set to the number of bytes that userspace has allocated to receive the kernel data. It will be updated to contain the real number bytes that have been copied to by the kernel. In the above example, if the number if subflows was 1, olen is equal to 'sizeof(struct mptcp_subflow_data) + sizeof(struct tcp_info). For 2 or more subflows olen is equal to 'sizeof(struct my_tcp_info)'. If there was more data that could not be copied due to lack of space in the option buffer, userspace can detect this by checking mptcp_subflow_data->num_subflows. Signed-off-by: Florian Westphal Signed-off-by: Mat Martineau --- include/uapi/linux/mptcp.h | 10 +++- net/mptcp/sockopt.c | 115 +++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index 3e9caeddda7e..3f013a513770 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -193,7 +193,15 @@ enum mptcp_event_attr { #define MPTCP_RST_EBADPERF 5 #define MPTCP_RST_EMIDDLEBOX 6 =20 +struct mptcp_subflow_data { + __u32 size_subflow_data; /* size of this structure in userspace */ + __u32 num_subflows; /* must be 0, set by kernel */ + __u32 size_kernel; /* must be 0, set by kernel */ + __u32 size_user; /* size of one element in data[] */ +} __attribute__((aligned(8))); + /* MPTCP socket options */ -#define MPTCP_INFO 1 +#define MPTCP_INFO 1 +#define MPTCP_TCPINFO 2 =20 #endif /* _UAPI_MPTCP_H */ diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index f7683c22911f..eb2905bfa089 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -14,6 +14,8 @@ #include #include "protocol.h" =20 +#define MIN_INFO_OPTLEN_SIZE 16 + static struct sock *__mptcp_tcp_fallback(struct mptcp_sock *msk) { sock_owned_by_me((const struct sock *)msk); @@ -727,6 +729,117 @@ static int mptcp_getsockopt_info(struct mptcp_sock *m= sk, char __user *optval, in return 0; } =20 +static int mptcp_put_subflow_data(struct mptcp_subflow_data *sfd, + char __user *optval, + u32 copied, + int __user *optlen) +{ + u32 copylen =3D min_t(u32, sfd->size_subflow_data, sizeof(*sfd)); + + if (copied) + copied +=3D sfd->size_subflow_data; + else + copied =3D copylen; + + if (put_user(copied, optlen)) + return -EFAULT; + + if (copy_to_user(optval, sfd, copylen)) + return -EFAULT; + + return 0; +} + +static int mptcp_get_subflow_data(struct mptcp_subflow_data *sfd, + char __user *optval, int __user *optlen) +{ + int len, copylen; + + if (get_user(len, optlen)) + return -EFAULT; + + /* if mptcp_subflow_data size is changed, need to adjust + * this function to deal with programs using old version. + */ + BUILD_BUG_ON(sizeof(*sfd) !=3D MIN_INFO_OPTLEN_SIZE); + + if (len < MIN_INFO_OPTLEN_SIZE) + return -EINVAL; + + memset(sfd, 0, sizeof(*sfd)); + + copylen =3D min_t(unsigned int, len, sizeof(*sfd)); + if (copy_from_user(sfd, optval, copylen)) + return -EFAULT; + + /* size_subflow_data is u32, but len is signed */ + if (sfd->size_subflow_data > INT_MAX || + sfd->size_user > INT_MAX) + return -EINVAL; + + if (sfd->size_subflow_data < MIN_INFO_OPTLEN_SIZE || + sfd->size_subflow_data > len) + return -EINVAL; + + if (sfd->num_subflows || sfd->size_kernel) + return -EINVAL; + + return len - sfd->size_subflow_data; +} + +static int mptcp_getsockopt_tcpinfo(struct mptcp_sock *msk, char __user *o= ptval, + int __user *optlen) +{ + struct mptcp_subflow_context *subflow; + struct sock *sk =3D &msk->sk.icsk_inet.sk; + unsigned int sfcount =3D 0, copied =3D 0; + struct mptcp_subflow_data sfd; + char __user *infoptr; + int len; + + len =3D mptcp_get_subflow_data(&sfd, optval, optlen); + if (len < 0) + return len; + + sfd.size_kernel =3D sizeof(struct tcp_info); + sfd.size_user =3D min_t(unsigned int, sfd.size_user, + sizeof(struct tcp_info)); + + infoptr =3D optval + sfd.size_subflow_data; + + lock_sock(sk); + + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk =3D mptcp_subflow_tcp_sock(subflow); + + ++sfcount; + + if (len && len >=3D sfd.size_user) { + struct tcp_info info; + + tcp_get_info(ssk, &info); + + if (copy_to_user(infoptr, &info, sfd.size_user)) { + release_sock(sk); + return -EFAULT; + } + + infoptr +=3D sfd.size_user; + copied +=3D sfd.size_user; + len -=3D sfd.size_user; + } + } + + release_sock(sk); + + sfd.num_subflows =3D sfcount; + + if (mptcp_put_subflow_data(&sfd, optval, copied, optlen)) + return -EFAULT; + + return 0; +} + static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname, char __user *optval, int __user *optlen) { @@ -747,6 +860,8 @@ static int mptcp_getsockopt_sol_mptcp(struct mptcp_sock= *msk, int optname, switch (optname) { case MPTCP_INFO: return mptcp_getsockopt_info(msk, optval, optlen); + case MPTCP_TCPINFO: + return mptcp_getsockopt_tcpinfo(msk, optval, optlen); } =20 return -EOPNOTSUPP; --=20 2.33.0