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 <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-10-12 14:02:29 +03:00 committed by Anas Nashif
commit c136a2eb83
3 changed files with 53 additions and 0 deletions

View file

@ -2060,6 +2060,28 @@ int bt_conn_auth_pairing_confirm(struct bt_conn *conn)
} }
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ #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 bt_conn_init(void)
{ {
int err, i; int err, i;

View file

@ -167,6 +167,15 @@ struct bt_conn *bt_conn_lookup_handle(u16_t handle);
/* Compare an address with bt_conn destination address */ /* 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); 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 /* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection
* with the specific state * with the specific state
*/ */

View file

@ -109,6 +109,9 @@ struct acl_data {
/** BT_BUF_ACL_IN */ /** BT_BUF_ACL_IN */
u8_t type; u8_t type;
/* Index into the bt_conn storage array */
u8_t id;
/** ACL connection handle */ /** ACL connection handle */
u16_t 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; struct bt_hci_cp_host_num_completed_packets *cp;
u16_t handle = acl(buf)->handle; u16_t handle = acl(buf)->handle;
struct bt_hci_handle_count *hc; struct bt_hci_handle_count *hc;
struct bt_conn *conn;
net_buf_destroy(buf); net_buf_destroy(buf);
@ -141,6 +145,21 @@ static void report_completed_packet(struct net_buf *buf)
return; 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); BT_DBG("Reporting completed packet for handle %u", handle);
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, 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); flags = bt_acl_flags(handle);
acl(buf)->handle = bt_acl_handle(handle); acl(buf)->handle = bt_acl_handle(handle);
acl(buf)->id = BT_CONN_ID_INVALID;
net_buf_pull(buf, sizeof(*hdr)); net_buf_pull(buf, sizeof(*hdr));
@ -476,6 +496,8 @@ static void hci_acl(struct net_buf *buf)
return; return;
} }
acl(buf)->id = bt_conn_get_id(conn);
bt_conn_recv(conn, buf, flags); bt_conn_recv(conn, buf, flags);
bt_conn_unref(conn); bt_conn_unref(conn);
} }