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

  • There is a further confusion I have when reading the text in the spec after the text quoted above.

    3.4.2.2

    ....

    If either Client Rx MTU or Service Rx MTU are incorrectly less than the default
    ATT_MTU, then the ATT_MTU shall not be changed and the ATT_MTU shall
    be the default ATT_MTU.
    If a device is both a client and a server, the following rules shall apply:
    1. A device's Exchange MTU Request shall contain the same MTU as the
    device's Exchange MTU Response (i.e. the MTU shall be symmetric).
    2. If MTU is exchanged in one direction, that is sufficient for both directions.
    3. It is permitted, (but not necessary - see 2.) to exchange MTU in both
    directions, but the MTUs shall be the same in each direction (see 1.)
    4. If an Attribute Protocol Request is received after the MTU Exchange
    Request is sent and before the MTU Exchange Response is received, the
    associated Attribute Protocol Response shall use the default MTU. Figure
    3.1 shows an example that is covered by this rule. In this case device A and
    device B both use the default MTU for the Attribute Protocol Response.
    5. Once the MTU Exchange Request has been sent, the initiating device shall
    not send an Attribute Protocol Indication or Notification until after the MTU
    Exchange Response has been received. Note: This stops the risk of a crossover
    condition where the MTU size is unknown for the Indication or
    Notification.

    If the device is playing the role of both server and client (or thinks it is) how do I interpret 5? As far as I know only servers send notification or indications. The bold text in 5 suggests that it is the server that sends the MTU request....contrary to all text above.

    HEELLLP!!! Confuse me more BT SIg!

  • Both Central and Peripheral devices can issue an MTU exchange request, regardless of GATT role. Our SoftDevice will handle the request so as to be in accordance with BT spec. 

    A handful of BT stacks do not expect a Peripheral to issue an MTU exchange first and can end up using undesirable MTU sizes for your link. The workaround is simply to delay the MTU exchange request a bit. 

    The SoftDevice API uses sd_ble_gattc_exchange_mtu_request, but it can be used by a GATT server as well. 



  • I am running into this same issue and looks like the thread is 2+ years old, still not marked as answered.

    I use nRF52, SDK 16.0.0 and I am working with a setup where all devices in my network are based on nRF52. One master establishes connections to multiple slaves.

    Looking at the implementation in nrf_ble_gatt.c (function on_connected_evt())  it is clear that the MTU exchange is requested for any new connection, regardless of the role. (line 150) 

    In the beginning of that function, the GAP role (periph or central) is checked, but it is not used as condition for the MTU exchange.

    It does not look like a "bug" to me, and in fact my connections are getting up quite OK. I do see some unexpected BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event on the client side for each connection, but I just ignore it and it does not break anything.

    That being said, it seems a bit dumb that upon connecting, both nRF52 devices will request the MTU exchange. Even if it works, I find it a bit disturbing.

    I can easily fix this by editing the code in the SDK, but I would rather not poke with the library code directly. In the SDK there are compile options for just about every feature you can imagine, but for some reason this MTU exchange has been left as a code block that is always executed.

    Any comments from Nordic what is the recommended solution here to ensure maximum interoperability?

    Looking at the code in nrf_ble_gatt.c, it seems that it would be quite trivial to add compile time options for:

    • disable automatic MTU exchange request completely (if you e.g. want to call it explicitly from the app, after a delay)
    • disable/enable automatic MTU exchange in periheral role 
    • disable/enable automatic MTU exchange in central role 

     

    (If 2nd and 3rd options are available then the 1st is kind of redundant, but anyway...)

    EDIT: I'm talking about compile time options above, but would be just as happy to have some parameter or option that can be changed at runtime.  

  • TylerD said:
    disable automatic MTU exchange request completely

    The automatic MTU exchange is a bit poorly worded. There's no automation built in to the SoftDevice, both the MTU exchange requests and the response are controlled by the application.

    We've added the ability of the GATT library to automatically issue an MTU exchange request upon connection establishment for both central, peripheral, client, and server. 
    This is due to the fact that if you develop a peripheral server you have no guarantee that a connected central client will issue its own MTU exchange request. That is unless you develop both the peripheral AND the central. 


     

    TylerD said:

    Looking at the implementation in nrf_ble_gatt.c (function on_connected_evt())  it is clear that the MTU exchange is requested for any new connection, regardless of the role. (line 150) 

    In the beginning of that function, the GAP role (periph or central) is checked, but it is not used as condition for the MTU exchange.

    I suggest you use the role check if you control both sides of the link, if you only control the peripheral I would leave it as is, and maybe delay the request a bit. 

  • Hey all, I wanted to chime in here and share more about the problems this GATT implementation is causing, particularly with Apple products. On some Apple devices it causes two "didConnect" callbacks to occur. I've been able to recreate it reliably on a 2017 Macbook Pro and iPhone 11 Pro Max. When I comment out the Nordic peripheral's MTU request it resolves the issue. 

    I suspect there's a race condition in Apple's CoreBluetooth implementation that causes the behavior to occur irregularly across devices. Below is a capture from Wireshark using Nordic's sniffer tool. It captures an "offending transaction" in which both the Macbook and Nordic peripheral both send MTU requests. This particular transaction resulted in the Macbook executing two "didConnect" callbacks. 

    Here's the context for my setup:
    - Our Nordic-based product is acting as a BLE Peripheral w/ GATT server implementation exclusively
    - Using nRF5 SDK 15.0.0 and SoftDevice 132
    - The peripheral negotiates a 247 byte MTU

    I think I can comfortably remove the MTU request from my firmware as it's only using GATT server functionality.  My product connects to a specific App on iOS and Android.  On the iOS side, we can always assume that CoreBluetooth will send a client->server MTU request automatically right after connection.  When it comes to Android the Application layer has access to initiating an MTU request, so we'll just have to be sure to initiate that procedure in the Android App code.  

    I hope this helps someone who's in a similar boat using Nordic products with Apple. 

    -Ray

Related