[nRF52833] GATT Read of HID Report Map Char exceeding ATT MTU

Hi,

I'm working on a legacy program (Peripheral) using nRF52833 and nRF5 SDK using SoftDevice S113.

Our application implements an HID device using the Keyboard/Mouse example code from the nRF5 SDK, which leverage the generic ble_hids component that implements HoGP (HID Service).

We see a failure mode where the HID enumeration fails because the GATT Read fails (due to a malformed packet exceeding MTU error). The HID report map (added to the GATT database via rep_map_char_add() ) Characteristic is longer than the negotiated ATT MTU, and the issue does not occur if the HID Report Map size is less than the negotiated MTU.

Are long reads handled internally by the SoftDevice (or other SDK libraries/modules)? Or is the expectation that the App (or ble_hids module) should handle long reads until the full Characteristic is read out (and cap the READ reply to the MTU size to force the Central to request subsequent READ_BLOB operations with offset)?

If it's the latter, does it mean App needs to add handling for every Service/Characteristic, of BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST for each GATT Read, and for each manually return data up to the current MTU?

Looking the HID examples in the SDK, I didn't see any special handling for GATT Read against the MTU (only Gatt Write/Notifications in Heart Rate Service or Nordic UART Service are breaking the Char Notifications in chunks). 

Is there something I need to enable in the SDK to allow GATT Read/Write of payloads > MTU, or anything specific at the App layer?

Thanks,

Marco

PS: I found a similar ticket here that describes a similar problem on a custom Service (instead of a standard Service like HID, supported in the nRF5 SDK).

  • Hello,

    The softdevice will take care of the potential fragmentation of the packet yes, e.g. if ATT_MTU < length. So this should not be a problem.

    It could be interesting to know what your ATT_MTU size is here and also the size of the HID report map. I do believe that there is a limitation in the USB spec that each descriptor can only be 255 (and unfortunately this also apply to HID over GATT). So in such case it must be split over several reports as described in the usb spec:

    If the above is not the problem, then you are not writing if you are receiving multiple BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events here, but if you are, it could be interesting to check what the handle and offset for each of them, ref:

    /**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */
    typedef struct
    {
      uint16_t                    handle;             /**< Attribute Handle. */
      ble_uuid_t                  uuid;               /**< Attribute UUID. */
      uint16_t                    offset;             /**< Offset for the read operation. */
    } ble_gatts_evt_read_t; 

    Kenneth

  • Hi Kenneth, thank you for confirming that softdevice will take care of the potential fragmentation.

    After taking a closer look at the HCI logs last night, we noticed our Central was requesting two ATT MTU negotiations (the first resulting in MTU of 247 bytes, second of 83 bytes).

    This behavior should not be allowed by the spec (by reading section "3.4.2.1 Exchange MTU Request"), and I believe this is causing the SoftDevice to get confused and accept the second negotiation of 83 bytes, but ignoring it internally and keep using the 247 bytes initially negotiated, which causes long reads to be rejected by the Central due to the "malformed packet exceeding MTU error".

    As an experiment, we tried lowering the Max ATT MTU on the peripheral side to 83, and this causes the second MTU negotiation to effectively be a nop(), causing the HID enumeration to complete successfully (and HID Report Map read is indeed fragmented into READ + READ_BLOB, by the SoftDevice).

    We will work on addressing the issue on the Central side.

    Thanks!

Related