trouble icon indicating copy to clipboard operation
trouble copied to clipboard

MTU handshake results in default size

Open pperanich opened this issue 11 months ago • 7 comments

When running the ble_bas_peripheral example on the Microbit, the agreed upon MTU results in the BLE default of 23 bytes, instead of the requested 247 that is specified L2CAP_MTU - 4. When running a similar application with nrf-softdevice (with the same devices for gatt server/client), the MTU handshake results in the upper limit being selected, i.e. whatever ATT_MTU sets.

pperanich avatar Jan 11 '25 16:01 pperanich

Looking through the code base, it appears that neither the Connection nor ConnectionManager's set_att_mtu method is called anywhere. When I change the visibility of this method to pub and add the following snippet to the ble_bas_peripheral example, the agreed MTU is larger, though still not the requested ATT_MTU. I.e it ends up being 185, instead of 247:

    info!("[adv] advertising");
    let conn = advertiser.accept().await?;
    conn.set_att_mtu(ATT_MTU as u16);  // <-- Add here.
    info!("[adv] connection established");
    Ok(conn)

If I add the following log to exchange_att_mtu:

    pub(crate) fn exchange_att_mtu(&self, conn: ConnHandle, mtu: u16) -> u16 {
        let mut state = self.state.borrow_mut();
        for storage in state.connections.iter_mut() {
            match storage.state {
                ConnectionState::Connected if storage.handle.unwrap() == conn => {
                    info!("storage.att_mtu = {:?}, mtu = {:?}", storage.att_mtu, mtu);  // <-- Added log
                    storage.att_mtu = storage.att_mtu.min(mtu);
                    return storage.att_mtu;
                }
                _ => {}
            }
        }
        mtu
    }

I get:

0.007110 INFO  [adv] advertising
└─ trouble_example_apps::ble_bas_peripheral::advertise::{async_fn#0} @ /Users/peranpl1/Documents/repos/oss/trouble/examples/apps/src/fmt.rs:143
11.909423 TRACE [host] connection with handle ConnHandle(0) established to BdAddr([b2, cf, 56, d5, 2c, 59])
└─ trouble_host::host::{impl#1}::handle_connection @ /Users/peranpl1/Documents/repos/oss/trouble/host/src/fmt.rs:117
11.910186 TRACE [link][poll_accept] connection handle ConnHandle(0) in role Peripheral accepted
└─ trouble_host::connection_manager::{impl#1}::poll_accept @ /Users/peranpl1/Documents/repos/oss/trouble/host/src/fmt.rs:117
11.910888 INFO  [adv] notifying connection of tick 1
└─ trouble_example_apps::ble_bas_peripheral::counter_task::{async_fn#0} @ /Users/peranpl1/Documents/repos/oss/trouble/examples/apps/src/fmt.rs:143
12.046569 WARN  [host] unsupported l2cap channel id 58
└─ trouble_host::host::{impl#1}::handle_acl @ /Users/peranpl1/Documents/repos/oss/trouble/host/src/fmt.rs:156
12.046844 WARN  [host] encountered error processing ACL data for ConnHandle(0): NotSupported
└─ trouble_host::host::{impl#3}::run_with_handler::{async_fn#0} @ /Users/peranpl1/Documents/repos/oss/trouble/host/src/fmt.rs:156
12.076995 INFO  storage.att_mtu = 247, mtu = 185
└─ trouble_host::connection_manager::{impl#1}::exchange_att_mtu @ /Users/peranpl1/Documents/repos/oss/trouble/host/src/fmt.rs:143
12.077453 INFO  [host] agreed att MTU of 185
└─ trouble_host::host::{impl#1}::handle_acl @ /Users/peranpl1/Documents/repos/oss/trouble/host/src/fmt.rs:143

Note: I seem to always get the above warning about unsupported l2cap channel id. Curious if anyone else has noticed this.

pperanich avatar Jan 13 '25 15:01 pperanich

I think #237 should fix using the l2cap - 4 as the default rather than 23. Wrt. set_att_mtu, it was used earlier when att mtu was explicitly set from the no longer existing gatt server. We could remove the method, or expose it.

In either case, if the other end chooses a lower value, it will pick the lowest (it looks like in your case the other end has a max of 185?)

lulf avatar Jan 13 '25 16:01 lulf

I would be in favor of removing the set_att_mtu methods if they are no longer in use.

It's interesting because when I run the ble_bas_peripheral example of the nrf-softdevice repo on the Microbit and use the same client-side device, the att mtu is negotiated to be 247.

pperanich avatar Jan 13 '25 16:01 pperanich

@pperanich Have you been able to test if you get the behaviour you expect now? (Can I close the issue?)

lulf avatar Feb 26 '25 20:02 lulf

I had tested after the above discussion and came to the same result, but I will try again with the latest updates and post the outcome below.

pperanich avatar Feb 26 '25 21:02 pperanich

Confirmed same behavior as before: nrf-softdevice implementation negotiates to 247 MTU, trouble implementation negotiates to 185 MTU with the same client (iPhone 15). Also tried with a Macbook with same result.

pperanich avatar Mar 06 '25 15:03 pperanich

So, I tried to reproduce this looking at the wireshark trace, and if I adjust this line https://github.com/embassy-rs/trouble/blob/main/examples/nrf-sdc/src/bin/ble_bas_peripheral.rs#L35 to 251, and use nrf connect to request a large MTU, the device replies with 247.

So I'm not sure what this could be, do you have any other modifications to your code than changing the l2cap mtu? (Note you don't need to use set_att_mtu).

lulf avatar Mar 14 '25 09:03 lulf