Bluetooth: host: Fallback to L2CAP for CPUP if rejected by master on LL

Fallback to L2CAP Connection Parameters Update Request if LL Connection
Update Request was rejected by remote device that has this marked as
supported in features. This can happen if procedure is supported only
by remote controller, but not enabled by host. This is connection
parameters update with iOS devices.

Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
This commit is contained in:
Szymon Janc 2018-11-06 13:48:07 +01:00 committed by Anas Nashif
commit b6979010c6
3 changed files with 34 additions and 10 deletions

View file

@ -202,9 +202,20 @@ static int send_conn_le_param_update(struct bt_conn *conn,
* 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)) ||
BT_FEAT_LE_CONN_PARAM_REQ_PROC(conn->le.features) &&
!atomic_test_bit(conn->flags, BT_CONN_SLAVE_PARAM_L2CAP)) ||
(conn->role == BT_HCI_ROLE_MASTER)) {
return bt_conn_le_conn_update(conn, param);
int rc;
rc = bt_conn_le_conn_update(conn, param);
/* store those in case of fallback to L2CAP */
if (rc == 0) {
conn->le.pending_latency = param->latency;
conn->le.pending_timeout = param->timeout;
}
return rc;
}
/* If remote master does not support LL Connection Parameters Request
@ -237,8 +248,8 @@ static void conn_le_update_timeout(struct k_work *work)
if (atomic_test_and_clear_bit(conn->flags, BT_CONN_SLAVE_PARAM_SET)) {
param = BT_LE_CONN_PARAM(conn->le.interval_min,
conn->le.interval_max,
conn->le.latency,
conn->le.timeout);
conn->le.pending_latency,
conn->le.pending_timeout);
send_conn_le_param_update(conn, param);
} else {
@ -1814,13 +1825,11 @@ int bt_conn_le_param_update(struct bt_conn *conn,
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
*/
/* store new conn params to be used by update timer */
conn->le.interval_min = param->interval_min;
conn->le.interval_max = param->interval_max;
conn->le.latency = param->latency;
conn->le.timeout = param->timeout;
conn->le.pending_latency = param->latency;
conn->le.pending_timeout = param->timeout;
atomic_set_bit(conn->flags, BT_CONN_SLAVE_PARAM_SET);
}

View file

@ -29,6 +29,7 @@ enum {
BT_CONN_AUTO_DATA_LEN, /* Auto data len change in progress */
BT_CONN_SLAVE_PARAM_UPDATE, /* If slave param update timer fired */
BT_CONN_SLAVE_PARAM_SET, /* If slave param were set from app */
BT_CONN_SLAVE_PARAM_L2CAP, /* If should force L2CAP for CPUP */
/* Total number of flags - must be at the end of the enum */
BT_CONN_NUM_FLAGS,
@ -46,6 +47,8 @@ struct bt_conn_le {
u16_t latency;
u16_t timeout;
u16_t pending_latency;
u16_t pending_timeout;
u8_t features[8];

View file

@ -1241,6 +1241,18 @@ static void le_conn_update_complete(struct net_buf *buf)
conn->le.latency = sys_le16_to_cpu(evt->latency);
conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout);
notify_le_param_updated(conn);
} else if (evt->status == BT_HCI_ERR_UNSUPP_REMOTE_FEATURE &&
conn->role == BT_HCI_ROLE_SLAVE &&
!atomic_test_and_set_bit(conn->flags,
BT_CONN_SLAVE_PARAM_L2CAP)) {
struct bt_le_conn_param param;
param.interval_min = conn->le.interval_min;
param.interval_max = conn->le.interval_max;
param.latency = conn->le.pending_latency;
param.timeout = conn->le.pending_timeout;
bt_l2cap_update_conn_param(conn, &param);
}
bt_conn_unref(conn);