aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorArman Uguray <armansito@chromium.org>2015-03-23 18:57:15 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-03-23 20:53:47 -0400
commit912098a6308e37208b8dcc46c57c66d0778a854b (patch)
treebcc9acea73780237f1b848122b9d4bfa797e2d9c /net
parent4117ed70a55128273f1b6d00c7725e4c8a5c0031 (diff)
Bluetooth: Add support for adv instance timeout
This patch implements support for the timeout parameter of the Add Advertising command. Signed-off-by: Arman Uguray <armansito@chromium.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c101
1 files changed, 81 insertions, 20 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 762ca9be9806..eda52397a648 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1336,6 +1336,49 @@ static bool hci_stop_discovery(struct hci_request *req)
1336 return false; 1336 return false;
1337} 1337}
1338 1338
1339static void advertising_added(struct sock *sk, struct hci_dev *hdev,
1340 u8 instance)
1341{
1342 struct mgmt_ev_advertising_added ev;
1343
1344 ev.instance = instance;
1345
1346 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
1347}
1348
1349static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
1350 u8 instance)
1351{
1352 struct mgmt_ev_advertising_removed ev;
1353
1354 ev.instance = instance;
1355
1356 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
1357}
1358
1359static void clear_adv_instance(struct hci_dev *hdev)
1360{
1361 struct hci_request req;
1362
1363 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
1364 return;
1365
1366 if (hdev->adv_instance.timeout)
1367 cancel_delayed_work(&hdev->adv_instance.timeout_exp);
1368
1369 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
1370 advertising_removed(NULL, hdev, 1);
1371 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
1372
1373 if (!hdev_is_powered(hdev) ||
1374 hci_dev_test_flag(hdev, HCI_ADVERTISING))
1375 return;
1376
1377 hci_req_init(&req, hdev);
1378 disable_advertising(&req);
1379 hci_req_run(&req, NULL);
1380}
1381
1339static int clean_up_hci_state(struct hci_dev *hdev) 1382static int clean_up_hci_state(struct hci_dev *hdev)
1340{ 1383{
1341 struct hci_request req; 1384 struct hci_request req;
@@ -1351,6 +1394,9 @@ static int clean_up_hci_state(struct hci_dev *hdev)
1351 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); 1394 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1352 } 1395 }
1353 1396
1397 if (hdev->adv_instance.timeout)
1398 clear_adv_instance(hdev);
1399
1354 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) 1400 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
1355 disable_advertising(&req); 1401 disable_advertising(&req);
1356 1402
@@ -6468,26 +6514,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
6468 return true; 6514 return true;
6469} 6515}
6470 6516
6471static void advertising_added(struct sock *sk, struct hci_dev *hdev,
6472 u8 instance)
6473{
6474 struct mgmt_ev_advertising_added ev;
6475
6476 ev.instance = instance;
6477
6478 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
6479}
6480
6481static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
6482 u8 instance)
6483{
6484 struct mgmt_ev_advertising_removed ev;
6485
6486 ev.instance = instance;
6487
6488 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
6489}
6490
6491static void add_advertising_complete(struct hci_dev *hdev, u8 status, 6517static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6492 u16 opcode) 6518 u16 opcode)
6493{ 6519{
@@ -6524,6 +6550,18 @@ unlock:
6524 hci_dev_unlock(hdev); 6550 hci_dev_unlock(hdev);
6525} 6551}
6526 6552
6553static void adv_timeout_expired(struct work_struct *work)
6554{
6555 struct hci_dev *hdev = container_of(work, struct hci_dev,
6556 adv_instance.timeout_exp.work);
6557
6558 hdev->adv_instance.timeout = 0;
6559
6560 hci_dev_lock(hdev);
6561 clear_adv_instance(hdev);
6562 hci_dev_unlock(hdev);
6563}
6564
6527static int add_advertising(struct sock *sk, struct hci_dev *hdev, 6565static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6528 void *data, u16 data_len) 6566 void *data, u16 data_len)
6529{ 6567{
@@ -6531,6 +6569,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6531 struct mgmt_rp_add_advertising rp; 6569 struct mgmt_rp_add_advertising rp;
6532 u32 flags; 6570 u32 flags;
6533 u8 status; 6571 u8 status;
6572 u16 timeout;
6534 int err; 6573 int err;
6535 struct mgmt_pending_cmd *cmd; 6574 struct mgmt_pending_cmd *cmd;
6536 struct hci_request req; 6575 struct hci_request req;
@@ -6543,6 +6582,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6543 status); 6582 status);
6544 6583
6545 flags = __le32_to_cpu(cp->flags); 6584 flags = __le32_to_cpu(cp->flags);
6585 timeout = __le16_to_cpu(cp->timeout);
6546 6586
6547 /* The current implementation only supports adding one instance and 6587 /* The current implementation only supports adding one instance and
6548 * doesn't support flags. 6588 * doesn't support flags.
@@ -6553,6 +6593,12 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6553 6593
6554 hci_dev_lock(hdev); 6594 hci_dev_lock(hdev);
6555 6595
6596 if (timeout && !hdev_is_powered(hdev)) {
6597 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6598 MGMT_STATUS_REJECTED);
6599 goto unlock;
6600 }
6601
6556 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || 6602 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6557 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || 6603 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6558 pending_find(MGMT_OP_SET_LE, hdev)) { 6604 pending_find(MGMT_OP_SET_LE, hdev)) {
@@ -6569,6 +6615,8 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6569 goto unlock; 6615 goto unlock;
6570 } 6616 }
6571 6617
6618 INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired);
6619
6572 hdev->adv_instance.flags = flags; 6620 hdev->adv_instance.flags = flags;
6573 hdev->adv_instance.adv_data_len = cp->adv_data_len; 6621 hdev->adv_instance.adv_data_len = cp->adv_data_len;
6574 hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len; 6622 hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
@@ -6580,6 +6628,16 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6580 memcpy(hdev->adv_instance.scan_rsp_data, 6628 memcpy(hdev->adv_instance.scan_rsp_data,
6581 cp->data + cp->adv_data_len, cp->scan_rsp_len); 6629 cp->data + cp->adv_data_len, cp->scan_rsp_len);
6582 6630
6631 if (hdev->adv_instance.timeout)
6632 cancel_delayed_work(&hdev->adv_instance.timeout_exp);
6633
6634 hdev->adv_instance.timeout = timeout;
6635
6636 if (timeout)
6637 queue_delayed_work(hdev->workqueue,
6638 &hdev->adv_instance.timeout_exp,
6639 msecs_to_jiffies(timeout * 1000));
6640
6583 if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE)) 6641 if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
6584 advertising_added(sk, hdev, 1); 6642 advertising_added(sk, hdev, 1);
6585 6643
@@ -6682,6 +6740,9 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6682 goto unlock; 6740 goto unlock;
6683 } 6741 }
6684 6742
6743 if (hdev->adv_instance.timeout)
6744 cancel_delayed_work(&hdev->adv_instance.timeout_exp);
6745
6685 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); 6746 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
6686 6747
6687 advertising_removed(sk, hdev, 1); 6748 advertising_removed(sk, hdev, 1);