Bluetooth: Split hci_request helpers to hci_request.[ch]
[cascardo/linux.git] / net / bluetooth / mgmt.c
index 827107d..95473e9 100644 (file)
@@ -32,6 +32,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/mgmt.h>
 
+#include "hci_request.h"
 #include "smp.h"
 
 #define MGMT_VERSION   1
@@ -1566,7 +1567,7 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
         * entries.
         */
        hci_req_init(&req, hdev);
-       hci_update_page_scan(hdev, &req);
+       __hci_update_page_scan(&req);
        update_class(&req);
        hci_req_run(&req, NULL);
 
@@ -1813,7 +1814,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
 
        if (conn_changed || discov_changed) {
                new_settings(hdev, cmd->sk);
-               hci_update_page_scan(hdev, NULL);
+               hci_update_page_scan(hdev);
                if (discov_changed)
                        mgmt_update_adv_data(hdev);
                hci_update_background_scan(hdev);
@@ -1847,7 +1848,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
                return err;
 
        if (changed) {
-               hci_update_page_scan(hdev, NULL);
+               hci_update_page_scan(hdev);
                hci_update_background_scan(hdev);
                return new_settings(hdev, sk);
        }
@@ -4697,7 +4698,7 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
        hci_req_init(&req, hdev);
 
        write_fast_connectable(&req, false);
-       hci_update_page_scan(hdev, &req);
+       __hci_update_page_scan(&req);
 
        /* Since only the advertising data flags will change, there
         * is no need to update the scan response data.
@@ -5473,7 +5474,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
                if (err)
                        goto unlock;
 
-               hci_update_page_scan(hdev, NULL);
+               hci_update_page_scan(hdev);
 
                goto added;
        }
@@ -5556,7 +5557,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                                goto unlock;
                        }
 
-                       hci_update_page_scan(hdev, NULL);
+                       hci_update_page_scan(hdev);
 
                        device_removed(sk, hdev, &cp->addr.bdaddr,
                                       cp->addr.type);
@@ -5607,7 +5608,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                        kfree(b);
                }
 
-               hci_update_page_scan(hdev, NULL);
+               hci_update_page_scan(hdev);
 
                list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
                        if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
@@ -5913,7 +5914,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        if (!buf)
                return -ENOMEM;
 
-       if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
+       if (memcpy_from_msg(buf, msg, msglen)) {
                err = -EFAULT;
                goto done;
        }
@@ -6097,6 +6098,11 @@ static int powered_update_hci(struct hci_dev *hdev)
                hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
        }
 
+       if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
+               u8 sc = 0x01;
+               hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, sizeof(sc), &sc);
+       }
+
        if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
            lmp_bredr_capable(hdev)) {
                struct hci_cp_write_le_host_supported cp;
@@ -6134,7 +6140,7 @@ static int powered_update_hci(struct hci_dev *hdev)
 
        if (lmp_bredr_capable(hdev)) {
                write_fast_connectable(&req, false);
-               hci_update_page_scan(hdev, &req);
+               __hci_update_page_scan(&req);
                update_class(&req);
                update_name(&req);
                update_eir(&req);
@@ -6146,8 +6152,7 @@ static int powered_update_hci(struct hci_dev *hdev)
 int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
        struct cmd_lookup match = { NULL, hdev };
-       u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
-       u8 zero_cod[] = { 0, 0, 0 };
+       u8 status, zero_cod[] = { 0, 0, 0 };
        int err;
 
        if (!test_bit(HCI_MGMT, &hdev->dev_flags))
@@ -6163,7 +6168,20 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
        }
 
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
-       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status_not_powered);
+
+       /* If the power off is because of hdev unregistration let
+        * use the appropriate INVALID_INDEX status. Otherwise use
+        * NOT_POWERED. We cover both scenarios here since later in
+        * mgmt_index_removed() any hci_conn callbacks will have already
+        * been triggered, potentially causing misleading DISCONNECTED
+        * status responses.
+        */
+       if (test_bit(HCI_UNREGISTER, &hdev->dev_flags))
+               status = MGMT_STATUS_INVALID_INDEX;
+       else
+               status = MGMT_STATUS_NOT_POWERED;
+
+       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
 
        if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
                mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
@@ -7064,13 +7082,15 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                 * kept and checking possible scan response data
                 * will be skipped.
                 */
-               if (hdev->discovery.uuid_count > 0) {
+               if (hdev->discovery.uuid_count > 0)
                        match = eir_has_uuids(eir, eir_len,
                                              hdev->discovery.uuid_count,
                                              hdev->discovery.uuids);
-                       if (!match)
-                               return;
-               }
+               else
+                       match = true;
+
+               if (!match && !scan_rsp_len)
+                       return;
 
                /* Copy EIR or advertising data into event */
                memcpy(ev->eir, eir, eir_len);
@@ -7079,8 +7099,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                 * provided, results with empty EIR or advertising data
                 * should be dropped since they do not match any UUID.
                 */
-               if (hdev->discovery.uuid_count > 0)
+               if (hdev->discovery.uuid_count > 0 && !scan_rsp_len)
                        return;
+
+               match = false;
        }
 
        if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))