aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2008-07-14 14:13:49 -0400
committerMarcel Holtmann <marcel@holtmann.org>2008-07-14 14:13:49 -0400
commit769be974d0c7b4fe1a52f9cdaad22259b60953f7 (patch)
treeb07af753550c892beb7223d474298806cbf919d5
parenta8bd28baf21b9ee6b8486666b771283e566c0d31 (diff)
[Bluetooth] Use ACL config stage to retrieve remote features
The Bluetooth technology introduces new features on a regular basis and for some of them it is important that the hardware on both sides support them. For features like Simple Pairing it is important that the host stacks on both sides have switched this feature on. To make valid decisions, a config stage during ACL link establishment has been introduced that retrieves remote features and if needed also the remote extended features (known as remote host features) before signalling this link as connected. This change introduces full reference counting of incoming and outgoing ACL links and the Bluetooth core will disconnect both if no owner of it is present. To better handle interoperability during the pairing phase the disconnect timeout for incoming connections has been increased to 10 seconds. This is five times more than for outgoing connections. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci.h2
-rw-r--r--include/net/bluetooth/hci_core.h3
-rw-r--r--net/bluetooth/hci_conn.c2
-rw-r--r--net/bluetooth/hci_core.c7
-rw-r--r--net/bluetooth/hci_event.c127
5 files changed, 118 insertions, 23 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 5ac0a18db63c..55576e848827 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -180,6 +180,8 @@ enum {
180 180
181#define LMP_SNIFF_SUBR 0x02 181#define LMP_SNIFF_SUBR 0x02
182 182
183#define LMP_SIMPLE_PAIR 0x08
184
183/* Connection modes */ 185/* Connection modes */
184#define HCI_CM_ACTIVE 0x0000 186#define HCI_CM_ACTIVE 0x0000
185#define HCI_CM_HOLD 0x0001 187#define HCI_CM_HOLD 0x0001
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f73cc2945700..28fbd0caa534 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -348,7 +348,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
348 if (conn->state == BT_CONNECTED) { 348 if (conn->state == BT_CONNECTED) {
349 timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT); 349 timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
350 if (!conn->out) 350 if (!conn->out)
351 timeo *= 2; 351 timeo *= 5;
352 } else 352 } else
353 timeo = msecs_to_jiffies(10); 353 timeo = msecs_to_jiffies(10);
354 } else 354 } else
@@ -463,6 +463,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
463#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) 463#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
464#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) 464#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
465#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) 465#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
466#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
466 467
467/* ----- HCI protocols ----- */ 468/* ----- HCI protocols ----- */
468struct hci_proto { 469struct hci_proto {
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 41351ba692e9..6f22533e7656 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -170,11 +170,13 @@ static void hci_conn_timeout(unsigned long arg)
170 170
171 switch (conn->state) { 171 switch (conn->state) {
172 case BT_CONNECT: 172 case BT_CONNECT:
173 case BT_CONNECT2:
173 if (conn->type == ACL_LINK) 174 if (conn->type == ACL_LINK)
174 hci_acl_connect_cancel(conn); 175 hci_acl_connect_cancel(conn);
175 else 176 else
176 hci_acl_disconn(conn, 0x13); 177 hci_acl_disconn(conn, 0x13);
177 break; 178 break;
179 case BT_CONFIG:
178 case BT_CONNECTED: 180 case BT_CONNECTED:
179 hci_acl_disconn(conn, 0x13); 181 hci_acl_disconn(conn, 0x13);
180 break; 182 break;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 69b2c1aac08a..f5b21cb93699 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1283,9 +1283,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
1283 struct hci_conn *c; 1283 struct hci_conn *c;
1284 c = list_entry(p, struct hci_conn, list); 1284 c = list_entry(p, struct hci_conn, list);
1285 1285
1286 if (c->type != type || c->state != BT_CONNECTED 1286 if (c->type != type || skb_queue_empty(&c->data_q))
1287 || skb_queue_empty(&c->data_q))
1288 continue; 1287 continue;
1288
1289 if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
1290 continue;
1291
1289 num++; 1292 num++;
1290 1293
1291 if (c->sent < min) { 1294 if (c->sent < min) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c8fda7dc2986..e3e360c3c536 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -624,6 +624,62 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
624 BT_DBG("%s status 0x%x", hdev->name, status); 624 BT_DBG("%s status 0x%x", hdev->name, status);
625} 625}
626 626
627static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
628{
629 struct hci_cp_read_remote_features *cp;
630 struct hci_conn *conn;
631
632 BT_DBG("%s status 0x%x", hdev->name, status);
633
634 if (!status)
635 return;
636
637 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_FEATURES);
638 if (!cp)
639 return;
640
641 hci_dev_lock(hdev);
642
643 conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
644 if (conn) {
645 if (conn->state == BT_CONFIG) {
646 conn->state = BT_CONNECTED;
647 hci_proto_connect_cfm(conn, status);
648 hci_conn_put(conn);
649 }
650 }
651
652 hci_dev_unlock(hdev);
653}
654
655static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
656{
657 struct hci_cp_read_remote_ext_features *cp;
658 struct hci_conn *conn;
659
660 BT_DBG("%s status 0x%x", hdev->name, status);
661
662 if (!status)
663 return;
664
665 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES);
666 if (!cp)
667 return;
668
669 hci_dev_lock(hdev);
670
671 conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
672 if (conn) {
673 if (conn->state == BT_CONFIG) {
674 conn->state = BT_CONNECTED;
675 hci_proto_connect_cfm(conn, status);
676 hci_conn_put(conn);
677 }
678 }
679
680 hci_dev_unlock(hdev);
681}
682
627static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) 683static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
628{ 684{
629 struct hci_cp_setup_sync_conn *cp; 685 struct hci_cp_setup_sync_conn *cp;
@@ -759,7 +815,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
759 815
760 if (!ev->status) { 816 if (!ev->status) {
761 conn->handle = __le16_to_cpu(ev->handle); 817 conn->handle = __le16_to_cpu(ev->handle);
762 conn->state = BT_CONNECTED; 818
819 if (conn->type == ACL_LINK) {
820 conn->state = BT_CONFIG;
821 hci_conn_hold(conn);
822 } else
823 conn->state = BT_CONNECTED;
763 824
764 if (test_bit(HCI_AUTH, &hdev->flags)) 825 if (test_bit(HCI_AUTH, &hdev->flags))
765 conn->link_mode |= HCI_LM_AUTH; 826 conn->link_mode |= HCI_LM_AUTH;
@@ -771,7 +832,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
771 if (conn->type == ACL_LINK) { 832 if (conn->type == ACL_LINK) {
772 struct hci_cp_read_remote_features cp; 833 struct hci_cp_read_remote_features cp;
773 cp.handle = ev->handle; 834 cp.handle = ev->handle;
774 hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp); 835 hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
836 sizeof(cp), &cp);
775 } 837 }
776 838
777 /* Set packet type for incoming connection */ 839 /* Set packet type for incoming connection */
@@ -781,10 +843,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
781 cp.pkt_type = cpu_to_le16(conn->pkt_type); 843 cp.pkt_type = cpu_to_le16(conn->pkt_type);
782 hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, 844 hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
783 sizeof(cp), &cp); 845 sizeof(cp), &cp);
784 } else {
785 /* Update disconnect timer */
786 hci_conn_hold(conn);
787 hci_conn_put(conn);
788 } 846 }
789 } else 847 } else
790 conn->state = BT_CLOSED; 848 conn->state = BT_CLOSED;
@@ -804,9 +862,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
804 } 862 }
805 } 863 }
806 864
807 hci_proto_connect_cfm(conn, ev->status); 865 if (ev->status) {
808 if (ev->status) 866 hci_proto_connect_cfm(conn, ev->status);
809 hci_conn_del(conn); 867 hci_conn_del(conn);
868 }
810 869
811unlock: 870unlock:
812 hci_dev_unlock(hdev); 871 hci_dev_unlock(hdev);
@@ -1006,14 +1065,29 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
1006 1065
1007 BT_DBG("%s status %d", hdev->name, ev->status); 1066 BT_DBG("%s status %d", hdev->name, ev->status);
1008 1067
1009 if (ev->status)
1010 return;
1011
1012 hci_dev_lock(hdev); 1068 hci_dev_lock(hdev);
1013 1069
1014 conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); 1070 conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
1015 if (conn) 1071 if (conn) {
1016 memcpy(conn->features, ev->features, 8); 1072 if (!ev->status)
1073 memcpy(conn->features, ev->features, 8);
1074
1075 if (conn->state == BT_CONFIG) {
1076 if (!ev->status && lmp_ssp_capable(hdev) &&
1077 lmp_ssp_capable(conn)) {
1078 struct hci_cp_read_remote_ext_features cp;
1079 cp.handle = ev->handle;
1080 cp.page = 0x01;
1081 hci_send_cmd(hdev,
1082 HCI_OP_READ_REMOTE_EXT_FEATURES,
1083 sizeof(cp), &cp);
1084 } else {
1085 conn->state = BT_CONNECTED;
1086 hci_proto_connect_cfm(conn, ev->status);
1087 hci_conn_put(conn);
1088 }
1089 }
1090 }
1017 1091
1018 hci_dev_unlock(hdev); 1092 hci_dev_unlock(hdev);
1019} 1093}
@@ -1180,6 +1254,14 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
1180 hci_cs_remote_name_req(hdev, ev->status); 1254 hci_cs_remote_name_req(hdev, ev->status);
1181 break; 1255 break;
1182 1256
1257 case HCI_OP_READ_REMOTE_FEATURES:
1258 hci_cs_read_remote_features(hdev, ev->status);
1259 break;
1260
1261 case HCI_OP_READ_REMOTE_EXT_FEATURES:
1262 hci_cs_read_remote_ext_features(hdev, ev->status);
1263 break;
1264
1183 case HCI_OP_SETUP_SYNC_CONN: 1265 case HCI_OP_SETUP_SYNC_CONN:
1184 hci_cs_setup_sync_conn(hdev, ev->status); 1266 hci_cs_setup_sync_conn(hdev, ev->status);
1185 break; 1267 break;
@@ -1422,19 +1504,24 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
1422 1504
1423 BT_DBG("%s", hdev->name); 1505 BT_DBG("%s", hdev->name);
1424 1506
1425 if (ev->status || ev->page != 0x01)
1426 return;
1427
1428 hci_dev_lock(hdev); 1507 hci_dev_lock(hdev);
1429 1508
1430 conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); 1509 conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
1431 if (conn) { 1510 if (conn) {
1432 struct inquiry_entry *ie; 1511 if (!ev->status && ev->page == 0x01) {
1512 struct inquiry_entry *ie;
1433 1513
1434 if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) 1514 if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)))
1435 ie->data.ssp_mode = (ev->features[0] & 0x01); 1515 ie->data.ssp_mode = (ev->features[0] & 0x01);
1436 1516
1437 conn->ssp_mode = (ev->features[0] & 0x01); 1517 conn->ssp_mode = (ev->features[0] & 0x01);
1518 }
1519
1520 if (conn->state == BT_CONFIG) {
1521 conn->state = BT_CONNECTED;
1522 hci_proto_connect_cfm(conn, ev->status);
1523 hci_conn_put(conn);
1524 }
1438 } 1525 }
1439 1526
1440 hci_dev_unlock(hdev); 1527 hci_dev_unlock(hdev);