Commit 83871f8c authored by Denis Kenzior's avatar Denis Kenzior Committed by Marcel Holtmann

Bluetooth: Fix hci_sock_recvmsg return value

If recvmsg is called with a destination buffer that is too small to
receive the contents of skb in its entirety, the return value from
recvmsg was inconsistent with common SOCK_SEQPACKET or SOCK_DGRAM
semantics.

If destination buffer provided by userspace is too small (e.g. len <
copied), then MSG_TRUNC flag is set and copied is returned.  Instead, it
should return the length of the message, which is consistent with how
other datagram based sockets act.  Quoting 'man recv':

"All  three calls return the length of the message on successful comple‐
tion.  If a message is too long to fit in the supplied  buffer,  excess
bytes  may  be discarded depending on the type of socket the message is
received from."

and

"MSG_TRUNC (since Linux 2.2)

    For   raw   (AF_PACKET),   Internet   datagram   (since    Linux
    2.4.27/2.6.8),  netlink  (since Linux 2.6.22), and UNIX datagram
    (since Linux 3.4) sockets: return the real length of the packet
    or datagram, even when it was longer than the passed buffer."
Signed-off-by: default avatarDenis Kenzior <denkenz@gmail.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent b5f34f94
...@@ -1048,6 +1048,7 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -1048,6 +1048,7 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sk_buff *skb; struct sk_buff *skb;
int copied, err; int copied, err;
unsigned int skblen;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p", sock, sk);
...@@ -1064,6 +1065,7 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -1064,6 +1065,7 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
if (!skb) if (!skb)
return err; return err;
skblen = skb->len;
copied = skb->len; copied = skb->len;
if (len < copied) { if (len < copied) {
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
...@@ -1089,6 +1091,9 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -1089,6 +1091,9 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
if (msg->msg_flags & MSG_TRUNC)
copied = skblen;
return err ? : copied; return err ? : copied;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment