Bluetooth: Add discovering event to the Management interface
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / bluetooth / hci_event.c
index 3fbfa50c2bff8a1fc9412319d5887aefa4938de0..e64a3de70d777e0e6e026961436cce511d2ef491 100644 (file)
@@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       clear_bit(HCI_INQUIRY, &hdev->flags);
+       if (test_bit(HCI_MGMT, &hdev->flags) &&
+                               test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+               mgmt_discovering(hdev->id, 0);
 
        hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
@@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       clear_bit(HCI_INQUIRY, &hdev->flags);
+       if (test_bit(HCI_MGMT, &hdev->flags) &&
+                               test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+               mgmt_discovering(hdev->id, 0);
 
        hci_conn_check_pending(hdev);
 }
@@ -183,6 +187,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
+       clear_bit(HCI_RESET, &hdev->flags);
+
        hci_req_complete(hdev, HCI_OP_RESET, status);
 }
 
@@ -193,14 +199,17 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (status)
-               return;
-
        sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
        if (!sent)
                return;
 
-       memcpy(hdev->dev_name, sent, 248);
+       if (test_bit(HCI_MGMT, &hdev->flags))
+               mgmt_set_local_name_complete(hdev->id, sent, status);
+
+       if (status)
+               return;
+
+       memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -212,7 +221,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (rp->status)
                return;
 
-       memcpy(hdev->dev_name, rp->name, 248);
+       memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
 }
 
 static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -819,16 +828,31 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
                                                                rp->status);
 }
 
+static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
+                                                       struct sk_buff *skb)
+{
+       struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+                                               rp->randomizer, rp->status);
+}
+
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%x", hdev->name, status);
 
        if (status) {
                hci_req_complete(hdev, HCI_OP_INQUIRY, status);
-
                hci_conn_check_pending(hdev);
-       } else
-               set_bit(HCI_INQUIRY, &hdev->flags);
+               return;
+       }
+
+       if (test_bit(HCI_MGMT, &hdev->flags) &&
+                                       !test_and_set_bit(HCI_INQUIRY,
+                                                       &hdev->flags))
+               mgmt_discovering(hdev->id, 1);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1192,7 +1216,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        BT_DBG("%s status %d", hdev->name, status);
 
-       clear_bit(HCI_INQUIRY, &hdev->flags);
+       if (test_bit(HCI_MGMT, &hdev->flags) &&
+                               test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+               mgmt_discovering(hdev->id, 0);
 
        hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
@@ -1212,7 +1238,13 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 
        hci_dev_lock(hdev);
 
-       for (; num_rsp; num_rsp--) {
+       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
+
+               if (test_bit(HCI_MGMT, &hdev->flags))
+                       mgmt_discovering(hdev->id, 1);
+       }
+
+       for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
@@ -1221,8 +1253,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                data.clock_offset       = info->clock_offset;
                data.rssi               = 0x00;
                data.ssp_mode           = 0x00;
-               info++;
                hci_inquiry_cache_update(hdev, &data);
+               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
+                                                                       NULL);
        }
 
        hci_dev_unlock(hdev);
@@ -1480,6 +1513,9 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
 
        hci_dev_lock(hdev);
 
+       if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
+               mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
+
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn && hci_outgoing_auth_needed(hdev, conn)) {
                struct hci_cp_auth_requested cp;
@@ -1749,6 +1785,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_pin_code_neg_reply(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_OOB_DATA:
+               hci_cc_read_local_oob_data_reply(hdev, skb);
+               break;
+
        case HCI_OP_LE_READ_BUFFER_SIZE:
                hci_cc_le_read_buffer_size(hdev, skb);
                break;
@@ -1847,7 +1887,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
        if (ev->opcode != HCI_OP_NOP)
                del_timer(&hdev->cmd_timer);
 
-       if (ev->ncmd) {
+       if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
                atomic_set(&hdev->cmd_cnt, 1);
                if (!skb_queue_empty(&hdev->cmd_q))
                        tasklet_schedule(&hdev->cmd_task);
@@ -2134,11 +2174,17 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
        hci_dev_lock(hdev);
 
+       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
+
+               if (test_bit(HCI_MGMT, &hdev->flags))
+                       mgmt_discovering(hdev->id, 1);
+       }
+
        if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
                struct inquiry_info_with_rssi_and_pscan_mode *info;
                info = (void *) (skb->data + 1);
 
-               for (; num_rsp; num_rsp--) {
+               for (; num_rsp; num_rsp--, info++) {
                        bacpy(&data.bdaddr, &info->bdaddr);
                        data.pscan_rep_mode     = info->pscan_rep_mode;
                        data.pscan_period_mode  = info->pscan_period_mode;
@@ -2147,13 +2193,15 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
-                       info++;
                        hci_inquiry_cache_update(hdev, &data);
+                       mgmt_device_found(hdev->id, &info->bdaddr,
+                                               info->dev_class, info->rssi,
+                                               NULL);
                }
        } else {
                struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
 
-               for (; num_rsp; num_rsp--) {
+               for (; num_rsp; num_rsp--, info++) {
                        bacpy(&data.bdaddr, &info->bdaddr);
                        data.pscan_rep_mode     = info->pscan_rep_mode;
                        data.pscan_period_mode  = info->pscan_period_mode;
@@ -2162,8 +2210,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
-                       info++;
                        hci_inquiry_cache_update(hdev, &data);
+                       mgmt_device_found(hdev->id, &info->bdaddr,
+                                               info->dev_class, info->rssi,
+                                               NULL);
                }
        }
 
@@ -2292,9 +2342,15 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        if (!num_rsp)
                return;
 
+       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
+
+               if (test_bit(HCI_MGMT, &hdev->flags))
+                       mgmt_discovering(hdev->id, 1);
+       }
+
        hci_dev_lock(hdev);
 
-       for (; num_rsp; num_rsp--) {
+       for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
                data.pscan_period_mode  = info->pscan_period_mode;
@@ -2303,8 +2359,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
                data.clock_offset       = info->clock_offset;
                data.rssi               = info->rssi;
                data.ssp_mode           = 0x01;
-               info++;
                hci_inquiry_cache_update(hdev, &data);
+               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
+                                               info->rssi, info->data);
        }
 
        hci_dev_unlock(hdev);
@@ -2353,9 +2410,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
                cp.capability = conn->io_capability;
-               cp.oob_data = 0;
                cp.authentication = hci_get_auth_req(conn);
 
+               if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
+                               hci_find_remote_oob_data(hdev, &conn->dst))
+                       cp.oob_data = 0x01;
+               else
+                       cp.oob_data = 0x00;
+
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
                                                        sizeof(cp), &cp);
        } else {
@@ -2385,8 +2447,6 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s
        if (!conn)
                goto unlock;
 
-       hci_conn_hold(conn);
-
        conn->remote_cap = ev->capability;
        conn->remote_oob = ev->oob_data;
        conn->remote_auth = ev->authentication;
@@ -2453,6 +2513,41 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
        hci_dev_unlock(hdev);
 }
 
+static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+                                                       struct sk_buff *skb)
+{
+       struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+       struct oob_data *data;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       if (!test_bit(HCI_MGMT, &hdev->flags))
+               goto unlock;
+
+       data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
+       if (data) {
+               struct hci_cp_remote_oob_data_reply cp;
+
+               bacpy(&cp.bdaddr, &ev->bdaddr);
+               memcpy(cp.hash, data->hash, sizeof(cp.hash));
+               memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
+
+               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
+                                                                       &cp);
+       } else {
+               struct hci_cp_remote_oob_data_neg_reply cp;
+
+               bacpy(&cp.bdaddr, &ev->bdaddr);
+               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
+                                                                       &cp);
+       }
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
 static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -2655,6 +2750,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_le_meta_evt(hdev, skb);
                break;
 
+       case HCI_EV_REMOTE_OOB_DATA_REQUEST:
+               hci_remote_oob_data_request_evt(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s event 0x%x", hdev->name, event);
                break;