Skip to content

Conversation

@chejinxian
Copy link
Contributor

Note: Please adhere to Contributing Guidelines.

Summary

  1. Cherry-pick the L2CAP modification patch from the Zephyr community.

  2. Adapt the related patch to support the multi-controller feature.

  3. Resolve compilation issues in the multi-controller shell adaptation to ensure that L2CAP-related commands can be use.

Impact

The actual functionality of protocols and profiles implemented above the L2CAP layer.

@chejinxian chejinxian requested a review from hyson710 as a code owner November 7, 2025 01:59
@CLAassistant
Copy link

CLAassistant commented Nov 7, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 15 committers have signed the CLA.

✅ chejinxian
✅ chengkai15
❌ sjanc
❌ alwa-nordic
❌ jhedberg
❌ makeshi
❌ lylezhu2012
❌ jerryyang35
❌ CC0918
❌ HaavardRei
❌ PavelVPV
❌ MarkWangChinese
❌ ceolin
❌ aahmed-dewinelabs
❌ mjchen0
You have signed the CLA already but the status is still pending? Let us recheck it.

if (seg->len > sdu_remaining) {
LOG_WRN("L2CAP RX PDU total exceeds SDU");
bt_l2cap_chan_disconnect(&chan->chan);
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM:fix exception

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM:remove invalid Header

* request resolves or times out we will act on all the channels in the
* supplied array, using the ident field to find them.
*/
l2cap_chan_send_req(chans[0], buf, L2CAP_CONN_TIMEOUT);
Copy link
Contributor

Choose a reason for hiding this comment

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

why reconfig was send by chans[0]?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please refer to the comments. Any L2CAP channel that receives a reconfiguration response or timeout can operate all associated channels based on the corresponding identifier.
For example:

static void le_ecred_reconf_rsp(struct bt_l2cap *l2cap, uint8_t ident,
				struct net_buf *buf)
{
	struct bt_conn *conn = l2cap->chan.chan.conn;
	struct bt_l2cap_ecred_reconf_rsp *rsp;
	struct bt_l2cap_le_chan *ch;
	uint16_t result;

	if (buf->len != sizeof(*rsp)) {
		LOG_ERR("Invalid ecred reconf rsp packet size (%u != %zu)",
			buf->len, sizeof(*rsp));
		return;
	}

	rsp = net_buf_pull_mem(buf, sizeof(*rsp));
	result = sys_le16_to_cpu(rsp->result);

	while ((ch = l2cap_lookup_ident(conn, ident, BT_L2CAP_ECRED_RECONF_REQ))) {
		/* Stop timer started on REQ send. The timer is only set on one
		 * of the channels, but we don't want to make assumptions on
		 * which one it is.
		 */
		k_work_cancel_delayable(&ch->rtx_work);

		if (result == BT_L2CAP_LE_SUCCESS) {
			ch->rx.mtu = ch->pending_rx_mtu;
		}

		ch->pending_rx_mtu = 0;
		ch->ident = 0U;
		ch->pending_req = 0U;

		if (ch->chan.ops->reconfigured) {
			ch->chan.ops->reconfigured(&ch->chan);
		}
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Therefore, at this step, it doesn't matter which channel is selected; however, the advantage of choosing chans[0] is that there's no need to verify the index validity.

By default, the number of incoming ACL data buffers is equal to
CONFIG_BT_MAX_CONN + 1.

config BT_BUF_ACL_RX_COUNT
Copy link
Contributor

Choose a reason for hiding this comment

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

please check how to fix zblue current config

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a notable issue, but we can proceed with the default value currently. Just depend on CONFIG_BT_MAX_CONN.

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM:add dynamic PSM feature

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM:fix multi Controller bug

break;
default:
timeout = K_FOREVER;
if (k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

As vela had disable RX WQ, then it may bt_att_chan_create_pdu fail when buf was exhausted. do we need to check that case ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This issue requires attention since almost all buffer allocations in the Zephyr protocol stack now occur within sys work queue threads, inherently creating scenarios with extensive use of K_NO_WAIT. However, validation through testing remains necessary to confirm this behavior.

This commit itself doesn't affect the logic, as the actual modification of K_NO_WAIT usage is localized in this code section:

struct net_buf bt_conn_create_pdu_timeout(struct net_buf_pool pool,
size_t reserve, k_timeout_t timeout)
#endif
{
struct net_buf *buf;

/*
* PDU must not be allocated from ISR as we block with 'K_FOREVER'
* during the allocation
*/
__ASSERT_NO_MSG(!k_is_in_isr());

if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) &&
k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) {
LOG_WRN("Timeout discarded. No blocking in syswq.");
timeout = K_NO_WAIT;
}

size_t reserve,
k_timeout_t timeout)
{
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

dito

break;
}

if (chan->conn->sec_level < br_chan->required_sec_level &&
Copy link
Contributor

Choose a reason for hiding this comment

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

@zhongzhijie1 could you please check if it was necessary to disconnect ACL connection?

((conn->br.remote_auth == BT_HCI_NO_BONDING_MITM) &&
(ssp_pair_method(conn) > JUST_WORKS))) {
return conn->br.remote_auth;
return conn->br.remote_auth | mitm;
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM:fix nobonding case MITM

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM

}

l2cap_send(conn, BT_L2CAP_CID_BR_SIG, buf);
if (bt_l2cap_br_send_cb(conn, BT_L2CAP_CID_BR_SIG, buf, l2cap_br_conn_rsp_sent_cb,
Copy link
Contributor

Choose a reason for hiding this comment

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

why should it send l2cap connection before disconnect ACL?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The disconnection occurred because the security requirements of L2CAP were not met; the reason must be communicated to the other party.

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM


#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
#if defined(CONFIG_BT_L2CAP_LOG_LEVEL_DBG)
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL) && defined(CONFIG_BT_L2CAP_LOG_LEVEL_DBG)
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

}

LOG_DBG("chan %p buf %p len %zu", br_chan, buf, buf->len);
LOG_DBG("chan %p buf %p len %u", br_chan, buf, buf->len);
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

/** L2CAP Endpoint Link Mode. Retransmission mode. */
#define BT_L2CAP_BR_LINK_MODE_RET 0x01
/** L2CAP Endpoint Link Mode. Flow control mode. */
#define BT_L2CAP_BR_LINK_MODE_FC 0x02
Copy link
Contributor

Choose a reason for hiding this comment

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

mark: big change for L2CAP flow control feature

Copy link
Contributor

@chengkai15 chengkai15 left a comment

Choose a reason for hiding this comment

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

LGTM

#define L2CAP_BR_S_FRAME_UD_FLAG 0xffffff00
#define L2CAP_BR_IS_S_FRAME(flag) \
((((uint32_t)flag) & L2CAP_BR_S_FRAME_FLAG_MASK) == L2CAP_BR_S_FRAME_UD_FLAG)
((POINTER_TO_UINT(flag) & L2CAP_BR_S_FRAME_FLAG_MASK) == L2CAP_BR_S_FRAME_UD_FLAG)
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

#if defined(CONFIG_BT_L2CAP_RET_FC)
if (BR_CHAN(chan)->tx.fcs == BT_L2CAP_BR_FCS_16BIT) {
/* If peer enables FCS, local also needs to enable it. */
if (BR_CHAN(chan)->tx.fcs != BR_CHAN(chan)->rx.fcs) {
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

struct bt_conn *conn = l2cap->chan.chan.conn;
struct bt_l2cap_br_chan *chan;

do {
Copy link
Contributor

Choose a reason for hiding this comment

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

ident is unique,maybe we only need to disconnect current L2CAP connection?


atomic_set_bit(l2cap->chan.flags, L2CAP_FLAG_SIG_INFO_PENDING);
l2cap->info_ident = l2cap_br_get_ident(conn->hdev);
l2cap->chan.ident = l2cap_br_get_ident(conn->hdev);
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

br_chan->rx.max_transmit = opt_ret_fc->max_transmit;
br_chan->rx.max_window = sys_le16_to_cpu(opt_ret_fc->tx_windows_size);
br_chan->rx.mps = sys_le16_to_cpu(opt_ret_fc->mps);

Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

continue;
}

if (ident == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

was it maybe last ident? and if so l2cap_br_send_reject would reject last cmd

atomic_clear_bit(BR_CHAN(chan)->flags, L2CAP_FLAG_CONN_PENDING);
break;
case BT_L2CAP_BR_PENDING:
br_chan->ident = ident;
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

goto failed;
}

if (br_chan->_sdu_len < seg->len) {
Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

mtu = sys_le16_to_cpu(opt_mtu->mtu);
if (mtu < L2CAP_BR_MIN_MTU) {
result = BT_L2CAP_CONF_UNACCEPT;
result = BT_L2CAP_CONF_REJECT;
Copy link
Contributor

Choose a reason for hiding this comment

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

could select min MTU?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It means config param invalid according to SPEC.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the parameters provided by the other party are incorrect, we should consider it an anomaly on their part and disconnect without hesitation.

chejinxian and others added 29 commits November 18, 2025 09:38
…ntifier retrieval

bug: v/76605

Resolve conflicts that occurred when synchronizing the L2CAP Echo implementation from the community.

Adapt the L2CAP Echo implementation to support the multi-controller feature

Signed-off-by: chejinxian1 <[email protected]>
Support zero-length SDU sending if the L2CAP channel connection is not
in basic mode.

Flag the zero-length SDU buffer and clear it if it has been processed.

Signed-off-by: Lyle Zhu <[email protected]>
If the received data length is less than 2 in none basic mode, the
L2CAP channel connection will be dropped.

Only check the received data length if the `SAR` is
`BT_L2CAP_CONTROL_SAR_START`.

Signed-off-by: Lyle Zhu <[email protected]>
Ensure that the BR/EDR L2CAP RX MTU is limited to the configured
BT_L2CAP_RX_MTU value during channel configuration.

This change prevent potential buffer overflow issues when receiving
data larger than the configured buffer size.

Signed-off-by: Jiawei Yang <[email protected]>
Channel tx_queue purging on disconnect was inconsistently handled
by the different channels: iso, l2cap, l2cap_br.

iso channels handled purging in the tx_data_pull hook.

l2cap and l2cap_br did the purging in channel delete functions
and did not expect tx_data_pull to be called for a disconnected
channel. Their data_pull functions could return a ptr to a
net_buf that was still on the tx_queue, which is problematic
when the conn tx_processor unrefs the returned buffer resulting
in multiple calls to the buf destroy function.

To make things consistent and correct, remove the code that tries
to purge tx_queues in the tx_processor and only do purging in
the channels themselves when they are deleted/disconnected.

Also refactor and clarify referencing of the net_buf returned
by tx_data_pull. It was confusing who had a reference and
when, which could vary depending on the length of the original
buffer. There are three cases: the buffer length is less
than the tx.mps, greater the mps but less than the mtu so
requiring segementation but not fragmentation, or greater than
both mps and mtu so requiring both segmentation and fragmentation.
The conn layer would increase the refcnt if the length was
greater than the mtu, but not have any awareness of whether
the net_buf was still on the tx_queue or not.

Now it is the tx_data_pull callbacks responsibitity to increment
the reference count if it is returning a pointer to a net_buf
that it is still keeping on the tx_queue for segmentation purposes.
The conn layer will now always transfer that reference into a
fragment view and not conditional it on the length relative to
the mtu, and always decrement the reference to the parent when
the fragment is destroyed.

So there is no risk of decrementing a reference to a net buf
that might still be on a tx_queue, which simplifies error
handling in particular.

Also add error handling paths for when asserts are not enabled.

Signed-off-by: Mike J. Chen <[email protected]>
When peer monitor and retransmission timeout are zero, set them to the
default values. This ensures that the monitor timeout is always a valid
value to avoid the L2CAP BR timer work queue hang.

Signed-off-by: Make Shi <[email protected]>
When the returned buffer is a `NULL` of the pull function, it means
there is not any data needs to be sent. However maybe there is any
frame pending on other L2CAP channel needs to be sent over the same
ACL connection.

Re-trigger the TX processor. It will call the pull function again
and the pending buffer will be pulled from following L2CAP.

Signed-off-by: Lyle Zhu <[email protected]>
When received the valid S frame, the retransmission timer should not
be restarted if unacknowledged I-frames have been sent but the
retransmission timer has not elapsed.

Signed-off-by: Lyle Zhu <[email protected]>
Now in other mode rather than basic mode, configuration parameters
include MTU, Flush Time and QoS have been checked.
But in basic mode, they also need to be checked, so the code about this
should not be controlled by macro CONFIG_BT_L2CAP_RET_FC.

Signed-off-by: Cheng Chang <[email protected]>
The implementation used BT_L2CAP_ECRED_MIN_MTU to check the lower limits
of both MTU and MPS, instead of BT_L2CAP_ECRED_MIN_MPS for MPS. While
these are the same here, confusion may arise. This commit fixes the
confusion.

Signed-off-by: Håvard Reierstad <[email protected]>
It needs to do l2cap unregister operation from app

Signed-off-by: Cheng Kai <[email protected]>
bug: v/76605

Add the `bt_l2cap_br_server_unregister_mc` interface and modify the list operations in `bt_l2cap_br_server_register_mc` to support the multi-controller feature.

Signed-off-by: chejinxian1 <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
Adds a missing requirement from Core Spec V6.0 Vol 3.A chapters 10.1
and 10.2 to ignore L2CAP_FLOW_CONTROL_CREDIT_IND packets with the
credit value set to 0.

Matches existing credit-related functions by checking that the CID
is in the dynamic range (you can't add credits to fixed channels).

Signed-off-by: Håvard Reierstad <[email protected]>
Check whether the connection response parameters both with and without
ECRED are within the valid ranges from the Bluetooth Core Specification
(part 3.A.4 v6.0). Changes validation checks in requests to match the
same pattern.

Signed-off-by: Håvard Reierstad <[email protected]>
L2CAP channels will now, along with the ident, store the opcode of the
pending request. This commit expands the ident lookup function to also
compare received response types to this opcode, and will ignore
unsolicited responses.

Setting of idents for channels are moved after verification of buffer
allocation for the request to be sent. A TODO is added for improving
this functionality at a later time.

Signed-off-by: Håvard Reierstad <[email protected]>
Add a Kconfig `BT_L2CAP_CONNLESS` to enable the feature.

Add an API `bt_l2cap_br_connless_register()` to register the monitor
to receive the unicast connectionless data.

Add an API `bt_l2cap_br_connless_unregister()` to unregister the
registered callbacks.

Add an API `bt_l2cap_br_connless_send()` to send unicast
connectionless data.

Signed-off-by: Lyle Zhu <[email protected]>
Iterate over the list of connections to find a connection
that is able to send data, instead of returning NULL if
the first connection can't send data.

This solves the problem with starvation of other connections.

Signed-off-by: Ahmed Ahmed <[email protected]>
A public API call that sends ACL data — for example, `bt_gatt_notify` —
can be invoked from a preemptive thread context. This API, in turn,
calls the `raise_data_ready` function, which adds an L2CAP channel to
the `l2cap_data_ready` list.

The atomic variable used to create a critical section around
`l2cap_data_ready` did not work, because a preemptive thread can be
pre-empted at any time. This means that regardless of the `atomic_set`
result, we cannot trust it — the thread could be preempted after the
call, and the atomic variable state could be changed (specifically by
the TX processor in this case). The same issue applies to
`bt_conn_data_ready`, which is called next.

When making an L2CAP channel ready for sending data, we need to use a
critical section when appending a channel to the `l2cap_data_ready`
list. The same applies to the `conn_ready` list.

Since cooperative threads can only be rescheduled explicitly, we must
ensure there are no rescheduling points when accessing either the
`l2cap_data_ready` or `conn_ready` lists.

For `l2cap_data_ready`, this occurs in `get_ready_chan`, which is called
from `l2cap_data_pull`, which in turn is called by the TX processor. For
`conn_ready`, it occurs in `get_conn_ready`, which is also called from
the TX processor. Both functions have no rescheduling points when
working with their respective lists, so they do not require a critical
section.

This change removes the atomic variables previously used to create a
critical section for both lists, as they were ineffective. Instead,
`k_sched_lock`/`k_sched_unlock` are used where code may be executed from
a preemptive thread context. The `sys_slist_find` function is used to
check whether a channel or connection is already in the corresponding
list.

Fixes #89705

Signed-off-by: Pavel Vasilyev <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
There is an issue found that the L2CAP BR channel attempts to send
signaling commands through fixed channel when the ACL connect is
broken. At this time, the ACL connect of fixed channel is invalid.
Then the `__assert` occurs in function `bt_conn_ref()`.

Fixed the issue by checking the ACL conn of the L2CAP channel before
sending the data.

Here is a referred fault case for this changes,
There are two connected L2CAP Channels. The first one is primary
connection of the profile. And the second one is secondary connection
of the profile. When the primary connection is broken, the secondary
connection should also be disconnected.
In normal case, if the primary connection is disconnected by calling
L2CAP channel disconnection function, the secondary connection will
be disconnected by calling L2CAP channel disconnection in the
disconnected callback of primary connection.

But there is a corner case is that, the ACL connection is broken.
When the disconnected callback of primary connection is called, the
function call of L2CAP channel disconnection for secondary connection
will be asserted. Because the signaling channel (fixed channel ID
0x01) is disconnected and the `chan->conn` of the fixed channel is
NULL in this time.

The call stack is,
o bt_conn_ref() -> Asserted in this function.
o bt_conn_data_ready() -> The parameter is `br_chan->chan.conn`.
  It is the NULL.
o raise_data_ready() -> The parameter `br_chan` is fixed channel.
o bt_l2cap_br_send_cb() -> The parameter is ACL conn and CID of fixed
  channel (cid = 0x01). The channel can be found, but `chan->conn` is
  NULL.
o l2cap_br_chan_send_req()
o bt_l2cap_br_chan_disconnect()
o bt_l2cap_chan_disconnect() -> The parameter is the channel of
  secondary connection. The state of secondary channel is connected,
  because the stack is handling the primary channel disconnecting.
  And the function is called in disconnected callback of primary
  channel.

Signed-off-by: Lyle Zhu <[email protected]>
when role is server and try to get chan by psm in application, it
works fail because chan do not store psm.

Signed-off-by: Cheng Chang <[email protected]>
add one Kconfig `BT_L2CAP_RX_FLUSH_TO` to configure the minimum L2CAP RX
flush timeout accepted during processing peer's l2cap flush timeout
configuration.

Signed-off-by: Mark Wang <[email protected]>
Some headsets reply conf_rsp with flush timeout (0xFFFF) even conf_req
don't configure the flush timeout, stack should accept it.

Signed-off-by: Mark Wang <[email protected]>
Adds support for the user defining their own channels within the
fixed L2CAP channel range. To make this possible, the
`bt_l2cap_fixed_chan` struct and `BT_L2CAP_CHANNEL_DEFINE` macro
needed to converted to public API. In the process of doing so, the
`_destroy` parameter was removed from the `BT_L2CAP_CHANNEL_DEFINE`
macro as it was never used (fixed channels will not be destroyed over
the lifetime of the connection). `BT_L2CAP_CHANNEL_DEFINE` is renamed
`BT_L2CAP_FIXED_CHANNEL_DEFINE` to avoid confusion

The `bt_l2cap_chan_send` function is updated to be able to send data
on fixed l2cap channels.

Signed-off-by: Håvard Reierstad <[email protected]>
Document the ownership contract and callback semantics for L2CAP
transmission buffers:

- Extend tx_queue documentation in bt_l2cap_le_chan to explain SDU/PDU
  storage, callback handling, and transmission order semantics
- Document bt_l2cap_create_frag responsibilities regarding callback
  invocation after HCI Number of Completed Packets or on disconnect
- Document bt_l2cap_send_pdu callback contract: invoked exactly once
  after transmission completes or with -ESHUTDOWN on disconnect

These documentation additions clarify the requirements for proper
buffer lifecycle management and callback invocation throughout the
L2CAP transmission path.

Signed-off-by: Aleksander Wasaznik <[email protected]>
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]>
…larity.

bug: v/76605

Rootcause: Remove the static definition from the `BT_L2CAP_FIXED_CHANNEL_DEFINE` macro to ensure that `_bt_l2cap_fixed_chan_list` in `defines.c` is valid for adaptation to openvela.

Signed-off-by: chejinxian1 <[email protected]>
…hell commands

bug: v/77156

Fix the definition conflict caused by the macro `CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC`.

Remove the `static` declaration in macro `shell_static_entry` to ensure that the shell command definitions can be referenced by `_shell_root_cmds_list` in defines.c.

Modify `defines.c` to comment out unused commands in `_shell_root_cmds_list` and manage the `net_buf_pool` segments of each shell command in `_net_buf_pool_list` using the macro `CONFIG_BT_MC_SHELL`. Also, comment out the `net_buf_pool` for unused commands.

Fix the incorrect parameter passing in the `adv-create` command.

Comment out invalid header file includes in `mible_test.c`.

Signed-off-by: chejinxian1 <[email protected]>
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.