]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
Bluetooth: MGMT: Fix Add Device to responding before completing
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 25 Nov 2024 20:42:10 +0000 (15:42 -0500)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 8 Jan 2025 16:14:01 +0000 (11:14 -0500)
Add Device with LE type requires updating resolving/accept list which
requires quite a number of commands to complete and each of them may
fail, so instead of pretending it would always work this checks the
return of hci_update_passive_scan_sync which indicates if everything
worked as intended.

Fixes: e8907f76544f ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/mgmt.c

index b31192d473d09b663dc7babd107b4894088ebf6d..de47ad999d7b64edb83b90f66397e0a9a0cf9468 100644 (file)
@@ -7655,6 +7655,24 @@ static void device_added(struct sock *sk, struct hci_dev *hdev,
        mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
 }
 
+static void add_device_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_device *cp = cmd->param;
+
+       if (!err) {
+               device_added(cmd->sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+                            cp->action);
+               device_flags_changed(NULL, hdev, &cp->addr.bdaddr,
+                                    cp->addr.type, hdev->conn_flags,
+                                    PTR_UINT(cmd->user_data));
+       }
+
+       mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                         mgmt_status(err), &cp->addr, sizeof(cp->addr));
+       mgmt_pending_free(cmd);
+}
+
 static int add_device_sync(struct hci_dev *hdev, void *data)
 {
        return hci_update_passive_scan_sync(hdev);
@@ -7663,6 +7681,7 @@ static int add_device_sync(struct hci_dev *hdev, void *data)
 static int add_device(struct sock *sk, struct hci_dev *hdev,
                      void *data, u16 len)
 {
+       struct mgmt_pending_cmd *cmd;
        struct mgmt_cp_add_device *cp = data;
        u8 auto_conn, addr_type;
        struct hci_conn_params *params;
@@ -7743,9 +7762,24 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
                        current_flags = params->flags;
        }
 
-       err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
-       if (err < 0)
+       cmd = mgmt_pending_new(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
                goto unlock;
+       }
+
+       cmd->user_data = UINT_PTR(current_flags);
+
+       err = hci_cmd_sync_queue(hdev, add_device_sync, cmd,
+                                add_device_complete);
+       if (err < 0) {
+               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                                       MGMT_STATUS_FAILED, &cp->addr,
+                                       sizeof(cp->addr));
+               mgmt_pending_free(cmd);
+       }
+
+       goto unlock;
 
 added:
        device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);