Skip to content

Commit d4d735f

Browse files
committed
Bluetooth: Host: Invoke tx callbacks when channel is deleted
When bt_l2cap_send_pdu() succeeds, it transfers buffer ownership to the stack, which must eventually invoke the provided callback. This contract is honored in all paths where transmission becomes impossible: - Normal transmission: callback invoked with err=0 after HCI Number of Completed Packets event (tx_notify_process) - Send errors (after tx allocated): callback invoked with err=-ESHUTDOWN via conn_tx_destroy - Send errors (before tx allocated): callback invoked with the specific error code in send_buf error_return path - Connection disconnect: callbacks invoked with err=-ESHUTDOWN via process_unack_tx -> conn_tx_destroy for all PDUs in tx_pending However, when a channel is deleted (l2cap_chan_del), PDUs remaining in the tx_queue are dropped without invoking their callbacks, violating the ownership contract. Fix this by extracting and invoking any non-NULL callbacks from the closure stored in buf->user_data before releasing the buffers. The callback is invoked with err=-ESHUTDOWN, making this path analogous to process_unack_tx: both drain queues of unsent PDUs when transmission becomes impossible due to external events (channel deletion vs connection disconnect). The only difference is the buffer lifecycle stage - in l2cap_chan_del, PDUs are still in tx_queue (closure in buf->user_data), while in process_unack_tx, they've progressed to tx_pending (callback in bt_conn_tx struct). Note: conn_tx_destroy() cannot be used here because no bt_conn_tx struct has been allocated yet - the closure is still in buf->user_data. Signed-off-by: Aleksander Wasaznik <[email protected]>
1 parent b3ccee4 commit d4d735f

File tree

1 file changed

+15
-0
lines changed

1 file changed

+15
-0
lines changed

subsys/bluetooth/host/l2cap.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,21 @@ void bt_l2cap_chan_del(struct bt_l2cap_chan *chan)
266266
* `l2cap_chan_destroy()` as it is not called for fixed channels.
267267
*/
268268
while ((buf = k_fifo_get(&le_chan->tx_queue, K_NO_WAIT))) {
269+
bt_conn_tx_cb_t cb = closure_cb(buf->user_data);
270+
271+
if (cb) {
272+
void *user_data = closure_data(buf->user_data);
273+
274+
/* When bt_l2cap_send_pdu() succeeds, the stack takes ownership
275+
* and must invoke the callback eventually. Since these PDUs will
276+
* never be transmitted, invoke the callback now with an error.
277+
* Note: We cannot use conn_tx_destroy() here because no bt_conn_tx
278+
* struct has been allocated yet - the closure is still in the
279+
* buf->user_data.
280+
*/
281+
cb(chan->conn, user_data, -ESHUTDOWN);
282+
}
283+
269284
net_buf_unref(buf);
270285
}
271286

0 commit comments

Comments
 (0)