espintcp: support non-blocking sends
authorSabrina Dubroca <sd@queasysnail.net>
Thu, 16 Jul 2020 08:09:01 +0000 (10:09 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Fri, 17 Jul 2020 08:21:03 +0000 (10:21 +0200)
Currently, non-blocking sends from userspace result in EOPNOTSUPP.

To support this, we need to tell espintcp_sendskb_locked() and
espintcp_sendskmsg_locked() that non-blocking operation was requested
from espintcp_sendmsg().

Fixes: e27cca96cd68 ("xfrm: add espintcp (RFC 8229)")
Reported-by: Andrew Cagney <cagney@libreswan.org>
Tested-by: Andrew Cagney <cagney@libreswan.org>
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/espintcp.c

index 100e296..5d3d2b9 100644 (file)
@@ -213,7 +213,7 @@ retry:
        return 0;
 }
 
-static int espintcp_push_msgs(struct sock *sk)
+static int espintcp_push_msgs(struct sock *sk, int flags)
 {
        struct espintcp_ctx *ctx = espintcp_getctx(sk);
        struct espintcp_msg *emsg = &ctx->partial;
@@ -227,12 +227,12 @@ static int espintcp_push_msgs(struct sock *sk)
        ctx->tx_running = 1;
 
        if (emsg->skb)
-               err = espintcp_sendskb_locked(sk, emsg, 0);
+               err = espintcp_sendskb_locked(sk, emsg, flags);
        else
-               err = espintcp_sendskmsg_locked(sk, emsg, 0);
+               err = espintcp_sendskmsg_locked(sk, emsg, flags);
        if (err == -EAGAIN) {
                ctx->tx_running = 0;
-               return 0;
+               return flags & MSG_DONTWAIT ? -EAGAIN : 0;
        }
        if (!err)
                memset(emsg, 0, sizeof(*emsg));
@@ -257,7 +257,7 @@ int espintcp_push_skb(struct sock *sk, struct sk_buff *skb)
        offset = skb_transport_offset(skb);
        len = skb->len - offset;
 
-       espintcp_push_msgs(sk);
+       espintcp_push_msgs(sk, 0);
 
        if (emsg->len) {
                kfree_skb(skb);
@@ -270,7 +270,7 @@ int espintcp_push_skb(struct sock *sk, struct sk_buff *skb)
        emsg->len = len;
        emsg->skb = skb;
 
-       espintcp_push_msgs(sk);
+       espintcp_push_msgs(sk, 0);
 
        return 0;
 }
@@ -287,7 +287,7 @@ static int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
        char buf[2] = {0};
        int err, end;
 
-       if (msg->msg_flags)
+       if (msg->msg_flags & ~MSG_DONTWAIT)
                return -EOPNOTSUPP;
 
        if (size > MAX_ESPINTCP_MSG)
@@ -298,9 +298,10 @@ static int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 
        lock_sock(sk);
 
-       err = espintcp_push_msgs(sk);
+       err = espintcp_push_msgs(sk, msg->msg_flags & MSG_DONTWAIT);
        if (err < 0) {
-               err = -ENOBUFS;
+               if (err != -EAGAIN || !(msg->msg_flags & MSG_DONTWAIT))
+                       err = -ENOBUFS;
                goto unlock;
        }
 
@@ -337,10 +338,9 @@ static int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 
        tcp_rate_check_app_limited(sk);
 
-       err = espintcp_push_msgs(sk);
+       err = espintcp_push_msgs(sk, msg->msg_flags & MSG_DONTWAIT);
        /* this message could be partially sent, keep it */
-       if (err < 0)
-               goto unlock;
+
        release_sock(sk);
 
        return size;
@@ -374,7 +374,7 @@ static void espintcp_tx_work(struct work_struct *work)
 
        lock_sock(sk);
        if (!ctx->tx_running)
-               espintcp_push_msgs(sk);
+               espintcp_push_msgs(sk, 0);
        release_sock(sk);
 }