Skip to content

[Bugfix] Missing notification data when length > 255 bytes#1113

Merged
h2zero merged 1 commit intomasterfrom
bugfix/notify-data-len
Mar 17, 2026
Merged

[Bugfix] Missing notification data when length > 255 bytes#1113
h2zero merged 1 commit intomasterfrom
bugfix/notify-data-len

Conversation

@h2zero
Copy link
Owner

@h2zero h2zero commented Mar 16, 2026

When the ACL buffer is less than the MTU, the data arrives in more than one mbuf. This combines the data from the mbuf chain and stores it before calling the appliation callback, ensuring it has all the data

Summary by CodeRabbit

  • Bug Fixes
    • Improved Bluetooth notification handling to assemble fragmented messages and deliver larger payloads reliably.
    • Ensures only matching characteristics are processed and unrelated notifications are skipped.
    • Added stricter validation and error handling for malformed or incomplete notifications to avoid incorrect data delivery.
    • Maintains concise logging for disconnect events to reduce noise.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

Arr, BLE GAP notification handling now looks up the characteristic by attribute handle, assembles fragmented mbuf payloads into a single value, validates total length (returns ATT error on mismatch/allocation failures), and invokes the characteristic notify callback only when assembly succeeds. Non-matching notifications are skipped.

Changes

Cohort / File(s) Summary
BLE Notification Fragment Handling
src/NimBLEClient.cpp
Reworked BLE_GAP_EVENT_NOTIFY_RX flow: locate characteristic by attr_handle, skip non-matches, assemble fragmented mbuf chain into a contiguous value, validate total length and return ATT errors on mismatch/allocation failure, and invoke characteristic notifyCallback(value, len) on success. Minor log formatting tweak for disconnect handling.

Sequence Diagram(s)

sequenceDiagram
    participant Peripheral as Peripheral (BLE Controller)
    participant GAP as NimBLE GAP handler
    participant Chr as NimBLERemoteCharacteristic
    participant App as App notifyCallback

    Peripheral->>GAP: BLE_GAP_EVENT_NOTIFY_RX (mbuf chain, attr_handle)
    GAP->>GAP: find characteristic by attr_handle
    alt characteristic not found
        GAP-->>Peripheral: ignore / skip notification
    else characteristic found
        GAP->>GAP: iterate mbuf chain, assemble payload, track total length
        alt length mismatch or alloc fail
            GAP-->>Peripheral: return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN
            GAP->>Chr: do not invoke callback (error state)
        else assembly success
            GAP->>Chr: set assembled value
            GAP->>App: invoke notifyCallback(value, length)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

Yarrr, fragmented packets off the prow,
Stitched by the handler, true and now,
Callbacks summoned when the whole is found,
Errors shown and tossed astern, unbound,
The BLE brig sails steady, bytes all sound.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately reflects the main change: fixing missing notification data for payloads exceeding 255 bytes by properly handling fragmented mbufs.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/notify-data-len
📝 Coding Plan
  • Generate coding plan for human review comments

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

@h2zero h2zero linked an issue Mar 16, 2026 that may be closed by this pull request
@h2zero h2zero force-pushed the bugfix/notify-data-len branch from 6d9c7cc to e46d741 Compare March 16, 2026 23:17
Copy link

@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/NimBLEClient.cpp`:
- Around line 1095-1106: When reassembly fails (rc != 0) do not set an empty
value on pChr->m_value and do not invoke pChr->m_notifyCallback, because
zero-length payloads are valid BLE notifications; instead bail out early on
error (or invoke a distinct error callback if you add one) so the application
can detect the failure. Locate the block handling rc in NimBLEClient.cpp
(references: rc, pChr->m_value, pChr->m_notifyCallback,
event->notify_rx.indication) and change it to skip calling m_notifyCallback when
rc != 0 (or call a new explicit error handler you add, e.g.,
pChr->m_notifyErrorCallback) rather than passing a zero-length value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 208409c8-5445-444c-abb5-0a10e1d5962f

📥 Commits

Reviewing files that changed from the base of the PR and between 6d9c7cc and e46d741.

📒 Files selected for processing (1)
  • src/NimBLEClient.cpp

@h2zero h2zero force-pushed the bugfix/notify-data-len branch from e46d741 to 50a3a32 Compare March 16, 2026 23:33
Copy link

@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.

🧹 Nitpick comments (1)
src/NimBLEClient.cpp (1)

1057-1074: Consider usin’ getCharacteristic() to avoid duplicate lookup logic, matey.

This search path repeats handle-matching logic already centralized in NimBLEClient::getCharacteristic(uint16_t). Reusing it would reduce drift risk.

🏴‍☠️ Suggested refactor
-            NimBLERemoteCharacteristic* pChr = nullptr;
-            for (const auto& svc : pClient->m_svcVec) {
-                // Dont waste cycles searching services without this handle in its range
-                if (svc->getEndHandle() < event->notify_rx.attr_handle) {
-                    continue;
-                }
-
-                for (const auto& chr : svc->m_vChars) {
-                    if (chr->getHandle() == event->notify_rx.attr_handle) {
-                        NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", chr->toString().c_str());
-                        pChr = chr;
-                        break;
-                    }
-                }
-
-                if (pChr == nullptr) {
-                    continue;
-                }
+            NimBLERemoteCharacteristic* pChr = pClient->getCharacteristic(event->notify_rx.attr_handle);
+            if (pChr == nullptr) {
+                NIMBLE_LOGE(LOG_TAG, "unknown handle: %d", event->notify_rx.attr_handle);
+                return BLE_ATT_ERR_INVALID_HANDLE;
+            }
+            NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", pChr->toString().c_str());
 
                 auto len = event->notify_rx.om->om_len;
                 if (pChr->m_value.setValue(event->notify_rx.om->om_data, len)) {
@@
-                break;
-            }
-
-            if (pChr == nullptr) {
-                NIMBLE_LOGE(LOG_TAG, "unknown handle: %d", event->notify_rx.attr_handle);
-                rc = BLE_ATT_ERR_INVALID_HANDLE;
-            }
+            return rc;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NimBLEClient.cpp` around lines 1057 - 1074, Replace the manual nested
service/characteristic lookup with the existing helper: call
pClient->getCharacteristic(event->notify_rx.attr_handle)
(NimBLEClient::getCharacteristic(uint16_t)) to obtain the
NimBLERemoteCharacteristic* instead of iterating svc->m_vChars; assign the
result to pChr, check for nullptr and log/handle notifications as before (use
the same NIMBLE_LOGD call with pChr->toString() when non-null). This removes the
duplicated handle-matching logic and centralizes lookup in
NimBLEClient::getCharacteristic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/NimBLEClient.cpp`:
- Around line 1057-1074: Replace the manual nested service/characteristic lookup
with the existing helper: call
pClient->getCharacteristic(event->notify_rx.attr_handle)
(NimBLEClient::getCharacteristic(uint16_t)) to obtain the
NimBLERemoteCharacteristic* instead of iterating svc->m_vChars; assign the
result to pChr, check for nullptr and log/handle notifications as before (use
the same NIMBLE_LOGD call with pChr->toString() when non-null). This removes the
duplicated handle-matching logic and centralizes lookup in
NimBLEClient::getCharacteristic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4060d1b0-58a4-4d1d-870a-6c94d48fb737

📥 Commits

Reviewing files that changed from the base of the PR and between e46d741 and 50a3a32.

📒 Files selected for processing (1)
  • src/NimBLEClient.cpp

When the ACL buffer is less than the MTU, the data arrives in more than one mbuf.
This combines the data from the mbuf chain and stores it before calling the appliation callback, ensuring it has all the data
@h2zero h2zero force-pushed the bugfix/notify-data-len branch from 50a3a32 to f23d2b2 Compare March 17, 2026 00:16
Copy link

@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.

🧹 Nitpick comments (1)
src/NimBLEClient.cpp (1)

1063-1064: Arr, consider a defensive null check fer the mbuf, savvy?

The code be accessin' event->notify_rx.om->om_len and om_data without first checkin' if om be NULL. While a NULL mbuf be rare in these waters (an exceptional situation per the BLE spec), a defensive check would prevent any potential kraken attacks (crashes) from sinkin' the ship.

🛡️ Proposed defensive check
         NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", event->notify_rx.attr_handle);

         NimBLERemoteCharacteristic* pChr = pClient->getCharacteristic(event->notify_rx.attr_handle);
         if (pChr == nullptr) {
             NIMBLE_LOGW(LOG_TAG, "unknown handle: %d", event->notify_rx.attr_handle);
             return BLE_ATT_ERR_INVALID_HANDLE;
         }

+        if (event->notify_rx.om == nullptr) {
+            NIMBLE_LOGE(LOG_TAG, "Notification mbuf is null");
+            return BLE_ATT_ERR_UNLIKELY;
+        }
+
         auto len = event->notify_rx.om->om_len;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NimBLEClient.cpp` around lines 1063 - 1064, The code dereferences
event->notify_rx.om without checking for NULL before reading om_len/om_data; add
a defensive null check for event->notify_rx.om at the start of the notification
handling block (the code that reads auto len = event->notify_rx.om->om_len and
calls pChr->m_value.setValue), and if NULL, handle gracefully (e.g., log via the
existing logger, skip processing/return early or mark the characteristic update
as failed) to avoid crashes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/NimBLEClient.cpp`:
- Around line 1063-1064: The code dereferences event->notify_rx.om without
checking for NULL before reading om_len/om_data; add a defensive null check for
event->notify_rx.om at the start of the notification handling block (the code
that reads auto len = event->notify_rx.om->om_len and calls
pChr->m_value.setValue), and if NULL, handle gracefully (e.g., log via the
existing logger, skip processing/return early or mark the characteristic update
as failed) to avoid crashes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 280e868e-8481-4d08-95d0-d47caa49c118

📥 Commits

Reviewing files that changed from the base of the PR and between 50a3a32 and f23d2b2.

📒 Files selected for processing (1)
  • src/NimBLEClient.cpp

@h2zero h2zero merged commit 2afee83 into master Mar 17, 2026
42 checks passed
@h2zero h2zero deleted the bugfix/notify-data-len branch March 17, 2026 00:37
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.

ACL buffer cannot be changed; and enables broken MTUs as client

1 participant