Commit 14b12d0b98f87162b7e9e93dde66d1af97886567

Authored by Jaikumar Ganesh
Committed by Gustavo F. Padovan
1 parent 96d97a673d

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>

Showing 7 changed files with 59 additions and 6 deletions Side-by-side Diff

include/net/bluetooth/bluetooth.h
... ... @@ -69,6 +69,13 @@
69 69 #define BT_FLUSHABLE_OFF 0
70 70 #define BT_FLUSHABLE_ON 1
71 71  
  72 +#define BT_POWER 9
  73 +struct bt_power {
  74 + __u8 force_active;
  75 +};
  76 +#define BT_POWER_FORCE_ACTIVE_OFF 0
  77 +#define BT_POWER_FORCE_ACTIVE_ON 1
  78 +
72 79 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
73 80 #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
74 81 #define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
... ... @@ -150,6 +157,7 @@
150 157 __u8 retries;
151 158 __u8 sar;
152 159 unsigned short channel;
  160 + __u8 force_active;
153 161 };
154 162 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
155 163  
include/net/bluetooth/hci_core.h
... ... @@ -438,7 +438,7 @@
438 438 int hci_conn_change_link_key(struct hci_conn *conn);
439 439 int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
440 440  
441   -void hci_conn_enter_active_mode(struct hci_conn *conn);
  441 +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
442 442 void hci_conn_enter_sniff_mode(struct hci_conn *conn);
443 443  
444 444 void hci_conn_hold_device(struct hci_conn *conn);
include/net/bluetooth/l2cap.h
... ... @@ -303,6 +303,7 @@
303 303 __u8 role_switch;
304 304 __u8 force_reliable;
305 305 __u8 flushable;
  306 + __u8 force_active;
306 307  
307 308 __u8 ident;
308 309  
net/bluetooth/hci_conn.c
... ... @@ -507,7 +507,7 @@
507 507 if (acl->state == BT_CONNECTED &&
508 508 (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
509 509 acl->power_save = 1;
510   - hci_conn_enter_active_mode(acl);
  510 + hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
511 511  
512 512 if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
513 513 /* defer SCO setup until mode change completed */
... ... @@ -688,7 +688,7 @@
688 688 EXPORT_SYMBOL(hci_conn_switch_role);
689 689  
690 690 /* Enter active mode */
691   -void hci_conn_enter_active_mode(struct hci_conn *conn)
  691 +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
692 692 {
693 693 struct hci_dev *hdev = conn->hdev;
694 694  
... ... @@ -697,7 +697,10 @@
697 697 if (test_bit(HCI_RAW, &hdev->flags))
698 698 return;
699 699  
700   - if (conn->mode != HCI_CM_SNIFF || !conn->power_save)
  700 + if (conn->mode != HCI_CM_SNIFF)
  701 + goto timer;
  702 +
  703 + if (!conn->power_save && !force_active)
701 704 goto timer;
702 705  
703 706 if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
net/bluetooth/hci_core.c
... ... @@ -1969,7 +1969,7 @@
1969 1969 while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
1970 1970 BT_DBG("skb %p len %d", skb, skb->len);
1971 1971  
1972   - hci_conn_enter_active_mode(conn);
  1972 + hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
1973 1973  
1974 1974 hci_send_frame(skb);
1975 1975 hdev->acl_last_tx = jiffies;
... ... @@ -2108,7 +2108,7 @@
2108 2108 if (conn) {
2109 2109 register struct hci_proto *hp;
2110 2110  
2111   - hci_conn_enter_active_mode(conn);
  2111 + hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
2112 2112  
2113 2113 /* Send to upper protocol */
2114 2114 hp = hci_proto[HCI_PROTO_L2CAP];
net/bluetooth/l2cap_core.c
... ... @@ -537,6 +537,8 @@
537 537 else
538 538 flags = ACL_START;
539 539  
  540 + bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
  541 +
540 542 hci_send_acl(conn->hcon, skb, flags);
541 543 }
542 544  
... ... @@ -590,6 +592,8 @@
590 592 else
591 593 flags = ACL_START;
592 594  
  595 + bt_cb(skb)->force_active = chan->force_active;
  596 +
593 597 hci_send_acl(chan->conn->hcon, skb, flags);
594 598 }
595 599  
... ... @@ -1215,6 +1219,7 @@
1215 1219 else
1216 1220 flags = ACL_START;
1217 1221  
  1222 + bt_cb(skb)->force_active = chan->force_active;
1218 1223 hci_send_acl(hcon, skb, flags);
1219 1224 }
1220 1225  
net/bluetooth/l2cap_sock.c
... ... @@ -390,6 +390,7 @@
390 390 struct sock *sk = sock->sk;
391 391 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
392 392 struct bt_security sec;
  393 + struct bt_power pwr;
393 394 int len, err = 0;
394 395  
395 396 BT_DBG("sk %p", sk);
... ... @@ -438,6 +439,21 @@
438 439  
439 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 457 default:
442 458 err = -ENOPROTOOPT;
443 459 break;
... ... @@ -538,6 +554,7 @@
538 554 struct sock *sk = sock->sk;
539 555 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
540 556 struct bt_security sec;
  557 + struct bt_power pwr;
541 558 int len, err = 0;
542 559 u32 opt;
543 560  
... ... @@ -614,6 +631,23 @@
614 631 chan->flushable = opt;
615 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 651 default:
618 652 err = -ENOPROTOOPT;
619 653 break;
... ... @@ -771,6 +805,7 @@
771 805 chan->role_switch = pchan->role_switch;
772 806 chan->force_reliable = pchan->force_reliable;
773 807 chan->flushable = pchan->flushable;
  808 + chan->force_active = pchan->force_active;
774 809 } else {
775 810  
776 811 switch (sk->sk_type) {
... ... @@ -801,6 +836,7 @@
801 836 chan->role_switch = 0;
802 837 chan->force_reliable = 0;
803 838 chan->flushable = BT_FLUSHABLE_OFF;
  839 + chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
804 840 }
805 841  
806 842 /* Default config options */