aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorArman Uguray <armansito@chromium.org>2015-03-23 18:57:13 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-03-23 20:53:47 -0400
commitda929335f27d955172539bf56bed1ac9ff9b8d45 (patch)
tree2491a4b271be7d5ae73b055de13acfef11ac8e7c /net
parent24b4f38fc9ebf93af223c67169a946d6baf9db61 (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.c103
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
106static const u16 mgmt_events[] = { 107static 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
6585static 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
6609unlock:
6610 hci_dev_unlock(hdev);
6611}
6612
6613static 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
6679unlock:
6680 hci_dev_unlock(hdev);
6681
6682 return err;
6683}
6684
6583static const struct hci_mgmt_handler mgmt_handlers[] = { 6685static 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
6671void mgmt_index_added(struct hci_dev *hdev) 6774void mgmt_index_added(struct hci_dev *hdev)