Bluetooth: notify userspace of security level change
[linux-flexiantxendom0-3.2.10.git] / net / bluetooth / hci_event.c
index 488fdbc..53680fe 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/interrupt.h>
 #include <net/sock.h>
 
-#include <asm/system.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
@@ -193,7 +192,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_RESET, status);
 
        /* Reset all non-persistent flags */
-       hdev->dev_flags &= ~(BIT(HCI_LE_SCAN));
+       hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS));
 
        hdev->discovery.state = DISCOVERY_STOPPED;
 }
@@ -552,19 +551,11 @@ static void hci_setup(struct hci_dev *hdev)
        if (hdev->hci_ver > BLUETOOTH_VER_1_1)
                hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
-       if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
-                                       test_bit(HCI_MGMT, &hdev->dev_flags)) {
-               struct hci_cp_write_local_name cp;
-
-               memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
-               hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
-       }
-
        if (hdev->features[6] & LMP_SIMPLE_PAIR) {
                if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
                        u8 mode = 0x01;
                        hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
-                                                       sizeof(mode), &mode);
+                                    sizeof(mode), &mode);
                } else {
                        struct hci_cp_write_eir cp;
 
@@ -585,14 +576,14 @@ static void hci_setup(struct hci_dev *hdev)
                struct hci_cp_read_local_ext_features cp;
 
                cp.page = 0x01;
-               hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
-                                                       sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
+                            &cp);
        }
 
        if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
                u8 enable = 1;
-               hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE,
-                                               sizeof(enable), &enable);
+               hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
+                            &enable);
        }
 }
 
@@ -636,8 +627,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
                link_policy |= HCI_LP_PARK;
 
        link_policy = cpu_to_le16(link_policy);
-       hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY,
-                                       sizeof(link_policy), &link_policy);
+       hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy),
+                    &link_policy);
 }
 
 static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
@@ -725,8 +716,8 @@ static void hci_set_le_support(struct hci_dev *hdev)
        }
 
        if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
-               hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
-                                                       sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
+                            &cp);
 }
 
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
@@ -984,8 +975,8 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
-               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
-                                                               0, rp->status);
+               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, ACL_LINK, 0,
+                                                rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1001,8 +992,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
-                                                               ACL_LINK, 0,
-                                                               rp->status);
+                                                    ACL_LINK, 0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1017,7 +1007,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_passkey_reply_complete(hdev, &rp->bdaddr, ACL_LINK,
-                                                               0, rp->status);
+                                                0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1033,8 +1023,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_passkey_neg_reply_complete(hdev, &rp->bdaddr,
-                                                               ACL_LINK, 0,
-                                                               rp->status);
+                                                    ACL_LINK, 0, rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1344,7 +1333,8 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
        return 1;
 }
 
-static inline int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e)
+static inline int hci_resolve_name(struct hci_dev *hdev,
+                                  struct inquiry_entry *e)
 {
        struct hci_cp_remote_name_req cp;
 
@@ -1376,14 +1366,14 @@ static bool hci_resolve_next_name(struct hci_dev *hdev)
 }
 
 static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
-                                       bdaddr_t *bdaddr, u8 *name, u8 name_len)
+                                  bdaddr_t *bdaddr, u8 *name, u8 name_len)
 {
        struct discovery_state *discov = &hdev->discovery;
        struct inquiry_entry *e;
 
        if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0,
-                                       name, name_len, conn->dev_class);
+               mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
+                                     name_len, conn->dev_class);
 
        if (discov->state == DISCOVERY_STOPPED)
                return;
@@ -1400,7 +1390,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
                list_del(&e->list);
                if (name)
                        mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
-                                       e->data.rssi, name, name_len);
+                                        e->data.rssi, name, name_len);
        }
 
        if (hci_resolve_next_name(hdev))
@@ -1609,7 +1599,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn)
                mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
-                                               conn->dst_type, status);
+                                      conn->dst_type, status);
 
        hci_dev_unlock(hdev);
 }
@@ -1725,8 +1715,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 
                name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                       info->dev_class, 0, !name_known, ssp,
-                                       NULL, 0);
+                                 info->dev_class, 0, !name_known, ssp, NULL,
+                                 0);
        }
 
        hci_dev_unlock(hdev);
@@ -1777,7 +1767,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        struct hci_cp_read_remote_features cp;
                        cp.handle = ev->handle;
                        hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
-                                                       sizeof(cp), &cp);
+                                    sizeof(cp), &cp);
                }
 
                /* Set packet type for incoming connection */
@@ -1785,14 +1775,14 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        struct hci_cp_change_conn_ptype cp;
                        cp.handle = ev->handle;
                        cp.pkt_type = cpu_to_le16(conn->pkt_type);
-                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
-                                                       sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp),
+                                    &cp);
                }
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
                        mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
-                                               conn->dst_type, ev->status);
+                                           conn->dst_type, ev->status);
        }
 
        if (conn->type == ACL_LINK)
@@ -1857,8 +1847,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        else
                                cp.role = 0x01; /* Remain slave */
 
-                       hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ,
-                                                       sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
+                                    &cp);
                } else {
                        struct hci_cp_accept_sync_conn_req cp;
 
@@ -1872,7 +1862,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        cp.retrans_effort = 0xff;
 
                        hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
-                                                       sizeof(cp), &cp);
+                                    sizeof(cp), &cp);
                }
        } else {
                /* Connection rejected */
@@ -1907,10 +1897,12 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
                                                conn->dst_type, ev->status);
                else
                        mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-                                                       conn->dst_type);
+                                                conn->dst_type);
        }
 
        if (ev->status == 0) {
+               if (conn->type == ACL_LINK && conn->flush_key)
+                       hci_remove_link_key(hdev, &conn->dst);
                hci_proto_disconn_cfm(conn, ev->reason);
                hci_conn_del(conn);
        }
@@ -1942,7 +1934,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                }
        } else {
                mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
-                                                               ev->status);
+                                ev->status);
        }
 
        clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
@@ -2003,7 +1995,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
 
        if (ev->status == 0)
                hci_check_pending_name(hdev, conn, &ev->bdaddr, ev->name,
-                                       strnlen(ev->name, HCI_MAX_NAME_LENGTH));
+                                      strnlen(ev->name, HCI_MAX_NAME_LENGTH));
        else
                hci_check_pending_name(hdev, conn, &ev->bdaddr, NULL, 0);
 
@@ -2047,6 +2039,12 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
 
                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
+               if (ev->status && conn->state == BT_CONNECTED) {
+                       hci_acl_disconn(conn, 0x13);
+                       hci_conn_put(conn);
+                       goto unlock;
+               }
+
                if (conn->state == BT_CONFIG) {
                        if (!ev->status)
                                conn->state = BT_CONNECTED;
@@ -2057,6 +2055,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
                        hci_encrypt_cfm(conn, ev->status, ev->encrypt);
        }
 
+unlock:
        hci_dev_unlock(hdev);
 }
 
@@ -2118,8 +2117,8 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
                hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
        } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, &conn->dst, conn->type,
-                                               conn->dst_type, 0, NULL, 0,
-                                               conn->dev_class);
+                                     conn->dst_type, 0, NULL, 0,
+                                     conn->dev_class);
 
        if (!hci_outgoing_auth_needed(hdev, conn)) {
                conn->state = BT_CONNECTED;
@@ -2321,6 +2320,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
 
        case HCI_OP_USER_PASSKEY_NEG_REPLY:
                hci_cc_user_passkey_neg_reply(hdev, skb);
+               break;
 
        case HCI_OP_LE_SET_SCAN_PARAM:
                hci_cc_le_set_scan_param(hdev, skb);
@@ -2531,7 +2531,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 }
 
 static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                          struct sk_buff *skb)
 {
        struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
        int i;
@@ -2823,10 +2823,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.ssp_mode           = 0x00;
 
                        name_known = hci_inquiry_cache_update(hdev, &data,
-                                                               false, &ssp);
+                                                             false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                               info->dev_class, info->rssi,
-                                               !name_known, ssp, NULL, 0);
+                                         info->dev_class, info->rssi,
+                                         !name_known, ssp, NULL, 0);
                }
        } else {
                struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -2841,10 +2841,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        name_known = hci_inquiry_cache_update(hdev, &data,
-                                                               false, &ssp);
+                                                             false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                               info->dev_class, info->rssi,
-                                               !name_known, ssp, NULL, 0);
+                                         info->dev_class, info->rssi,
+                                         !name_known, ssp, NULL, 0);
                }
        }
 
@@ -2869,9 +2869,9 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
 
                ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
                if (ie)
-                       ie->data.ssp_mode = (ev->features[0] & 0x01);
+                       ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
 
-               if (ev->features[0] & 0x01)
+               if (ev->features[0] & LMP_HOST_SSP)
                        set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
        }
 
@@ -2886,8 +2886,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
                hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
        } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, &conn->dst, conn->type,
-                                               conn->dst_type, 0, NULL, 0,
-                                               conn->dev_class);
+                                     conn->dst_type, 0, NULL, 0,
+                                     conn->dev_class);
 
        if (!hci_outgoing_auth_needed(hdev, conn)) {
                conn->state = BT_CONNECTED;
@@ -2993,17 +2993,16 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 
                if (test_bit(HCI_MGMT, &hdev->dev_flags))
                        name_known = eir_has_data_type(info->data,
-                                                       sizeof(info->data),
-                                                       EIR_NAME_COMPLETE);
+                                                      sizeof(info->data),
+                                                      EIR_NAME_COMPLETE);
                else
                        name_known = true;
 
                name_known = hci_inquiry_cache_update(hdev, &data, name_known,
-                                                                       &ssp);
+                                                     &ssp);
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
-                                               info->dev_class, info->rssi,
-                                               !name_known, ssp, info->data,
-                                               sizeof(info->data));
+                                 info->dev_class, info->rssi, !name_known,
+                                 ssp, info->data, sizeof(info->data));
        }
 
        hci_dev_unlock(hdev);
@@ -3164,7 +3163,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 
 confirm:
        mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
-                                                               confirm_hint);
+                                 confirm_hint);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -3205,7 +3204,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
         * the mgmt_auth_failed event */
        if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
                mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
-                                                               ev->status);
+                                ev->status);
 
        hci_conn_put(conn);
 
@@ -3224,13 +3223,13 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
 
        ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
        if (ie)
-               ie->data.ssp_mode = (ev->features[0] & 0x01);
+               ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
 
        hci_dev_unlock(hdev);
 }
 
 static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                                  struct sk_buff *skb)
 {
        struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
        struct oob_data *data;
@@ -3296,7 +3295,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
-                                               conn->dst_type, 0, NULL, 0, 0);
+                                     conn->dst_type, 0, NULL, 0, NULL);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
@@ -3327,8 +3326,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
 
                rssi = ev->data[ev->length];
                mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
-                                       NULL, rssi, 0, 1, ev->data,
-                                       ev->length);
+                                 NULL, rssi, 0, 1, ev->data, ev->length);
 
                ptr += sizeof(*ev) + ev->length + 1;
        }