Skip to content

bluetooth: strip Broadcom vendor bits from legacy LE adv report type - #57

Open
josemiguelo wants to merge 1 commit into
t2linux:mainfrom
josemiguelo:bluetooth-bcm-adv-type
Open

bluetooth: strip Broadcom vendor bits from legacy LE adv report type#57
josemiguelo wants to merge 1 commit into
t2linux:mainfrom
josemiguelo:bluetooth-bcm-adv-type

Conversation

@josemiguelo

Copy link
Copy Markdown

Bluetooth: LE auto-reconnect never fires on BCM4364 (ROM firmware) — strip vendor bits from adv report type

Hardware / software

  • MacBookPro16,1 (T2), Bluetooth BCM4364B3 "Trinidad Olympic" on hci_uart_bcm, ROM firmware (BCM (001.016.091) build 0115; no brcm/BCM.hcd exists for this model — t2linux only ships BT firmware for 15,4 / 16,3 / Air9,1)
  • Fedora 44, bluez 5.87. Reproduced on kernel-7.0.10-201.t2.fc44, 6.19.12-210.t2 and — with the
    stock module — on the current kernel-7.1.9-200.t2.fc44, so this is not an old-kernel artifact.
  • Peripherals: Logitech MX Master 3 (BLE HID), Keychron K15 Max (BLE HID)

Symptom

Bonded LE HID devices don't reconnect when woken. dmesg fills with

Bluetooth: hci0: unknown advertising packet type: 0x81
Bluetooth: hci0: unknown advertising packet type: 0xa1
Bluetooth: hci0: unknown advertising packet type: 0x91

Tally over several boots (144 drops): 0xa1×35 0x81×35 0x91×17 0x11×8 0x21×6 0x90×4 0x80×4 0x14×4 0xa0×3 0x10×2 0xa2 0x93 0x24 0x23. The low nibble is always a valid legacy type (0–4); the upper nibble is 0x1/0x2/0x8/0x9/0xa vendor noise.

Root cause (btmon)

The controller reports the mouse's reconnect adverts with garbage high bits in Event_Type most of the time, and cleanly sometimes:

> HCI Event: LE Meta Event (0x3e) plen 12          2026-08-28 11:37:40
      LE Advertising Report (0x02)
        Event type: Reserved (0x81)                 <- dropped by process_adv_report()
        Address: E8:BB:F0:C3:98:2F (Static)
        Data length: 0

> HCI Event: LE Meta Event (0x3e) plen 12          2026-08-28 11:38:20
      LE Advertising Report (0x02)
        Event type: Connectable directed - ADV_DIRECT_IND (0x01)
        Address: E8:BB:F0:C3:98:2F (Static)
< HCI Command: LE Create Connection (0x08|0x000d)   +3 ms
> HCI Event: LE Enhanced Connection Complete       +70 ms, Status: Success
> HCI Event: Encryption Change                      Enabled with AES-CCM
kernel: logitech-hidpp-device ...: HID++ 4.5 device connected.

hci_le_adv_report_evt()process_adv_report() rejects any type > LE_ADV_SCAN_RSP, so the passive-scan auto-connect for bonded peripherals never triggers on the mangled reports. Reconnection only happens when a report slips through clean (~1 in 20). Every userspace path (bluetoothctl connect, L2CAP sockets) goes through the same scan-then-connect code, so no userspace workaround exists — a bluetoothctl connect loop only raises the odds.

Fix

Mask the type to its low nibble for Broadcom controllers (hdev->manufacturer == 15) when it is out of range, before validation. 2 lines of logic in net/bluetooth/hci_event.c; other vendors untouched.

This repo has carried the same shape of quirk before: 9001-Bluetooth-hci_event-Add-quirk-to-ignore-byte-in-LE-Extended-Adv-Report.patch patched the extended adv report path in this very file for T2 controllers. This is the legacy-report counterpart.

Scope / risk

  • Keyed on the local controller (hdev->manufacturer == 15), not on the peer device, and only for Event_Type > 0x04 — reports that were being discarded anyway. Valid reports (0x0–0x4) take the exact same path as before, so devices that work today are unaffected; the BR/EDR path is not involved.
  • Low nibbles ≥ 5 stay invalid and are still dropped.
  • Broadcom controllers with proper firmware never emit such types → inert there.
  • Worst case if the low nibble were ever wrong (never observed in 144 samples; the same mouse also emits the clean 0x01 for the same packet): a stray LE Create Connection that times out after a few seconds. No effect on established links.

Verification

Built the patched bluetooth module via DKMS (sources byte-identical to the stock module — all 3818 text symbols match in size; only the quirk differs).

On 7.0.10-201.t2, after reboot:

  • journalctl -k -b | grep -c "unknown advertising packet type"0 (was 39 in the previous half-day)
  • mouse reconnects on wake reliably; keyboard likewise.

Re-confirmed on 7.1.9-200.t2 (2026-09-02): after the kernel upgrade the DKMS package was dropped and the machine ran the stock module again — the MX Master 3 and Keychron K15 Max immediately stopped auto-reconnecting. Rebuilding the patched module for 7.1.9 restored reliable reconnect. The bug is present in current kernels.

Patch file: 9002-Bluetooth-hci_event-strip-Broadcom-vendor-bits-from-adv-type.patch (git format-patch, Signed-off-by).
Applies cleanly with git am on v7.1.9 and on v7.2.2 (the KVER this repo's main currently targets).


How to confirm this on your own machine

Nothing here changes anything on your system. You need at least one bonded BLE peripheral (mouse,
keyboard) for the bug to be observable at all — the mangled reports only appear when a paired device
is advertising to reconnect.

1. Count the dropped reports.

journalctl -k | grep -c "unknown advertising packet type"

Non-zero means your controller is emitting advertising types the kernel discards.

2. Look at what is being dropped.

journalctl -k | grep -o "unknown advertising packet type: 0x.." | sort | uniq -c | sort -rn

The signature is that every value has a valid legacy type in the low nibble (0x0-0x4) and vendor
noise in the high nibble (0x1/0x2/0x8/0x9/0xa). Mine, over several boots and 144 drops:

 35 0xa1    35 0x81    17 0x91     8 0x11     6 0x21
  4 0x90     4 0x80     4 0x14     3 0xa0     2 0x10

3. Confirm the controller is Broadcom running ROM firmware.

journalctl -k -b | grep -i "Bluetooth: hci0"
ls /lib/firmware/brcm/BCM*.hcd 2>/dev/null || echo "no patchram for this model"

Affected machines show a BCM (...) build string with no patchram ever loaded — there is no
"Patch file" / .hcd line, because t2linux ships BT firmware for only a few models. Mine reports
BCM (001.016.091) build 0115 on a BCM4364B3.

4. Watch it happen live.

sudo btmon

Let a bonded BLE mouse or keyboard sleep, then wake it, and watch for:

> HCI Event: LE Meta Event (0x3e) plen 12
      LE Advertising Report (0x02)
        Event type: Reserved (0x81)

Reserved (0x8x/0x9x/0xax) is the bug. Keep watching and the same device will occasionally emit a
clean Connectable directed - ADV_DIRECT_IND (0x01) and reconnect within ~70 ms. That contrast — same
device, same packet, sometimes clean — is what shows this is a report-parsing problem and not a link
or pairing problem.

5. The user-visible symptom: bonded LE HID devices do not reconnect when woken. They sit
disconnected until you retry by hand enough times for a clean report to land.

Verify the fix before it is merged

You do not need to rebuild a kernel — the bluetooth module can be rebuilt on its own via DKMS,
which also survives kernel updates. Requires dkms, kernel-devel for your running kernel, git
and patch, and Secure Boot off (the default on T2 Macs).

Create /usr/src/bluetooth-t2adv-1.0/ containing this PR's .patch file plus two others:

dkms.conf

PACKAGE_NAME="bluetooth-t2adv"
PACKAGE_VERSION="1.0"
BUILD_DIR="${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build"
PRE_BUILD="fetch-src.sh ${kernelver} ${BUILD_DIR}"
MAKE[0]="make -C ${kernel_source_dir} M=${BUILD_DIR}/src/net/bluetooth modules"
CLEAN="make -C ${kernel_source_dir} M=${BUILD_DIR}/src/net/bluetooth clean"
BUILT_MODULE_NAME[0]="bluetooth"
BUILT_MODULE_LOCATION[0]="src/net/bluetooth/"
DEST_MODULE_LOCATION[0]="/updates/"
AUTOINSTALL="yes"

fetch-src.sh (make it executable)

#!/bin/bash
# fetch-src.sh <kernelver> <build-dir>: sparse-clone net/bluetooth at the
# upstream tag matching this kernel and apply the quirk patch.
set -euo pipefail
kv=$1; dir=$2
ver=${kv%%-*}            # 7.1.9-200.t2.fc44.x86_64 -> 7.1.9
ver=${ver%.0}            # 7.1.0 -> 7.1 (upstream tags x.y.0 as vx.y)
cd "$dir"
rm -rf src
git clone --quiet --depth 1 --filter=blob:none --sparse --branch "v$ver" \
    https://github.com/gregkh/linux src
git -C src sparse-checkout set net/bluetooth
patch -p1 -d src < "$dir"/*.patch

Then:

sudo dkms install bluetooth-t2adv/1.0
sudo reboot

Only net/bluetooth is fetched, at the tag matching your running kernel, so this keeps working
across kernel updates for as long as the patch applies.

Verify after installing

Confirm you are actually running the rebuilt module:

modinfo --field=filename bluetooth      # -> /lib/modules/<ver>/extra/bluetooth.ko.xz

Then:

journalctl -k -b | grep -c "unknown advertising packet type"      # -> 0

and let each bonded LE peripheral sleep and wake it: it should reconnect on its own within a second
or two, every time, with no manual retries.

On my machine the current boot reports 0 dropped advertising reports, against 39 over a
comparable half-day on the stock module.

To go back at any time:

sudo dkms remove bluetooth-t2adv/1.0 --all && sudo reboot

Broadcom controllers running ROM firmware on T2 Macs (no patchram
available, e.g. BCM4364B3 on MacBookPro16,1 via hci_uart_bcm) set vendor
bits 0x10/0x20/0x80 in the legacy LE Advertising Report Event_Type, so
ADV_DIRECT_IND arrives as 0x81/0x91/0xa1 and process_adv_report() drops
it as unknown.

Directed advertising is exactly what bonded LE HID peripherals use to
reconnect, so the passive-scan auto-connect never fires and mice and
keyboards only reconnect when a report happens through clean, roughly
1 in 20. Every userspace path goes through the same scan-then-connect
code, so there is no workaround outside the kernel.

The real type is always in the low nibble; mask it for Broadcom
controllers when it is out of range. This repo already carries the
extended-report counterpart of the same quirk in
9001-Bluetooth-hci_event-Add-quirk-to-ignore-byte-in-LE-Extended-Adv-Report.patch.

Applies cleanly with git am on v7.1.9 and v7.2.3.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant