2 * https://www.tcpdump.org/linktypes/LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR.html
4 * Copyright 2014, Christopher D. Kilgour, techie at whiterocker dot com
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <wiretap/wtap.h>
18 #include "packet-btle.h"
20 #define LE_DEWHITENED 0x0001
21 #define LE_SIGPOWER_VALID 0x0002
22 #define LE_NOISEPOWER_VALID 0x0004
23 #define LE_PACKET_DECRYPTED 0x0008
24 #define LE_REF_AA_VALID 0x0010
25 #define LE_AA_OFFENSES_VALID 0x0020
26 #define LE_CHANNEL_ALIASED 0x0040
27 #define LE_PDU_TYPE 0x0380
28 #define LE_CRC_CHECKED 0x0400
29 #define LE_CRC_VALID 0x0800
30 #define LE_MIC_CHECKED 0x1000
31 #define LE_MIC_VALID 0x2000
34 #define BTLE_RF_OCTETS 10
36 static int proto_btle_rf
;
38 static int hf_btle_rf_signed_byte_unused
;
39 static int hf_btle_rf_unsigned_byte_unused
;
40 static int hf_btle_rf_word_unused
;
41 static int hf_btle_rf_channel
;
42 static int hf_btle_rf_signal_dbm
;
43 static int hf_btle_rf_noise_dbm
;
44 static int hf_btle_rf_access_address_offenses
;
45 static int hf_btle_rf_reference_access_address
;
46 static int hf_btle_rf_flags
;
47 static int hf_btle_rf_dewhitened_flag
;
48 static int hf_btle_rf_sigpower_valid_flag
;
49 static int hf_btle_rf_noisepower_valid_flag
;
50 static int hf_btle_rf_packet_decrypted_flag
;
51 static int hf_btle_rf_ref_aa_valid_flag
;
52 static int hf_btle_rf_aa_offenses_valid_flag
;
53 static int hf_btle_rf_channel_aliased_flag
;
54 static int hf_btle_rf_pdu_type
;
55 static int hf_btle_rf_crc_checked_flag
;
56 static int hf_btle_rf_crc_valid_flag
;
57 static int hf_btle_rf_mic_checked_flag
;
58 static int hf_btle_rf_mic_valid_flag
;
59 static int hf_btle_rf_phy
;
61 static int * const hfs_btle_rf_flags
[] = {
62 &hf_btle_rf_dewhitened_flag
,
63 &hf_btle_rf_sigpower_valid_flag
,
64 &hf_btle_rf_noisepower_valid_flag
,
65 &hf_btle_rf_packet_decrypted_flag
,
66 &hf_btle_rf_ref_aa_valid_flag
,
67 &hf_btle_rf_aa_offenses_valid_flag
,
68 &hf_btle_rf_channel_aliased_flag
,
70 &hf_btle_rf_crc_checked_flag
,
71 &hf_btle_rf_crc_valid_flag
,
72 &hf_btle_rf_mic_checked_flag
,
73 &hf_btle_rf_mic_valid_flag
,
78 static int ett_btle_rf
;
79 static int ett_btle_rf_flags
;
81 static dissector_handle_t btle_rf_handle
;
82 static dissector_handle_t btle_handle
;
84 void proto_register_btle_rf(void);
85 void proto_reg_handoff_btle_rf(void);
87 static const value_string le_phys
[] =
96 static const value_string le_pdus
[] =
98 { 0, "Advertising or Data (Unspecified Direction)" },
99 { 1, "Auxiliary Advertising" },
100 { 2, "Data, Central to Peripheral" },
101 { 3, "Data, Peripheral to Central" },
102 { 4, "Connected Isochronous, Central to Peripheral" },
103 { 5, "Connected Isochronous, Peripheral to Central" },
104 { 6, "Broadcast Isochronous" },
110 btle_rf_channel_type(uint8_t rf_channel
)
112 if (rf_channel
<= 39) {
117 return "Advertising channel";
119 return "Data channel";
122 return "Illegal channel";
126 btle_rf_channel_index(uint8_t rf_channel
)
128 if (rf_channel
<= 39) {
129 if (rf_channel
== 39) {
132 else if (rf_channel
>= 13) {
133 return rf_channel
- 2;
135 else if (rf_channel
== 12) {
138 else if (rf_channel
>= 1) {
139 return rf_channel
- 1;
149 dissect_btle_rf(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
152 proto_tree
*btle_rf_tree
;
154 btle_context_t context
;
158 bluetooth_data_t
*bluetooth_data
= (bluetooth_data_t
*) data
;
160 if (tvb_captured_length(tvb
) < BTLE_RF_OCTETS
)
163 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BTLE RF");
164 col_clear(pinfo
->cinfo
, COL_INFO
);
166 flags
= tvb_get_letohs(tvb
, 8);
168 memset(&context
, 0, sizeof(context
));
169 context
.previous_protocol_data
.bluetooth_data
= bluetooth_data
;
170 context
.aa_category
= E_AA_NO_COMMENT
;
171 context
.crc_checked_at_capture
= !!(flags
& LE_CRC_CHECKED
);
172 context
.crc_valid_at_capture
= !!(flags
& LE_CRC_VALID
);
173 context
.mic_checked_at_capture
= !!(flags
& LE_MIC_CHECKED
);
174 context
.mic_valid_at_capture
= !!(flags
& LE_MIC_VALID
);
176 switch ((flags
& LE_PDU_TYPE
) >> 7)
178 case 0: // Advertising or Data (Unspecified Direction)
179 // backwards compatible path
180 context
.pdu_type
= BTLE_PDU_TYPE_UNKNOWN
;
182 case 1: // Auxiliary Advertising
183 // advertising is never encrypted, so MIC flags are repurposed
184 context
.pdu_type
= BTLE_PDU_TYPE_ADVERTISING
;
185 context
.mic_checked_at_capture
= false;
186 context
.mic_valid_at_capture
= false;
188 // context.aux_pdu_type values defined in aux_pdu_common_vals of packet-btle.c
189 // they match with the definition for this link type
190 context
.aux_pdu_type
= (flags
& 0x3000) >> 12;
191 context
.aux_pdu_type_valid
= true;
193 case 2: // Data, Central to Peripheral
194 context
.pdu_type
= BTLE_PDU_TYPE_DATA
;
195 context
.direction
= BTLE_DIR_CENTRAL_PERIPHERAL
;
196 pinfo
->p2p_dir
= P2P_DIR_SENT
;
198 case 3: // Data, Peripheral to Central
199 context
.pdu_type
= BTLE_PDU_TYPE_DATA
;
200 context
.direction
= BTLE_DIR_PERIPHERAL_CENTRAL
;
201 pinfo
->p2p_dir
= P2P_DIR_RECV
;
203 case 4: // Connected Isochronous, Central to Peripheral
204 context
.pdu_type
= BTLE_PDU_TYPE_CONNECTEDISO
;
205 context
.direction
= BTLE_DIR_CENTRAL_PERIPHERAL
;
206 pinfo
->p2p_dir
= P2P_DIR_SENT
;
208 case 5: // Connected Isochronous, Peripheral to Central
209 context
.pdu_type
= BTLE_PDU_TYPE_CONNECTEDISO
;
210 context
.direction
= BTLE_DIR_PERIPHERAL_CENTRAL
;
211 pinfo
->p2p_dir
= P2P_DIR_RECV
;
213 case 6: // Broadcast Isochronous
214 context
.pdu_type
= BTLE_PDU_TYPE_BROADCASTISO
;
217 context
.pdu_type
= BTLE_PDU_TYPE_UNKNOWN
;
221 ti
= proto_tree_add_item(tree
, proto_btle_rf
, tvb
, 0, tvb_captured_length(tvb
), ENC_NA
);
222 btle_rf_tree
= proto_item_add_subtree(ti
, ett_btle_rf
);
224 ti
= proto_tree_add_item(btle_rf_tree
, hf_btle_rf_channel
, tvb
, 0, 1, ENC_LITTLE_ENDIAN
);
225 rf_channel
= tvb_get_uint8(tvb
, 0);
226 proto_item_append_text(ti
, ", %d MHz, %s %d", 2402+2*rf_channel
,
227 btle_rf_channel_type(rf_channel
),
228 btle_rf_channel_index(rf_channel
));
229 context
.channel
= btle_rf_channel_index(rf_channel
);
231 if (flags
& LE_CHANNEL_ALIASED
) {
232 proto_item_append_text(ti
, " [aliased]");
235 context
.phy
= (flags
& LE_PHY
) >> 14;
237 if (flags
& LE_SIGPOWER_VALID
) {
238 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_signal_dbm
, tvb
, 1, 1, ENC_LITTLE_ENDIAN
);
241 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_signed_byte_unused
, tvb
, 1, 1, ENC_LITTLE_ENDIAN
);
244 if (flags
& LE_NOISEPOWER_VALID
) {
245 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_noise_dbm
, tvb
, 2, 1, ENC_LITTLE_ENDIAN
);
248 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_signed_byte_unused
, tvb
, 2, 1, ENC_LITTLE_ENDIAN
);
251 if (flags
& LE_AA_OFFENSES_VALID
) {
252 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_access_address_offenses
, tvb
, 3, 1, ENC_LITTLE_ENDIAN
);
253 aa_offenses
= tvb_get_uint8(tvb
, 3);
254 if (aa_offenses
> 0) {
255 if (flags
& LE_REF_AA_VALID
) {
256 context
.aa_category
= E_AA_BIT_ERRORS
;
259 context
.aa_category
= E_AA_ILLEGAL
;
262 else if (flags
& LE_REF_AA_VALID
) {
263 context
.aa_category
= E_AA_MATCHED
;
267 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_unsigned_byte_unused
, tvb
, 3, 1, ENC_LITTLE_ENDIAN
);
270 if (flags
& LE_REF_AA_VALID
) {
271 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_reference_access_address
, tvb
, 4, 4, ENC_LITTLE_ENDIAN
);
274 proto_tree_add_item(btle_rf_tree
, hf_btle_rf_word_unused
, tvb
, 4, 4, ENC_LITTLE_ENDIAN
);
277 proto_tree_add_bitmask_with_flags(btle_rf_tree
, tvb
, 8, hf_btle_rf_flags
, ett_btle_rf_flags
, hfs_btle_rf_flags
, ENC_LITTLE_ENDIAN
, BMT_NO_APPEND
);
279 btle_tvb
= tvb_new_subset_remaining(tvb
, BTLE_RF_OCTETS
);
280 return BTLE_RF_OCTETS
+call_dissector_with_data(btle_handle
, btle_tvb
, pinfo
, tree
, &context
);
284 proto_register_btle_rf(void)
286 static hf_register_info hf
[] = {
287 { &hf_btle_rf_signed_byte_unused
,
288 { "Unused signed byte", "btle_rf.signed_byte_unused",
293 { &hf_btle_rf_unsigned_byte_unused
,
294 { "Unused unsigned byte", "btle_rf.unsigned_byte_unused",
299 { &hf_btle_rf_word_unused
,
300 { "Unused word", "btle_rf.word_unused",
305 { &hf_btle_rf_channel
,
306 { "RF Channel", "btle_rf.channel",
311 { &hf_btle_rf_signal_dbm
,
312 { "Signal dBm", "btle_rf.signal_dbm",
317 { &hf_btle_rf_noise_dbm
,
318 { "Noise dBm", "btle_rf.noise_dbm",
323 { &hf_btle_rf_access_address_offenses
,
324 { "Access Address Offenses", "btle_rf.access_address_offenses",
329 { &hf_btle_rf_reference_access_address
,
330 { "Reference Access Address", "btle_rf.reference_access_address",
336 { "Flags", "btle_rf.flags",
341 { &hf_btle_rf_dewhitened_flag
,
342 { "Dewhitened", "btle_rf.flags.dewhitened",
347 { &hf_btle_rf_sigpower_valid_flag
,
348 { "Signal Power Valid", "btle_rf.flags.signal_dbm_valid",
350 NULL
, LE_SIGPOWER_VALID
,
353 { &hf_btle_rf_noisepower_valid_flag
,
354 { "Noise Power Valid", "btle_rf.flags.noise_dbm_valid",
356 NULL
, LE_NOISEPOWER_VALID
,
359 { &hf_btle_rf_packet_decrypted_flag
,
360 { "Decrypted", "btle_rf.flags.decrypted",
362 NULL
, LE_PACKET_DECRYPTED
,
365 { &hf_btle_rf_ref_aa_valid_flag
,
366 { "Reference Access Address Valid",
367 "btle_rf.flags.reference_access_address_valid",
369 NULL
, LE_REF_AA_VALID
,
372 { &hf_btle_rf_aa_offenses_valid_flag
,
373 { "Access Address Offenses Valid",
374 "btle_rf.flags.access_address_offenses_valid",
376 NULL
, LE_AA_OFFENSES_VALID
,
379 { &hf_btle_rf_channel_aliased_flag
,
380 { "Channel Aliased", "btle_rf.flags.channel_aliased",
382 NULL
, LE_CHANNEL_ALIASED
,
385 { &hf_btle_rf_pdu_type
,
386 { "PDU Type", "btle_rf.pdu_type",
388 VALS(le_pdus
), LE_PDU_TYPE
,
391 { &hf_btle_rf_crc_checked_flag
,
392 { "CRC Checked", "btle_rf.flags.crc_checked",
394 NULL
, LE_CRC_CHECKED
,
397 { &hf_btle_rf_crc_valid_flag
,
398 { "CRC Valid", "btle_rf.flags.crc_valid",
403 { &hf_btle_rf_mic_checked_flag
,
404 { "MIC Checked", "btle_rf.flags.mic_checked",
406 NULL
, LE_MIC_CHECKED
,
409 { &hf_btle_rf_mic_valid_flag
,
410 { "MIC Valid", "btle_rf.flags.mic_valid",
416 { "PHY", "btle_rf.phy",
418 VALS(le_phys
), LE_PHY
,
423 static int *ett
[] = {
428 proto_btle_rf
= proto_register_protocol("Bluetooth Low Energy RF Info",
429 "BTLE RF", "btle_rf");
430 proto_register_field_array(proto_btle_rf
, hf
, array_length(hf
));
431 proto_register_subtree_array(ett
, array_length(ett
));
432 btle_rf_handle
= register_dissector("btle_rf", dissect_btle_rf
, proto_btle_rf
);
436 proto_reg_handoff_btle_rf(void)
438 dissector_add_uint("bluetooth.encap", WTAP_ENCAP_BLUETOOTH_LE_LL_WITH_PHDR
, btle_rf_handle
);
439 btle_handle
= find_dissector_add_dependency("btle", proto_btle_rf
);
443 * Editor modelines - https://www.wireshark.org/tools/modelines.html
448 * indent-tabs-mode: nil
451 * vi: set shiftwidth=4 tabstop=8 expandtab:
452 * :indentSize=4:tabSize=8:noTabs=true: