This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Unexpected and unhandled MTU exchange request from peripheral followed by unexpected packet fragmentation

I've attached a Wireshark capture of an issue I am attempting to troubleshoot. I am confused as to why the peripheral is sending an Exchange MTU Request (No. 157) to the central. Afterwards, even though it appears the MTU is successfully negotiated to 512 I see packet fragmentation on my 65-72 byte notifications. I do not see fragmentation during the BLE DFU process with larger packets, so I'm sure it is something in my application code. Has anyone seen this before?

mtu_request_from_peripheral_and_unexpected_fragmentation.pcapng

UPDATE:

After diving into the SDK a little more I've found that if the max MTU is greater than the default MTU the device will attempt to negotiate to the maximum. When the MTU is negotiated it appears that the packet size is supposed to be updated as well. I've set up logging ( will add log output soon ) on my device and am seeing some odd ordering in the log messages. I also see logs from the default MTU Exchange Response handler even though my central is responding with an error.

Is it possible to disable the automatic MTU negotiation and still allow the request from the central to negotiate a larger MTU? The library I'm using (go-ble) talks directly to the Linux HCI device and has not implemented handlers for all incoming request types.

Logs from NRF52, line 7 comes from on_exchange_mtu_rsp_evt in components/ble/nrf_ble_gatt.c. I assume this is being called in reponse to the Request Not Supported packet sent from my central.

<debug> nrf_ble_gatt: Requesting to update ATT MTU to 512 bytes on connection 0x0.
<debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0.
<info> app: Connected.
<debug> nrf_ble_gatt: Peer on connection 0x0 requested an ATT MTU of 515 bytes.
<debug> nrf_ble_gatt: Updating ATT MTU to 512 bytes (desired: 512) on connection 0x0.
<debug> app: UNHANDLED BLE EVENT: 85
<debug> nrf_ble_gatt: ATT MTU updated to 23 bytes on connection 0x0 (response).
<info> app: Data len is set to 0x17(23)
<debug> app: UNHANDLED BLE EVENT: 58
<debug> nrf_ble_gatt: Data length updated to 27 on connection 0x0.
<debug> nrf_ble_gatt: max_rx_octets: 27
<debug> nrf_ble_gatt: max_tx_octets: 27
<debug> nrf_ble_gatt: max_rx_time: 328
<debug> nrf_ble_gatt: max_tx_time: 328
<info> app: Data len updated to 27!

  • I've spent some time looking into exactly this.

    Why are you confused about that? I however wonder why your Linux computer says "Request Not Supported", since it immediately after initiates its own ATT Exchange, which succeeds.

    The problem I'm seeing is that very few BLE libraries expect the peripheral to be sending an exchange MTU Request. Of course it's unsupported, they expect to send the request themselves and handle the response. The handlers are registered for Response, not Request.

    The real fault here is this:

    If the Error Response is sent by the server with the error code set to Request
    Not Supported, the Attribute Opcode is not supported and the default MTU
    shall be used.

    When the softdevice (acting as server) receives Request Not Supported it appears to lock the MTU for that connection, even if the client sends an Exchange MTU Request of its own and gets a responsse that a larger MTU has been negotiated. Softdevice callback to the firmware stack reports that the data size is now 242, but when sending a notification only the first 20 bytes are actually transmitted.

    At the very least you should reject the larger size, responding with 23. It would be preferable to simply accept the more standard client-initiated exchange and raise the MTU despite the client rejecting the first unexpected server-initated exchange.

    I believe that would be valid according to the BLE spec, since it specifically says "If the Error Response is sent by the SERVER". I don't believe the server is required to ignore the client-initiated exchange, even if the client responded originally with Request Not Supported.

Related