mptcp: add SIOCINQ, OUTQ and OUTQNSD ioctls
authorFlorian Westphal <fw@strlen.de>
Fri, 3 Dec 2021 22:35:34 +0000 (14:35 -0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 7 Dec 2021 19:36:29 +0000 (11:36 -0800)
Allows to query in-sequence data ready for read(), total bytes in
write queue and total bytes in write queue that have not yet been sent.

v2: remove unneeded READ_ONCE() (Paolo Abeni)
v3: check for new data unconditionally in SIOCINQ ioctl (Mat Martineau)

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/mptcp/protocol.c

index ffc8068..943f74e 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 #include <net/mptcp.h>
 #include <net/xfrm.h>
+#include <asm/ioctls.h>
 #include "protocol.h"
 #include "mib.h"
 
@@ -3211,6 +3212,57 @@ static int mptcp_forward_alloc_get(const struct sock *sk)
        return sk->sk_forward_alloc + mptcp_sk(sk)->rmem_fwd_alloc;
 }
 
+static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v)
+{
+       const struct sock *sk = (void *)msk;
+       u64 delta;
+
+       if (sk->sk_state == TCP_LISTEN)
+               return -EINVAL;
+
+       if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
+               return 0;
+
+       delta = msk->write_seq - v;
+       if (delta > INT_MAX)
+               delta = INT_MAX;
+
+       return (int)delta;
+}
+
+static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+       struct mptcp_sock *msk = mptcp_sk(sk);
+       bool slow;
+       int answ;
+
+       switch (cmd) {
+       case SIOCINQ:
+               if (sk->sk_state == TCP_LISTEN)
+                       return -EINVAL;
+
+               lock_sock(sk);
+               __mptcp_move_skbs(msk);
+               answ = mptcp_inq_hint(sk);
+               release_sock(sk);
+               break;
+       case SIOCOUTQ:
+               slow = lock_sock_fast(sk);
+               answ = mptcp_ioctl_outq(msk, READ_ONCE(msk->snd_una));
+               unlock_sock_fast(sk, slow);
+               break;
+       case SIOCOUTQNSD:
+               slow = lock_sock_fast(sk);
+               answ = mptcp_ioctl_outq(msk, msk->snd_nxt);
+               unlock_sock_fast(sk, slow);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return put_user(answ, (int __user *)arg);
+}
+
 static struct proto mptcp_prot = {
        .name           = "MPTCP",
        .owner          = THIS_MODULE,
@@ -3223,6 +3275,7 @@ static struct proto mptcp_prot = {
        .shutdown       = mptcp_shutdown,
        .destroy        = mptcp_destroy,
        .sendmsg        = mptcp_sendmsg,
+       .ioctl          = mptcp_ioctl,
        .recvmsg        = mptcp_recvmsg,
        .release_cb     = mptcp_release_cb,
        .hash           = mptcp_hash,