aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/af_bluetooth.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/af_bluetooth.c')
-rw-r--r--net/bluetooth/af_bluetooth.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index ed0f22f57668..c4cf3f595004 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -265,6 +265,115 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
265} 265}
266EXPORT_SYMBOL(bt_sock_recvmsg); 266EXPORT_SYMBOL(bt_sock_recvmsg);
267 267
268static long bt_sock_data_wait(struct sock *sk, long timeo)
269{
270 DECLARE_WAITQUEUE(wait, current);
271
272 add_wait_queue(sk_sleep(sk), &wait);
273 for (;;) {
274 set_current_state(TASK_INTERRUPTIBLE);
275
276 if (!skb_queue_empty(&sk->sk_receive_queue))
277 break;
278
279 if (sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN))
280 break;
281
282 if (signal_pending(current) || !timeo)
283 break;
284
285 set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
286 release_sock(sk);
287 timeo = schedule_timeout(timeo);
288 lock_sock(sk);
289 clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
290 }
291
292 __set_current_state(TASK_RUNNING);
293 remove_wait_queue(sk_sleep(sk), &wait);
294 return timeo;
295}
296
297int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
298 struct msghdr *msg, size_t size, int flags)
299{
300 struct sock *sk = sock->sk;
301 int err = 0;
302 size_t target, copied = 0;
303 long timeo;
304
305 if (flags & MSG_OOB)
306 return -EOPNOTSUPP;
307
308 msg->msg_namelen = 0;
309
310 BT_DBG("sk %p size %zu", sk, size);
311
312 lock_sock(sk);
313
314 target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
315 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
316
317 do {
318 struct sk_buff *skb;
319 int chunk;
320
321 skb = skb_dequeue(&sk->sk_receive_queue);
322 if (!skb) {
323 if (copied >= target)
324 break;
325
326 if ((err = sock_error(sk)) != 0)
327 break;
328 if (sk->sk_shutdown & RCV_SHUTDOWN)
329 break;
330
331 err = -EAGAIN;
332 if (!timeo)
333 break;
334
335 timeo = bt_sock_data_wait(sk, timeo);
336
337 if (signal_pending(current)) {
338 err = sock_intr_errno(timeo);
339 goto out;
340 }
341 continue;
342 }
343
344 chunk = min_t(unsigned int, skb->len, size);
345 if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
346 skb_queue_head(&sk->sk_receive_queue, skb);
347 if (!copied)
348 copied = -EFAULT;
349 break;
350 }
351 copied += chunk;
352 size -= chunk;
353
354 sock_recv_ts_and_drops(msg, sk, skb);
355
356 if (!(flags & MSG_PEEK)) {
357 skb_pull(skb, chunk);
358 if (skb->len) {
359 skb_queue_head(&sk->sk_receive_queue, skb);
360 break;
361 }
362 kfree_skb(skb);
363
364 } else {
365 /* put message back and return */
366 skb_queue_head(&sk->sk_receive_queue, skb);
367 break;
368 }
369 } while (size);
370
371out:
372 release_sock(sk);
373 return copied ? : err;
374}
375EXPORT_SYMBOL(bt_sock_stream_recvmsg);
376
268static inline unsigned int bt_accept_poll(struct sock *parent) 377static inline unsigned int bt_accept_poll(struct sock *parent)
269{ 378{
270 struct list_head *p, *n; 379 struct list_head *p, *n;