Bluetooth: Implement the Remove Advertising command
authorArman Uguray <armansito@chromium.org>
Mon, 23 Mar 2015 22:57:13 +0000 (15:57 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 24 Mar 2015 00:53:47 +0000 (01:53 +0100)
This patch implements the "Remove Advertising" mgmt command.

Signed-off-by: Arman Uguray <armansito@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/mgmt.c

index 7b4c0b027e9029258d58232126e95bca1d79a94c..5e5a738ea95cfc4a5d72df868aebc5ecede9631a 100644 (file)
@@ -101,6 +101,7 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_READ_EXT_INDEX_LIST,
        MGMT_OP_READ_ADV_FEATURES,
        MGMT_OP_ADD_ADVERTISING,
+       MGMT_OP_REMOVE_ADVERTISING,
 };
 
 static const u16 mgmt_events[] = {
@@ -6518,6 +6519,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
        hci_dev_lock(hdev);
 
        if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
+           pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
            pending_find(MGMT_OP_SET_LE, hdev)) {
                err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                      MGMT_STATUS_BUSY);
@@ -6580,6 +6582,106 @@ unlock:
        return err;
 }
 
+static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
+                                       u16 opcode)
+{
+       struct mgmt_pending_cmd *cmd;
+       struct mgmt_rp_remove_advertising rp;
+
+       BT_DBG("status %d", status);
+
+       hci_dev_lock(hdev);
+
+       /* A failure status here only means that we failed to disable
+        * advertising. Otherwise, the advertising instance has been removed,
+        * so report success.
+        */
+       cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
+       if (!cmd)
+               goto unlock;
+
+       rp.instance = 1;
+
+       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
+                         &rp, sizeof(rp));
+       mgmt_pending_remove(cmd);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
+                             void *data, u16 data_len)
+{
+       struct mgmt_cp_remove_advertising *cp = data;
+       struct mgmt_rp_remove_advertising rp;
+       int err;
+       struct mgmt_pending_cmd *cmd;
+       struct hci_request req;
+
+       BT_DBG("%s", hdev->name);
+
+       /* The current implementation only allows modifying instance no 1. A
+        * value of 0 indicates that all instances should be cleared.
+        */
+       if (cp->instance > 1)
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
+                                      MGMT_STATUS_INVALID_PARAMS);
+
+       hci_dev_lock(hdev);
+
+       if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
+           pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
+           pending_find(MGMT_OP_SET_LE, hdev)) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
+                                     MGMT_STATUS_BUSY);
+               goto unlock;
+       }
+
+       if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
+                                     MGMT_STATUS_INVALID_PARAMS);
+               goto unlock;
+       }
+
+       memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
+
+       advertising_removed(sk, hdev, 1);
+
+       hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
+
+       /* If the HCI_ADVERTISING flag is set or the device isn't powered then
+        * we have no HCI communication to make. Simply return.
+        */
+       if (!hdev_is_powered(hdev) ||
+           hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
+               rp.instance = 1;
+               err = mgmt_cmd_complete(sk, hdev->id,
+                                       MGMT_OP_REMOVE_ADVERTISING,
+                                       MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
+               goto unlock;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
+                              data_len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+       hci_req_init(&req, hdev);
+       disable_advertising(&req);
+
+       err = hci_req_run(&req, remove_advertising_complete);
+       if (err < 0)
+               mgmt_pending_remove(cmd);
+
+unlock:
+       hci_dev_unlock(hdev);
+
+       return err;
+}
+
 static const struct hci_mgmt_handler mgmt_handlers[] = {
        { NULL }, /* 0x0000 (no command) */
        { read_version,            MGMT_READ_VERSION_SIZE,
@@ -6666,6 +6768,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
        { read_adv_features,       MGMT_READ_ADV_FEATURES_SIZE },
        { add_advertising,         MGMT_ADD_ADVERTISING_SIZE,
                                                HCI_MGMT_VAR_LEN },
+       { remove_advertising,      MGMT_REMOVE_ADVERTISING_SIZE },
 };
 
 void mgmt_index_added(struct hci_dev *hdev)