Skip to content

feat(L2CAP): add disconnect API and harden CoC send/error handling#1139

Merged
h2zero merged 1 commit intomasterfrom
l2cap-update
Mar 31, 2026
Merged

feat(L2CAP): add disconnect API and harden CoC send/error handling#1139
h2zero merged 1 commit intomasterfrom
l2cap-update

Conversation

@h2zero
Copy link
Copy Markdown
Owner

@h2zero h2zero commented Mar 31, 2026

  • Add NimBLEL2CAPChannel::disconnect() and getConnHandle().
  • Fix CoC TX mbuf ownership handling in writeFragment(): treat BLE_HS_ENOMEM / BLE_HS_EAGAIN as consumed buffer, only free local tx mbuf on BLE_HS_EBUSY.

Summary by CodeRabbit

  • New Features

    • Added ability to disconnect L2CAP channels programmatically with proper status reporting.
    • Added method to retrieve the connection handle associated with an L2CAP channel.
  • Bug Fixes

    • Improved handling of transmission buffer exhaustion to prevent premature resource cleanup during retries.
    • Enhanced error recovery for busy channel conditions during data transmission.

- Add NimBLEL2CAPChannel::disconnect() and getConnHandle().
- Fix CoC TX mbuf ownership handling in writeFragment():
  treat BLE_HS_ENOMEM / BLE_HS_EAGAIN as consumed buffer,
  only free local tx mbuf on BLE_HS_EBUSY.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

📝 Walkthrough

Walkthrough

Arr, this pull request be addin' two new public APIs to the NimBLEL2CAPChannel class, matey! The disconnect() method handles channel disconnection with proper error handling, while getConnHandle() retrieves the connection handle. Additionally, the retry behavior in writeFragment was adjusted to handle different error codes separately - avoidin' unnecessary buffer deallocation fer certain error conditions.

Changes

Cohort / File(s) Summary
L2CAP Channel Header Declaration
src/NimBLEL2CAPChannel.h
Added two new public method declarations: disconnect() and getConnHandle() with appropriate return types and const qualifiers.
L2CAP Channel Implementation
src/NimBLEL2CAPChannel.cpp
Implemented disconnect() with channel validation and non-fatal error handling fer BLE_HS_ENOTCONN and BLE_HS_EALREADY. Implemented getConnHandle() to return connection handle with fallback to BLE_HS_CONN_HANDLE_NONE. Modified writeFragment retry logic to differentiate buffer consumption errors (BLE_HS_ENOMEM, BLE_HS_EAGAIN) from busy channel errors (BLE_HS_EBUSY).

Possibly related issues

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🏴‍☠️ With disconnect and handles in hand,
The L2CAP channels now sail the seas grand,
Retry logic set true on the seven seas,
No buffers lost to the breeze, if ye please! 🌊

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures both main changes: adding disconnect/getConnHandle APIs and hardening CoC send error handling with improved mbuf management.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch l2cap-update

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/NimBLEL2CAPChannel.cpp`:
- Around line 135-147: The BLE send-error handling incorrectly assumes nimble
frees the mbuf for BLE_HS_ENOMEM and BLE_HS_EAGAIN; add os_mbuf_free_chain(txd)
before the continue in the BLE_HS_ENOMEM and BLE_HS_EAGAIN case blocks (the same
cleanup already present in the BLE_HS_EBUSY branch) in the switch that handles
ble_l2cap_send results so txd is freed on those error paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 92085361-7183-4af6-9a07-48e22f76c8e9

📥 Commits

Reviewing files that changed from the base of the PR and between bc2b46e and 113c9e1.

📒 Files selected for processing (2)
  • src/NimBLEL2CAPChannel.cpp
  • src/NimBLEL2CAPChannel.h

Comment on lines 135 to 147
case BLE_HS_ENOMEM:
case BLE_HS_EAGAIN:
/* ble_l2cap_send already consumed and freed txd on these errors */
NIMBLE_LOGD(LOG_TAG, "ble_l2cap_send returned %d (consumed buffer). Retrying shortly...", res);
ble_npl_time_delay(ble_npl_time_ms_to_ticks32(RetryTimeout));
continue;

case BLE_HS_EBUSY:
NIMBLE_LOGD(LOG_TAG, "ble_l2cap_send returned %d. Retrying shortly...", res);
/* Channel busy; txd not consumed */
NIMBLE_LOGD(LOG_TAG, "ble_l2cap_send returned %d (busy). Retrying shortly...", res);
os_mbuf_free_chain(txd);
ble_npl_time_delay(ble_npl_time_ms_to_ticks32(RetryTimeout));
continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

NimBLE ble_l2cap_send mbuf buffer ownership on BLE_HS_ENOMEM BLE_HS_EAGAIN error codes

💡 Result:

In NimBLE, for ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu), the function consumes (frees) the supplied mbuf only on success. On error returns such as BLE_HS_ENOMEM (heap exhaustion, no memory) or BLE_HS_EAGAIN (operation would block), the caller retains ownership of the mbuf and must free it using os_mbuf_free_chain(sdu) to avoid leaks. BLE_HS_ENOMEM typically occurs due to mbuf pool exhaustion when the stack cannot allocate additional buffers for transmission or fragmentation. BLE_HS_EAGAIN indicates the controller cannot accept the full packet immediately (e.g., transmit queue full), so the remainder may be enqueued, but the input mbuf is not consumed on this error.

Citations:


Shiver me timbers! Ye've got a memory leak on yer hands, cap'n!

The code be mistaken about buffer ownership. NimBLE's ble_l2cap_send only frees the mbuf on success; on errors like BLE_HS_ENOMEM and BLE_HS_EAGAIN, the caller retains ownership and must free it. Yet yer code be skippin' os_mbuf_free_chain(txd) on those very errors while properly freeein' it for BLE_HS_EBUSY. This be a memory leak that'll drain yer treasure chest over time, matey!

Add os_mbuf_free_chain(txd) before continue in both the BLE_HS_ENOMEM and BLE_HS_EAGAIN cases, just like ye do fer BLE_HS_EBUSY.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NimBLEL2CAPChannel.cpp` around lines 135 - 147, The BLE send-error
handling incorrectly assumes nimble frees the mbuf for BLE_HS_ENOMEM and
BLE_HS_EAGAIN; add os_mbuf_free_chain(txd) before the continue in the
BLE_HS_ENOMEM and BLE_HS_EAGAIN case blocks (the same cleanup already present in
the BLE_HS_EBUSY branch) in the switch that handles ble_l2cap_send results so
txd is freed on those error paths.

@h2zero h2zero merged commit 209f2f4 into master Mar 31, 2026
42 checks passed
@h2zero h2zero deleted the l2cap-update branch March 31, 2026 23:30
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.

2 participants