|
@@ -1294,7 +1294,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
|
|
|
DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
|
|
|
struct sk_buff *skb;
|
|
|
unsigned int ulen, copied;
|
|
|
- int peeked, off = 0;
|
|
|
+ int peeked, peeking, off;
|
|
|
int err;
|
|
|
int is_udplite = IS_UDPLITE(sk);
|
|
|
bool checksum_valid = false;
|
|
@@ -1304,15 +1304,16 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
|
|
|
return ip_recv_error(sk, msg, len, addr_len);
|
|
|
|
|
|
try_again:
|
|
|
+ peeking = off = sk_peek_offset(sk, flags);
|
|
|
skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
|
|
|
&peeked, &off, &err);
|
|
|
if (!skb)
|
|
|
- goto out;
|
|
|
+ return err;
|
|
|
|
|
|
ulen = skb->len;
|
|
|
copied = len;
|
|
|
- if (copied > ulen)
|
|
|
- copied = ulen;
|
|
|
+ if (copied > ulen - off)
|
|
|
+ copied = ulen - off;
|
|
|
else if (copied < ulen)
|
|
|
msg->msg_flags |= MSG_TRUNC;
|
|
|
|
|
@@ -1322,16 +1323,16 @@ try_again:
|
|
|
* coverage checksum (UDP-Lite), do it before the copy.
|
|
|
*/
|
|
|
|
|
|
- if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
|
|
|
+ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov || peeking) {
|
|
|
checksum_valid = !udp_lib_checksum_complete(skb);
|
|
|
if (!checksum_valid)
|
|
|
goto csum_copy_err;
|
|
|
}
|
|
|
|
|
|
if (checksum_valid || skb_csum_unnecessary(skb))
|
|
|
- err = skb_copy_datagram_msg(skb, 0, msg, copied);
|
|
|
+ err = skb_copy_datagram_msg(skb, off, msg, copied);
|
|
|
else {
|
|
|
- err = skb_copy_and_csum_datagram_msg(skb, 0, msg);
|
|
|
+ err = skb_copy_and_csum_datagram_msg(skb, off, msg);
|
|
|
|
|
|
if (err == -EINVAL)
|
|
|
goto csum_copy_err;
|
|
@@ -1344,7 +1345,8 @@ try_again:
|
|
|
UDP_INC_STATS_USER(sock_net(sk),
|
|
|
UDP_MIB_INERRORS, is_udplite);
|
|
|
}
|
|
|
- goto out_free;
|
|
|
+ skb_free_datagram_locked(sk, skb);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
if (!peeked)
|
|
@@ -1368,9 +1370,7 @@ try_again:
|
|
|
if (flags & MSG_TRUNC)
|
|
|
err = ulen;
|
|
|
|
|
|
-out_free:
|
|
|
- skb_free_datagram_locked(sk, skb);
|
|
|
-out:
|
|
|
+ __skb_free_datagram_locked(sk, skb, peeking ? -err : err);
|
|
|
return err;
|
|
|
|
|
|
csum_copy_err:
|