]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/bluetooth/mgmt.c
Bluetooth: Pass initiator/acceptor information to hci_conn_security()
[mirror_ubuntu-bionic-kernel.git] / net / bluetooth / mgmt.c
index d66463a52280407c1e56594650e0a4c028d3edda..190668367e422b7ace0e04946ae59c35d34ba6c6 100644 (file)
@@ -92,6 +92,7 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_READ_UNCONF_INDEX_LIST,
        MGMT_OP_READ_CONFIG_INFO,
        MGMT_OP_SET_EXTERNAL_CONFIG,
+       MGMT_OP_SET_PUBLIC_ADDRESS,
 };
 
 static const u16 mgmt_events[] = {
@@ -554,12 +555,12 @@ static u32 get_supported_settings(struct hci_dev *hdev)
        settings |= MGMT_SETTING_POWERED;
        settings |= MGMT_SETTING_PAIRABLE;
        settings |= MGMT_SETTING_DEBUG_KEYS;
+       settings |= MGMT_SETTING_CONNECTABLE;
+       settings |= MGMT_SETTING_DISCOVERABLE;
 
        if (lmp_bredr_capable(hdev)) {
-               settings |= MGMT_SETTING_CONNECTABLE;
                if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
                        settings |= MGMT_SETTING_FAST_CONNECTABLE;
-               settings |= MGMT_SETTING_DISCOVERABLE;
                settings |= MGMT_SETTING_BREDR;
                settings |= MGMT_SETTING_LINK_SECURITY;
 
@@ -905,6 +906,16 @@ static void update_adv_data(struct hci_request *req)
        hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
 }
 
+int mgmt_update_adv_data(struct hci_dev *hdev)
+{
+       struct hci_request req;
+
+       hci_req_init(&req, hdev);
+       update_adv_data(&req);
+
+       return hci_req_run(&req, NULL);
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
        u8 *ptr = data;
@@ -1038,6 +1049,13 @@ static bool get_connectable(struct hci_dev *hdev)
        return test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
 }
 
+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 enable_advertising(struct hci_request *req)
 {
        struct hci_dev *hdev = req->hdev;
@@ -1045,12 +1063,18 @@ static void enable_advertising(struct hci_request *req)
        u8 own_addr_type, enable = 0x01;
        bool connectable;
 
-       /* Clear the HCI_ADVERTISING bit temporarily so that the
+       if (hci_conn_num(hdev, LE_LINK) > 0)
+               return;
+
+       if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
+               disable_advertising(req);
+
+       /* Clear the HCI_LE_ADV bit temporarily so that the
         * hci_update_random_address knows that it's safe to go ahead
         * and write a new random address. The flag will be set back on
         * as soon as the SET_ADV_ENABLE HCI command completes.
         */
-       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+       clear_bit(HCI_LE_ADV, &hdev->dev_flags);
 
        connectable = get_connectable(hdev);
 
@@ -1073,13 +1097,6 @@ static void enable_advertising(struct hci_request *req)
        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,
@@ -1111,19 +1128,14 @@ static void rpa_expired(struct work_struct *work)
 
        set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
 
-       if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
-           hci_conn_num(hdev, LE_LINK) > 0)
+       if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                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);
 }
 
@@ -1249,7 +1261,7 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
        }
 }
 
-static void hci_stop_discovery(struct hci_request *req)
+static bool hci_stop_discovery(struct hci_request *req)
 {
        struct hci_dev *hdev = req->hdev;
        struct hci_cp_remote_name_req_cancel cp;
@@ -1264,32 +1276,39 @@ static void hci_stop_discovery(struct hci_request *req)
                        hci_req_add_le_scan_disable(req);
                }
 
-               break;
+               return true;
 
        case DISCOVERY_RESOLVING:
                e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
                                                     NAME_PENDING);
                if (!e)
-                       return;
+                       break;
 
                bacpy(&cp.bdaddr, &e->data.bdaddr);
                hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
                            &cp);
 
-               break;
+               return true;
 
        default:
                /* Passive scanning */
-               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
                        hci_req_add_le_scan_disable(req);
+                       return true;
+               }
+
                break;
        }
+
+       return false;
 }
 
 static int clean_up_hci_state(struct hci_dev *hdev)
 {
        struct hci_request req;
        struct hci_conn *conn;
+       bool discov_stopped;
+       int err;
 
        hci_req_init(&req, hdev);
 
@@ -1299,10 +1318,10 @@ static int clean_up_hci_state(struct hci_dev *hdev)
                hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        }
 
-       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+       if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
                disable_advertising(&req);
 
-       hci_stop_discovery(&req);
+       discov_stopped = hci_stop_discovery(&req);
 
        list_for_each_entry(conn, &hdev->conn_hash.list, list) {
                struct hci_cp_disconnect dc;
@@ -1336,7 +1355,11 @@ static int clean_up_hci_state(struct hci_dev *hdev)
                }
        }
 
-       return hci_req_run(&req, clean_up_hci_complete);
+       err = hci_req_run(&req, clean_up_hci_complete);
+       if (!err && discov_stopped)
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+
+       return err;
 }
 
 static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -1414,6 +1437,11 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip)
        return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
 }
 
+int mgmt_new_settings(struct hci_dev *hdev)
+{
+       return new_settings(hdev, NULL);
+}
+
 struct cmd_lookup {
        struct sock *sk;
        struct hci_dev *hdev;
@@ -1725,7 +1753,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_mode *cp;
-       bool changed;
+       bool conn_changed, discov_changed;
 
        BT_DBG("status 0x%02x", status);
 
@@ -1742,15 +1770,25 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
        }
 
        cp = cmd->param;
-       if (cp->val)
-               changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-       else
-               changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+       if (cp->val) {
+               conn_changed = !test_and_set_bit(HCI_CONNECTABLE,
+                                                &hdev->dev_flags);
+               discov_changed = false;
+       } else {
+               conn_changed = test_and_clear_bit(HCI_CONNECTABLE,
+                                                 &hdev->dev_flags);
+               discov_changed = test_and_clear_bit(HCI_DISCOVERABLE,
+                                                   &hdev->dev_flags);
+       }
 
        send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
 
-       if (changed)
+       if (conn_changed || discov_changed) {
                new_settings(hdev, cmd->sk);
+               if (discov_changed)
+                       mgmt_update_adv_data(hdev);
+               hci_update_background_scan(hdev);
+       }
 
 remove_cmd:
        mgmt_pending_remove(cmd);
@@ -1779,8 +1817,10 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
        if (err < 0)
                return err;
 
-       if (changed)
+       if (changed) {
+               hci_update_background_scan(hdev);
                return new_settings(hdev, sk);
+       }
 
        return 0;
 }
@@ -1860,11 +1900,9 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
        if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
                write_fast_connectable(&req, false);
 
-       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
-           hci_conn_num(hdev, LE_LINK) == 0) {
-               disable_advertising(&req);
+       /* Update the advertising parameters if necessary */
+       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                enable_advertising(&req);
-       }
 
        err = hci_req_run(&req, set_connectable_complete);
        if (err < 0) {
@@ -2149,6 +2187,8 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status)
                update_scan_rsp_data(&req);
                hci_req_run(&req, NULL);
 
+               hci_update_background_scan(hdev);
+
                hci_dev_unlock(hdev);
        }
 }
@@ -2226,7 +2266,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
                hci_cp.le = val;
                hci_cp.simul = lmp_le_br_capable(hdev);
        } else {
-               if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+               if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
                        disable_advertising(&req);
        }
 
@@ -3115,7 +3155,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
 
                conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
-                                     sec_level, auth_type);
+                                     sec_level, HCI_LE_CONN_TIMEOUT,
+                                     HCI_ROLE_MASTER);
        }
 
        if (IS_ERR(conn)) {
@@ -3161,7 +3202,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        cmd->user_data = conn;
 
        if (conn->state == BT_CONNECTED &&
-           hci_conn_security(conn, sec_level, auth_type))
+           hci_conn_security(conn, sec_level, auth_type, true))
                pairing_complete(cmd, 0);
 
        err = 0;
@@ -3721,11 +3762,21 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
                        goto failed;
                }
 
-               if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
-                       err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
-                                        MGMT_STATUS_REJECTED);
-                       mgmt_pending_remove(cmd);
-                       goto failed;
+               if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) {
+                       /* Don't let discovery abort an outgoing
+                        * connection attempt that's using directed
+                        * advertising.
+                        */
+                       if (hci_conn_hash_lookup_state(hdev, LE_LINK,
+                                                      BT_CONNECT)) {
+                               err = cmd_status(sk, hdev->id,
+                                                MGMT_OP_START_DISCOVERY,
+                                                MGMT_STATUS_REJECTED);
+                               mgmt_pending_remove(cmd);
+                               goto failed;
+                       }
+
+                       disable_advertising(&req);
                }
 
                /* If controller is scanning, it means the background scanning
@@ -3928,7 +3979,8 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
 
        hci_dev_lock(hdev);
 
-       err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
+       err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
+                                 cp->addr.type);
        if (err < 0) {
                status = MGMT_STATUS_FAILED;
                goto done;
@@ -3963,7 +4015,8 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
 
        hci_dev_lock(hdev);
 
-       err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
+       err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
+                                 cp->addr.type);
        if (err < 0) {
                status = MGMT_STATUS_INVALID_PARAMS;
                goto done;
@@ -4028,6 +4081,11 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status)
                return;
        }
 
+       if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
+               set_bit(HCI_ADVERTISING, &hdev->dev_flags);
+       else
+               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+
        mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
                             &match);
 
@@ -4068,7 +4126,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
         * necessary).
         */
        if (!hdev_is_powered(hdev) || val == enabled ||
-           hci_conn_num(hdev, LE_LINK) > 0) {
+           hci_conn_num(hdev, LE_LINK) > 0 ||
+           (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
+            hdev->le_scan_type == LE_SCAN_ACTIVE)) {
                bool changed = false;
 
                if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
@@ -4320,7 +4380,8 @@ static void set_bredr_scan(struct hci_request *req)
         */
        write_fast_connectable(req, false);
 
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
+           !list_empty(&hdev->whitelist))
                scan |= SCAN_PAGE;
        if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
                scan |= SCAN_INQUIRY;
@@ -4434,7 +4495,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        hci_req_init(&req, hdev);
 
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
+           !list_empty(&hdev->whitelist))
                set_bredr_scan(&req);
 
        /* Since only the advertising data flags will change, there
@@ -5161,6 +5223,27 @@ unlock:
        return err;
 }
 
+/* Helper for Add/Remove Device commands */
+static void update_page_scan(struct hci_dev *hdev, u8 scan)
+{
+       if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
+               return;
+
+       if (!hdev_is_powered(hdev))
+               return;
+
+       /* If HCI_CONNECTABLE is set then Add/Remove Device should not
+        * make any changes to page scanning.
+        */
+       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+               return;
+
+       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+               scan |= SCAN_INQUIRY;
+
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+}
+
 static void device_added(struct sock *sk, struct hci_dev *hdev,
                         bdaddr_t *bdaddr, u8 type, u8 action)
 {
@@ -5182,7 +5265,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
 
        BT_DBG("%s", hdev->name);
 
-       if (!bdaddr_type_is_le(cp->addr.type) ||
+       if (!bdaddr_type_is_valid(cp->addr.type) ||
            !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
                return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
                                    MGMT_STATUS_INVALID_PARAMS,
@@ -5195,6 +5278,30 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
+       if (cp->addr.type == BDADDR_BREDR) {
+               bool update_scan;
+
+               /* Only "connect" action supported for now */
+               if (cp->action != 0x01) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                                          MGMT_STATUS_INVALID_PARAMS,
+                                          &cp->addr, sizeof(cp->addr));
+                       goto unlock;
+               }
+
+               update_scan = list_empty(&hdev->whitelist);
+
+               err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
+                                         cp->addr.type);
+               if (err)
+                       goto unlock;
+
+               if (update_scan)
+                       update_page_scan(hdev, SCAN_PAGE);
+
+               goto added;
+       }
+
        if (cp->addr.type == BDADDR_LE_PUBLIC)
                addr_type = ADDR_LE_DEV_PUBLIC;
        else
@@ -5216,6 +5323,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
+added:
        device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
 
        err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
@@ -5251,13 +5359,33 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                struct hci_conn_params *params;
                u8 addr_type;
 
-               if (!bdaddr_type_is_le(cp->addr.type)) {
+               if (!bdaddr_type_is_valid(cp->addr.type)) {
                        err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
                                           MGMT_STATUS_INVALID_PARAMS,
                                           &cp->addr, sizeof(cp->addr));
                        goto unlock;
                }
 
+               if (cp->addr.type == BDADDR_BREDR) {
+                       err = hci_bdaddr_list_del(&hdev->whitelist,
+                                                 &cp->addr.bdaddr,
+                                                 cp->addr.type);
+                       if (err) {
+                               err = cmd_complete(sk, hdev->id,
+                                                  MGMT_OP_REMOVE_DEVICE,
+                                                  MGMT_STATUS_INVALID_PARAMS,
+                                                  &cp->addr, sizeof(cp->addr));
+                               goto unlock;
+                       }
+
+                       if (list_empty(&hdev->whitelist))
+                               update_page_scan(hdev, SCAN_DISABLED);
+
+                       device_removed(sk, hdev, &cp->addr.bdaddr,
+                                      cp->addr.type);
+                       goto complete;
+               }
+
                if (cp->addr.type == BDADDR_LE_PUBLIC)
                        addr_type = ADDR_LE_DEV_PUBLIC;
                else
@@ -5287,6 +5415,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
        } else {
                struct hci_conn_params *p, *tmp;
+               struct bdaddr_list *b, *btmp;
 
                if (cp->addr.type) {
                        err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
@@ -5295,6 +5424,14 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                        goto unlock;
                }
 
+               list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
+                       device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
+                       list_del(&b->list);
+                       kfree(b);
+               }
+
+               update_page_scan(hdev, SCAN_DISABLED);
+
                list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
                        if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
                                continue;
@@ -5309,6 +5446,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                hci_update_background_scan(hdev);
        }
 
+complete:
        err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
                           MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr));
 
@@ -5450,6 +5588,7 @@ static int set_external_config(struct sock *sk, struct hci_dev *hdev,
 
                        queue_work(hdev->req_workqueue, &hdev->power_on);
                } else {
+                       set_bit(HCI_RAW, &hdev->flags);
                        mgmt_index_added(hdev);
                }
        }
@@ -5459,6 +5598,58 @@ unlock:
        return err;
 }
 
+static int set_public_address(struct sock *sk, struct hci_dev *hdev,
+                             void *data, u16 len)
+{
+       struct mgmt_cp_set_public_address *cp = data;
+       bool changed;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (hdev_is_powered(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
+                                 MGMT_STATUS_REJECTED);
+
+       if (!bacmp(&cp->bdaddr, BDADDR_ANY))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+
+       if (!hdev->set_bdaddr)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       hci_dev_lock(hdev);
+
+       changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
+       bacpy(&hdev->public_addr, &cp->bdaddr);
+
+       err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (!changed)
+               goto unlock;
+
+       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags))
+               err = new_options(hdev, sk);
+
+       if (is_configured(hdev)) {
+               mgmt_index_removed(hdev);
+
+               clear_bit(HCI_UNCONFIGURED, &hdev->dev_flags);
+
+               set_bit(HCI_CONFIG, &hdev->dev_flags);
+               set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+
+               queue_work(hdev->req_workqueue, &hdev->power_on);
+       }
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
 static const struct mgmt_handler {
        int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
                     u16 data_len);
@@ -5522,6 +5713,7 @@ static const struct mgmt_handler {
        { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE },
        { read_config_info,       false, MGMT_READ_CONFIG_INFO_SIZE },
        { set_external_config,    false, MGMT_SET_EXTERNAL_CONFIG_SIZE },
+       { set_public_address,     false, MGMT_SET_PUBLIC_ADDRESS_SIZE },
 };
 
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
@@ -5576,7 +5768,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 
                if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) &&
                    opcode != MGMT_OP_READ_CONFIG_INFO &&
-                   opcode != MGMT_OP_SET_EXTERNAL_CONFIG) {
+                   opcode != MGMT_OP_SET_EXTERNAL_CONFIG &&
+                   opcode != MGMT_OP_SET_PUBLIC_ADDRESS) {
                        err = cmd_status(sk, index, opcode,
                                         MGMT_STATUS_INVALID_INDEX);
                        goto done;
@@ -5856,92 +6049,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev)
        hci_dev_unlock(hdev);
 }
 
-void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
-{
-       bool changed;
-
-       /* Nothing needed here if there's a pending command since that
-        * commands request completion callback takes care of everything
-        * necessary.
-        */
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
-               return;
-
-       /* Powering off may clear the scan mode - don't let that interfere */
-       if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
-               return;
-
-       if (discoverable) {
-               changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
-       } else {
-               clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
-               changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
-       }
-
-       if (changed) {
-               struct hci_request req;
-
-               /* In case this change in discoverable was triggered by
-                * a disabling of connectable there could be a need to
-                * update the advertising flags.
-                */
-               hci_req_init(&req, hdev);
-               update_adv_data(&req);
-               hci_req_run(&req, NULL);
-
-               new_settings(hdev, NULL);
-       }
-}
-
-void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
-{
-       bool changed;
-
-       /* Nothing needed here if there's a pending command since that
-        * commands request completion callback takes care of everything
-        * necessary.
-        */
-       if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
-               return;
-
-       /* Powering off may clear the scan mode - don't let that interfere */
-       if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
-               return;
-
-       if (connectable)
-               changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-       else
-               changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-
-       if (changed)
-               new_settings(hdev, NULL);
-}
-
-void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
-{
-       /* Powering off may stop advertising - don't let that interfere */
-       if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
-               return;
-
-       if (advertising)
-               set_bit(HCI_ADVERTISING, &hdev->dev_flags);
-       else
-               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-}
-
-void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
-{
-       u8 mgmt_err = mgmt_status(status);
-
-       if (scan & SCAN_PAGE)
-               mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
-                                    cmd_status_rsp, &mgmt_err);
-
-       if (scan & SCAN_INQUIRY)
-               mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
-                                    cmd_status_rsp, &mgmt_err);
-}
-
 void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
                       bool persistent)
 {
@@ -6660,7 +6767,6 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 {
        char buf[512];
        struct mgmt_ev_device_found *ev = (void *) buf;
-       struct smp_irk *irk;
        size_t ev_size;
 
        /* Don't send events for a non-kernel initiated discovery. With
@@ -6682,15 +6788,8 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 
        memset(buf, 0, sizeof(buf));
 
-       irk = hci_get_irk(hdev, bdaddr, addr_type);
-       if (irk) {
-               bacpy(&ev->addr.bdaddr, &irk->bdaddr);
-               ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
-       } else {
-               bacpy(&ev->addr.bdaddr, bdaddr);
-               ev->addr.type = link_to_bdaddr(link_type, addr_type);
-       }
-
+       bacpy(&ev->addr.bdaddr, bdaddr);
+       ev->addr.type = link_to_bdaddr(link_type, addr_type);
        ev->rssi = rssi;
        ev->flags = cpu_to_le32(flags);
 
@@ -6763,32 +6862,16 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
 static void adv_enable_complete(struct hci_dev *hdev, u8 status)
 {
        BT_DBG("%s status %u", hdev->name, status);
-
-       /* Clear the advertising mgmt setting if we failed to re-enable it */
-       if (status) {
-               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-               new_settings(hdev, NULL);
-       }
 }
 
 void mgmt_reenable_advertising(struct hci_dev *hdev)
 {
        struct hci_request req;
 
-       if (hci_conn_num(hdev, LE_LINK) > 0)
-               return;
-
        if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                return;
 
        hci_req_init(&req, hdev);
        enable_advertising(&req);
-
-       /* If this fails we have no option but to let user space know
-        * that we've disabled advertising.
-        */
-       if (hci_req_run(&req, adv_enable_complete) < 0) {
-               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-               new_settings(hdev, NULL);
-       }
+       hci_req_run(&req, adv_enable_complete);
 }