|
@@ -4164,145 +4164,9 @@ done:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
|
|
|
-{
|
|
|
- struct hci_dev *hdev = req->hdev;
|
|
|
- struct hci_cp_inquiry cp;
|
|
|
- /* General inquiry access code (GIAC) */
|
|
|
- u8 lap[3] = { 0x33, 0x8b, 0x9e };
|
|
|
-
|
|
|
- *status = mgmt_bredr_support(hdev);
|
|
|
- if (*status)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
|
|
|
- *status = MGMT_STATUS_BUSY;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- hci_inquiry_cache_flush(hdev);
|
|
|
-
|
|
|
- memset(&cp, 0, sizeof(cp));
|
|
|
- memcpy(&cp.lap, lap, sizeof(cp.lap));
|
|
|
- cp.length = DISCOV_BREDR_INQUIRY_LEN;
|
|
|
-
|
|
|
- hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
|
|
|
-{
|
|
|
- struct hci_dev *hdev = req->hdev;
|
|
|
- struct hci_cp_le_set_scan_param param_cp;
|
|
|
- struct hci_cp_le_set_scan_enable enable_cp;
|
|
|
- u8 own_addr_type;
|
|
|
- int err;
|
|
|
-
|
|
|
- *status = mgmt_le_support(hdev);
|
|
|
- if (*status)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
|
|
|
- /* Don't let discovery abort an outgoing connection attempt
|
|
|
- * that's using directed advertising.
|
|
|
- */
|
|
|
- if (hci_lookup_le_connect(hdev)) {
|
|
|
- *status = MGMT_STATUS_REJECTED;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- cancel_adv_timeout(hdev);
|
|
|
- disable_advertising(req);
|
|
|
- }
|
|
|
-
|
|
|
- /* If controller is scanning, it means the background scanning is
|
|
|
- * running. Thus, we should temporarily stop it in order to set the
|
|
|
- * discovery scanning parameters.
|
|
|
- */
|
|
|
- if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
|
|
|
- hci_req_add_le_scan_disable(req);
|
|
|
-
|
|
|
- /* All active scans will be done with either a resolvable private
|
|
|
- * address (when privacy feature has been enabled) or non-resolvable
|
|
|
- * private address.
|
|
|
- */
|
|
|
- err = hci_update_random_address(req, true, &own_addr_type);
|
|
|
- if (err < 0) {
|
|
|
- *status = MGMT_STATUS_FAILED;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- memset(¶m_cp, 0, sizeof(param_cp));
|
|
|
- param_cp.type = LE_SCAN_ACTIVE;
|
|
|
- param_cp.interval = cpu_to_le16(interval);
|
|
|
- param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
|
|
|
- param_cp.own_address_type = own_addr_type;
|
|
|
-
|
|
|
- hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
|
|
|
- ¶m_cp);
|
|
|
-
|
|
|
- memset(&enable_cp, 0, sizeof(enable_cp));
|
|
|
- enable_cp.enable = LE_SCAN_ENABLE;
|
|
|
- enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
|
|
|
-
|
|
|
- hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
|
|
|
- &enable_cp);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static bool trigger_discovery(struct hci_request *req, u8 *status)
|
|
|
-{
|
|
|
- struct hci_dev *hdev = req->hdev;
|
|
|
-
|
|
|
- switch (hdev->discovery.type) {
|
|
|
- case DISCOV_TYPE_BREDR:
|
|
|
- if (!trigger_bredr_inquiry(req, status))
|
|
|
- return false;
|
|
|
- break;
|
|
|
-
|
|
|
- case DISCOV_TYPE_INTERLEAVED:
|
|
|
- if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
|
|
|
- &hdev->quirks)) {
|
|
|
- /* During simultaneous discovery, we double LE scan
|
|
|
- * interval. We must leave some time for the controller
|
|
|
- * to do BR/EDR inquiry.
|
|
|
- */
|
|
|
- if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
|
|
|
- status))
|
|
|
- return false;
|
|
|
-
|
|
|
- if (!trigger_bredr_inquiry(req, status))
|
|
|
- return false;
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
|
|
|
- *status = MGMT_STATUS_NOT_SUPPORTED;
|
|
|
- return false;
|
|
|
- }
|
|
|
- /* fall through */
|
|
|
-
|
|
|
- case DISCOV_TYPE_LE:
|
|
|
- if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
|
|
|
- return false;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- *status = MGMT_STATUS_INVALID_PARAMS;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static void start_discovery_complete(struct hci_dev *hdev, u8 status,
|
|
|
- u16 opcode)
|
|
|
+void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
|
|
|
{
|
|
|
struct mgmt_pending_cmd *cmd;
|
|
|
- unsigned long timeout;
|
|
|
|
|
|
BT_DBG("status %d", status);
|
|
|
|
|
@@ -4317,61 +4181,6 @@ static void start_discovery_complete(struct hci_dev *hdev, u8 status,
|
|
|
mgmt_pending_remove(cmd);
|
|
|
}
|
|
|
|
|
|
- if (status) {
|
|
|
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
|
|
- goto unlock;
|
|
|
- }
|
|
|
-
|
|
|
- hci_discovery_set_state(hdev, DISCOVERY_FINDING);
|
|
|
-
|
|
|
- /* If the scan involves LE scan, pick proper timeout to schedule
|
|
|
- * hdev->le_scan_disable that will stop it.
|
|
|
- */
|
|
|
- switch (hdev->discovery.type) {
|
|
|
- case DISCOV_TYPE_LE:
|
|
|
- timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
|
|
|
- break;
|
|
|
- case DISCOV_TYPE_INTERLEAVED:
|
|
|
- /* When running simultaneous discovery, the LE scanning time
|
|
|
- * should occupy the whole discovery time sine BR/EDR inquiry
|
|
|
- * and LE scanning are scheduled by the controller.
|
|
|
- *
|
|
|
- * For interleaving discovery in comparison, BR/EDR inquiry
|
|
|
- * and LE scanning are done sequentially with separate
|
|
|
- * timeouts.
|
|
|
- */
|
|
|
- if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
|
|
|
- timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
|
|
|
- else
|
|
|
- timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
|
|
|
- break;
|
|
|
- case DISCOV_TYPE_BREDR:
|
|
|
- timeout = 0;
|
|
|
- break;
|
|
|
- default:
|
|
|
- BT_ERR("Invalid discovery type %d", hdev->discovery.type);
|
|
|
- timeout = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (timeout) {
|
|
|
- /* When service discovery is used and the controller has
|
|
|
- * a strict duplicate filter, it is important to remember
|
|
|
- * the start and duration of the scan. This is required
|
|
|
- * for restarting scanning during the discovery phase.
|
|
|
- */
|
|
|
- if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
|
|
|
- &hdev->quirks) &&
|
|
|
- hdev->discovery.result_filtering) {
|
|
|
- hdev->discovery.scan_start = jiffies;
|
|
|
- hdev->discovery.scan_duration = timeout;
|
|
|
- }
|
|
|
-
|
|
|
- queue_delayed_work(hdev->req_workqueue,
|
|
|
- &hdev->le_scan_disable, timeout);
|
|
|
- }
|
|
|
-
|
|
|
-unlock:
|
|
|
hci_dev_unlock(hdev);
|
|
|
}
|
|
|
|
|
@@ -4407,7 +4216,6 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
|
|
{
|
|
|
struct mgmt_cp_start_discovery *cp = data;
|
|
|
struct mgmt_pending_cmd *cmd;
|
|
|
- struct hci_request req;
|
|
|
u8 status;
|
|
|
int err;
|
|
|
|
|
@@ -4436,14 +4244,6 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
|
|
goto failed;
|
|
|
}
|
|
|
|
|
|
- cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
|
|
|
- if (!cmd) {
|
|
|
- err = -ENOMEM;
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- cmd->cmd_complete = generic_cmd_complete;
|
|
|
-
|
|
|
/* Clear the discovery filter first to free any previously
|
|
|
* allocated memory for the UUID list.
|
|
|
*/
|
|
@@ -4452,22 +4252,17 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
|
|
|
hdev->discovery.type = cp->type;
|
|
|
hdev->discovery.report_invalid_rssi = false;
|
|
|
|
|
|
- hci_req_init(&req, hdev);
|
|
|
-
|
|
|
- if (!trigger_discovery(&req, &status)) {
|
|
|
- err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
|
|
|
- status, &cp->type, sizeof(cp->type));
|
|
|
- mgmt_pending_remove(cmd);
|
|
|
+ cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
|
|
|
+ if (!cmd) {
|
|
|
+ err = -ENOMEM;
|
|
|
goto failed;
|
|
|
}
|
|
|
|
|
|
- err = hci_req_run(&req, start_discovery_complete);
|
|
|
- if (err < 0) {
|
|
|
- mgmt_pending_remove(cmd);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
+ cmd->cmd_complete = generic_cmd_complete;
|
|
|
|
|
|
hci_discovery_set_state(hdev, DISCOVERY_STARTING);
|
|
|
+ queue_work(hdev->req_workqueue, &hdev->discov_update);
|
|
|
+ err = 0;
|
|
|
|
|
|
failed:
|
|
|
hci_dev_unlock(hdev);
|
|
@@ -4486,7 +4281,6 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
|
|
|
{
|
|
|
struct mgmt_cp_start_service_discovery *cp = data;
|
|
|
struct mgmt_pending_cmd *cmd;
|
|
|
- struct hci_request req;
|
|
|
const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
|
|
|
u16 uuid_count, expected_len;
|
|
|
u8 status;
|
|
@@ -4574,23 +4368,9 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- hci_req_init(&req, hdev);
|
|
|
-
|
|
|
- if (!trigger_discovery(&req, &status)) {
|
|
|
- err = mgmt_cmd_complete(sk, hdev->id,
|
|
|
- MGMT_OP_START_SERVICE_DISCOVERY,
|
|
|
- status, &cp->type, sizeof(cp->type));
|
|
|
- mgmt_pending_remove(cmd);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
- err = hci_req_run(&req, start_discovery_complete);
|
|
|
- if (err < 0) {
|
|
|
- mgmt_pending_remove(cmd);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
-
|
|
|
hci_discovery_set_state(hdev, DISCOVERY_STARTING);
|
|
|
+ queue_work(hdev->req_workqueue, &hdev->discov_update);
|
|
|
+ err = 0;
|
|
|
|
|
|
failed:
|
|
|
hci_dev_unlock(hdev);
|