Commit 769be974d0c7b4fe1a52f9cdaad22259b60953f7
1 parent
a8bd28baf2
Exists in
master
and in
7 other branches
[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>
Showing 5 changed files with 118 additions and 23 deletions Side-by-side Diff
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
... | ... | @@ -348,7 +348,7 @@ |
348 | 348 | if (conn->state == BT_CONNECTED) { |
349 | 349 | timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT); |
350 | 350 | if (!conn->out) |
351 | - timeo *= 2; | |
351 | + timeo *= 5; | |
352 | 352 | } else |
353 | 353 | timeo = msecs_to_jiffies(10); |
354 | 354 | } else |
... | ... | @@ -463,6 +463,7 @@ |
463 | 463 | #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) |
464 | 464 | #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) |
465 | 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 | 468 | /* ----- HCI protocols ----- */ |
468 | 469 | struct hci_proto { |
net/bluetooth/hci_conn.c
... | ... | @@ -170,11 +170,13 @@ |
170 | 170 | |
171 | 171 | switch (conn->state) { |
172 | 172 | case BT_CONNECT: |
173 | + case BT_CONNECT2: | |
173 | 174 | if (conn->type == ACL_LINK) |
174 | 175 | hci_acl_connect_cancel(conn); |
175 | 176 | else |
176 | 177 | hci_acl_disconn(conn, 0x13); |
177 | 178 | break; |
179 | + case BT_CONFIG: | |
178 | 180 | case BT_CONNECTED: |
179 | 181 | hci_acl_disconn(conn, 0x13); |
180 | 182 | break; |
net/bluetooth/hci_core.c
... | ... | @@ -1283,9 +1283,12 @@ |
1283 | 1283 | struct hci_conn *c; |
1284 | 1284 | c = list_entry(p, struct hci_conn, list); |
1285 | 1285 | |
1286 | - if (c->type != type || c->state != BT_CONNECTED | |
1287 | - || skb_queue_empty(&c->data_q)) | |
1286 | + if (c->type != type || skb_queue_empty(&c->data_q)) | |
1288 | 1287 | continue; |
1288 | + | |
1289 | + if (c->state != BT_CONNECTED && c->state != BT_CONFIG) | |
1290 | + continue; | |
1291 | + | |
1289 | 1292 | num++; |
1290 | 1293 | |
1291 | 1294 | if (c->sent < min) { |
net/bluetooth/hci_event.c
... | ... | @@ -624,6 +624,62 @@ |
624 | 624 | BT_DBG("%s status 0x%x", hdev->name, status); |
625 | 625 | } |
626 | 626 | |
627 | +static 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 | + | |
655 | +static 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 | + | |
627 | 683 | static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) |
628 | 684 | { |
629 | 685 | struct hci_cp_setup_sync_conn *cp; |
630 | 686 | |
... | ... | @@ -759,8 +815,13 @@ |
759 | 815 | |
760 | 816 | if (!ev->status) { |
761 | 817 | conn->handle = __le16_to_cpu(ev->handle); |
762 | - conn->state = BT_CONNECTED; | |
763 | 818 | |
819 | + if (conn->type == ACL_LINK) { | |
820 | + conn->state = BT_CONFIG; | |
821 | + hci_conn_hold(conn); | |
822 | + } else | |
823 | + conn->state = BT_CONNECTED; | |
824 | + | |
764 | 825 | if (test_bit(HCI_AUTH, &hdev->flags)) |
765 | 826 | conn->link_mode |= HCI_LM_AUTH; |
766 | 827 | |
... | ... | @@ -771,7 +832,8 @@ |
771 | 832 | if (conn->type == ACL_LINK) { |
772 | 833 | struct hci_cp_read_remote_features cp; |
773 | 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 | 839 | /* Set packet type for incoming connection */ |
... | ... | @@ -781,10 +843,6 @@ |
781 | 843 | cp.pkt_type = cpu_to_le16(conn->pkt_type); |
782 | 844 | hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, |
783 | 845 | sizeof(cp), &cp); |
784 | - } else { | |
785 | - /* Update disconnect timer */ | |
786 | - hci_conn_hold(conn); | |
787 | - hci_conn_put(conn); | |
788 | 846 | } |
789 | 847 | } else |
790 | 848 | conn->state = BT_CLOSED; |
791 | 849 | |
... | ... | @@ -804,9 +862,10 @@ |
804 | 862 | } |
805 | 863 | } |
806 | 864 | |
807 | - hci_proto_connect_cfm(conn, ev->status); | |
808 | - if (ev->status) | |
865 | + if (ev->status) { | |
866 | + hci_proto_connect_cfm(conn, ev->status); | |
809 | 867 | hci_conn_del(conn); |
868 | + } | |
810 | 869 | |
811 | 870 | unlock: |
812 | 871 | hci_dev_unlock(hdev); |
813 | 872 | |
814 | 873 | |
... | ... | @@ -1006,15 +1065,30 @@ |
1006 | 1065 | |
1007 | 1066 | BT_DBG("%s status %d", hdev->name, ev->status); |
1008 | 1067 | |
1009 | - if (ev->status) | |
1010 | - return; | |
1011 | - | |
1012 | 1068 | hci_dev_lock(hdev); |
1013 | 1069 | |
1014 | 1070 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
1015 | - if (conn) | |
1016 | - memcpy(conn->features, ev->features, 8); | |
1071 | + if (conn) { | |
1072 | + if (!ev->status) | |
1073 | + memcpy(conn->features, ev->features, 8); | |
1017 | 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 | + } | |
1091 | + | |
1018 | 1092 | hci_dev_unlock(hdev); |
1019 | 1093 | } |
1020 | 1094 | |
... | ... | @@ -1180,6 +1254,14 @@ |
1180 | 1254 | hci_cs_remote_name_req(hdev, ev->status); |
1181 | 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 | 1265 | case HCI_OP_SETUP_SYNC_CONN: |
1184 | 1266 | hci_cs_setup_sync_conn(hdev, ev->status); |
1185 | 1267 | break; |
1186 | 1268 | |
1187 | 1269 | |
1188 | 1270 | |
... | ... | @@ -1422,19 +1504,24 @@ |
1422 | 1504 | |
1423 | 1505 | BT_DBG("%s", hdev->name); |
1424 | 1506 | |
1425 | - if (ev->status || ev->page != 0x01) | |
1426 | - return; | |
1427 | - | |
1428 | 1507 | hci_dev_lock(hdev); |
1429 | 1508 | |
1430 | 1509 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
1431 | 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))) | |
1435 | - ie->data.ssp_mode = (ev->features[0] & 0x01); | |
1514 | + if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) | |
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 | 1527 | hci_dev_unlock(hdev); |