[Bluetooth] Track status of remote Simple Pairing mode
[pandora-kernel.git] / net / bluetooth / hci_event.c
index e476761..c8fda7d 100644 (file)
@@ -391,6 +391,35 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, status);
 }
 
+static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_ssp_mode *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->ssp_mode = rp->mode;
+}
+
+static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       if (status)
+               return;
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
+       if (!sent)
+               return;
+
+       hdev->ssp_mode = *((__u8 *) sent);
+}
+
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_read_local_version *rp = (void *) skb->data;
@@ -707,6 +736,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                memcpy(data.dev_class, info->dev_class, 3);
                data.clock_offset       = info->clock_offset;
                data.rssi               = 0x00;
+               data.ssp_mode           = 0x00;
                info++;
                hci_inquiry_cache_update(hdev, &data);
        }
@@ -1084,6 +1114,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_host_buffer_size(hdev, skb);
                break;
 
+       case HCI_OP_READ_SSP_MODE:
+               hci_cc_read_ssp_mode(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_SSP_MODE:
+               hci_cc_write_ssp_mode(hdev, skb);
+               break;
+
        case HCI_OP_READ_LOCAL_VERSION:
                hci_cc_read_local_version(hdev, skb);
                break;
@@ -1353,6 +1391,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        memcpy(data.dev_class, info->dev_class, 3);
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
+                       data.ssp_mode           = 0x00;
                        info++;
                        hci_inquiry_cache_update(hdev, &data);
                }
@@ -1367,6 +1406,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        memcpy(data.dev_class, info->dev_class, 3);
                        data.clock_offset       = info->clock_offset;
                        data.rssi               = info->rssi;
+                       data.ssp_mode           = 0x00;
                        info++;
                        hci_inquiry_cache_update(hdev, &data);
                }
@@ -1377,7 +1417,27 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
 static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       struct hci_ev_remote_ext_features *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
        BT_DBG("%s", hdev->name);
+
+       if (ev->status || ev->page != 0x01)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+       if (conn) {
+               struct inquiry_entry *ie;
+
+               if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)))
+                       ie->data.ssp_mode = (ev->features[0] & 0x01);
+
+               conn->ssp_mode = (ev->features[0] & 0x01);
+       }
+
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1457,6 +1517,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
                memcpy(data.dev_class, info->dev_class, 3);
                data.clock_offset       = info->clock_offset;
                data.rssi               = info->rssi;
+               data.ssp_mode           = 0x01;
                info++;
                hci_inquiry_cache_update(hdev, &data);
        }
@@ -1464,6 +1525,53 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        hci_dev_unlock(hdev);
 }
 
+static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_io_capa_request *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (conn)
+               hci_conn_hold(conn);
+
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (conn)
+               hci_conn_put(conn);
+
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_remote_host_features *ev = (void *) skb->data;
+       struct inquiry_entry *ie;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr)))
+               ie->data.ssp_mode = (ev->features[0] & 0x01);
+
+       hci_dev_unlock(hdev);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_event_hdr *hdr = (void *) skb->data;
@@ -1588,6 +1696,18 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_extended_inquiry_result_evt(hdev, skb);
                break;
 
+       case HCI_EV_IO_CAPA_REQUEST:
+               hci_io_capa_request_evt(hdev, skb);
+               break;
+
+       case HCI_EV_SIMPLE_PAIR_COMPLETE:
+               hci_simple_pair_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_REMOTE_HOST_FEATURES:
+               hci_remote_host_features_evt(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s event 0x%x", hdev->name, event);
                break;