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

Why is BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST coming from a GATT server?

Using nRF5 SDK 14.0.0 with Softdevice s132 v5.0.0 on nRF52832.

I've set up my nrf to be a GATT client (in central role), and I'm using bluez on my Linux desktop with a LairdTech BT831 dongle as a GATT server (in peripheral role).

I found that when the client connects to the server, the server sends an ATT EXCHANGE MTU REQUEST. This is received by the softdevice on the client and I get a BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event, which is very confusing to me -- the MTU is in the client_rx_mtu field, which makes no sense because the server is telling me its MTU.

Q1: I thought the BLE spec was that only the client could initiate an ATT exchange MTU request?

Q2: Why wouldn't the softdevice event be something like BLE_GATTC_EVT_EXCHANGE_MTU_REQUEST? (I know, this isn't in the header files, but it's an event for the client, not the nonexistent server).

Thanks!

--Rob

  • Hey Rob,

    that is an excellent question. 

    From BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G:

    4.3 SERVER CONFIGURATION

     

    This procedure is used by the client to configure the Attribute Protocol. This procedure has only one sub-procedure used to set the MTU sizes.

     

    4.3.1 Exchange MTU

     

    This sub-procedure is used by the client to set the ATT_MTU to the maximum possible value that can be supported by both devices when the client supports a value greater than the default ATT_MTU for the Attribute Protocol. This subprocedure shall only be initiated once during a connection.

     

    This sub-procedure shall not be used on a BR/EDR physical link since the MTU size is negotiated using L2CAP channel configuration procedures.

     

    The Attribute Protocol Exchange MTU Request is used by this sub-procedure. The Client Rx MTU parameter shall be set to the maximum MTU that this client can receive.

     

    Two possible responses can be sent from the server for the Exchange MTU Request: Exchange MTU Response and Error Response.

     

    Error Response is returned if an error occurred on the server.

     

    The server shall respond to this message with an Exchange MTU Response with the Server Rx MTU parameter set to the maximum MTU that this server can receive.

     

    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.

     

    Once the messages have been exchanged, the ATT_MTU shall be set to the minimum of the Client Rx MTU and Server Rx MTU values. 

    "This sub-procedure is used by the client " Indicates that MTU exchange is only used by the Client, but the paragraph does not explicitly prohibit the server from doing the same. BT spec is usually not this vague in its description. 

    I need to start an investigation on our side. Do note that our GATT library will automatically issue an MTU exchange whenever a connection is established, regardless if it's a Client or Server. This does cause some issues with certain Android BLE stacks and BlueEZ. 

    EDIT:
    You can of course easily disable this GATT library feature.

    Cheers,

    Håkon.

  • This is a bug. If nrf_ble_gatt.c sends the MTU request from the GATT server, it causes problems. For example, HID over GATT on Windows 10 (at least the version on my Stream 7 tablet) will retrieve only the first packet of the report descriptor if the Windows device supports ATT over 23 but data length of only 27. As a result, HID over GATT will not work for any non-trivial device. One solution is to disable MTU over 23, but this severely limits the speed of HID over GATT. If, instead, the GATT server waits for the Windows device to send the request (*as it should*), it works correctly. Please provide a way to disable this incorrect use of the specification in the nrf_ble_gatt.c. It should only be sent by GATT clients. Thanks!

  • As a workaround you need to put in a check for the GATT role in nrf_ble_gatt.c in the function on_connected_evt, where it initiates the mtu exchange request with a call to sd_ble_gattc_exchange_mtu_request.  

  • FWIW this bit me when trying to implement a linux NUS client to upload logs from a device.  The workaround does allow for 247 MTU when the request comes from the linux client.   

    Unfortunately the workaround breaks the nRF UART v2.0 client app for android as that app doesn't request an MTU change.  Any suggestions for getting both to work?

  • You can delay the MTU exchange until after you know what kind of device you're connected to.

Related