Bluetooth: Move Start Discovery to req_workqueue

Since discovery also deals with LE scanning it makes sense to move it
behind the same req_workqueue as other LE scanning changes. This also
simplifies the logic since we do many of the actions in a synchronous
manner.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Johan Hedberg
2015-11-11 08:30:30 +02:00
committed by Marcel Holtmann
parent a1d01db120
commit e68f072b73
3 changed files with 213 additions and 229 deletions

View File

@@ -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(&param_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),
&param_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);