aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
authorJaikumar Ganesh <jaikumar@google.com>2011-05-23 21:06:04 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-06-08 15:58:19 -0400
commit14b12d0b98f87162b7e9e93dde66d1af97886567 (patch)
tree3ee2430863ad890b9b36ee4172fadc5147a01ad0 /net/bluetooth/l2cap_sock.c
parent96d97a673d42408c0f960cc54d44be7629343bce (diff)
Bluetooth: Add BT_POWER L2CAP socket option.
Add BT_POWER socket option used to control the power characteristics of the underlying ACL link. When the remote end has put the link in sniff mode and the host stack wants to send data we need need to explicitly exit sniff mode to work well with certain devices (For example, A2DP on Plantronics Voyager 855). However, this causes problems with HID devices. Hence, moving into active mode when sending data, irrespective of who set the sniff mode has been made as a socket option. By default, we will move into active mode. HID devices can set the L2CAP socket option to prevent this from happening. Currently, this has been implemented for L2CAP sockets. This has been tested with incoming and outgoing L2CAP sockets for HID and A2DP. Based on discussions on linux-bluetooth and patches submitted by Andrei Emeltchenko. Signed-off-by: Jaikumar Ganesh <jaikumar@google.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index b79fb7561836..bec3e043b254 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -390,6 +390,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
390 struct sock *sk = sock->sk; 390 struct sock *sk = sock->sk;
391 struct l2cap_chan *chan = l2cap_pi(sk)->chan; 391 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
392 struct bt_security sec; 392 struct bt_security sec;
393 struct bt_power pwr;
393 int len, err = 0; 394 int len, err = 0;
394 395
395 BT_DBG("sk %p", sk); 396 BT_DBG("sk %p", sk);
@@ -438,6 +439,21 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
438 439
439 break; 440 break;
440 441
442 case BT_POWER:
443 if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
444 && sk->sk_type != SOCK_RAW) {
445 err = -EINVAL;
446 break;
447 }
448
449 pwr.force_active = chan->force_active;
450
451 len = min_t(unsigned int, len, sizeof(pwr));
452 if (copy_to_user(optval, (char *) &pwr, len))
453 err = -EFAULT;
454
455 break;
456
441 default: 457 default:
442 err = -ENOPROTOOPT; 458 err = -ENOPROTOOPT;
443 break; 459 break;
@@ -538,6 +554,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
538 struct sock *sk = sock->sk; 554 struct sock *sk = sock->sk;
539 struct l2cap_chan *chan = l2cap_pi(sk)->chan; 555 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
540 struct bt_security sec; 556 struct bt_security sec;
557 struct bt_power pwr;
541 int len, err = 0; 558 int len, err = 0;
542 u32 opt; 559 u32 opt;
543 560
@@ -614,6 +631,23 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
614 chan->flushable = opt; 631 chan->flushable = opt;
615 break; 632 break;
616 633
634 case BT_POWER:
635 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
636 chan->chan_type != L2CAP_CHAN_RAW) {
637 err = -EINVAL;
638 break;
639 }
640
641 pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
642
643 len = min_t(unsigned int, sizeof(pwr), optlen);
644 if (copy_from_user((char *) &pwr, optval, len)) {
645 err = -EFAULT;
646 break;
647 }
648 chan->force_active = pwr.force_active;
649 break;
650
617 default: 651 default:
618 err = -ENOPROTOOPT; 652 err = -ENOPROTOOPT;
619 break; 653 break;
@@ -771,6 +805,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
771 chan->role_switch = pchan->role_switch; 805 chan->role_switch = pchan->role_switch;
772 chan->force_reliable = pchan->force_reliable; 806 chan->force_reliable = pchan->force_reliable;
773 chan->flushable = pchan->flushable; 807 chan->flushable = pchan->flushable;
808 chan->force_active = pchan->force_active;
774 } else { 809 } else {
775 810
776 switch (sk->sk_type) { 811 switch (sk->sk_type) {
@@ -801,6 +836,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent)
801 chan->role_switch = 0; 836 chan->role_switch = 0;
802 chan->force_reliable = 0; 837 chan->force_reliable = 0;
803 chan->flushable = BT_FLUSHABLE_OFF; 838 chan->flushable = BT_FLUSHABLE_OFF;
839 chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
804 } 840 }
805 841
806 /* Default config options */ 842 /* Default config options */