Skip to content

Commit

Permalink
Bluetooth: MGMT: Make MGMT_OP_LOAD_CONN_PARAM update existing connection
Browse files Browse the repository at this point in the history
This makes MGMT_OP_LOAD_CONN_PARAM update existing connection by
dectecting the request is just for one connection, parameters already
exists and there is a connection.

Since this is a new behavior the revision is also updated to enable
userspace to detect it.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information
Vudentz committed Jul 15, 2024
1 parent ecb1e1d commit 0ece498
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
3 changes: 3 additions & 0 deletions include/net/bluetooth/hci_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ int hci_suspend_sync(struct hci_dev *hdev);
int hci_resume_sync(struct hci_dev *hdev);

struct hci_conn;
struct hci_conn_params;

int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);

Expand All @@ -156,3 +157,5 @@ int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn);

int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
struct hci_conn_params *params);
18 changes: 18 additions & 0 deletions net/bluetooth/hci_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -6724,3 +6724,21 @@ int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)

return -ENOENT;
}

int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
struct hci_conn_params *params)
{
struct hci_cp_le_conn_update cp;

memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
cp.conn_interval_min = cpu_to_le16(params->conn_min_interval);
cp.conn_interval_max = cpu_to_le16(params->conn_max_interval);
cp.conn_latency = cpu_to_le16(params->conn_latency);
cp.supervision_timeout = cpu_to_le16(params->supervision_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);

return __hci_cmd_sync_status(hdev, HCI_OP_LE_CONN_UPDATE,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
50 changes: 48 additions & 2 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
#include "aosp.h"

#define MGMT_VERSION 1
#define MGMT_REVISION 22
#define MGMT_REVISION 23

static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
Expand Down Expand Up @@ -7813,6 +7813,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
return err;
}

static int conn_update_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn_params *params = data;
struct hci_conn *conn;

conn = hci_conn_hash_lookup_le(hdev, &params->addr, params->addr_type);
if (!conn)
return -ECANCELED;

return hci_le_conn_update_sync(hdev, conn, params);
}

static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
Expand Down Expand Up @@ -7846,13 +7858,15 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,

hci_dev_lock(hdev);

hci_conn_params_clear_disabled(hdev);
if (param_count > 1)
hci_conn_params_clear_disabled(hdev);

for (i = 0; i < param_count; i++) {
struct mgmt_conn_param *param = &cp->params[i];
struct hci_conn_params *hci_param;
u16 min, max, latency, timeout;
u8 addr_type;
bool update;

bt_dev_dbg(hdev, "Adding %pMR (type %u)", &param->addr.bdaddr,
param->addr.type);
Expand All @@ -7879,6 +7893,19 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
continue;
}

/* Detect when the loading is for an existing parameter then
* attempt to trigger the connection update procedure.
*/
if (!i && param_count == 1) {
hci_param = hci_conn_params_lookup(hdev,
&param->addr.bdaddr,
addr_type);
if (hci_param)
update = true;
else
hci_conn_params_clear_disabled(hdev);
}

hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
addr_type);
if (!hci_param) {
Expand All @@ -7890,6 +7917,25 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
hci_param->conn_max_interval = max;
hci_param->conn_latency = latency;
hci_param->supervision_timeout = timeout;

/* Check if we need to trigger a connection update */
if (update) {
struct hci_conn *conn;

/* Lookup for existing connection as central and check
* if parameters match and if they don't then trigger
* a connection update.
*/
conn = hci_conn_hash_lookup_le(hdev, &hci_param->addr,
addr_type);
if (conn && conn->role == HCI_ROLE_MASTER &&
(conn->le_conn_min_interval != min ||
conn->le_conn_max_interval != max ||
conn->le_conn_latency != latency ||
conn->le_supv_timeout != timeout))
hci_cmd_sync_queue(hdev, conn_update_sync,
hci_param, NULL);
}
}

hci_dev_unlock(hdev);
Expand Down

0 comments on commit 0ece498

Please sign in to comment.