AsahiLinux / docs

Hardware and software docs / wiki
Other
1.76k stars 49 forks source link

Documenting vendor specific HCI commands on macOS #85

Open jonas2515 opened 10 months ago

jonas2515 commented 10 months ago

macOS sends a bunch of custom (vendor defined) HCI commands to the Broadcom bluetooth chip. Some of them appear to affect things like audio latency, some appear to be setting up AWDL/continuity things.

The commands are from a 2020 M1 Macbook Pro, would be interesting to see if they are the same on other models. They can be snooped on macOS using "PacketLogger" from the XCode Development tools.

Here's a list of the vendor specific commands (listed as hcitool cmd to quickly try them):

commands during controller init sequence ``` # these vendor specific commands get sent as part of the init sequence after turning on bluetooth on macOS sudo hcitool cmd 0x3f 0x0e2 0x2a 0x00 0x00 0x00 0x01 > HCI Event: 0x0e plen 13 01 E2 FC 00 00 00 00 00 00 00 00 00 00 sudo hcitool cmd 0x3f 0x11c 0x51 0x00 > HCI Event: 0x0e plen 7 01 1C FD 00 51 00 00 sudo hcitool cmd 0x3f 0x0e9 0x02 0x1e 0xae 0x7f 0xc4 0xa2 0xaf 0x01 0x3b 0xfc 0x12 0x96 0x7e 0xfe 0x7f 0x21 0x8d 0x00 0xef 0x4e 0xf3 0x9f 0x10 0x14 > HCI Event: 0x0e plen 6 01 E9 FC 00 02 7F sudo hcitool cmd 0x3f 0x0e9 0x02 0x79 0x26 0x77 0xcb 0xa1 0x71 0x50 0x6e 0xcd 0x7d 0x6e 0xc8 0x73 0xe7 0x26 0x8e 0x00 0x90 0xe5 0x58 0x4e 0xe9 0xf8 > HCI Event: 0x0e plen 6 01 E9 FC 00 02 7E sudo hcitool cmd 0x3f 0x0e9 0x02 0x3b 0xb0 0x3f 0x90 0x75 0xb1 0x6c 0x4b 0x4e 0x32 0x19 0x88 0x2b 0x95 0x6d 0xb3 0x00 0x7e 0xa5 0x06 0x6e 0x6b 0x88 > HCI Event: 0x0e plen 6 01 E9 FC 00 02 7D sudo hcitool cmd 0x3f 0x0e9 0x01 0xab 0x10 0x84 0x00 > HCI Event: 0x0e plen 5 01 E9 FC 00 01 sudo hcitool cmd 0x3f 0x0e2 0x1c 0x00 0x00 0x00 0x0a > HCI Event: 0x0e plen 13 01 E2 FC 00 00 00 00 00 00 00 00 00 00 # this one seems to set how many packets to buffer before transmitting (set to 1 here with 0x01) sudo hcitool cmd 0x3f 0x0e2 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 > HCI Event: 0x0e plen 13 01 E2 FC 00 00 00 00 00 00 00 00 00 00 sudo hcitool cmd 0x3f 0x148 0x01 0xa5 0x90 0x72 0xdd 0x8a 0x52 > HCI Event: 0x0e plen 5 01 48 FD 00 02 sudo hcitool cmd 0x3f 0x147 0x00 0x00 0x01 > HCI Event: 0x0e plen 4 01 47 FD 00 sudo hcitool cmd 0x3f 0x148 0x00 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 5 01 48 FD 00 03 sudo hcitool cmd 0x3f 0x1f2 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x01 > HCI Event: 0x0e plen 36 01 F2 FD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 sudo hcitool cmd 0x3f 0x148 0x01 0x83 0x6f 0xb3 0x8a 0xf4 0x28 > HCI Event: 0x0e plen 5 01 48 FD 00 04 sudo hcitool cmd 0x3f 0x0e2 0x26 0x00 0x00 0x00 0x01 0x00 > HCI Event: 0x0e plen 13 01 E2 FC 00 00 00 00 00 00 00 00 00 00 sudo hcitool cmd 0x3f 0x148 0x01 0x7d 0xec 0xfc 0xd1 0x98 0x1c > HCI Event: 0x0e plen 5 01 48 FD 00 05 # this one returns "Unsupported Feature or Parameter Value" sudo hcitool cmd 0x3f 0x0e9 0x32 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xa6 0x09 > HCI Event: 0x0e plen 5 01 E9 FC 11 32 sudo hcitool cmd 0x3f 0x148 0x01 0xbb 0x94 0xb8 0x34 0x86 0x27 > HCI Event: 0x0e plen 5 01 48 FD 00 06 sudo hcitool cmd 0x3f 0x0e9 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x04 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 6 01 E9 FC 00 05 00 sudo hcitool cmd 0x3f 0x14e 0x01 0x01 0xa5 0x90 0x72 0xdd 0x8a 0x52 > HCI Event: 0x0e plen 4 01 4E FD 12 sudo hcitool cmd 0x3f 0x14e 0x06 0x01 0xa5 0x90 0x72 0xdd 0x8a 0x52 > HCI Event: 0x0e plen 4 01 4E FD 12 sudo hcitool cmd 0x3f 0x14e 0x03 0x01 0x65 0x09 0xb9 0x27 0x21 0x74 > HCI Event: 0x0e plen 4 01 4E FD 00 sudo hcitool cmd 0x3f 0x14e 0x05 0x01 0x66 0x20 0x29 0xf4 0x27 0x47 > HCI Event: 0x0e plen 4 01 4E FD 00 sudo hcitool cmd 0x3f 0x0e9 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x12 0x18 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14a 0x01 0xb0 0x01 0xb0 0x01 0x00 0x07 0x00 > HCI Event: 0x0e plen 4 01 4A FD 00 sudo hcitool cmd 0x3f 0x0e9 0x05 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x02 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14b 0x01 0x11 0x02 0x01 0x1a 0x02 0x0a 0x05 0x0a 0xff 0x4c 0x00 0x10 0x05 0x45 0x1c 0x83 0xd7 0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 4 01 4B FD 00 sudo hcitool cmd 0x3f 0x0e9 0x07 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x02 > HCI Event: 0x0e plen 7 01 E9 FC 00 07 02 08 sudo hcitool cmd 0x3f 0x14d 0x01 0x01 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 4 01 4D FD 00 sudo hcitool cmd 0x3f 0x0e9 0x1e > HCI Event: 0x0e plen 7 01 E9 FC 00 1E 64 64 sudo hcitool cmd 0x3f 0x14a 0x05 0xb0 0x01 0xb0 0x01 0x00 0x07 0x00 > HCI Event: 0x0e plen 4 01 4A FD 00 sudo hcitool cmd 0x3f 0x0e9 0x35 0x02 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14b 0x05 0x11 0x02 0x01 0x1a 0x02 0x0a 0x05 0x0a 0xff 0x4c 0x00 0x10 0x05 0x45 0x1c 0x83 0xd7 0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x0e9 0x32 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x9c 0x12 > HCI Event: 0x0e plen 5 01 E9 FC 11 32 # this one makes the device appear in AirDrop sudo hcitool cmd 0x3f 0x14d 0x05 0x01 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 4 01 4D FD 00 sudo hcitool cmd 0x3f 0x0e9 0x01 0xab 0x10 0x84 0x00 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x0e9 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x04 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 6 01 E9 FC 00 05 00 sudo hcitool cmd 0x3f 0x0e9 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x12 0x18 > HCI Event: 0x0e plen 7 01 E9 FC 00 07 00 07 sudo hcitool cmd 0x3f 0x14d 0x01 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14d 0x05 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14a 0x01 0xb0 0x01 0xb0 0x01 0x00 0x07 0x00 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14b 0x01 0x11 0x02 0x01 0x1a 0x02 0x0a 0x05 0x0a 0xff 0x4c 0x00 0x10 0x05 0x45 0x1c 0x83 0xd7 0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 4 01 4B FD 00 sudo hcitool cmd 0x3f 0x14d 0x01 0x01 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x14a 0x05 0xb0 0x01 0xb0 0x01 0x00 0x07 0x00 > HCI Event: 0x0e plen 4 01 4A FD 00 sudo hcitool cmd 0x3f 0x14b 0x05 0x11 0x02 0x01 0x1a 0x02 0x0a 0x05 0x0a 0xff 0x4c 0x00 0x10 0x05 0x45 0x1c 0x83 0xd7 0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 4 01 4B FD 00 sudo hcitool cmd 0x3f 0x14d 0x05 0x01 0x00 0x00 0x00 0x00 0x00 > HCI Event: 0x0e plen 4 01 4D FD 00 # from now on only similar series of 0x0e9 commands get executed periodically (something that seems to be related to LE stuff: LE scanning gets disabled, command sequence is executed, LE scanning enabled again) ```
commands after connecting an a2dp sink ``` sudo hcitool cmd 0x3f 0x0e2 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 ```
commands after starting to play on a2dp sink ``` # broadcom set ACL priority (0x0b 0x00 is the connection handle) sudo hcitool cmd 0x3f 0x057 0x0b 0x00 0x01 > HCI Event: 0x13 plen 5 01 0B 00 01 00 sudo hcitool cmd 0x3f 0x0e2 0x04 0x00 0x00 0x00 0x2d 0x00 0x00 0x00 # here the 0x0c 0x00 is a connection handle # after sending this command we get a vendor defined event (len 180, starts with seq 0x88 0x1d 0x01 0x15 0x00, the last two bytes is the connection handle) every second, they stop again when disconnecting the device sudo hcitool cmd 0x3f 0x1dd 0x0c 0x00 0x1d 0x01 # here 0x0c 0x00 is a connection handle # after this we start getting a few vendor defined events (len 224, starting with 0xb5 0x00 0x00 0x01) sudo hcitool cmd 0x3f 0x205 0x01 0x02 0x02 0x00 0x02 0x00 0x0c 0x00 # here 0x0c 0x00 is a connection handle sudo hcitool cmd 0x3f 0x0e2 0x15 0x00 0x00 0x00 0x0c 0x00 0x01 0x06 0x00 0x83 # here 0x0c 0x00 is a connection handle sudo hcitool cmd 0x3f 0x22d 0x00 0x0c 0x00 0x07 0xc2 0x81 0x00 0x00 0x00 0x00 0x00 ```
commands after ending audio stream a2dp sink ``` # here the 0x0d 0x00 is a connection handle sudo hcitool cmd 0x3f 0x1dd 0x0d 0x00 0x00 0x00 # here 0x0d 0x00 is a connection handle sudo hcitool cmd 0x3f 0x22d 0x00 0x0d 0x00 0x00 0xbb 0xb0 0x00 0x00 0x00 0x00 0x00 # broadcom set ACL priority (0x0d 0x00 is the connection handle) sudo hcitool cmd 0x3f 0x057 0x0d 0x00 0x00 sudo hcitool cmd 0x3f 0x0e2 0x04 0x00 0x00 0x00 0x2d 0x00 0x00 0x00 ```
commands after disconnecting an a2dp sink ``` sudo hcitool cmd 0x3f 0x0e2 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 ```
commands after connecting magic keyboard or mouse ``` sudo hcitool cmd 0x3f 0x0e2 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 # here 0x10 0x00 is a connection handle # sent every time after moving the connection to sniff mode, sometimes card returns "Command Disallowed" sudo hcitool cmd 0x3f 0x206 0x10 0x00 0x01 0x01 0x64 0x00 0x00 0x00 ```

Nothing special seems to happen on disconnecting magic keyboard or mouse.

The different kinds of OCFs seen are

Mostly relevant to us is the 0x057 "set ACL priority" command, as that fixes audio choppiness during BT scans or connection requests. Also the 0x0e2 command that sets the num of buffers to queue before transmitting seems interesting from a latency standpoint.

jonas2515 commented 10 months ago

Status update:

jiska2342 commented 10 months ago

Hi all,

I did a bit of reverse engineering to find more commands 🎉

On startup, bluetoothd checks which Broadcom chip the device has and then creates a list of supported vendor-specific commands. That means, depending on the Broadcom chip, there might be different vendor-specific features available. My reverse engineering here is based on an iPhone 13 mini SRD on iOS 16.3 as well as an M1 MacBook on macOS 13.4.1. Apple could ask Broadcom to add more features any time, and these could be added on both ends, *OS and the Broadcom firmware, just through a software update. Yet, in my experience, these vendor-specific commands tend to be very stable across versions, and if a new feature is added, they would add new commands rather than repurposing old command IDs.

Internally, bluetoothd has a list of commands mapped to names. However, the command IDs used there have a different numbering scheme than HCI. So far, I haven't found the part that does the translation between the two. Luckily, I was able to dynamically print the command names with Frida before the HCI packets are composed, allowing me to map the most relevant HCI commands to names.

Here are the results:

0xfc57 BD_VSC_WRITE_HI_PRIO_CONN (macOS) / BD_VSC_HI_PRIO_CONN (iOS name)

0xfce2
    0x00    BD_VSC_OLYMPIC_NUM_CMPLT_PKT_THRESH
    0x04    BD_VSC_OLYMPIC_SET_HI_PRIO_RSSI
    0x0b    BD_VSC_OLYMPIC_CHANGE_LE_SETTINGS                   // attempted on M1 but only supported on iOS
    0x15    BD_VSC_OLYMPIC_ANTENNA_PREF_B
    0x19    BD_VSC_OLYMPIC_A2DP_ACL_SIMULTANEOUS
    0x1c    BD_VSC_OLYMPIC_SET_MIN_AFH_LE_CHANNELS
    0x1e    BD_VSC_OLYMPIC_ADV_DUPLICATE_FILTER_BYPASS_CONFIG   // attempted on M1 but only supported on iOS
    0x26    BD_VSC_OLYMPIC_SET_SAR_LOCATION
    0x2a    BD_VSC_ENABLE_HOST_WAKE_REPORT
    0x2c    BD_VSC_OLYMPIC_SET_EXT_SCAN_LIMITS                  // attempted on M1 but only supported on iOS
    0x2d    BD_VSC_OLYMPIC_GET_EXT_ADV_DROPPED
    0x31    BD_VSC_OLYMPIC_SET_EXT_SCAN_BUFFERS                 // attempted on M1 but only supported on iOS
    0x36    BT_VSC_OLYMPIC_SET_RETAIN_LE_SCAN_DUPLICATES_ON_START  // attempted on M1 but only supported on iOS
    0x3a    BD_VSC_ENABLE_POWER_TAG

0xfce9
    0x01    BD_VSC_LE_META_ENA_FEATURES
    0x02    BD_VSC_LE_META_ADD_IRK_TO_LIST
    0x03    BD_VSC_LE_META_REMV_IRK_FROM_LIST
    0x05    BD_VSC_LE_META_ADV_PCF_FEATURE_SEL
    0x07    BD_VSC_LE_META_ADV_PCF_SERVICE_UUID // on macOS
    0x1e    BD_VSC_LE_META_RESET_ADV_MATCHING_RULES
    0x20    BD_VSC_LE_META_RESET_ZONE_MONITOR_FEAT
    0x50    BD_VSC_LE_META_ADV_PCF_SERVICE_UUID // on iOS
    0x35    BD_VSC_LE_META_CONFIG_ADV_MATCHING_ADDRESS_LIST
    0x37    BD_VSC_LE_META_ADD_ADV_MATCHING_RULE_ENHANCED

0xfd02  BD_VSC_ENA_WBS

0xfd03  BD_VSC_SET_VS_EVENT_MASK

0xfd1c 
    0x51    BD_VSC_ENABLE_DISABLE_FW_LOG_STREAMING

0xfd47  BD_VSC_ENABLE_EXTENDED_DUPLICATE_FILTER

0xfd48  ?? used but no name

0xfd5c  BD_VSC_REMOTE_AP_WRITE_LOCAL_STATE

0xfd7f  BD_VSC_LTE_VSC

0xfdea  BD_VSC_ENABLE_LMP_ROUTING_THROUGH_VSE

0xfdf2  BD_VSC_BEAMFORMING_MRC_CONTROL   // Beamforming MRC Global control Enable

0xfdfd  BD_VSC_HDR_CONTROL      // attempted on M1 but only supported on iOS

0xfddd  BD_VSC_OLYMPIC_ENHANCED_LINK_QUAL_STATS

0xfe00  BD_VSC_PHY_STATISTIC

0xfe06  BD_VSC_CENTRAL_SKIP_SNIFF_MODE

0xfe2c
    0x03    BD_VSC_MATCHTABLE_CONFIG
    0x04    BD_VSC_MATCHTABLE_PARAMS
    0x07    BD_VSC_ADVBUFMATCH_CONTROL

0xfe29  BD_VSC_OP_POWER_LDO_DURING_SLEEP

0xfe2d  BD_VSC_HP_BF

0xfe3c  BD_VSC_DUP_FILTER_REPORT_ENABLE

0xfe49  BD_VSC_SET_BTSC_PAGE_SCAN

0xfe65  BD_VSC_OP_HID_HIGH_PRIORITY_ACL_CONN

0xfe6e  BD_VSC_SCO_BUFFER_SIZE_CONTROL

0xfff2  BD_VSC_BTCLK_SENSORC_TIMESYNC   // attempted on M1 but only supported on iOS

These were commands I observed when enabling/disabling Bluetooth, connecting AirPods, a Bose headset, tethering with an iPhone, Apple Magic Keyboard and Magic Trackpad.

It might be worth to invest more time on static reversing of bluetoothd, as the full command list is much larger. Also, as bluetoothd composes all those HCI packets, the binary even contains information about what the values inside these packets could mean!

In case anyone wants to reproduce this with different peripherals or log Bluetooth packets along with system log messages to get more insights into what functionality these packets might implement, here are the scripts I used: asahi-bt-hooks.zip

jiska2342 commented 10 months ago

Edit: I just realised 2-3 more commands being used when suspending the M1 and logging for a longer time, so I added these to the list above, such as BD_VSC_REMOTE_AP_WRITE_LOCAL_STATE.

jonas2515 commented 7 months ago

Took me a while to get back to this, thanks a lot for all the reverse engineering work Jiska, it's quite crazy how many Apple-specific features this firmware has..

I've opened an issue with BlueZ to figure out how we can integrate those vendor specific commands: https://github.com/bluez/bluez/issues/722