Skip to content

Conversation

alwa-nordic
Copy link
Contributor

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.

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]>
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a contract violation in the Bluetooth L2CAP layer where transmission callbacks were not being invoked when channels are deleted, leaving callers without notification that their buffers will never be transmitted.

  • Added callback extraction and invocation before buffer cleanup in bt_l2cap_chan_del()
  • Callbacks are invoked with -ESHUTDOWN error code to indicate transmission failure
  • Maintains consistency with other transmission failure paths in the codebase

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link

sonarqubecloud bot commented Oct 6, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant