]> Gentwo Git Trees - linux/.git/commitdiff
Bluetooth: MGMT: Allow use of Set Device Flags without Add Device
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 6 Oct 2025 20:32:24 +0000 (16:32 -0400)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 1 Dec 2025 21:00:06 +0000 (16:00 -0500)
In certain cases setting devices flags like HCI_CONN_FLAG_PAST it
shouldn't require to do Add Device first since it may not need to add
an auto-connect policy, so this instead just automatically creates
a hci_conn_params if one cannot be found using HCI_AUTO_CONN_DISABLED.

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

index 7dbd3d57e66c212b93c94928911e234076acf319..c11cdef42b6f66e521c4d3adcc13610655cb412f 100644 (file)
@@ -5122,6 +5122,69 @@ static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
        mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
 }
 
+static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
+{
+       struct hci_conn *conn;
+
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
+       if (!conn)
+               return false;
+
+       if (conn->dst_type != type)
+               return false;
+
+       if (conn->state != BT_CONNECTED)
+               return false;
+
+       return true;
+}
+
+/* This function requires the caller holds hdev->lock */
+static struct hci_conn_params *hci_conn_params_set(struct hci_dev *hdev,
+                                                  bdaddr_t *addr, u8 addr_type,
+                                                  u8 auto_connect)
+{
+       struct hci_conn_params *params;
+
+       params = hci_conn_params_add(hdev, addr, addr_type);
+       if (!params)
+               return NULL;
+
+       if (params->auto_connect == auto_connect)
+               return params;
+
+       hci_pend_le_list_del_init(params);
+
+       switch (auto_connect) {
+       case HCI_AUTO_CONN_DISABLED:
+       case HCI_AUTO_CONN_LINK_LOSS:
+               /* If auto connect is being disabled when we're trying to
+                * connect to device, keep connecting.
+                */
+               if (params->explicit_connect)
+                       hci_pend_le_list_add(params, &hdev->pend_le_conns);
+               break;
+       case HCI_AUTO_CONN_REPORT:
+               if (params->explicit_connect)
+                       hci_pend_le_list_add(params, &hdev->pend_le_conns);
+               else
+                       hci_pend_le_list_add(params, &hdev->pend_le_reports);
+               break;
+       case HCI_AUTO_CONN_DIRECT:
+       case HCI_AUTO_CONN_ALWAYS:
+               if (!is_connected(hdev, addr, addr_type))
+                       hci_pend_le_list_add(params, &hdev->pend_le_conns);
+               break;
+       }
+
+       params->auto_connect = auto_connect;
+
+       bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
+                  addr, addr_type, auto_connect);
+
+       return params;
+}
+
 static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
                            u16 len)
 {
@@ -5165,9 +5228,16 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
        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;
+               /* Create a new hci_conn_params if it doesn't exist */
+               params = hci_conn_params_set(hdev, &cp->addr.bdaddr,
+                                            le_addr_type(cp->addr.type),
+                                            HCI_AUTO_CONN_DISABLED);
+               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 = hdev->conn_flags;
@@ -7554,68 +7624,6 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
        return err;
 }
 
-static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
-{
-       struct hci_conn *conn;
-
-       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
-       if (!conn)
-               return false;
-
-       if (conn->dst_type != type)
-               return false;
-
-       if (conn->state != BT_CONNECTED)
-               return false;
-
-       return true;
-}
-
-/* This function requires the caller holds hdev->lock */
-static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
-                              u8 addr_type, u8 auto_connect)
-{
-       struct hci_conn_params *params;
-
-       params = hci_conn_params_add(hdev, addr, addr_type);
-       if (!params)
-               return -EIO;
-
-       if (params->auto_connect == auto_connect)
-               return 0;
-
-       hci_pend_le_list_del_init(params);
-
-       switch (auto_connect) {
-       case HCI_AUTO_CONN_DISABLED:
-       case HCI_AUTO_CONN_LINK_LOSS:
-               /* If auto connect is being disabled when we're trying to
-                * connect to device, keep connecting.
-                */
-               if (params->explicit_connect)
-                       hci_pend_le_list_add(params, &hdev->pend_le_conns);
-               break;
-       case HCI_AUTO_CONN_REPORT:
-               if (params->explicit_connect)
-                       hci_pend_le_list_add(params, &hdev->pend_le_conns);
-               else
-                       hci_pend_le_list_add(params, &hdev->pend_le_reports);
-               break;
-       case HCI_AUTO_CONN_DIRECT:
-       case HCI_AUTO_CONN_ALWAYS:
-               if (!is_connected(hdev, addr, addr_type))
-                       hci_pend_le_list_add(params, &hdev->pend_le_conns);
-               break;
-       }
-
-       params->auto_connect = auto_connect;
-
-       bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
-                  addr, addr_type, auto_connect);
-
-       return 0;
-}
-
 static void device_added(struct sock *sk, struct hci_dev *hdev,
                         bdaddr_t *bdaddr, u8 type, u8 action)
 {
@@ -7727,17 +7735,13 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
        /* If the connection parameters don't exist for this device,
         * they will be created and configured with defaults.
         */
-       if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
-                               auto_conn) < 0) {
+       params = hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
+                                    auto_conn);
+       if (!params) {
                err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
                                        MGMT_STATUS_FAILED, &cp->addr,
                                        sizeof(cp->addr));
                goto unlock;
-       } else {
-               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
-                                               addr_type);
-               if (params)
-                       current_flags = params->flags;
        }
 
        cmd = mgmt_pending_new(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);