diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_conn.c | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 7 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 127 |
3 files changed, 114 insertions, 22 deletions
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 | ||
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 | static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) | 683 | static 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 | ||
811 | unlock: | 870 | unlock: |
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); |