From c136a2eb83ed5fa1fc0cda91ef616440feeef23c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 12 Oct 2017 14:02:29 +0300 Subject: [PATCH] Bluetooth: Fix reporting packets for disconnected connections A connection might have gotten disconnected by the time that an ACL buffer is free up, in which case there is no need to send a HCI command for it. Signed-off-by: Johan Hedberg --- subsys/bluetooth/host/conn.c | 22 ++++++++++++++++++++++ subsys/bluetooth/host/conn_internal.h | 9 +++++++++ subsys/bluetooth/host/hci_core.c | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index afa3c3e012b..6c466eb087c 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2060,6 +2060,28 @@ int bt_conn_auth_pairing_confirm(struct bt_conn *conn) } #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ +u8_t bt_conn_get_id(struct bt_conn *conn) +{ + return conn - conns; +} + +struct bt_conn *bt_conn_lookup_id(u8_t id) +{ + struct bt_conn *conn; + + if (id >= ARRAY_SIZE(conns)) { + return NULL; + } + + conn = &conns[id]; + + if (!atomic_get(&conn->ref)) { + return NULL; + } + + return bt_conn_ref(conn); +} + int bt_conn_init(void) { int err, i; diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 9b18dd9e496..23b00104088 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -167,6 +167,15 @@ struct bt_conn *bt_conn_lookup_handle(u16_t handle); /* Compare an address with bt_conn destination address */ int bt_conn_addr_le_cmp(const struct bt_conn *conn, const bt_addr_le_t *peer); + +/* Helpers for identifying & looking up connections based on the the index to + * the connection list. This is useful for O(1) lookups, but can't be used + * e.g. as the handle since that's assigned to us by the controller. + */ +#define BT_CONN_ID_INVALID 0xff +u8_t bt_conn_get_id(struct bt_conn *conn); +struct bt_conn *bt_conn_lookup_id(u8_t id); + /* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection * with the specific state */ diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 658264594cb..3d161565a9f 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -109,6 +109,9 @@ struct acl_data { /** BT_BUF_ACL_IN */ u8_t type; + /* Index into the bt_conn storage array */ + u8_t id; + /** ACL connection handle */ u16_t handle; }; @@ -133,6 +136,7 @@ static void report_completed_packet(struct net_buf *buf) struct bt_hci_cp_host_num_completed_packets *cp; u16_t handle = acl(buf)->handle; struct bt_hci_handle_count *hc; + struct bt_conn *conn; net_buf_destroy(buf); @@ -141,6 +145,21 @@ static void report_completed_packet(struct net_buf *buf) return; } + conn = bt_conn_lookup_id(acl(buf)->id); + if (!conn) { + BT_WARN("Unable to look up conn with id 0x%02x", acl(buf)->id); + return; + } + + if (conn->state != BT_CONN_CONNECTED && + conn->state != BT_CONN_DISCONNECT) { + BT_WARN("Not reporting packet for non-connected conn"); + bt_conn_unref(conn); + return; + } + + bt_conn_unref(conn); + BT_DBG("Reporting completed packet for handle %u", handle); buf = bt_hci_cmd_create(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, @@ -458,6 +477,7 @@ static void hci_acl(struct net_buf *buf) flags = bt_acl_flags(handle); acl(buf)->handle = bt_acl_handle(handle); + acl(buf)->id = BT_CONN_ID_INVALID; net_buf_pull(buf, sizeof(*hdr)); @@ -476,6 +496,8 @@ static void hci_acl(struct net_buf *buf) return; } + acl(buf)->id = bt_conn_get_id(conn); + bt_conn_recv(conn, buf, flags); bt_conn_unref(conn); }