Understanding Maximum BT GATT notification size

I'm working with a BLE peripheral application that must transfer large amounts of data to a phone central. The application uses the MTU negotiation to determine the max notification size it can send. I ran into a problem where the BLE stack reported a TX MTU or 517 when connected to a Pixel 7 Pro, but if I try and send a gatt notification of size 517 (513 + 4 byte header), I get an error from the ATT stack:

BLE: Updated MTU: TX: 517 RX: 247 bytes

...

bt_att: No ATT channel for MTU 517

bt_gatt: No buffer available to send notification

If I clamp the max size of the message fragments to CONFIG_BT_L2CAP_TX_MTU=498 then the notification goes through. My impression was that the ATT layer is allowed to send any data equal or under the size of the negotiated TX MTU but it seems like this isn't the case. I also thought that the L2CAP layer is responsible to fragmentation and reassembly of incoming and outgoing messages in which case the L2CAP MTU should be abstracted away from the ATT layer. Is CONFIG_BT_L2CAP_TX_MTU actually just the MTU between the ATT and L2CAP layer and not the L2CAP <-> HCI?

One other weird thing I noticed was that in the ble gatt tester in btp_gatt.c, the max notification size is set like so:

/* TODO there should be better way of determining max supported MTU */
#define MAX_NOTIF_DATA (MIN(BT_L2CAP_RX_MTU, BT_L2CAP_TX_MTU) - 3)
I don't see why the L2CAP_RX_MTU would affect the maximum gatt notification size, the TODO would also indicate that this isn't the optimal way of determining the max notification size. Please help clarify which variables actually determine the maximum allowable gatt notification size.

 

Parents
  • Hi,

    You are right that the minimum will be used (as it must be supported by both peers). This is generally how most parameters are handled in Bluetooth. I did not get how the API documentation for the GATT callback is misleading, though?

    PS: In most cases an ATT MTU of 247 is use also for high throughput, as that is the largest that can fit in a BLE packet with data length extension (a longer ATT MTU will cause fragmentation on the physical layer so the throughput will not increase).

Reply
  • Hi,

    You are right that the minimum will be used (as it must be supported by both peers). This is generally how most parameters are handled in Bluetooth. I did not get how the API documentation for the GATT callback is misleading, though?

    PS: In most cases an ATT MTU of 247 is use also for high throughput, as that is the largest that can fit in a BLE packet with data length extension (a longer ATT MTU will cause fragmentation on the physical layer so the throughput will not increase).

Children
  • Thank you for confirming.

    The documentation for the callback states that callback gets an updated TX ATT MTU and RX ATT MTU.

    - Being unfamiliar with BLE, i assumed this meant that there were two individual MTU's, one in each direction. Every example using this callback prints these as tx:%d and rx:%d updated MTU, when in reality only the min of the two is used by both devices in the connection.

    - The "tx" and "rx" MTUs are actually "server" and "client" MTUs. On a server device its locally supported MTU is reported as the "rx" MTU and the client device MTU is the "tx". From the server perspective it doesn't make a ton of sense to me why my MTU is the "rx" MTU when its just the MTU i can support for both incoming and outgoing messages.

    It would be nice if there was some example that uses the negotiated MTU values in the callback to determine some notification size.

Related