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: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
ecb1e1dcb7
commit
0ece498c27
3 changed files with 69 additions and 2 deletions
|
@ -138,6 +138,7 @@ int hci_suspend_sync(struct hci_dev *hdev);
|
||||||
int hci_resume_sync(struct hci_dev *hdev);
|
int hci_resume_sync(struct hci_dev *hdev);
|
||||||
|
|
||||||
struct hci_conn;
|
struct hci_conn;
|
||||||
|
struct hci_conn_params;
|
||||||
|
|
||||||
int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);
|
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_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_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;
|
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"
|
#include "aosp.h"
|
||||||
|
|
||||||
#define MGMT_VERSION 1
|
#define MGMT_VERSION 1
|
||||||
#define MGMT_REVISION 22
|
#define MGMT_REVISION 23
|
||||||
|
|
||||||
static const u16 mgmt_commands[] = {
|
static const u16 mgmt_commands[] = {
|
||||||
MGMT_OP_READ_INDEX_LIST,
|
MGMT_OP_READ_INDEX_LIST,
|
||||||
|
@ -7813,6 +7813,18 @@ unlock:
|
||||||
return err;
|
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, ¶ms->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,
|
static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
u16 len)
|
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_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++) {
|
for (i = 0; i < param_count; i++) {
|
||||||
struct mgmt_conn_param *param = &cp->params[i];
|
struct mgmt_conn_param *param = &cp->params[i];
|
||||||
struct hci_conn_params *hci_param;
|
struct hci_conn_params *hci_param;
|
||||||
u16 min, max, latency, timeout;
|
u16 min, max, latency, timeout;
|
||||||
u8 addr_type;
|
u8 addr_type;
|
||||||
|
bool update;
|
||||||
|
|
||||||
bt_dev_dbg(hdev, "Adding %pMR (type %u)", ¶m->addr.bdaddr,
|
bt_dev_dbg(hdev, "Adding %pMR (type %u)", ¶m->addr.bdaddr,
|
||||||
param->addr.type);
|
param->addr.type);
|
||||||
|
@ -7879,6 +7893,19 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
continue;
|
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,
|
||||||
|
¶m->addr.bdaddr,
|
||||||
|
addr_type);
|
||||||
|
if (hci_param)
|
||||||
|
update = true;
|
||||||
|
else
|
||||||
|
hci_conn_params_clear_disabled(hdev);
|
||||||
|
}
|
||||||
|
|
||||||
hci_param = hci_conn_params_add(hdev, ¶m->addr.bdaddr,
|
hci_param = hci_conn_params_add(hdev, ¶m->addr.bdaddr,
|
||||||
addr_type);
|
addr_type);
|
||||||
if (!hci_param) {
|
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_max_interval = max;
|
||||||
hci_param->conn_latency = latency;
|
hci_param->conn_latency = latency;
|
||||||
hci_param->supervision_timeout = timeout;
|
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);
|
hci_dev_unlock(hdev);
|
||||||
|
|
Loading…
Add table
Reference in a new issue