[Bugfix] Missing notification data when length > 255 bytes#1112
[Bugfix] Missing notification data when length > 255 bytes#1112
Conversation
Seconds to milliseconds
IDF 5.2 introduced a new member, cpfd, to the ble_gatt_chr_def struct. It needs to be initialized to nullptr in order to avoid accessing uninitialized memory. By initializing the whole struct, we get everything initialized in a backward-compatible way.
Fixed issue #492
…te callback (#157) Updates the interface to use a typedef'd std::function for the advertise callback, which is backwards compatible but also allows std::bind and lambda functions.
…via public API. (#156) * Adds NimBLEClient::setConnection to allow servers to read the name of connected clients by passing their connection info to the Client class. * Adds NimBLEClient::clearConnection to be able to reuse the client without deleting and recreating.
Add return value to `deleteAllBonds`.
…sKey Input (#165) * Make NimBLEConnInfo functions const. * Update callback functions and update client to use new functions. * Update examples. * Update migration guide. --------- Co-authored-by: Casey Smith <csmith@morningstarcorp.com>
* NimBLEConnInfo - Note that the connection handle is the same as the connection id in the comment for getConnHandle() * NimBLEServer - int disconnect(const NimBLEConnInfo&) helper method
iOS devices specifically expect to receive the ID key of the bonded device even when RPA is not used. This sets the default value of the key distribution config to provide the ID key as well as the encryption key.
Adds a callback that is called when the identity address of the peer is resolved, this is useful for adding it to a whitelist.
This prevents a situation where the whitelist contains the address but the procedure errors and the address cannot be added again.
This provides and easy way to check if the peer address is a Resolvable Private Address.
* Add method to erase all service UUIDS.
* Adds a new method, getPeerName to NimBLEServer to read the name from the peers device name characteristic. * Adds a setting to automatically get the name of the peer when connected and provide it as an additional parameter in the onConnect callback. * Adds callback with client name after authentication as it may change.
This refactors the handling of sending notifications and indications for greater efficiency. * Adds client subscription state tracking to NimBLECharacteristic rather than relying on the stack. * Notifications/indications are now sent directly, no longer calling the callback to read the values. This avoids delays and flash writes in the stack, allowing for greater throughput.
Adds a new overloaded callback to NimBLECharacteristicCallbacks for the notification/indication onStatus method that provides a NimBLEConnInfo reference.
The previous implementation incorrectly used the service's end handle when searching for descriptors, which caused it to retrieve descriptors from subsequent characteristics as well. This fix calculates the correct end handle by finding the next characteristic's handle and using (next_handle - 1) as the search limit. This ensures only descriptors belonging to the current characteristic are retrieved. Fixes incorrect descriptor retrieval when multiple characteristics exist in the same service.
Redefining the kconfig BLE options for the esp32p4 is no longer needed as bluetooth support is enabled in newer esp-idf versions and can be added to the project config if older versions are used.
This changes how attribute handles are set so they can be correctly identified when there is more than one attribute with the same UUID. Instead of reading from the stack by UUID to get the handles this will now use the registration callback to set them correctly. This also improves handling of dynamic service changes by properly removing characteristics/descriptors when required and resetting the GATT when advertising is started instead of after the last client disconnects. * Adds NimBLEUUID constructor overload for ble_uuid_t*. * NimBLECharacteristic::getDescriptorByUUID now takes an optional index value to support multiple same-uuid descriptors.
Co-authored-by: doudar <17362216+doudar@users.noreply.github.com>
…able_observer_mode field for ESP-IDF >= 5.4.2 The NimBLEScan constructor previously used positional struct initialization, which no longer matches the ble_gap_disc_params layout in newer ESP-IDF versions (>= 5.4.2) where the field `disable_observer_mode` was added. This is caused by -Wmissing-field-initializers. Switch to designated initializers to make the field assignments explicit and more robust across ESP-IDF/NimBLE revisions. The new field is only initialized when building against ESP-IDF 5.4.2 or later to maintain backwards compatibility.
…FIG_USING_NIMBLE_COMPONENT
Co-authored-by: doudar <17362216+doudar@users.noreply.github.com>
📝 WalkthroughWalkthroughArrr — Client DISCONNECT logging was condensed to a single-line format, and NOTIFY_RX was changed to assemble multi-fragment BLE notifications by walking mbuf fragments (using Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Comment |
|
Arrrr, let’s lay eyes on this code and see if any beasties be lurkin’ in these waters! 🔴 [BUG]: Hardcoded buffer size might lead to overflow.
🔴 [SECURITY FLAW]: Lack of bounds check before copying data via
🔴 [PERFORMANCE ISSUE]: Inefficient handling of datagrams from the
🔴 [CODE SMELL]: Incomplete error handling for oversized messages.
🔴 [STYLE ISSUE]: Nested
Arrr, some rough seas here, but the ship can be patched up nicely with these fixes. Don’t ignore the dangers of buffer overflows and inefficiencies, or ye may lose critical treasure (yer users’ data)! —CodePirate (AI) |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/NimBLEClient.cpp (2)
1069-1072: Arrr, guard the first fragment before yememcpy.The first chunk is copied before any size/null check. Add a fast guard so malformed input can’t overrun
buf.⚓ Proposed hardening patch
- uint8_t buf[BLE_ATT_ATTR_MAX_LEN]; - uint16_t len = event->notify_rx.om->om_len; - memcpy(buf, event->notify_rx.om->om_data, len); + uint8_t buf[BLE_ATT_ATTR_MAX_LEN]; + if (event->notify_rx.om == nullptr || + event->notify_rx.om->om_len > BLE_ATT_ATTR_MAX_LEN) { + NIMBLE_LOGE(LOG_TAG, "Invalid notification mbuf length"); + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + uint16_t len = event->notify_rx.om->om_len; + memcpy(buf, event->notify_rx.om->om_data, len);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEClient.cpp` around lines 1069 - 1072, Add a fast guard before the memcpy in NimBLEClient.cpp: validate that event->notify_rx.om is non-NULL, that event->notify_rx.om->om_data is non-NULL, and that the length (event->notify_rx.om->om_len) does not exceed the destination buffer size (BLE_ATT_ATTR_MAX_LEN) and is non-negative/meaningful; if the checks fail, bail out (return/continue/log) rather than calling memcpy into buf. Specifically protect the memcpy(buf, event->notify_rx.om->om_data, len) by checking the om pointer, om_data, and that len <= BLE_ATT_ATTR_MAX_LEN (and optionally len > 0) before performing the copy.
1076-1080: Arrr, overlong notification drops still be hidden from application code.When overflow hits, the packet is dropped with only a log. Consider an app-level overflow callback so user code can react (metrics/retry/reconnect).
Based on learnings: In NimBLEStream (src/NimBLEStream.cpp, NimBLE-Arduino), the author's preference regarding RX buffer overflow in pushRx is that the bigger concern is not partial vs. full drops, but that the application layer has no notification mechanism when data is dropped. A user-settable overflow callback is the preferred direction over silently accepting partial writes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEClient.cpp` around lines 1076 - 1080, The notification-drop branch in NimBLEClient.cpp currently only logs and returns BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN, leaving apps unaware of dropped data; add a user-settable overflow callback on the client (e.g., a std::function<void(size_t attempted, size_t available)> named rxOverflowCallback and a setter setRxOverflowCallback) in the NimBLEClient class, invoke this callback right before returning in the overflow branch (pass attempted length and remaining buffer size or next->om_len), and ensure the callback is default-null-checked so behavior remains unchanged if unset.
🤖 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 1069-1072: Add a fast guard before the memcpy in NimBLEClient.cpp:
validate that event->notify_rx.om is non-NULL, that event->notify_rx.om->om_data
is non-NULL, and that the length (event->notify_rx.om->om_len) does not exceed
the destination buffer size (BLE_ATT_ATTR_MAX_LEN) and is
non-negative/meaningful; if the checks fail, bail out (return/continue/log)
rather than calling memcpy into buf. Specifically protect the memcpy(buf,
event->notify_rx.om->om_data, len) by checking the om pointer, om_data, and that
len <= BLE_ATT_ATTR_MAX_LEN (and optionally len > 0) before performing the copy.
- Around line 1076-1080: The notification-drop branch in NimBLEClient.cpp
currently only logs and returns BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN, leaving apps
unaware of dropped data; add a user-settable overflow callback on the client
(e.g., a std::function<void(size_t attempted, size_t available)> named
rxOverflowCallback and a setter setRxOverflowCallback) in the NimBLEClient
class, invoke this callback right before returning in the overflow branch (pass
attempted length and remaining buffer size or next->om_len), and ensure the
callback is default-null-checked so behavior remains unchanged if unset.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 314745aa-ca61-4c82-89e5-baa7bc8eca67
📒 Files selected for processing (1)
src/NimBLEClient.cpp
970537a to
7e9783c
Compare
There was a problem hiding this comment.
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 1069-1085: Pre-calc the total length of the mbuf chain starting at
event->notify_rx.om (traverse with SLIST_NEXT) before calling
chr->m_value.setValue so you can preventively check against the characteristic's
maximum instead of reacting to NimBLEAttValue::append failures; handle and honor
the return value of chr->m_value.setValue (do not ignore it) and if the total
exceeds capacity, invoke a user-settable overflow/notification-truncation
callback on the characteristic (add an onOverflow/onTruncated callback to the
characteristic class) with details of the truncated data, then return a non-zero
error code to the NimBLE stack instead of 0 to signal failure to the app; also
remove the post-append length-only check and use the precomputed total_len for
validation to simplify logic (refer to event->notify_rx.om, SLIST_NEXT,
chr->m_value, setValue, NimBLEAttValue::append).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ff66abd2-73a6-443c-8981-f2fbde59bf86
📒 Files selected for processing (1)
src/NimBLEClient.cpp
7e9783c to
21c2cf6
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/NimBLEClient.cpp (1)
1054-1076: Arrr, keep handle lookup on the existing helper.This open-codes work
NimBLEClient::getCharacteristic()already does at Lines 865-877, and the two paths already differ on service-range checks. Reusing the helper keeps notification lookup rules in one place.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/NimBLEClient.cpp` around lines 1054 - 1076, The notification handling currently duplicates characteristic lookup logic; replace the manual service/characteristic iteration with the existing helper NimBLEClient::getCharacteristic() to centralize lookup rules: call pClient->getCharacteristic(event->notify_rx.attr_handle) (or the appropriate overload) to obtain the NimBLERemoteCharacteristic pointer, check for nullptr and handle as before, and remove the duplicated loops and service-range checks so all lookup behavior is maintained in getCharacteristic().
🤖 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 1084-1096: The logged ATT status `rc` is a raw ATT error but
`NimBLEUtils::returnCodeToString()` expects errors with `BLE_HS_ERR_ATT_BASE`
added, so the string becomes "Unknown"; update the log call in the error path to
pass the adjusted code (e.g., call
NimBLEUtils::returnCodeToString(BLE_HS_ERR_ATT_BASE + rc)) only for ATT status
values, leaving non-ATT rc untouched so the human-readable string matches the
numeric code.
---
Nitpick comments:
In `@src/NimBLEClient.cpp`:
- Around line 1054-1076: The notification handling currently duplicates
characteristic lookup logic; replace the manual service/characteristic iteration
with the existing helper NimBLEClient::getCharacteristic() to centralize lookup
rules: call pClient->getCharacteristic(event->notify_rx.attr_handle) (or the
appropriate overload) to obtain the NimBLERemoteCharacteristic pointer, check
for nullptr and handle as before, and remove the duplicated loops and
service-range checks so all lookup behavior is maintained in
getCharacteristic().
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 46972862-ec15-47a5-9c6a-ab4fac8aa48f
📒 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
21c2cf6 to
c9cbff0
Compare
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.
Fixes #1041
Summary by CodeRabbit
Bug Fixes
Style