|
@@ -349,7 +349,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
|
|
}
|
|
|
|
|
|
chunk = min_t(unsigned int, skb->len, size);
|
|
|
- if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
|
|
|
+ if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
|
|
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
|
if (!copied)
|
|
|
copied = -EFAULT;
|
|
@@ -361,7 +361,33 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
|
|
|
sock_recv_ts_and_drops(msg, sk, skb);
|
|
|
|
|
|
if (!(flags & MSG_PEEK)) {
|
|
|
- skb_pull(skb, chunk);
|
|
|
+ int skb_len = skb_headlen(skb);
|
|
|
+
|
|
|
+ if (chunk <= skb_len) {
|
|
|
+ __skb_pull(skb, chunk);
|
|
|
+ } else {
|
|
|
+ struct sk_buff *frag;
|
|
|
+
|
|
|
+ __skb_pull(skb, skb_len);
|
|
|
+ chunk -= skb_len;
|
|
|
+
|
|
|
+ skb_walk_frags(skb, frag) {
|
|
|
+ if (chunk <= frag->len) {
|
|
|
+ /* Pulling partial data */
|
|
|
+ skb->len -= chunk;
|
|
|
+ skb->data_len -= chunk;
|
|
|
+ __skb_pull(frag, chunk);
|
|
|
+ break;
|
|
|
+ } else if (frag->len) {
|
|
|
+ /* Pulling all frag data */
|
|
|
+ chunk -= frag->len;
|
|
|
+ skb->len -= frag->len;
|
|
|
+ skb->data_len -= frag->len;
|
|
|
+ __skb_pull(frag, frag->len);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (skb->len) {
|
|
|
skb_queue_head(&sk->sk_receive_queue, skb);
|
|
|
break;
|