aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/af_bluetooth.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-23 14:47:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-23 14:47:02 -0400
commit5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch)
tree7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /net/bluetooth/af_bluetooth.c
parent02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff)
parentec37a48d1d16c30b655ac5280209edf52a6775d4 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits) bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL. vlan: Calling vlan_hwaccel_do_receive() is always valid. tproxy: use the interface primary IP address as a default value for --on-ip tproxy: added IPv6 support to the socket match cxgb3: function namespace cleanup tproxy: added IPv6 support to the TPROXY target tproxy: added IPv6 socket lookup function to nf_tproxy_core be2net: Changes to use only priority codes allowed by f/w tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled tproxy: added tproxy sockopt interface in the IPV6 layer tproxy: added udp6_lib_lookup function tproxy: added const specifiers to udp lookup functions tproxy: split off ipv6 defragmentation to a separate module l2tp: small cleanup nf_nat: restrict ICMP translation for embedded header can: mcp251x: fix generation of error frames can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set can-raw: add msg_flags to distinguish local traffic 9p: client code cleanup rds: make local functions/variables static ... Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and drivers/net/wireless/ath/ath9k/debug.c as per David
Diffstat (limited to 'net/bluetooth/af_bluetooth.c')
-rw-r--r--net/bluetooth/af_bluetooth.c114
1 files changed, 111 insertions, 3 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 421c45bd1b95..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;
@@ -297,13 +406,12 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
297 mask |= POLLERR; 406 mask |= POLLERR;
298 407
299 if (sk->sk_shutdown & RCV_SHUTDOWN) 408 if (sk->sk_shutdown & RCV_SHUTDOWN)
300 mask |= POLLRDHUP; 409 mask |= POLLRDHUP | POLLIN | POLLRDNORM;
301 410
302 if (sk->sk_shutdown == SHUTDOWN_MASK) 411 if (sk->sk_shutdown == SHUTDOWN_MASK)
303 mask |= POLLHUP; 412 mask |= POLLHUP;
304 413
305 if (!skb_queue_empty(&sk->sk_receive_queue) || 414 if (!skb_queue_empty(&sk->sk_receive_queue))
306 (sk->sk_shutdown & RCV_SHUTDOWN))
307 mask |= POLLIN | POLLRDNORM; 415 mask |= POLLIN | POLLRDNORM;
308 416
309 if (sk->sk_state == BT_CLOSED) 417 if (sk->sk_state == BT_CLOSED)