aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/bluetooth/bluetooth.h8
-rw-r--r--include/net/bluetooth/hci_core.h2
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--net/bluetooth/hci_conn.c9
-rw-r--r--net/bluetooth/hci_core.c4
-rw-r--r--net/bluetooth/l2cap_core.c5
-rw-r--r--net/bluetooth/l2cap_sock.c36
7 files changed, 59 insertions, 6 deletions
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 43750439c521..af930a3a66be 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -69,6 +69,13 @@ struct bt_security {
69#define BT_FLUSHABLE_OFF 0 69#define BT_FLUSHABLE_OFF 0
70#define BT_FLUSHABLE_ON 1 70#define BT_FLUSHABLE_ON 1
71 71
72#define BT_POWER 9
73struct 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#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) 79#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
73#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) 80#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
74#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg) 81#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
@@ -150,6 +157,7 @@ struct bt_skb_cb {
150 __u8 retries; 157 __u8 retries;
151 __u8 sar; 158 __u8 sar;
152 unsigned short channel; 159 unsigned short channel;
160 __u8 force_active;
153}; 161};
154#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) 162#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
155 163
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5be150229574..818eadbc3f7f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -438,7 +438,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
438int hci_conn_change_link_key(struct hci_conn *conn); 438int hci_conn_change_link_key(struct hci_conn *conn);
439int hci_conn_switch_role(struct hci_conn *conn, __u8 role); 439int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
440 440
441void hci_conn_enter_active_mode(struct hci_conn *conn); 441void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
442void hci_conn_enter_sniff_mode(struct hci_conn *conn); 442void hci_conn_enter_sniff_mode(struct hci_conn *conn);
443 443
444void hci_conn_hold_device(struct hci_conn *conn); 444void hci_conn_hold_device(struct hci_conn *conn);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index a2dcbfff1c51..0529d278e068 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -303,6 +303,7 @@ struct l2cap_chan {
303 __u8 role_switch; 303 __u8 role_switch;
304 __u8 force_reliable; 304 __u8 force_reliable;
305 __u8 flushable; 305 __u8 flushable;
306 __u8 force_active;
306 307
307 __u8 ident; 308 __u8 ident;
308 309
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ce67d0ff486f..0408a93570d6 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -507,7 +507,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
507 if (acl->state == BT_CONNECTED && 507 if (acl->state == BT_CONNECTED &&
508 (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { 508 (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
509 acl->power_save = 1; 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 if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) { 512 if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
513 /* defer SCO setup until mode change completed */ 513 /* defer SCO setup until mode change completed */
@@ -688,7 +688,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
688EXPORT_SYMBOL(hci_conn_switch_role); 688EXPORT_SYMBOL(hci_conn_switch_role);
689 689
690/* Enter active mode */ 690/* Enter active mode */
691void hci_conn_enter_active_mode(struct hci_conn *conn) 691void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
692{ 692{
693 struct hci_dev *hdev = conn->hdev; 693 struct hci_dev *hdev = conn->hdev;
694 694
@@ -697,7 +697,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
697 if (test_bit(HCI_RAW, &hdev->flags)) 697 if (test_bit(HCI_RAW, &hdev->flags))
698 return; 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 goto timer; 704 goto timer;
702 705
703 if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { 706 if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ff6b784c58c5..e14e8a1cb04e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1969,7 +1969,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
1969 while (quote-- && (skb = skb_dequeue(&conn->data_q))) { 1969 while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
1970 BT_DBG("skb %p len %d", skb, skb->len); 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 hci_send_frame(skb); 1974 hci_send_frame(skb);
1975 hdev->acl_last_tx = jiffies; 1975 hdev->acl_last_tx = jiffies;
@@ -2108,7 +2108,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
2108 if (conn) { 2108 if (conn) {
2109 register struct hci_proto *hp; 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 /* Send to upper protocol */ 2113 /* Send to upper protocol */
2114 hp = hci_proto[HCI_PROTO_L2CAP]; 2114 hp = hci_proto[HCI_PROTO_L2CAP];
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index bb6be6377891..6908a835a7a3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -537,6 +537,8 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
537 else 537 else
538 flags = ACL_START; 538 flags = ACL_START;
539 539
540 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
541
540 hci_send_acl(conn->hcon, skb, flags); 542 hci_send_acl(conn->hcon, skb, flags);
541} 543}
542 544
@@ -590,6 +592,8 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
590 else 592 else
591 flags = ACL_START; 593 flags = ACL_START;
592 594
595 bt_cb(skb)->force_active = chan->force_active;
596
593 hci_send_acl(chan->conn->hcon, skb, flags); 597 hci_send_acl(chan->conn->hcon, skb, flags);
594} 598}
595 599
@@ -1215,6 +1219,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
1215 else 1219 else
1216 flags = ACL_START; 1220 flags = ACL_START;
1217 1221
1222 bt_cb(skb)->force_active = chan->force_active;
1218 hci_send_acl(hcon, skb, flags); 1223 hci_send_acl(hcon, skb, flags);
1219} 1224}
1220 1225
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 */