Bluetooth: Fix connection parameters update
This fixes a few issues with the handling of Connection Parameter update in the Host: - starting conn param update timer as master - ignoring 5 seconds slave timer when calling bt_conn_le_param_update - starting conn param update timer on every PHY update Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
This commit is contained in:
parent
73c2178027
commit
75405f5613
3 changed files with 81 additions and 27 deletions
|
@ -190,16 +190,43 @@ bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void le_conn_update(struct k_work *work)
|
||||
static int send_conn_le_param_update(struct bt_conn *conn,
|
||||
const struct bt_le_conn_param *param)
|
||||
{
|
||||
BT_DBG("conn %p features 0x%02x params (%d-%d %d %d)", conn,
|
||||
conn->le.features[0], param->interval_min,
|
||||
param->interval_max, param->latency, param->timeout);
|
||||
|
||||
/* Use LE connection parameter request if both local and remote support
|
||||
* it; or if local role is master then use LE connection update.
|
||||
*/
|
||||
if ((BT_FEAT_LE_CONN_PARAM_REQ_PROC(bt_dev.le.features) &&
|
||||
BT_FEAT_LE_CONN_PARAM_REQ_PROC(conn->le.features)) ||
|
||||
(conn->role == BT_HCI_ROLE_MASTER)) {
|
||||
return bt_conn_le_conn_update(conn, param);
|
||||
}
|
||||
|
||||
/* If remote master does not support LL Connection Parameters Request
|
||||
* Procedure
|
||||
*/
|
||||
return bt_l2cap_update_conn_param(conn, param);
|
||||
}
|
||||
|
||||
static void conn_le_update_timeout(struct k_work *work)
|
||||
{
|
||||
struct bt_conn_le *le = CONTAINER_OF(work, struct bt_conn_le,
|
||||
update_work);
|
||||
struct bt_conn *conn = CONTAINER_OF(le, struct bt_conn, le);
|
||||
const struct bt_le_conn_param *param;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
||||
conn->state == BT_CONN_CONNECT) {
|
||||
bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
conn->role == BT_CONN_ROLE_MASTER) {
|
||||
if (conn->state == BT_CONN_CONNECT) {
|
||||
bt_conn_disconnect(conn,
|
||||
BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -208,7 +235,9 @@ static void le_conn_update(struct k_work *work)
|
|||
conn->le.latency,
|
||||
conn->le.timeout);
|
||||
|
||||
bt_conn_le_param_update(conn, param);
|
||||
send_conn_le_param_update(conn, param);
|
||||
|
||||
atomic_set_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE);
|
||||
}
|
||||
|
||||
static struct bt_conn *conn_new(void)
|
||||
|
@ -1385,7 +1414,7 @@ struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer)
|
|||
conn->type = BT_CONN_TYPE_LE;
|
||||
conn->le.interval_min = BT_GAP_INIT_CONN_INT_MIN;
|
||||
conn->le.interval_max = BT_GAP_INIT_CONN_INT_MAX;
|
||||
k_delayed_work_init(&conn->le.update_work, le_conn_update);
|
||||
k_delayed_work_init(&conn->le.update_work, conn_le_update_timeout);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
@ -1749,22 +1778,27 @@ int bt_conn_le_param_update(struct bt_conn *conn,
|
|||
return -EALREADY;
|
||||
}
|
||||
|
||||
/* Cancel any pending update */
|
||||
k_delayed_work_cancel(&conn->le.update_work);
|
||||
|
||||
/* Use LE connection parameter request if both local and remote support
|
||||
* it; or if local role is master then use LE connection update.
|
||||
*/
|
||||
if ((BT_FEAT_LE_CONN_PARAM_REQ_PROC(bt_dev.le.features) &&
|
||||
BT_FEAT_LE_CONN_PARAM_REQ_PROC(conn->le.features)) ||
|
||||
(conn->role == BT_HCI_ROLE_MASTER)) {
|
||||
return bt_conn_le_conn_update(conn, param);
|
||||
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
|
||||
conn->role == BT_CONN_ROLE_MASTER) {
|
||||
return send_conn_le_param_update(conn, param);
|
||||
}
|
||||
|
||||
/* If remote master does not support LL Connection Parameters Request
|
||||
* Procedure
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
|
||||
/* if slave conn param update timer expired just send request */
|
||||
if (atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE)) {
|
||||
return send_conn_le_param_update(conn, param);
|
||||
}
|
||||
|
||||
/* store new conn params to be used by update timer
|
||||
* TODO this overwrites current latency and timeout
|
||||
*/
|
||||
return bt_l2cap_update_conn_param(conn, param);
|
||||
conn->le.interval_min = param->interval_min;
|
||||
conn->le.interval_max = param->interval_max;
|
||||
conn->le.latency = param->latency;
|
||||
conn->le.timeout = param->timeout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_conn_disconnect(struct bt_conn *conn, u8_t reason)
|
||||
|
|
|
@ -27,6 +27,7 @@ enum {
|
|||
BT_CONN_CLEANUP, /* Disconnected, pending cleanup */
|
||||
BT_CONN_AUTO_PHY_UPDATE, /* Auto-update PHY */
|
||||
BT_CONN_AUTO_DATA_LEN, /* Auto data len change in progress */
|
||||
BT_CONN_SLAVE_PARAM_UPDATE, /* If slave param update timer fired */
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
BT_CONN_NUM_FLAGS,
|
||||
|
|
|
@ -736,16 +736,23 @@ static int hci_le_set_phy(struct bt_conn *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void update_conn_param(struct bt_conn *conn)
|
||||
static void slave_update_conn_param(struct bt_conn *conn)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BT_PERIPHERAL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* don't start timer again on PHY update etc */
|
||||
if (atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_UPDATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Core 4.2 Vol 3, Part C, 9.3.12.2
|
||||
* The Peripheral device should not perform a Connection Parameter
|
||||
* Update procedure within 5 s after establishing a connection.
|
||||
*/
|
||||
k_delayed_work_submit(&conn->le.update_work,
|
||||
conn->role == BT_HCI_ROLE_MASTER ? K_NO_WAIT :
|
||||
CONN_UPDATE_TIMEOUT);
|
||||
k_delayed_work_submit(&conn->le.update_work, CONN_UPDATE_TIMEOUT);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
|
@ -938,7 +945,10 @@ static void le_enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
|
|||
}
|
||||
}
|
||||
|
||||
update_conn_param(conn);
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
|
||||
conn->role == BT_CONN_ROLE_SLAVE) {
|
||||
slave_update_conn_param(conn);
|
||||
}
|
||||
|
||||
done:
|
||||
bt_conn_unref(conn);
|
||||
|
@ -1029,7 +1039,10 @@ static void le_remote_feat_complete(struct net_buf *buf)
|
|||
}
|
||||
}
|
||||
|
||||
update_conn_param(conn);
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
|
||||
conn->role == BT_CONN_ROLE_SLAVE) {
|
||||
slave_update_conn_param(conn);
|
||||
}
|
||||
|
||||
done:
|
||||
bt_conn_unref(conn);
|
||||
|
@ -1058,7 +1071,10 @@ static void le_data_len_change(struct net_buf *buf)
|
|||
goto done;
|
||||
}
|
||||
|
||||
update_conn_param(conn);
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
|
||||
conn->role == BT_CONN_ROLE_SLAVE) {
|
||||
slave_update_conn_param(conn);
|
||||
}
|
||||
|
||||
done:
|
||||
bt_conn_unref(conn);
|
||||
|
@ -1095,7 +1111,10 @@ static void le_phy_update_complete(struct net_buf *buf)
|
|||
}
|
||||
}
|
||||
|
||||
update_conn_param(conn);
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
|
||||
conn->role == BT_CONN_ROLE_SLAVE) {
|
||||
slave_update_conn_param(conn);
|
||||
}
|
||||
|
||||
done:
|
||||
bt_conn_unref(conn);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue