Bluetooth: Add delay before sending Connection Update

BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] page 368:

  "The Peripheral device should not perform a Connection Parameter Update
   procedure within T GAP (conn_pause_peripheral) after establishing a
   connection."

> HCI Event: LE Meta Event (0x3e) plen 19 [hci1] 11:14:22.496358
      LE Connection Complete (0x01)
        Status: Success (0x00)
        Handle: 74
        Role: Slave (0x01)
        Peer address type: Public (0x00)
        Peer address: 7C:7A:91:18:82:46 (Intel Corporate)
        Connection interval: 70.00 msec (0x0038)
        Connection latency: 0.00 msec (0x0000)
        Supervision timeout: 420 msec (0x002a)
        Master clock accuracy: 0x01
...[5 seconds interval]...
< ACL Data TX: Handle 74 flags 0x00 dlen 16 [hci1] 11:14:27.493541
      LE L2CAP: Connection Parameter Update Request (0x12) ident 1 len 8
        Min interval: 24
        Max interval: 40
        Slave latency: 0
        Timeout multiplier: 42

Change-Id: Ibb301ea00c127542ba299ad0b94825ad1ed05c5c
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2016-05-23 16:17:20 +03:00
commit 562b491182
3 changed files with 41 additions and 10 deletions

View file

@ -136,6 +136,21 @@ void notify_le_param_updated(struct bt_conn *conn)
} }
} }
static void le_conn_update(struct nano_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;
param = BT_LE_CONN_PARAM(conn->le.interval_min,
conn->le.interval_max,
conn->le.latency,
conn->le.timeout);
bt_conn_le_param_update(conn, param);
}
static struct bt_conn *conn_new(void) static struct bt_conn *conn_new(void)
{ {
struct bt_conn *conn = NULL; struct bt_conn *conn = NULL;
@ -1005,6 +1020,7 @@ struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer)
conn->type = BT_CONN_TYPE_LE; conn->type = BT_CONN_TYPE_LE;
conn->le.interval_min = BT_GAP_INIT_CONN_INT_MIN; conn->le.interval_min = BT_GAP_INIT_CONN_INT_MIN;
conn->le.interval_max = BT_GAP_INIT_CONN_INT_MAX; conn->le.interval_max = BT_GAP_INIT_CONN_INT_MAX;
nano_delayed_work_init(&conn->le.update_work, le_conn_update);
return conn; return conn;
} }
@ -1086,6 +1102,10 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
notify_connected(conn); notify_connected(conn);
} }
/* Cancel Connection Update if it is pending */
if (conn->type == BT_CONN_TYPE_LE)
nano_delayed_work_cancel(&conn->le.update_work);
/* Release the reference we took for the very first /* Release the reference we took for the very first
* state transition. * state transition.
*/ */
@ -1289,6 +1309,9 @@ int bt_conn_le_param_update(struct bt_conn *conn,
return -EALREADY; return -EALREADY;
} }
/* Cancel any pending update */
nano_delayed_work_cancel(&conn->le.update_work);
if ((conn->role == BT_HCI_ROLE_SLAVE) && if ((conn->role == BT_HCI_ROLE_SLAVE) &&
!(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) { !(bt_dev.le.features[0] & BT_HCI_LE_CONN_PARAM_REQ_PROC)) {
return bt_l2cap_update_conn_param(conn, param); return bt_l2cap_update_conn_param(conn, param);

View file

@ -3,7 +3,7 @@
*/ */
/* /*
* Copyright (c) 2015-2016 Intel Corporation * Copyright (c) 2015 Intel Corporation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include <misc/nano_work.h>
typedef enum __packed { typedef enum __packed {
BT_CONN_DISCONNECTED, BT_CONN_DISCONNECTED,
@ -50,6 +51,9 @@ struct bt_conn_le {
uint16_t timeout; uint16_t timeout;
uint8_t features[8]; uint8_t features[8];
/* Delayed work for connection update handling */
struct nano_delayed_work update_work;
}; };
#if defined(CONFIG_BLUETOOTH_BREDR) #if defined(CONFIG_BLUETOOTH_BREDR)
@ -135,7 +139,7 @@ void bt_conn_ssp_auth(struct bt_conn *conn, uint32_t passkey);
/* Look up an existing connection */ /* Look up an existing connection */
struct bt_conn *bt_conn_lookup_handle(uint16_t handle); struct bt_conn *bt_conn_lookup_handle(uint16_t handle);
/* Look up a connection state. For NULL peer, returns the first connection /* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection
* with the specific state * with the specific state
*/ */
struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer, struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer,

View file

@ -58,6 +58,9 @@
#define BT_DBG(fmt, ...) #define BT_DBG(fmt, ...)
#endif #endif
/* Peripheral timeout to initialize Connection Parameter Update procedure */
#define CONN_UPDATE_TIMEOUT (5 * sys_clock_ticks_per_sec)
/* Stacks for the fibers */ /* Stacks for the fibers */
static BT_STACK_NOINIT(rx_fiber_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE); static BT_STACK_NOINIT(rx_fiber_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE);
static BT_STACK_NOINIT(cmd_tx_fiber_stack, 256); static BT_STACK_NOINIT(cmd_tx_fiber_stack, 256);
@ -590,15 +593,16 @@ static int hci_le_read_remote_features(struct bt_conn *conn)
return 0; return 0;
} }
static int update_conn_param(struct bt_conn *conn) static void update_conn_param(struct bt_conn *conn)
{ {
const struct bt_le_conn_param *param; /*
* Core 4.2 Vol 3, Part C, 9.3.12.2
param = BT_LE_CONN_PARAM(conn->le.interval_min, * The Peripheral device should not perform a Connection Parameter
conn->le.interval_max, * Update procedure within 5 s after establishing a connection.
conn->le.latency, */
conn->le.timeout); nano_delayed_work_submit(&conn->le.update_work,
return bt_conn_le_param_update(conn, param); conn->role == BT_HCI_ROLE_MASTER ? TICKS_NONE :
CONN_UPDATE_TIMEOUT);
} }
static void le_conn_complete(struct net_buf *buf) static void le_conn_complete(struct net_buf *buf)