summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Grandel <fgrandel@gmail.com>2015-06-18 03:16:48 +0200
committerMarcel Holtmann <marcel@holtmann.org>2015-06-18 18:11:52 +0200
commit01948331af001cd893c8733a4288e9ad246f62f3 (patch)
tree33ee0686cd75b9aa5b74da40cb810636b3714f30
parentfffd38bca51c9a1c00508b754ab66edb6f39cf37 (diff)
downloadlinux-stable-01948331af001cd893c8733a4288e9ad246f62f3.tar.gz
linux-stable-01948331af001cd893c8733a4288e9ad246f62f3.tar.bz2
linux-stable-01948331af001cd893c8733a4288e9ad246f62f3.zip
Bluetooth: mgmt: multi adv for remove_advertising*()
The remove_advertising() and remove_advertising_complete() functions had instance identifiers hard coded. Notably, when passing in 0x00 as an instance identifier to signal that all instances should be removed then the mgmt API would return a hard coded 0x01 rather than returning the expected value 0x00. This bug is being fixed by always referencing the instance identifier from the management API call instead. remove_advertising() is refactored to use the new dynamic advertising instance list. The logic is being changed to make multi-instance advertising actually work, notably the schedule_adv_instance() method is being referenced to make sure that other instances will continue to advertise even if one instance is being removed. The code is made more readable by factoring advertising instance management and initialization into the low-level hci_remove_adv_instance() and hci_adv_instances_clear() functions. The method now references the clear_adv_instance() helper method to remove duplicate logic and code. Signed-off-by: Florian Grandel <fgrandel@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--net/bluetooth/mgmt.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0cc685495510..c8ed16d8d999 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7248,6 +7248,7 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct mgmt_pending_cmd *cmd;
+ struct mgmt_cp_remove_advertising *cp;
struct mgmt_rp_remove_advertising rp;
BT_DBG("status %d", status);
@@ -7262,7 +7263,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
if (!cmd)
goto unlock;
- rp.instance = 1;
+ cp = cmd->param;
+ rp.instance = cp->instance;
mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
&rp, sizeof(rp));
@@ -7277,21 +7279,25 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_cp_remove_advertising *cp = data;
struct mgmt_rp_remove_advertising rp;
+ struct adv_info *adv_instance;
int err;
struct mgmt_pending_cmd *cmd;
struct hci_request req;
BT_DBG("%s", hdev->name);
- /* The current implementation only allows modifying instance no 1. A
- * value of 0 indicates that all instances should be cleared.
- */
- if (cp->instance > 1)
- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
- MGMT_STATUS_INVALID_PARAMS);
-
hci_dev_lock(hdev);
+ if (cp->instance)
+ adv_instance = hci_find_adv_instance(hdev, cp->instance);
+
+ if (!(cp->instance == 0x00 || adv_instance)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_REMOVE_ADVERTISING,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
+
if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7306,21 +7312,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- if (hdev->adv_instance_timeout)
- cancel_delayed_work(&hdev->adv_instance_expire);
-
- memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
+ hci_req_init(&req, hdev);
- advertising_removed(sk, hdev, 1);
+ clear_adv_instance(hdev, &req, cp->instance, true);
- hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+ if (list_empty(&hdev->adv_instances))
+ disable_advertising(&req);
- /* If the HCI_ADVERTISING flag is set or the device isn't powered then
- * we have no HCI communication to make. Simply return.
+ /* If no HCI commands have been collected so far or the HCI_ADVERTISING
+ * flag is set or the device isn't powered then we have no HCI
+ * communication to make. Simply return.
*/
- if (!hdev_is_powered(hdev) ||
+ if (skb_queue_empty(&req.cmd_q) ||
+ !hdev_is_powered(hdev) ||
hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
- rp.instance = 1;
+ rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_REMOVE_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
@@ -7334,9 +7340,6 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- hci_req_init(&req, hdev);
- disable_advertising(&req);
-
err = hci_req_run(&req, remove_advertising_complete);
if (err < 0)
mgmt_pending_remove(cmd);