aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Grandel <fgrandel@gmail.com>2015-06-17 21:16:45 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-06-18 12:11:52 -0400
commit7816b82039b56308a0d685e97d4a9f4b52e239bd (patch)
tree0b97f6239ce2362044a81668d22a52fee9fa65cc /net
parentf63ba24b97ac795c516315c2b1b8a8463a6acd46 (diff)
Bluetooth: mgmt: multi adv for set_advertising*()
The set_advertising() and set_advertising_complete() methods rely on the now obsolete hci_dev->adv_instance structure. We replace this reference by an equivalent access to the newly introduced dynamic advertising instance list. This patch introduces a helper function that schedules an advertising instance correctly calculating advertising timing based on the timeout and duration settings of the instance. Scheduling is factored into its own function for readability and code sharing. Signed-off-by: Florian Grandel <fgrandel@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c100
1 files changed, 94 insertions, 6 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 04efc56d1641..55765dd79070 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1471,6 +1471,73 @@ static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
1471 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk); 1471 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1472} 1472}
1473 1473
1474static int schedule_adv_instance(struct hci_request *req, u8 instance,
1475 bool force) {
1476 struct hci_dev *hdev = req->hdev;
1477 struct adv_info *adv_instance = NULL;
1478 u16 timeout;
1479
1480 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
1481 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
1482 return -EPERM;
1483
1484 if (hdev->adv_instance_timeout)
1485 return -EBUSY;
1486
1487 adv_instance = hci_find_adv_instance(hdev, instance);
1488 if (!adv_instance)
1489 return -ENOENT;
1490
1491 /* A zero timeout means unlimited advertising. As long as there is
1492 * only one instance, duration should be ignored. We still set a timeout
1493 * in case further instances are being added later on.
1494 *
1495 * If the remaining lifetime of the instance is more than the duration
1496 * then the timeout corresponds to the duration, otherwise it will be
1497 * reduced to the remaining instance lifetime.
1498 */
1499 if (adv_instance->timeout == 0 ||
1500 adv_instance->duration <= adv_instance->remaining_time)
1501 timeout = adv_instance->duration;
1502 else
1503 timeout = adv_instance->remaining_time;
1504
1505 /* The remaining time is being reduced unless the instance is being
1506 * advertised without time limit.
1507 */
1508 if (adv_instance->timeout)
1509 adv_instance->remaining_time =
1510 adv_instance->remaining_time - timeout;
1511
1512 hdev->adv_instance_timeout = timeout;
1513 queue_delayed_work(hdev->workqueue,
1514 &hdev->adv_instance_expire,
1515 msecs_to_jiffies(timeout * 1000));
1516
1517 /* If we're just re-scheduling the same instance again then do not
1518 * execute any HCI commands. This happens when a single instance is
1519 * being advertised.
1520 */
1521 if (!force && hdev->cur_adv_instance == instance &&
1522 hci_dev_test_flag(hdev, HCI_LE_ADV))
1523 return 0;
1524
1525 hdev->cur_adv_instance = instance;
1526 update_adv_data(req);
1527 update_scan_rsp_data(req);
1528 enable_advertising(req);
1529
1530 return 0;
1531}
1532
1533static void cancel_adv_timeout(struct hci_dev *hdev)
1534{
1535 if (hdev->adv_instance_timeout) {
1536 hdev->adv_instance_timeout = 0;
1537 cancel_delayed_work(&hdev->adv_instance_expire);
1538 }
1539}
1540
1474static void clear_adv_instance(struct hci_dev *hdev) 1541static void clear_adv_instance(struct hci_dev *hdev)
1475{ 1542{
1476 struct hci_request req; 1543 struct hci_request req;
@@ -4681,6 +4748,9 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4681{ 4748{
4682 struct cmd_lookup match = { NULL, hdev }; 4749 struct cmd_lookup match = { NULL, hdev };
4683 struct hci_request req; 4750 struct hci_request req;
4751 u8 instance;
4752 struct adv_info *adv_instance;
4753 int err;
4684 4754
4685 hci_dev_lock(hdev); 4755 hci_dev_lock(hdev);
4686 4756
@@ -4706,18 +4776,31 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4706 sock_put(match.sk); 4776 sock_put(match.sk);
4707 4777
4708 /* If "Set Advertising" was just disabled and instance advertising was 4778 /* If "Set Advertising" was just disabled and instance advertising was
4709 * set up earlier, then enable the advertising instance. 4779 * set up earlier, then re-enable multi-instance advertising.
4710 */ 4780 */
4711 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || 4781 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
4712 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) 4782 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) ||
4783 list_empty(&hdev->adv_instances))
4713 goto unlock; 4784 goto unlock;
4714 4785
4786 instance = hdev->cur_adv_instance;
4787 if (!instance) {
4788 adv_instance = list_first_entry_or_null(&hdev->adv_instances,
4789 struct adv_info, list);
4790 if (!adv_instance)
4791 goto unlock;
4792
4793 instance = adv_instance->instance;
4794 }
4795
4715 hci_req_init(&req, hdev); 4796 hci_req_init(&req, hdev);
4716 4797
4717 update_adv_data(&req); 4798 err = schedule_adv_instance(&req, instance, true);
4718 enable_advertising(&req); 4799
4800 if (!err)
4801 err = hci_req_run(&req, enable_advertising_instance);
4719 4802
4720 if (hci_req_run(&req, enable_advertising_instance) < 0) 4803 if (err)
4721 BT_ERR("Failed to re-configure advertising"); 4804 BT_ERR("Failed to re-configure advertising");
4722 4805
4723unlock: 4806unlock:
@@ -4802,8 +4885,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4802 else 4885 else
4803 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); 4886 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
4804 4887
4888 cancel_adv_timeout(hdev);
4889
4805 if (val) { 4890 if (val) {
4806 /* Switch to instance "0" for the Set Advertising setting. */ 4891 /* Switch to instance "0" for the Set Advertising setting.
4892 * We cannot use update_[adv|scan_rsp]_data() here as the
4893 * HCI_ADVERTISING flag is not yet set.
4894 */
4807 update_inst_adv_data(&req, 0x00); 4895 update_inst_adv_data(&req, 0x00);
4808 update_inst_scan_rsp_data(&req, 0x00); 4896 update_inst_scan_rsp_data(&req, 0x00);
4809 enable_advertising(&req); 4897 enable_advertising(&req);