Bluetooth: Fix missing connection cleanup in some scenarios
If the TX thread is not in k_poll() when conn->state gets set to DISCONNECTED and a dummy buffer is pushed to conn->tx_queue the bt_conn_prepare_events() function would have failed to add the connection to the poll list for cleanup. To ensure the cleanup always happens introduce a new flag that indicates that a cleanup must happen. The extra benefit of the flag is that we no-longer need a dummy buffer, but can simply use the conn_change signal to wake up the TX thread. Change-Id: I369584d305261ab3666b931c786daff9d131d228 Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
fb3317b7a1
commit
6c995a5053
2 changed files with 31 additions and 18 deletions
|
@ -1020,6 +1020,25 @@ static bool send_buf(struct bt_conn *conn, struct net_buf *buf)
|
|||
|
||||
static struct k_poll_signal conn_change = K_POLL_SIGNAL_INITIALIZER();
|
||||
|
||||
static void conn_cleanup(struct bt_conn *conn)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
/* Give back any allocated buffers */
|
||||
while ((buf = net_buf_get(&conn->tx_queue, K_NO_WAIT))) {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
BT_ASSERT(!conn->pending_pkts);
|
||||
|
||||
bt_conn_reset_rx_state(conn);
|
||||
|
||||
/* Release the reference we took for the very first
|
||||
* state transition.
|
||||
*/
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
|
||||
int bt_conn_prepare_events(struct k_poll_event events[])
|
||||
{
|
||||
int i, ev_count = 0;
|
||||
|
@ -1037,6 +1056,12 @@ int bt_conn_prepare_events(struct k_poll_event events[])
|
|||
continue;
|
||||
}
|
||||
|
||||
if (conn->state == BT_CONN_DISCONNECTED &&
|
||||
atomic_test_and_clear_bit(conn->flags, BT_CONN_CLEANUP)) {
|
||||
conn_cleanup(conn);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1059,23 +1084,10 @@ void bt_conn_process_tx(struct bt_conn *conn)
|
|||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
if (conn->state == BT_CONN_DISCONNECTED &&
|
||||
atomic_test_and_clear_bit(conn->flags, BT_CONN_CLEANUP)) {
|
||||
BT_DBG("handle %u disconnected - cleaning up", conn->handle);
|
||||
|
||||
/* Give back any allocated buffers */
|
||||
while ((buf = net_buf_get(&conn->tx_queue, K_NO_WAIT))) {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
BT_ASSERT(!conn->pending_pkts);
|
||||
|
||||
bt_conn_reset_rx_state(conn);
|
||||
|
||||
/* Release the reference we took for the very first
|
||||
* state transition.
|
||||
*/
|
||||
bt_conn_unref(conn);
|
||||
|
||||
conn_cleanup(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1171,8 +1183,8 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
|
|||
k_delayed_work_cancel(&conn->le.update_work);
|
||||
}
|
||||
|
||||
net_buf_put(&conn->tx_queue,
|
||||
bt_conn_create_pdu(NULL, 0));
|
||||
atomic_set_bit(conn->flags, BT_CONN_CLEANUP);
|
||||
k_poll_signal(&conn_change, 0);
|
||||
/* The last ref will be dropped by the tx_thread */
|
||||
} else if (old_state == BT_CONN_CONNECT) {
|
||||
/* conn->err will be set in this case */
|
||||
|
|
|
@ -23,6 +23,7 @@ enum {
|
|||
BT_CONN_BR_PAIRING, /* BR connection in pairing context */
|
||||
BT_CONN_BR_NOBOND, /* SSP no bond pairing tracker */
|
||||
BT_CONN_BR_PAIRING_INITIATOR, /* local host starts authentication */
|
||||
BT_CONN_CLEANUP, /* Disconnected, pending cleanup */
|
||||
|
||||
/* Total number of flags - must be at the end of the enum */
|
||||
BT_CONN_NUM_FLAGS,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue