diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index 221bc413c4b..3403e8d308b 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -52,9 +52,6 @@ config BT_ATT_SENT_CB_AFTER_TX Zephyr fork). It is a temporary solution allowing to control flow of GATT notifications with HID reports for HID use-case. - Enabling this option may require increasing CONFIG_BT_CONN_TX_MAX in - configuration, because ATT would use additional TX contexts. - config BT_EATT bool "Enhanced ATT Bearers support [EXPERIMENTAL]" depends on BT_L2CAP_ECRED diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index d0b6264aaed..f4d1f84c8cd 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -712,10 +712,12 @@ static int send_buf(struct bt_conn *conn, struct net_buf *buf, uint16_t frag_len = MIN(conn_mtu(conn), len); /* If ATT sent callback is delayed until data transmission - * is done by BLE controller, the transmitted buffer may - * have an additional reference. The reference is used to - * extend lifetime of the net buffer until the data - * transmission is confirmed by ACK of the remote. + * is done by BLE controller (CONFIG_BT_ATT_SENT_CB_AFTER_TX), + * the `chan_send` function from `att.c` introduces an additional + * reference. The reference is used to extend lifetime of the net + * buffer until the data transmission is confirmed by ACK of the + * remote (the reference is removed when the TX callback passed + * to `bt_l2cap_send_pdu` is called). * * send_buf function can be called multiple times, if buffer * has to be fragmented over HCI. In that case, the callback diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 0879163a8a1..df5c4a8f4bc 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -273,6 +273,21 @@ static void l2cap_chan_del(struct bt_l2cap_chan *chan) * `l2cap_chan_destroy()` as it is not called for fixed channels. */ while ((buf = k_fifo_get(&le_chan->tx_queue, K_NO_WAIT))) { + bt_conn_tx_cb_t cb = closure_cb(buf->user_data); + + if (cb) { + void *user_data = closure_data(buf->user_data); + + /* When bt_l2cap_send_pdu() succeeds, the stack takes ownership + * and must invoke the callback eventually. Since these PDUs will + * never be transmitted, invoke the callback now with an error. + * Note: We cannot use conn_tx_destroy() here because no bt_conn_tx + * struct has been allocated yet - the closure is still in the + * buf->user_data. + */ + cb(chan->conn, user_data, -ESHUTDOWN); + } + net_buf_unref(buf); } @@ -761,9 +776,11 @@ int bt_l2cap_send_pdu(struct bt_l2cap_le_chan *le_chan, struct net_buf *pdu, return -ENOTCONN; } - /* Allow for an additional buffer reference if callback is provided. This can be used to - * extend lifetime of the net buffer until the data transmission is confirmed by ACK of the - * remote. + /* If ATT sent callback is delayed until data transmission is done by BLE controller + * (CONFIG_BT_ATT_SENT_CB_AFTER_TX), the `chan_send` function from `att.c` introduces an + * additional reference. The reference is used to extend lifetime of the net buffer until + * the data transmission is confirmed by ACK of the remote (the reference is removed when + * the TX callback passed to `bt_l2cap_send_pdu` is called). */ if (pdu->ref > 1 + (cb ? 1 : 0)) { /* The host may alter the buf contents when fragmenting. Higher