]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/bluetooth/mgmt.c
Bluetooth: Use unresolvable private address for active scanning
[mirror_ubuntu-artful-kernel.git] / net / bluetooth / mgmt.c
index e8b9d2f261eeadc102505d1bc1e55aa9c72d48f6..5d309d4ab527ebc98944d553adbc3cb3c73d0199 100644 (file)
@@ -81,6 +81,7 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_SET_SCAN_PARAMS,
        MGMT_OP_SET_SECURE_CONN,
        MGMT_OP_SET_DEBUG_KEYS,
+       MGMT_OP_SET_PRIVACY,
        MGMT_OP_LOAD_IRKS,
 };
 
@@ -106,6 +107,7 @@ static const u16 mgmt_events[] = {
        MGMT_EV_DEVICE_UNBLOCKED,
        MGMT_EV_DEVICE_UNPAIRED,
        MGMT_EV_PASSKEY_NOTIFY,
+       MGMT_EV_NEW_IRK,
 };
 
 #define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
@@ -389,6 +391,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
        if (lmp_le_capable(hdev)) {
                settings |= MGMT_SETTING_LE;
                settings |= MGMT_SETTING_ADVERTISING;
+               settings |= MGMT_SETTING_PRIVACY;
        }
 
        return settings;
@@ -437,6 +440,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
                settings |= MGMT_SETTING_DEBUG_KEYS;
 
+       if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+               settings |= MGMT_SETTING_PRIVACY;
+
        return settings;
 }
 
@@ -811,6 +817,54 @@ static void update_class(struct hci_request *req)
        hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
 }
 
+static u8 get_adv_type(struct hci_dev *hdev)
+{
+       struct pending_cmd *cmd;
+       bool connectable;
+
+       /* If there's a pending mgmt command the flag will not yet have
+        * it's final value, so check for this first.
+        */
+       cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
+       if (cmd) {
+               struct mgmt_mode *cp = cmd->param;
+               connectable = !!cp->val;
+       } else {
+               connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+       }
+
+       return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
+}
+
+static void enable_advertising(struct hci_request *req)
+{
+       struct hci_dev *hdev = req->hdev;
+       struct hci_cp_le_set_adv_param cp;
+       u8 own_addr_type, enable = 0x01;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (hci_update_random_address(req, false, &own_addr_type) < 0)
+               return;
+
+       cp.min_interval = __constant_cpu_to_le16(0x0800);
+       cp.max_interval = __constant_cpu_to_le16(0x0800);
+       cp.type = get_adv_type(hdev);
+       cp.own_address_type = own_addr_type;
+       cp.channel_map = hdev->le_adv_channel_map;
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+}
+
+static void disable_advertising(struct hci_request *req)
+{
+       u8 enable = 0x00;
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+}
+
 static void service_cache_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
@@ -832,12 +886,39 @@ static void service_cache_off(struct work_struct *work)
        hci_req_run(&req, NULL);
 }
 
+static void rpa_expired(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                           rpa_expired.work);
+       struct hci_request req;
+
+       BT_DBG("");
+
+       set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+
+       if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
+           hci_conn_num(hdev, LE_LINK) > 0)
+               return;
+
+       /* The generation of a new RPA and programming it into the
+        * controller happens in the enable_advertising() function.
+        */
+
+       hci_req_init(&req, hdev);
+
+       disable_advertising(&req);
+       enable_advertising(&req);
+
+       hci_req_run(&req, NULL);
+}
+
 static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
 {
        if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
                return;
 
        INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
+       INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
 
        /* Non-mgmt controlled devices get this bit set
         * implicitly so that pairing works for them, however
@@ -1344,50 +1425,6 @@ static void write_fast_connectable(struct hci_request *req, bool enable)
                hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
 }
 
-static u8 get_adv_type(struct hci_dev *hdev)
-{
-       struct pending_cmd *cmd;
-       bool connectable;
-
-       /* If there's a pending mgmt command the flag will not yet have
-        * it's final value, so check for this first.
-        */
-       cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
-       if (cmd) {
-               struct mgmt_mode *cp = cmd->param;
-               connectable = !!cp->val;
-       } else {
-               connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-       }
-
-       return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
-}
-
-static void enable_advertising(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       struct hci_cp_le_set_adv_param cp;
-       u8 enable = 0x01;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.min_interval = __constant_cpu_to_le16(0x0800);
-       cp.max_interval = __constant_cpu_to_le16(0x0800);
-       cp.type = get_adv_type(hdev);
-       cp.own_address_type = hdev->own_addr_type;
-       cp.channel_map = 0x07;
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
-}
-
-static void disable_advertising(struct hci_request *req)
-{
-       u8 enable = 0x00;
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
-}
-
 static void set_connectable_complete(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
@@ -3258,7 +3295,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
        struct hci_request req;
        /* General inquiry access code (GIAC) */
        u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       u8 status;
+       u8 status, own_addr_type;
        int err;
 
        BT_DBG("%s", hdev->name);
@@ -3351,10 +3388,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
                }
 
                memset(&param_cp, 0, sizeof(param_cp));
+
+               /* All active scans will be done with either a resolvable
+                * private address (when privacy feature has been enabled)
+                * or unresolvable private address.
+                */
+               err = hci_update_random_address(&req, true, &own_addr_type);
+               if (err < 0) {
+                       err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+                                        MGMT_STATUS_FAILED);
+                       mgmt_pending_remove(cmd);
+                       goto failed;
+               }
+
                param_cp.type = LE_SCAN_ACTIVE;
                param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
                param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
-               param_cp.own_address_type = hdev->own_addr_type;
+               param_cp.own_address_type = own_addr_type;
                hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
                            &param_cp);
 
@@ -4182,6 +4232,51 @@ unlock:
        return err;
 }
 
+static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
+                      u16 len)
+{
+       struct mgmt_cp_set_privacy *cp = cp_data;
+       bool changed;
+       int err;
+
+       BT_DBG("request for %s", hdev->name);
+
+       if (!lmp_le_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       if (cp->privacy != 0x00 && cp->privacy != 0x01)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
+                                 MGMT_STATUS_INVALID_PARAMS);
+
+       if (hdev_is_powered(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
+                                 MGMT_STATUS_REJECTED);
+
+       hci_dev_lock(hdev);
+
+       if (cp->privacy) {
+               changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
+               memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
+               set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+       } else {
+               changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
+               memset(hdev->irk, 0, sizeof(hdev->irk));
+               clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+       }
+
+       err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (changed)
+               err = new_settings(hdev, sk);
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
 static bool irk_is_valid(struct mgmt_irk_info *irk)
 {
        switch (irk->addr.type) {
@@ -4396,7 +4491,7 @@ static const struct mgmt_handler {
        { set_scan_params,        false, MGMT_SET_SCAN_PARAMS_SIZE },
        { set_secure_conn,        false, MGMT_SETTING_SIZE },
        { set_debug_keys,         false, MGMT_SETTING_SIZE },
-       { },
+       { set_privacy,            false, MGMT_SET_PRIVACY_SIZE },
        { load_irks,              true,  MGMT_LOAD_IRKS_SIZE },
 };
 
@@ -4563,11 +4658,6 @@ static int powered_update_hci(struct hci_dev *hdev)
        }
 
        if (lmp_le_capable(hdev)) {
-               /* Set random address to static address if configured */
-               if (bacmp(&hdev->static_addr, BDADDR_ANY))
-                       hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
-                                   &hdev->static_addr);
-
                /* Make sure the controller has a good default for
                 * advertising data. This also applies to the case
                 * where BR/EDR was toggled during the AUTO_OFF phase.
@@ -4771,6 +4861,17 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
 
        memset(&ev, 0, sizeof(ev));
 
+       /* Devices using resolvable or non-resolvable random addresses
+        * without providing an indentity resolving key don't require
+        * to store long term keys. Their addresses will change the
+        * next time around.
+        *
+        * Only when a remote device provides an identity address
+        * make sure the long term key is stored. If the remote
+        * identity is known, the long term keys are internally
+        * mapped to the identity address. So allow static random
+        * and public addresses here.
+        */
        if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
            (key->bdaddr.b[5] & 0xc0) != 0xc0)
                ev.store_hint = 0x00;