From 4817c96b6880a50326d2884f2d60eff28f95bba5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 15 Sep 2015 17:19:45 +0300 Subject: [PATCH] Bluetooth: Fix returning unacknowledged packets upon disconnection The core specification says the following about the treatment of unacknowledged packets when a disconnection occurs (page 773 in core spec 4.2): "When the Host receives a Disconnection Complete, Disconnection Physical Link Complete or Disconnection Logical Link Complete event, the Host shall assume that all unacknowledged HCI Data Packets that have been sent to the Controller for the returned Handle have been flushed, and that the corresponding data buffers have been freed. A Primary Controller does not have to notify the Host about this in a Number Of Completed Packets event" This patch adds tracking of unacknowledged packets on a per-connection basis and makes sure the semaphore that counts controller buffers is given back the appropriate amount when a disconnection occurs. Change-Id: I2ff4d12ffa50d4dda5b3e8c75fc75b4c0927e609 Signed-off-by: Johan Hedberg --- net/bluetooth/conn.c | 9 +++++++++ net/bluetooth/conn_internal.h | 2 ++ net/bluetooth/hci_core.c | 18 +++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/conn.c b/net/bluetooth/conn.c index 3fcf130e5a9..dfc6631bf1b 100644 --- a/net/bluetooth/conn.c +++ b/net/bluetooth/conn.c @@ -317,6 +317,8 @@ static void conn_tx_fiber(int arg1, int arg2) BT_DBG("passing buf %p len %u to driver\n", buf, buf->len); bt_dev.drv->send(buf); bt_buf_put(buf); + + conn->pending_pkts++; } BT_DBG("handle %u disconnected - cleaning up\n", conn->handle); @@ -326,6 +328,13 @@ static void conn_tx_fiber(int arg1, int arg2) bt_buf_put(buf); } + /* Return any unacknowledged packets */ + if (conn->pending_pkts) { + while (conn->pending_pkts--) { + nano_fiber_sem_give(&bt_dev.le_pkts_sem); + } + } + bt_conn_reset_rx_state(conn); BT_DBG("handle %u exiting\n", conn->handle); diff --git a/net/bluetooth/conn_internal.h b/net/bluetooth/conn_internal.h index 1863a62b70a..ec047cdee8e 100644 --- a/net/bluetooth/conn_internal.h +++ b/net/bluetooth/conn_internal.h @@ -60,6 +60,8 @@ struct bt_conn { bt_addr_le_t init_addr; bt_addr_le_t resp_addr; + uint8_t pending_pkts; + uint8_t encrypt; bt_security_t sec_level; bt_security_t required_sec_level; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 89b4359a9dd..06cd6758c0f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -473,14 +473,30 @@ static void hci_num_completed_packets(struct bt_buf *buf) for (i = 0; i < num_handles; i++) { uint16_t handle, count; + struct bt_conn *conn; handle = sys_le16_to_cpu(evt->h[i].handle); count = sys_le16_to_cpu(evt->h[i].count); BT_DBG("handle %u count %u\n", handle, count); - while (count--) + conn = bt_conn_lookup_handle(handle); + if (conn) { + if (conn->pending_pkts >= count) { + conn->pending_pkts -= count; + } else { + BT_ERR("completed packets mismatch: %u > %u\n", + count, conn->pending_pkts); + conn->pending_pkts = 0; + } + bt_conn_put(conn); + } else { + BT_ERR("No matching connection for handle %u", handle); + } + + while (count--) { nano_fiber_sem_give(&bt_dev.le_pkts_sem); + } } }