Bluetooth: MGMT: Make MGMT_OP_LOAD_CONN_PARAM update existing connection

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: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent ecb1e1dc
......@@ -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);
......@@ -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);
......@@ -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);
}
......@@ -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,
......@@ -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)
{
......@@ -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);
......@@ -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) {
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment