diff options
Diffstat (limited to 'net/bluetooth/hci_event.c')
-rw-r--r-- | net/bluetooth/hci_event.c | 87 |
1 files changed, 85 insertions, 2 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ac2c5e89617c..a40170e022e8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -45,6 +45,8 @@ | |||
45 | #include <net/bluetooth/bluetooth.h> | 45 | #include <net/bluetooth/bluetooth.h> |
46 | #include <net/bluetooth/hci_core.h> | 46 | #include <net/bluetooth/hci_core.h> |
47 | 47 | ||
48 | static int enable_le; | ||
49 | |||
48 | /* Handle HCI Event packets */ | 50 | /* Handle HCI Event packets */ |
49 | 51 | ||
50 | static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) | 52 | static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -525,6 +527,20 @@ static void hci_setup_event_mask(struct hci_dev *hdev) | |||
525 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); | 527 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); |
526 | } | 528 | } |
527 | 529 | ||
530 | static void hci_set_le_support(struct hci_dev *hdev) | ||
531 | { | ||
532 | struct hci_cp_write_le_host_supported cp; | ||
533 | |||
534 | memset(&cp, 0, sizeof(cp)); | ||
535 | |||
536 | if (enable_le) { | ||
537 | cp.le = 1; | ||
538 | cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); | ||
539 | } | ||
540 | |||
541 | hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp); | ||
542 | } | ||
543 | |||
528 | static void hci_setup(struct hci_dev *hdev) | 544 | static void hci_setup(struct hci_dev *hdev) |
529 | { | 545 | { |
530 | hci_setup_event_mask(hdev); | 546 | hci_setup_event_mask(hdev); |
@@ -542,6 +558,17 @@ static void hci_setup(struct hci_dev *hdev) | |||
542 | 558 | ||
543 | if (hdev->features[7] & LMP_INQ_TX_PWR) | 559 | if (hdev->features[7] & LMP_INQ_TX_PWR) |
544 | hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); | 560 | hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); |
561 | |||
562 | if (hdev->features[7] & LMP_EXTFEATURES) { | ||
563 | struct hci_cp_read_local_ext_features cp; | ||
564 | |||
565 | cp.page = 0x01; | ||
566 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, | ||
567 | sizeof(cp), &cp); | ||
568 | } | ||
569 | |||
570 | if (hdev->features[4] & LMP_LE) | ||
571 | hci_set_le_support(hdev); | ||
545 | } | 572 | } |
546 | 573 | ||
547 | static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) | 574 | static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -658,6 +685,21 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb | |||
658 | hdev->features[6], hdev->features[7]); | 685 | hdev->features[6], hdev->features[7]); |
659 | } | 686 | } |
660 | 687 | ||
688 | static void hci_cc_read_local_ext_features(struct hci_dev *hdev, | ||
689 | struct sk_buff *skb) | ||
690 | { | ||
691 | struct hci_rp_read_local_ext_features *rp = (void *) skb->data; | ||
692 | |||
693 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | ||
694 | |||
695 | if (rp->status) | ||
696 | return; | ||
697 | |||
698 | memcpy(hdev->extfeatures, rp->features, 8); | ||
699 | |||
700 | hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status); | ||
701 | } | ||
702 | |||
661 | static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) | 703 | static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) |
662 | { | 704 | { |
663 | struct hci_rp_read_buffer_size *rp = (void *) skb->data; | 705 | struct hci_rp_read_buffer_size *rp = (void *) skb->data; |
@@ -892,6 +934,21 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) | |||
892 | hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); | 934 | hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); |
893 | } | 935 | } |
894 | 936 | ||
937 | static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, | ||
938 | struct sk_buff *skb) | ||
939 | { | ||
940 | struct hci_cp_read_local_ext_features cp; | ||
941 | __u8 status = *((__u8 *) skb->data); | ||
942 | |||
943 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
944 | |||
945 | if (status) | ||
946 | return; | ||
947 | |||
948 | cp.page = 0x01; | ||
949 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp); | ||
950 | } | ||
951 | |||
895 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | 952 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
896 | { | 953 | { |
897 | BT_DBG("%s status 0x%x", hdev->name, status); | 954 | BT_DBG("%s status 0x%x", hdev->name, status); |
@@ -1826,6 +1883,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1826 | hci_cc_read_local_features(hdev, skb); | 1883 | hci_cc_read_local_features(hdev, skb); |
1827 | break; | 1884 | break; |
1828 | 1885 | ||
1886 | case HCI_OP_READ_LOCAL_EXT_FEATURES: | ||
1887 | hci_cc_read_local_ext_features(hdev, skb); | ||
1888 | break; | ||
1889 | |||
1829 | case HCI_OP_READ_BUFFER_SIZE: | 1890 | case HCI_OP_READ_BUFFER_SIZE: |
1830 | hci_cc_read_buffer_size(hdev, skb); | 1891 | hci_cc_read_buffer_size(hdev, skb); |
1831 | break; | 1892 | break; |
@@ -1894,6 +1955,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1894 | hci_cc_le_ltk_neg_reply(hdev, skb); | 1955 | hci_cc_le_ltk_neg_reply(hdev, skb); |
1895 | break; | 1956 | break; |
1896 | 1957 | ||
1958 | case HCI_OP_WRITE_LE_HOST_SUPPORTED: | ||
1959 | hci_cc_write_le_host_supported(hdev, skb); | ||
1960 | break; | ||
1961 | |||
1897 | default: | 1962 | default: |
1898 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1963 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
1899 | break; | 1964 | break; |
@@ -2793,21 +2858,36 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, | |||
2793 | { | 2858 | { |
2794 | struct hci_ev_le_ltk_req *ev = (void *) skb->data; | 2859 | struct hci_ev_le_ltk_req *ev = (void *) skb->data; |
2795 | struct hci_cp_le_ltk_reply cp; | 2860 | struct hci_cp_le_ltk_reply cp; |
2861 | struct hci_cp_le_ltk_neg_reply neg; | ||
2796 | struct hci_conn *conn; | 2862 | struct hci_conn *conn; |
2863 | struct link_key *ltk; | ||
2797 | 2864 | ||
2798 | BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); | 2865 | BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); |
2799 | 2866 | ||
2800 | hci_dev_lock(hdev); | 2867 | hci_dev_lock(hdev); |
2801 | 2868 | ||
2802 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | 2869 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
2870 | if (conn == NULL) | ||
2871 | goto not_found; | ||
2803 | 2872 | ||
2804 | memset(&cp, 0, sizeof(cp)); | 2873 | ltk = hci_find_ltk(hdev, ev->ediv, ev->random); |
2874 | if (ltk == NULL) | ||
2875 | goto not_found; | ||
2876 | |||
2877 | memcpy(cp.ltk, ltk->val, sizeof(ltk->val)); | ||
2805 | cp.handle = cpu_to_le16(conn->handle); | 2878 | cp.handle = cpu_to_le16(conn->handle); |
2806 | memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk)); | 2879 | conn->pin_length = ltk->pin_len; |
2807 | 2880 | ||
2808 | hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); | 2881 | hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); |
2809 | 2882 | ||
2810 | hci_dev_unlock(hdev); | 2883 | hci_dev_unlock(hdev); |
2884 | |||
2885 | return; | ||
2886 | |||
2887 | not_found: | ||
2888 | neg.handle = ev->handle; | ||
2889 | hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(neg), &neg); | ||
2890 | hci_dev_unlock(hdev); | ||
2811 | } | 2891 | } |
2812 | 2892 | ||
2813 | static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) | 2893 | static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -3022,3 +3102,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) | |||
3022 | hci_send_to_sock(hdev, skb, NULL); | 3102 | hci_send_to_sock(hdev, skb, NULL); |
3023 | kfree_skb(skb); | 3103 | kfree_skb(skb); |
3024 | } | 3104 | } |
3105 | |||
3106 | module_param(enable_le, bool, 0444); | ||
3107 | MODULE_PARM_DESC(enable_le, "Enable LE support"); | ||