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 <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2015-09-15 17:19:45 +03:00 committed by Anas Nashif
commit 4817c96b68
3 changed files with 28 additions and 1 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}
}