ble-sniffer doesn't follow the device

I'm trying to capture a ble connection with nrfutil.

What I've done:

- installed nrfutil on my arch based linux machine

- install ble-sniffer

- setup the nRF52840 Dongle with the given firmware.

- the device itself (usb, tty, etc) works

I can start sniffing the advertising paket with 

nrfutil ble-sniffer sniff --port /dev/ttyACM1 --log-level=info --log-output=stdout --json

It works fine an gives several devices like this:

{"type":"log","data":{"level":"INFO","message":"Device added: {\"address\":{\"address\":\"f8:55:48:13:9c:a9\",\"type\":\"Public\"},\"name\":{\"name\":\"DEMO9CA9\",\"ty\":\"ShortenedLocalName\"},\"rssi\":-57,\"is_followed\":false}","timestamp":"2026-04-21T10:11:38.484Z"}}

But if I try to follow the device of interest I got the following output:

$nrfutil ble-sniffer sniff --port /dev/ttyACM1 --follow f8:55:48:13:9c:a9 --log-level=info --log-output=stdout --json
{"type":"log","data":{"level":"INFO","message":"nrfutil-ble-sniffer (version = 0.18.0, platform = x86_64-unknown-linux-gnu, classification = nrf-external) invoked with sniff --port /dev/ttyACM1 --follow f8:55:48:13:9c:a9 --log-level=info --log-output=stdout --json ","timestamp":"2026-04-21T10:12:39.446Z"}}
{"type":"log","data":{"level":"INFO","message":"Attempt opening serial port at /dev/ttyACM1","timestamp":"2026-04-21T10:12:39.447Z"}}
{"type":"log","data":{"level":"INFO","message":"Subscribing to event DEVICE_ADDED","timestamp":"2026-04-21T10:12:39.448Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending version request","timestamp":"2026-04-21T10:12:39.448Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending ping request","timestamp":"2026-04-21T10:12:39.448Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending timestamp request","timestamp":"2026-04-21T10:12:39.448Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending advertisement hop sequence request for channels [37, 38, 39]","timestamp":"2026-04-21T10:12:39.451Z"}}
{"type":"log","data":{"level":"INFO","message":"Changing state from IDLE to SCANNING","timestamp":"2026-04-21T10:12:39.452Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending scan packet","timestamp":"2026-04-21T10:12:39.452Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending request to use temporary key [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]","timestamp":"2026-04-21T10:12:39.453Z"}}
{"type":"log","data":{"level":"INFO","message":"Changing state from SCANNING to FOLLOWING","timestamp":"2026-04-21T10:12:39.454Z"}}
{"type":"log","data":{"level":"WARN","message":"No device with address f8:55:48:13:9c:a9 random found. Still sending the follow request call, but no device is registered as followed.","timestamp":"2026-04-21T10:12:39.454Z"}}
{"type":"log","data":{"level":"INFO","message":"Sending follow request to follow device with address f8:55:48:13:9c:a9 random","timestamp":"2026-04-21T10:12:39.454Z"}}

In the resulting pcap file there are only advertising pakets.

There is the warning ""WARN","message":"No device with address f8:55:48:13:9c:a9 ... The ble-sniffer doesn't scan and add the device before it starts following.


Whats wrong here?

Parents Reply Children
  • It seems that the bug is still present in v0.20.0, here are my findings;

    Environment

    - nrfutil: 8.2.0 (c910332, 2026-04-21)
    - nrfutil-ble-sniffer: 0.20.0 (1d77b74, 2026-06-02)
    - Dongle: nRF52840 Dongle PCA10059, serial 2E3B1D3B264894A2
    - Sniffer firmware: 4.1.1 (flashed via `nrfutil device program`)
    - Host: Raspberry Pi 5, aarch64, Linux 6.18
    - Target device: ESP32-based BLE peripheral, public address `84:1f:e8:51:8a:16`, advertises as `BlueLink:09271`

    What works

    Without `--follow`, the sniffer captures the target's advertisements correctly:


    $ ./nrfutil ble-sniffer sniff --port /dev/ttyACM0 --output-pcap-file test.pcap
    # -> 2785 packets in 15 seconds, target device visible in pcap


    $ tshark -r test.pcap -Y "btle.advertising_address == 84:1f:e8:51:8a:16"
    20 0.178367 Espressif_51:8a:16 → Broadcast LE LL 58 ADV_IND
    21 0.179867 Espressif_51:8a:16 → Broadcast LE LL 58 ADV_IND
    ...

    What fails

    With `--follow`, the target device is never captured:


    $ ./nrfutil ble-sniffer sniff --port /dev/ttyACM0 --follow 84:1F:E8:51:8A:16 \
    --output-pcap-file follow.pcap
    # -> 4000+ packets from OTHER devices, zero from the target

    Same result with `--follow-by-name "BlueLink:09271"`.

    Root cause (from trace log)

    Running with `--log-level trace --log-output stdout` reveals the exact problem:


    [05:43:16.329Z] INFO - Changing state from IDLE to SCANNING
    [05:43:16.329Z] INFO - Sending scan packet
    [05:43:16.330Z] INFO - Changing state from SCANNING to FOLLOWING
    [05:43:16.330Z] WARN - No device with address 84:1f:e8:51:8a:16 random found.
    Still sending the follow request call, but no device
    is registered as followed.
    [05:43:16.330Z] INFO - Sending follow request to follow device with address
    84:1f:e8:51:8a:16 random

    Two bugs visible here:

    1. Timing: The follow command is sent **1 ms after the scan command**, before the sniffer has discovered any devices. The state transitions `IDLE → SCANNING → FOLLOWING` within the same millisecond. The warning `"No device with address ... found"` confirms the device hasn't been seen yet.

    2. Address type: The follow request uses address type **random**, but the target device uses a **public** address (Espressif OUI `84:1F:E8`). The sniffer firmware then filters for a random-address device that doesn't exist. This is confirmed by the unfollowed capture where tshark shows `randomized_tx: False` for this device.

    The `--follow-by-name` variant has the same timing problem:


    [05:44:19.888Z] INFO - Changing state from IDLE to SCANNING
    [05:44:19.888Z] WARN - No device with name BlueLink:09271 found.
    Can't send follow request call.

    It also fires immediately, but unlike `--follow` it doesn't even send the follow command — it silently falls back to unfollowed mode.

    Expected behavior

    The sniffer should:

    1. Start scanning
    2. Wait until the target device is discovered (by address or name)
    3. Read the correct address type (public/random) from the discovered device
    4. **Then** send the follow command with the correct address type

    Workaround

    I wrote a Python script that talks to the sniffer firmware directly over the serial protocol, implementing the correct scan-then-follow sequence. It discovers the device, reads the address type, then sends the follow command:


    # Scan until target is found
    info = extract_adv_info(pkt)
    if info['addr_str'] == target_mac and not found:
    # Send follow with the DISCOVERED address type
    cmd_follow(target_display_bytes, info['addr_type'])

    With this workaround, the firmware correctly enters FOLLOWING state and tracks the device through a connection (I can see it transition from ADV_PDU events to empty-data-PDU events when the phone connects).

    The fix in v0.19.0 did not resolve the issue. The `--follow` and `--follow-by-name` options are non-functional in 0.20.0 because the follow command races the scan, and `--follow` additionally hardcodes the address type to random.

Related