aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorFlorian Grandel <fgrandel@gmail.com>2015-06-17 21:16:48 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-06-18 12:11:52 -0400
commit01948331af001cd893c8733a4288e9ad246f62f3 (patch)
tree33ee0686cd75b9aa5b74da40cb810636b3714f30 /net/bluetooth/mgmt.c
parentfffd38bca51c9a1c00508b754ab66edb6f39cf37 (diff)
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>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-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,
7248 u16 opcode) 7248 u16 opcode)
7249{ 7249{
7250 struct mgmt_pending_cmd *cmd; 7250 struct mgmt_pending_cmd *cmd;
7251 struct mgmt_cp_remove_advertising *cp;
7251 struct mgmt_rp_remove_advertising rp; 7252 struct mgmt_rp_remove_advertising rp;
7252 7253
7253 BT_DBG("status %d", status); 7254 BT_DBG("status %d", status);
@@ -7262,7 +7263,8 @@ static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
7262 if (!cmd) 7263 if (!cmd)
7263 goto unlock; 7264 goto unlock;
7264 7265
7265 rp.instance = 1; 7266 cp = cmd->param;
7267 rp.instance = cp->instance;
7266 7268
7267 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS, 7269 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
7268 &rp, sizeof(rp)); 7270 &rp, sizeof(rp));
@@ -7277,21 +7279,25 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7277{ 7279{
7278 struct mgmt_cp_remove_advertising *cp = data; 7280 struct mgmt_cp_remove_advertising *cp = data;
7279 struct mgmt_rp_remove_advertising rp; 7281 struct mgmt_rp_remove_advertising rp;
7282 struct adv_info *adv_instance;
7280 int err; 7283 int err;
7281 struct mgmt_pending_cmd *cmd; 7284 struct mgmt_pending_cmd *cmd;
7282 struct hci_request req; 7285 struct hci_request req;
7283 7286
7284 BT_DBG("%s", hdev->name); 7287 BT_DBG("%s", hdev->name);
7285 7288
7286 /* The current implementation only allows modifying instance no 1. A
7287 * value of 0 indicates that all instances should be cleared.
7288 */
7289 if (cp->instance > 1)
7290 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
7291 MGMT_STATUS_INVALID_PARAMS);
7292
7293 hci_dev_lock(hdev); 7289 hci_dev_lock(hdev);
7294 7290
7291 if (cp->instance)
7292 adv_instance = hci_find_adv_instance(hdev, cp->instance);
7293
7294 if (!(cp->instance == 0x00 || adv_instance)) {
7295 err = mgmt_cmd_status(sk, hdev->id,
7296 MGMT_OP_REMOVE_ADVERTISING,
7297 MGMT_STATUS_INVALID_PARAMS);
7298 goto unlock;
7299 }
7300
7295 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || 7301 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
7296 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || 7302 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
7297 pending_find(MGMT_OP_SET_LE, hdev)) { 7303 pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -7306,21 +7312,21 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7306 goto unlock; 7312 goto unlock;
7307 } 7313 }
7308 7314
7309 if (hdev->adv_instance_timeout) 7315 hci_req_init(&req, hdev);
7310 cancel_delayed_work(&hdev->adv_instance_expire);
7311
7312 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
7313 7316
7314 advertising_removed(sk, hdev, 1); 7317 clear_adv_instance(hdev, &req, cp->instance, true);
7315 7318
7316 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); 7319 if (list_empty(&hdev->adv_instances))
7320 disable_advertising(&req);
7317 7321
7318 /* If the HCI_ADVERTISING flag is set or the device isn't powered then 7322 /* If no HCI commands have been collected so far or the HCI_ADVERTISING
7319 * we have no HCI communication to make. Simply return. 7323 * flag is set or the device isn't powered then we have no HCI
7324 * communication to make. Simply return.
7320 */ 7325 */
7321 if (!hdev_is_powered(hdev) || 7326 if (skb_queue_empty(&req.cmd_q) ||
7327 !hdev_is_powered(hdev) ||
7322 hci_dev_test_flag(hdev, HCI_ADVERTISING)) { 7328 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
7323 rp.instance = 1; 7329 rp.instance = cp->instance;
7324 err = mgmt_cmd_complete(sk, hdev->id, 7330 err = mgmt_cmd_complete(sk, hdev->id,
7325 MGMT_OP_REMOVE_ADVERTISING, 7331 MGMT_OP_REMOVE_ADVERTISING,
7326 MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); 7332 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
@@ -7334,9 +7340,6 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
7334 goto unlock; 7340 goto unlock;
7335 } 7341 }
7336 7342
7337 hci_req_init(&req, hdev);
7338 disable_advertising(&req);
7339
7340 err = hci_req_run(&req, remove_advertising_complete); 7343 err = hci_req_run(&req, remove_advertising_complete);
7341 if (err < 0) 7344 if (err < 0)
7342 mgmt_pending_remove(cmd); 7345 mgmt_pending_remove(cmd);