diff options
author | Arman Uguray <armansito@chromium.org> | 2015-03-23 18:57:15 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-03-23 20:53:47 -0400 |
commit | 912098a6308e37208b8dcc46c57c66d0778a854b (patch) | |
tree | bcc9acea73780237f1b848122b9d4bfa797e2d9c /net | |
parent | 4117ed70a55128273f1b6d00c7725e4c8a5c0031 (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.c | 101 |
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 | ||
1339 | static 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 | |||
1349 | static 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 | |||
1359 | static 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 | |||
1339 | static int clean_up_hci_state(struct hci_dev *hdev) | 1382 | static 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 | ||
6471 | static 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 | |||
6481 | static 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 | |||
6491 | static void add_advertising_complete(struct hci_dev *hdev, u8 status, | 6517 | static 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 | ||
6553 | static 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 | |||
6527 | static int add_advertising(struct sock *sk, struct hci_dev *hdev, | 6565 | static 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); |