diff --git a/subsys/bluetooth/host/classic/conn_br.c b/subsys/bluetooth/host/classic/conn_br.c index f57b33a1509..27f6dbb7d8b 100644 --- a/subsys/bluetooth/host/classic/conn_br.c +++ b/subsys/bluetooth/host/classic/conn_br.c @@ -143,3 +143,30 @@ const bt_addr_t *bt_conn_get_dst_br(const struct bt_conn *conn) return &conn->br.dst; } + +void bt_br_acl_recv(struct bt_conn *conn, struct net_buf *buf, bool complete) +{ + uint16_t acl_total_len; + struct bt_l2cap_hdr *hdr; + struct net_buf_simple_state state; + + do { + net_buf_simple_save(&buf->b, &state); + + hdr = (void *)buf->data; + acl_total_len = sys_le16_to_cpu(hdr->len) + sizeof(*hdr); + if (buf->len > acl_total_len) { + LOG_DBG("Multiple L2CAP packet (%u > %u)", buf->len, acl_total_len); + buf->len = acl_total_len; + } else if (buf->len < acl_total_len) { + LOG_ERR("Short packet (%u < %u)", buf->len, acl_total_len); + break; + } + bt_l2cap_recv(conn, net_buf_ref(buf), complete); + + net_buf_simple_restore(&buf->b, &state); + net_buf_pull(buf, acl_total_len); + } while (buf->len > 0); + + net_buf_unref(buf); +} diff --git a/subsys/bluetooth/host/classic/conn_br_internal.h b/subsys/bluetooth/host/classic/conn_br_internal.h index 7ca84974702..f40b9ea9e7f 100644 --- a/subsys/bluetooth/host/classic/conn_br_internal.h +++ b/subsys/bluetooth/host/classic/conn_br_internal.h @@ -10,3 +10,5 @@ */ int bt_hci_connect_br_cancel(struct bt_conn *conn); + +void bt_br_acl_recv(struct bt_conn *conn, struct net_buf *buf, bool complete); diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 4f8725663ee..03c5e1073a0 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -388,12 +388,11 @@ void bt_conn_reset_rx_state(struct bt_conn *conn) conn->rx = NULL; } -static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags) +static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, + uint8_t flags) { uint16_t acl_total_len; - bt_acl_set_ncp_sent(buf, false); - /* Check packet boundary flags */ switch (flags) { case BT_ACL_START: @@ -405,7 +404,7 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags LOG_DBG("First, len %u final %u", buf->len, (buf->len < sizeof(uint16_t)) ? 0 : sys_get_le16(buf->data)); - conn->rx = net_buf_ref(buf); + conn->rx = buf; break; case BT_ACL_CONT: if (!conn->rx) { @@ -435,6 +434,7 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags } net_buf_add_mem(conn->rx, buf->data, buf->len); + net_buf_unref(buf); break; default: /* BT_ACL_START_NO_FLUSH and BT_ACL_COMPLETE are not allowed on @@ -451,10 +451,6 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags /* Still not enough data received to retrieve the L2CAP header * length field. */ - bt_send_one_host_num_completed_packets(conn->handle); - bt_acl_set_ncp_sent(buf, true); - net_buf_unref(buf); - return; } @@ -462,16 +458,10 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags if (conn->rx->len < acl_total_len) { /* L2CAP frame not complete. */ - bt_send_one_host_num_completed_packets(conn->handle); - bt_acl_set_ncp_sent(buf, true); - net_buf_unref(buf); - return; } - net_buf_unref(buf); - - if (conn->rx->len > acl_total_len) { + if ((conn->type != BT_CONN_TYPE_BR) && (conn->rx->len > acl_total_len)) { LOG_ERR("ACL len mismatch (%u > %u)", conn->rx->len, acl_total_len); bt_conn_reset_rx_state(conn); return; @@ -481,10 +471,12 @@ static void bt_acl_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags buf = conn->rx; conn->rx = NULL; - __ASSERT(buf->ref == 1, "buf->ref %d", buf->ref); - LOG_DBG("Successfully parsed %u byte L2CAP packet", buf->len); - bt_l2cap_recv(conn, buf, true); + if (IS_ENABLED(CONFIG_BT_CLASSIC) && (conn->type == BT_CONN_TYPE_BR)) { + bt_br_acl_recv(conn, buf, true); + } else { + bt_l2cap_recv(conn, buf, true); + } } void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags) diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index eddd2eb2c72..88a77ce94bb 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -213,12 +213,7 @@ struct acl_data { struct bt_buf_data buf_data; /* Index into the bt_conn storage array */ - uint8_t index; - - /** Host has already sent a Host Number of Completed Packets - * for this buffer. - */ - bool host_ncp_sent; + uint8_t index; /** ACL connection handle */ uint16_t handle; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 45be1425f46..0c52fa437f5 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -235,11 +235,6 @@ static void handle_vs_event(uint8_t event, struct net_buf *buf, /* Other possible errors are handled by handle_event_common function */ } -void bt_acl_set_ncp_sent(struct net_buf *packet, bool value) -{ - acl(packet)->host_ncp_sent = value; -} - void bt_send_one_host_num_completed_packets(uint16_t handle) { if (!IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL)) { @@ -278,7 +273,9 @@ __weak void bt_testing_trace_event_acl_pool_destroy(struct net_buf *buf) #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) void bt_hci_host_num_completed_packets(struct net_buf *buf) { + struct bt_hci_cp_host_num_completed_packets *cp; uint16_t handle = acl(buf)->handle; + struct bt_hci_handle_count *hc; struct bt_conn *conn; uint8_t index = acl(buf)->index; @@ -288,10 +285,6 @@ void bt_hci_host_num_completed_packets(struct net_buf *buf) net_buf_destroy(buf); - if (acl(buf)->host_ncp_sent) { - return; - } - /* Do nothing if controller to host flow control is not supported */ if (!BT_CMD_TEST(bt_dev.supported_commands, 10, 5)) { return; @@ -312,7 +305,23 @@ void bt_hci_host_num_completed_packets(struct net_buf *buf) bt_conn_unref(conn); - bt_send_one_host_num_completed_packets(handle); + LOG_DBG("Reporting completed packet for handle %u", handle); + + buf = bt_hci_cmd_create(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, + sizeof(*cp) + sizeof(*hc)); + if (!buf) { + LOG_ERR("Unable to allocate new HCI command"); + return; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->num_handles = sys_cpu_to_le16(1); + + hc = net_buf_add(buf, sizeof(*hc)); + hc->handle = sys_cpu_to_le16(handle); + hc->count = sys_cpu_to_le16(1); + + bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf); } #endif /* defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) */ diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 226353f96e6..b6ebdba31a7 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -582,5 +582,3 @@ int bt_hci_le_read_max_data_len(uint16_t *tx_octets, uint16_t *tx_time); bool bt_drv_quirk_no_auto_dle(void); void bt_tx_irq_raise(void); -void bt_send_one_host_num_completed_packets(uint16_t handle); -void bt_acl_set_ncp_sent(struct net_buf *packet, bool value);