diff options
-rw-r--r-- | include/net/bluetooth/bluetooth.h | 2 | ||||
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 109 |
2 files changed, 111 insertions, 0 deletions
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 30fce0128dd7..d81ea7997701 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h | |||
@@ -126,6 +126,8 @@ int bt_sock_unregister(int proto); | |||
126 | void bt_sock_link(struct bt_sock_list *l, struct sock *s); | 126 | void bt_sock_link(struct bt_sock_list *l, struct sock *s); |
127 | void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); | 127 | void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); |
128 | int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); | 128 | int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); |
129 | int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
130 | struct msghdr *msg, size_t len, int flags); | ||
129 | uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); | 131 | uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); |
130 | int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); | 132 | int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); |
131 | int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); | 133 | int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); |
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 | } |
266 | EXPORT_SYMBOL(bt_sock_recvmsg); | 266 | EXPORT_SYMBOL(bt_sock_recvmsg); |
267 | 267 | ||
268 | static 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 | |||
297 | int 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 | |||
371 | out: | ||
372 | release_sock(sk); | ||
373 | return copied ? : err; | ||
374 | } | ||
375 | EXPORT_SYMBOL(bt_sock_stream_recvmsg); | ||
376 | |||
268 | static inline unsigned int bt_accept_poll(struct sock *parent) | 377 | static inline unsigned int bt_accept_poll(struct sock *parent) |
269 | { | 378 | { |
270 | struct list_head *p, *n; | 379 | struct list_head *p, *n; |