diff options
author | Arman Uguray <armansito@chromium.org> | 2015-03-23 18:57:13 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-03-23 20:53:47 -0400 |
commit | da929335f27d955172539bf56bed1ac9ff9b8d45 (patch) | |
tree | 2491a4b271be7d5ae73b055de13acfef11ac8e7c /net | |
parent | 24b4f38fc9ebf93af223c67169a946d6baf9db61 (diff) |
Bluetooth: Implement the Remove Advertising command
This patch implements the "Remove Advertising" mgmt 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 | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7b4c0b027e90..5e5a738ea95c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -101,6 +101,7 @@ static const u16 mgmt_commands[] = { | |||
101 | MGMT_OP_READ_EXT_INDEX_LIST, | 101 | MGMT_OP_READ_EXT_INDEX_LIST, |
102 | MGMT_OP_READ_ADV_FEATURES, | 102 | MGMT_OP_READ_ADV_FEATURES, |
103 | MGMT_OP_ADD_ADVERTISING, | 103 | MGMT_OP_ADD_ADVERTISING, |
104 | MGMT_OP_REMOVE_ADVERTISING, | ||
104 | }; | 105 | }; |
105 | 106 | ||
106 | static const u16 mgmt_events[] = { | 107 | static const u16 mgmt_events[] = { |
@@ -6518,6 +6519,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, | |||
6518 | hci_dev_lock(hdev); | 6519 | hci_dev_lock(hdev); |
6519 | 6520 | ||
6520 | if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || | 6521 | if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || |
6522 | pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || | ||
6521 | pending_find(MGMT_OP_SET_LE, hdev)) { | 6523 | pending_find(MGMT_OP_SET_LE, hdev)) { |
6522 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | 6524 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, |
6523 | MGMT_STATUS_BUSY); | 6525 | MGMT_STATUS_BUSY); |
@@ -6580,6 +6582,106 @@ unlock: | |||
6580 | return err; | 6582 | return err; |
6581 | } | 6583 | } |
6582 | 6584 | ||
6585 | static void remove_advertising_complete(struct hci_dev *hdev, u8 status, | ||
6586 | u16 opcode) | ||
6587 | { | ||
6588 | struct mgmt_pending_cmd *cmd; | ||
6589 | struct mgmt_rp_remove_advertising rp; | ||
6590 | |||
6591 | BT_DBG("status %d", status); | ||
6592 | |||
6593 | hci_dev_lock(hdev); | ||
6594 | |||
6595 | /* A failure status here only means that we failed to disable | ||
6596 | * advertising. Otherwise, the advertising instance has been removed, | ||
6597 | * so report success. | ||
6598 | */ | ||
6599 | cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev); | ||
6600 | if (!cmd) | ||
6601 | goto unlock; | ||
6602 | |||
6603 | rp.instance = 1; | ||
6604 | |||
6605 | mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS, | ||
6606 | &rp, sizeof(rp)); | ||
6607 | mgmt_pending_remove(cmd); | ||
6608 | |||
6609 | unlock: | ||
6610 | hci_dev_unlock(hdev); | ||
6611 | } | ||
6612 | |||
6613 | static int remove_advertising(struct sock *sk, struct hci_dev *hdev, | ||
6614 | void *data, u16 data_len) | ||
6615 | { | ||
6616 | struct mgmt_cp_remove_advertising *cp = data; | ||
6617 | struct mgmt_rp_remove_advertising rp; | ||
6618 | int err; | ||
6619 | struct mgmt_pending_cmd *cmd; | ||
6620 | struct hci_request req; | ||
6621 | |||
6622 | BT_DBG("%s", hdev->name); | ||
6623 | |||
6624 | /* The current implementation only allows modifying instance no 1. A | ||
6625 | * value of 0 indicates that all instances should be cleared. | ||
6626 | */ | ||
6627 | if (cp->instance > 1) | ||
6628 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, | ||
6629 | MGMT_STATUS_INVALID_PARAMS); | ||
6630 | |||
6631 | hci_dev_lock(hdev); | ||
6632 | |||
6633 | if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || | ||
6634 | pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || | ||
6635 | pending_find(MGMT_OP_SET_LE, hdev)) { | ||
6636 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, | ||
6637 | MGMT_STATUS_BUSY); | ||
6638 | goto unlock; | ||
6639 | } | ||
6640 | |||
6641 | if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) { | ||
6642 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, | ||
6643 | MGMT_STATUS_INVALID_PARAMS); | ||
6644 | goto unlock; | ||
6645 | } | ||
6646 | |||
6647 | memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); | ||
6648 | |||
6649 | advertising_removed(sk, hdev, 1); | ||
6650 | |||
6651 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); | ||
6652 | |||
6653 | /* If the HCI_ADVERTISING flag is set or the device isn't powered then | ||
6654 | * we have no HCI communication to make. Simply return. | ||
6655 | */ | ||
6656 | if (!hdev_is_powered(hdev) || | ||
6657 | hci_dev_test_flag(hdev, HCI_ADVERTISING)) { | ||
6658 | rp.instance = 1; | ||
6659 | err = mgmt_cmd_complete(sk, hdev->id, | ||
6660 | MGMT_OP_REMOVE_ADVERTISING, | ||
6661 | MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); | ||
6662 | goto unlock; | ||
6663 | } | ||
6664 | |||
6665 | cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data, | ||
6666 | data_len); | ||
6667 | if (!cmd) { | ||
6668 | err = -ENOMEM; | ||
6669 | goto unlock; | ||
6670 | } | ||
6671 | |||
6672 | hci_req_init(&req, hdev); | ||
6673 | disable_advertising(&req); | ||
6674 | |||
6675 | err = hci_req_run(&req, remove_advertising_complete); | ||
6676 | if (err < 0) | ||
6677 | mgmt_pending_remove(cmd); | ||
6678 | |||
6679 | unlock: | ||
6680 | hci_dev_unlock(hdev); | ||
6681 | |||
6682 | return err; | ||
6683 | } | ||
6684 | |||
6583 | static const struct hci_mgmt_handler mgmt_handlers[] = { | 6685 | static const struct hci_mgmt_handler mgmt_handlers[] = { |
6584 | { NULL }, /* 0x0000 (no command) */ | 6686 | { NULL }, /* 0x0000 (no command) */ |
6585 | { read_version, MGMT_READ_VERSION_SIZE, | 6687 | { read_version, MGMT_READ_VERSION_SIZE, |
@@ -6666,6 +6768,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { | |||
6666 | { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE }, | 6768 | { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE }, |
6667 | { add_advertising, MGMT_ADD_ADVERTISING_SIZE, | 6769 | { add_advertising, MGMT_ADD_ADVERTISING_SIZE, |
6668 | HCI_MGMT_VAR_LEN }, | 6770 | HCI_MGMT_VAR_LEN }, |
6771 | { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE }, | ||
6669 | }; | 6772 | }; |
6670 | 6773 | ||
6671 | void mgmt_index_added(struct hci_dev *hdev) | 6774 | void mgmt_index_added(struct hci_dev *hdev) |