summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorFlorian Grandel <fgrandel@gmail.com>2015-06-17 21:16:46 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-06-18 12:11:52 -0400
commit847818d9c05f8951270600c0d3260871dbc23134 (patch)
tree64b2c6ab733b134910271ca920a94eb23671baf7 /net/bluetooth/mgmt.c
parent7816b82039b56308a0d685e97d4a9f4b52e239bd (diff)
Bluetooth: mgmt: multi adv for clear_adv_instances()
The clear_adv_instance() function could not clean up multiple advertising instances previously. It is being changed to provide both, a means to clean up a single instance and cleaning up all instances at once. An additional instance parameter is being introduced to achieve this. Passing in 0x00 to this parameter signifies that all instances should be cleaned up. This semantics has been chosen similarly to the semantics of the instance parameter in the remove_advertising() function. When removing a single instance the method also ensures that another instance will be scheduled if available. When the currently advertising method is being removed, it will be canceled immediately. 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.c97
1 files changed, 81 insertions, 16 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 55765dd79070..ac5fc357c757 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1538,27 +1538,74 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
1538 } 1538 }
1539} 1539}
1540 1540
1541static void clear_adv_instance(struct hci_dev *hdev) 1541/* For a single instance:
1542 * - force == true: The instance will be removed even when its remaining
1543 * lifetime is not zero.
1544 * - force == false: the instance will be deactivated but kept stored unless
1545 * the remaining lifetime is zero.
1546 *
1547 * For instance == 0x00:
1548 * - force == true: All instances will be removed regardless of their timeout
1549 * setting.
1550 * - force == false: Only instances that have a timeout will be removed.
1551 */
1552static void clear_adv_instance(struct hci_dev *hdev, struct hci_request *req,
1553 u8 instance, bool force)
1542{ 1554{
1543 struct hci_request req; 1555 struct adv_info *adv_instance, *n, *next_instance = NULL;
1556 int err;
1557 u8 rem_inst;
1544 1558
1545 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) 1559 /* Cancel any timeout concerning the removed instance(s). */
1546 return; 1560 if (!instance || hdev->cur_adv_instance == instance)
1561 cancel_adv_timeout(hdev);
1547 1562
1548 if (hdev->adv_instance_timeout) 1563 /* Get the next instance to advertise BEFORE we remove
1549 cancel_delayed_work(&hdev->adv_instance_expire); 1564 * the current one. This can be the same instance again
1565 * if there is only one instance.
1566 */
1567 if (instance && hdev->cur_adv_instance == instance)
1568 next_instance = hci_get_next_instance(hdev, instance);
1550 1569
1551 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); 1570 if (instance == 0x00) {
1552 advertising_removed(NULL, hdev, 1); 1571 list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances,
1553 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); 1572 list) {
1573 if (!(force || adv_instance->timeout))
1574 continue;
1554 1575
1555 if (!hdev_is_powered(hdev) || 1576 rem_inst = adv_instance->instance;
1577 err = hci_remove_adv_instance(hdev, rem_inst);
1578 if (!err)
1579 advertising_removed(NULL, hdev, rem_inst);
1580 }
1581 hdev->cur_adv_instance = 0x00;
1582 } else {
1583 adv_instance = hci_find_adv_instance(hdev, instance);
1584
1585 if (force || (adv_instance && adv_instance->timeout &&
1586 !adv_instance->remaining_time)) {
1587 /* Don't advertise a removed instance. */
1588 if (next_instance &&
1589 next_instance->instance == instance)
1590 next_instance = NULL;
1591
1592 err = hci_remove_adv_instance(hdev, instance);
1593 if (!err)
1594 advertising_removed(NULL, hdev, instance);
1595 }
1596 }
1597
1598 if (list_empty(&hdev->adv_instances)) {
1599 hdev->cur_adv_instance = 0x00;
1600 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
1601 }
1602
1603 if (!req || !hdev_is_powered(hdev) ||
1556 hci_dev_test_flag(hdev, HCI_ADVERTISING)) 1604 hci_dev_test_flag(hdev, HCI_ADVERTISING))
1557 return; 1605 return;
1558 1606
1559 hci_req_init(&req, hdev); 1607 if (next_instance)
1560 disable_advertising(&req); 1608 schedule_adv_instance(req, next_instance->instance, false);
1561 hci_req_run(&req, NULL);
1562} 1609}
1563 1610
1564static int clean_up_hci_state(struct hci_dev *hdev) 1611static int clean_up_hci_state(struct hci_dev *hdev)
@@ -1576,8 +1623,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
1576 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); 1623 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1577 } 1624 }
1578 1625
1579 if (hdev->adv_instance_timeout) 1626 clear_adv_instance(hdev, NULL, 0x00, false);
1580 clear_adv_instance(hdev);
1581 1627
1582 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) 1628 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
1583 disable_advertising(&req); 1629 disable_advertising(&req);
@@ -2532,6 +2578,9 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
2532 val = !!cp->val; 2578 val = !!cp->val;
2533 enabled = lmp_host_le_capable(hdev); 2579 enabled = lmp_host_le_capable(hdev);
2534 2580
2581 if (!val)
2582 clear_adv_instance(hdev, NULL, 0x00, true);
2583
2535 if (!hdev_is_powered(hdev) || val == enabled) { 2584 if (!hdev_is_powered(hdev) || val == enabled) {
2536 bool changed = false; 2585 bool changed = false;
2537 2586
@@ -7018,10 +7067,26 @@ unlock:
7018 7067
7019void mgmt_adv_timeout_expired(struct hci_dev *hdev) 7068void mgmt_adv_timeout_expired(struct hci_dev *hdev)
7020{ 7069{
7070 u8 instance;
7071 struct hci_request req;
7072
7021 hdev->adv_instance_timeout = 0; 7073 hdev->adv_instance_timeout = 0;
7022 7074
7075 instance = get_current_adv_instance(hdev);
7076 if (instance == 0x00)
7077 return;
7078
7023 hci_dev_lock(hdev); 7079 hci_dev_lock(hdev);
7024 clear_adv_instance(hdev); 7080 hci_req_init(&req, hdev);
7081
7082 clear_adv_instance(hdev, &req, instance, false);
7083
7084 if (list_empty(&hdev->adv_instances))
7085 disable_advertising(&req);
7086
7087 if (!skb_queue_empty(&req.cmd_q))
7088 hci_req_run(&req, NULL);
7089
7025 hci_dev_unlock(hdev); 7090 hci_dev_unlock(hdev);
7026} 7091}
7027 7092