Bluetooth: MGMT: Fix Get Device Flags
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 15 Aug 2022 23:14:32 +0000 (16:14 -0700)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 25 Aug 2022 23:26:16 +0000 (16:26 -0700)
Get Device Flags don't check if device does actually use an RPA in which
case it shall only set HCI_CONN_FLAG_REMOTE_WAKEUP if LL Privacy is
enabled.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/mgmt.c

index 6e31023..566b629 100644 (file)
@@ -4547,6 +4547,22 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
                               MGMT_STATUS_NOT_SUPPORTED);
 }
 
+static u32 get_params_flags(struct hci_dev *hdev,
+                           struct hci_conn_params *params)
+{
+       u32 flags = hdev->conn_flags;
+
+       /* Devices using RPAs can only be programmed in the acceptlist if
+        * LL Privacy has been enable otherwise they cannot mark
+        * HCI_CONN_FLAG_REMOTE_WAKEUP.
+        */
+       if ((flags & HCI_CONN_FLAG_REMOTE_WAKEUP) && !use_ll_privacy(hdev) &&
+           hci_find_irk_by_addr(hdev, &params->addr, params->addr_type))
+               flags &= ~HCI_CONN_FLAG_REMOTE_WAKEUP;
+
+       return flags;
+}
+
 static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
                            u16 data_len)
 {
@@ -4578,10 +4594,10 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
        } else {
                params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
                                                le_addr_type(cp->addr.type));
-
                if (!params)
                        goto done;
 
+               supported_flags = get_params_flags(hdev, params);
                current_flags = params->flags;
        }
 
@@ -4649,38 +4665,35 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
                        bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
                                    &cp->addr.bdaddr, cp->addr.type);
                }
-       } else {
-               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
-                                               le_addr_type(cp->addr.type));
-               if (params) {
-                       /* Devices using RPAs can only be programmed in the
-                        * acceptlist LL Privacy has been enable otherwise they
-                        * cannot mark HCI_CONN_FLAG_REMOTE_WAKEUP.
-                        */
-                       if ((current_flags & HCI_CONN_FLAG_REMOTE_WAKEUP) &&
-                           !use_ll_privacy(hdev) &&
-                           hci_find_irk_by_addr(hdev, &params->addr,
-                                                params->addr_type)) {
-                               bt_dev_warn(hdev,
-                                           "Cannot set wakeable for RPA");
-                               goto unlock;
-                       }
 
-                       params->flags = current_flags;
-                       status = MGMT_STATUS_SUCCESS;
+               goto unlock;
+       }
 
-                       /* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
-                        * has been set.
-                        */
-                       if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
-                               hci_update_passive_scan(hdev);
-               } else {
-                       bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
-                                   &cp->addr.bdaddr,
-                                   le_addr_type(cp->addr.type));
-               }
+       params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
+                                       le_addr_type(cp->addr.type));
+       if (!params) {
+               bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
+                           &cp->addr.bdaddr, le_addr_type(cp->addr.type));
+               goto unlock;
+       }
+
+       supported_flags = get_params_flags(hdev, params);
+
+       if ((supported_flags | current_flags) != supported_flags) {
+               bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
+                           current_flags, supported_flags);
+               goto unlock;
        }
 
+       params->flags = current_flags;
+       status = MGMT_STATUS_SUCCESS;
+
+       /* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
+        * has been set.
+        */
+       if (params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY)
+               hci_update_passive_scan(hdev);
+
 unlock:
        hci_dev_unlock(hdev);