BTSNOOP(7)
π btsnoop(7) β BTSnoop/Monitor protocol documentation π
okay so this is btsnoop(7), straight out of the Linux System Administration section of the manual β and bestie, it's literally the blueprint for how HCI/PHY traffic gets recorded and transported. no cap. β¨
β¨ SYNOPSIS β¨
This document describes the BTSnoop/Monitor formats used to record and transport HCI/PHY traffic. The formats are used by tools such as btmon and the BlueZ btsnoop implementation.
like, if you've ever wondered how btmon and the BlueZ btsnoop girlies do their thing? it's this. π«Ά
πΈ DESCRIPTION πΈ
π Opcode definitions
The following opcodes are used by the BTSnoop/Monitor formats. The numeric values match the definitions in src/shared/btsnoop.h.
π BTSnoop opcodes
BTSNOOP_OPCODE_NEW_INDEXβ code0(dec) /0x0000(hex) β New controller index (parameters: type, bus, bdaddr, name)BTSNOOP_OPCODE_DEL_INDEXβ code1(dec) /0x0001(hex) β Deleted controller indexBTSNOOP_OPCODE_COMMAND_PKTβ code2(dec) /0x0002(hex) β HCI Command packetBTSNOOP_OPCODE_EVENT_PKTβ code3(dec) /0x0003(hex) β HCI Event packetBTSNOOP_OPCODE_ACL_TX_PKTβ code4(dec) /0x0004(hex) β Outgoing ACL packetBTSNOOP_OPCODE_ACL_RX_PKTβ code5(dec) /0x0005(hex) β Incoming ACL packetBTSNOOP_OPCODE_SCO_TX_PKTβ code6(dec) /0x0006(hex) β Outgoing SCO packetBTSNOOP_OPCODE_SCO_RX_PKTβ code7(dec) /0x0007(hex) β Incoming SCO packetBTSNOOP_OPCODE_OPEN_INDEXβ code8(dec) /0x0008(hex) β HCI transport for the specified controller openedBTSNOOP_OPCODE_CLOSE_INDEXβ code9(dec) /0x0009(hex) β HCI transport for the specified controller closedBTSNOOP_OPCODE_INDEX_INFOβ code10(dec) /0x000a(hex) β Index information (parameters: bdaddr, manufacturer)BTSNOOP_OPCODE_VENDOR_DIAGβ code11(dec) /0x000b(hex) β Vendor diagnostic informationBTSNOOP_OPCODE_SYSTEM_NOTEβ code12(dec) /0x000c(hex) β System noteBTSNOOP_OPCODE_USER_LOGGINGβ code13(dec) /0x000d(hex) β User logging (parameters: priority, ident_len, ident)BTSNOOP_OPCODE_CTRL_OPENβ code14(dec) /0x000e(hex) β Control channel openedBTSNOOP_OPCODE_CTRL_CLOSEβ code15(dec) /0x000f(hex) β Control channel closedBTSNOOP_OPCODE_CTRL_COMMANDβ code16(dec) /0x0010(hex) β Control command packetBTSNOOP_OPCODE_CTRL_EVENTβ code17(dec) /0x0011(hex) β Control event packetBTSNOOP_OPCODE_ISO_TX_PKTβ code18(dec) /0x0012(hex) β Outgoing ISO packetBTSNOOP_OPCODE_ISO_RX_PKTβ code19(dec) /0x0013(hex) β Incoming ISO packet
π¦ New Index
Code: 0x0000
Parameters:
- Type (1 octet)
- Bus (1 octet)
- BD_Addr (6 octets)
- Name (8 octets)
This opcode indicates that a new controller instance with a given index was added. With some transports (for example a single TTY device) the index is implicitly 0.
lowkey important: that implicit 0 thing is transport-dependent, so don't go assuming it everywhere π
π Deleted Index
Code: 0x0001
Indicates that the controller with a specific index was removed.
bye bestie π that index is gone.
π§ TTY-based protocol
The TTY protocol used by btmon with the --tty option is a little-endian packet format. Each packet uses this header:
struct tty_hdr {
uint16_t data_len;
uint16_t opcode;
uint8_t flags;
uint8_t hdr_len;
uint8_t ext_hdr[0];
} __attribute__ ((packed));
The payload starts at ext_hdr + hdr_len and has length data_len - 4 - hdr_len.
like, that math is literally doing the most but it's giving exact byte boundaries, periodt. π
π Extended header format
Each extension field is encoded as:
struct {
uint8_t type;
uint8_t value[length];
};
Defined types:
β¦and the actual list of defined types is literally in part 2, bestie β stay tuned π«Άβ¨
β¨ Extended header types β¨
Okay so these are the little extension fields you can slap onto the end of a packet record, and each one has a type number and a length. Here's the whole lineup, bestie:
- Type
1, length1 byteβ Command drops (like, dropped HCI command packets π«³) - Type
2, length1 byteβ Event drops (dropped HCI event packets, rip) - Type
3, length1 byteβ ACL TX drops - Type
4, length1 byteβ ACL RX drops - Type
5, length1 byteβ SCO TX drops - Type
6, length1 byteβ SCO RX drops - Type
7, length1 byteβ Other drops - Type
8, length4 bytesβ a 32-bit timestamp, measured in 1/10th ms β±οΈ
The drops fields are literally just a count β the number of packets the implementation had to drop since the last reported drop count. Not cumulative, bestie, it resets each time. π
And here's the rule you cannot skip: extension fields must be sorted by increasing type so that unknown types can be skipped and the payload location discovered. Yes, this is load-bearing. Do not come crying to me when you write them out of order and everything falls apart π
π RESOURCES π
That's the spot. Go forth. β¨
π REPORTING BUGS π
linux-bluetooth@vger.kernel.org
Found something cursed? Email the list, don't suffer in silence, fr fr.
π¦ SEE ALSO π¦
The other main character, obvi. Go read that one too π
π COPYRIGHT π
Free use of this software is granted under the terms of the GNU Lesser General Public Licenses (LGPL).
Like, actually free. Slay. π
And that's the whole page, bestie β brought to you by BlueZ, dated February 2026, filed under BTSNOOP(7) in the manual pages. Go capture some packets, king. π β¨
π¦ where this page comes from
- centos-stream 9: bluez-libs-devel 5.87+2.git8750129efca8-1.el9 Β· GPLv2+
- centos-stream 9: bluez-libs-devel 5.87+2.git8750129efca8-1.el9 Β· GPLv2+
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms