From ef94a80bfa86362cfca09e1982010b5a9a47d247 Mon Sep 17 00:00:00 2001 From: Christopher Kilgour Date: Fri, 21 Feb 2014 23:39:45 -0800 Subject: [PATCH] Introduces two new Bluetooth DLTs for RF-based captures. Adds support for BLUETOOTH_LE_LL_WITH_PHDR, dissector integrates with existing BTLE dissector. Fixes BTLE dissector to correctly extract packet CRC. Adds CRC checking to BTLE dissector. Provides optional context to BTLE dissector that allows RF captures to provide link-layer hints for dissection details. Significantly, parameters for determining CRC correctness are provided, as well as Access Address validity information. Change-Id: I7d4936b053353a7f9c524021c01f67f5828253fb Reviewed-on: https://code.wireshark.org/review/310 Reviewed-by: Anders Broman --- epan/CMakeLists.txt | 1 + epan/dissectors/Makefile.common | 4 +- epan/dissectors/packet-btle.c | 182 +++++++++++++-- epan/dissectors/packet-btle.h | 76 +++++++ epan/dissectors/packet-btle_rf.c | 376 +++++++++++++++++++++++++++++++ wiretap/pcap-common.c | 5 + wiretap/wtap.c | 5 + wiretap/wtap.h | 2 + 8 files changed, 634 insertions(+), 17 deletions(-) create mode 100644 epan/dissectors/packet-btle.h create mode 100644 epan/dissectors/packet-btle_rf.c diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index d257b3d937..81973e1500 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -430,6 +430,7 @@ set(DISSECTOR_SRC dissectors/packet-bthid.c dissectors/packet-bthsp.c dissectors/packet-btle.c + dissectors/packet-btle_rf.c dissectors/packet-btl2cap.c dissectors/packet-btmcap.c dissectors/packet-btobex.c diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 207f646e64..93bbc3c483 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -350,7 +350,8 @@ DISSECTOR_SRC = \ packet-bthid.c \ packet-bthsp.c \ packet-btl2cap.c \ - packet-btle.c \ + packet-btle.c \ + packet-btle_rf.c \ packet-btmcap.c \ packet-btobex.c \ packet-btrfcomm.c \ @@ -1331,6 +1332,7 @@ DISSECTOR_INCLUDES = \ packet-btavdtp.h \ packet-bthci_acl.h \ packet-btl2cap.h \ + packet-btle.h \ packet-btrfcomm.h \ packet-btsdp.h \ packet-c1222.h \ diff --git a/epan/dissectors/packet-btle.c b/epan/dissectors/packet-btle.c index 76612b982f..7f61741d97 100644 --- a/epan/dissectors/packet-btle.c +++ b/epan/dissectors/packet-btle.c @@ -4,6 +4,7 @@ * * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com * Copyright 2013, Michal Labedzki for Tieto Corporation + * Copyright 2014, Christopher D. Kilgour, techie at whiterocker dot com * * Wireshark - Network traffic analyzer * By Gerald Combs @@ -31,6 +32,7 @@ #include #include +#include "packet-btle.h" #include "packet-bluetooth-hci.h" #include "packet-bthci_acl.h" @@ -117,6 +119,12 @@ static gint ett_channel_map = -1; static gint ett_scan_response_data = -1; static expert_field ei_unknown_data = EI_INIT; +static expert_field ei_access_address_matched = EI_INIT; +static expert_field ei_access_address_bit_errors = EI_INIT; +static expert_field ei_access_address_illegal = EI_INIT; +static expert_field ei_crc_cannot_be_determined = EI_INIT; +static expert_field ei_crc_correct = EI_INIT; +static expert_field ei_crc_incorrect = EI_INIT; static dissector_handle_t btle_handle; static dissector_handle_t btcommon_ad_handle; @@ -211,8 +219,95 @@ dissect_bd_addr(gint hf_bd_addr, proto_tree *tree, tvbuff_t *tvb, gint offset) return offset; } +/* + * Implements Bluetooth Vol 6, Part B, Section 3.1.1 (ref Figure 3.2) + * + * At entry: tvb is entire BTLE packet without preamble + * payload_len is the Length field from the BTLE PDU header + * crc_init as defined in the specifications + * + * This implementation operates on nibbles and is therefore + * endian-neutral. + */ +static guint32 +btle_crc(tvbuff_t *tvb, const guint8 payload_len, const guint32 crc_init) +{ + static const guint16 btle_crc_next_state_flips[256] = { + 0x0000, 0x32d8, 0x196c, 0x2bb4, 0x0cb6, 0x3e6e, 0x15da, 0x2702, + 0x065b, 0x3483, 0x1f37, 0x2def, 0x0aed, 0x3835, 0x1381, 0x2159, + 0x065b, 0x3483, 0x1f37, 0x2def, 0x0aed, 0x3835, 0x1381, 0x2159, + 0x0000, 0x32d8, 0x196c, 0x2bb4, 0x0cb6, 0x3e6e, 0x15da, 0x2702, + 0x0cb6, 0x3e6e, 0x15da, 0x2702, 0x0000, 0x32d8, 0x196c, 0x2bb4, + 0x0aed, 0x3835, 0x1381, 0x2159, 0x065b, 0x3483, 0x1f37, 0x2def, + 0x0aed, 0x3835, 0x1381, 0x2159, 0x065b, 0x3483, 0x1f37, 0x2def, + 0x0cb6, 0x3e6e, 0x15da, 0x2702, 0x0000, 0x32d8, 0x196c, 0x2bb4, + 0x196c, 0x2bb4, 0x0000, 0x32d8, 0x15da, 0x2702, 0x0cb6, 0x3e6e, + 0x1f37, 0x2def, 0x065b, 0x3483, 0x1381, 0x2159, 0x0aed, 0x3835, + 0x1f37, 0x2def, 0x065b, 0x3483, 0x1381, 0x2159, 0x0aed, 0x3835, + 0x196c, 0x2bb4, 0x0000, 0x32d8, 0x15da, 0x2702, 0x0cb6, 0x3e6e, + 0x15da, 0x2702, 0x0cb6, 0x3e6e, 0x196c, 0x2bb4, 0x0000, 0x32d8, + 0x1381, 0x2159, 0x0aed, 0x3835, 0x1f37, 0x2def, 0x065b, 0x3483, + 0x1381, 0x2159, 0x0aed, 0x3835, 0x1f37, 0x2def, 0x065b, 0x3483, + 0x15da, 0x2702, 0x0cb6, 0x3e6e, 0x196c, 0x2bb4, 0x0000, 0x32d8, + 0x32d8, 0x0000, 0x2bb4, 0x196c, 0x3e6e, 0x0cb6, 0x2702, 0x15da, + 0x3483, 0x065b, 0x2def, 0x1f37, 0x3835, 0x0aed, 0x2159, 0x1381, + 0x3483, 0x065b, 0x2def, 0x1f37, 0x3835, 0x0aed, 0x2159, 0x1381, + 0x32d8, 0x0000, 0x2bb4, 0x196c, 0x3e6e, 0x0cb6, 0x2702, 0x15da, + 0x3e6e, 0x0cb6, 0x2702, 0x15da, 0x32d8, 0x0000, 0x2bb4, 0x196c, + 0x3835, 0x0aed, 0x2159, 0x1381, 0x3483, 0x065b, 0x2def, 0x1f37, + 0x3835, 0x0aed, 0x2159, 0x1381, 0x3483, 0x065b, 0x2def, 0x1f37, + 0x3e6e, 0x0cb6, 0x2702, 0x15da, 0x32d8, 0x0000, 0x2bb4, 0x196c, + 0x2bb4, 0x196c, 0x32d8, 0x0000, 0x2702, 0x15da, 0x3e6e, 0x0cb6, + 0x2def, 0x1f37, 0x3483, 0x065b, 0x2159, 0x1381, 0x3835, 0x0aed, + 0x2def, 0x1f37, 0x3483, 0x065b, 0x2159, 0x1381, 0x3835, 0x0aed, + 0x2bb4, 0x196c, 0x32d8, 0x0000, 0x2702, 0x15da, 0x3e6e, 0x0cb6, + 0x2702, 0x15da, 0x3e6e, 0x0cb6, 0x2bb4, 0x196c, 0x32d8, 0x0000, + 0x2159, 0x1381, 0x3835, 0x0aed, 0x2def, 0x1f37, 0x3483, 0x065b, + 0x2159, 0x1381, 0x3835, 0x0aed, 0x2def, 0x1f37, 0x3483, 0x065b, + 0x2702, 0x15da, 0x3e6e, 0x0cb6, 0x2bb4, 0x196c, 0x32d8, 0x0000 + }; + gint offset = 4; /* skip AA, CRC applies over PDU */ + guint32 state = crc_init; + guint8 bytes_to_go = 2+payload_len; /* PDU includes header and payload */ + while( bytes_to_go-- ) { + guint8 byte = tvb_get_guint8(tvb, offset++); + guint8 nibble = (byte & 0xf); + guint8 index = ((state >> 16) & 0xf0) | nibble; + state = ((state << 4) ^ btle_crc_next_state_flips[index]) & 0xffffff; + nibble = ((byte >> 4) & 0xf); + index = ((state >> 16) & 0xf0) | nibble; + state = ((state << 4) ^ btle_crc_next_state_flips[index]) & 0xffffff; + } + return state; +} + +/* + * Reverses the bits in each byte of a 32-bit word. + * + * Needed because CRCs are transmitted in bit-reversed order compared + * to the rest of the BTLE packet. See BT spec, Vol 6, Part B, + * Section 1.2. + */ +static guint32 +reverse_bits_per_byte(const guint32 val) +{ + const guint8 nibble_rev[16] = { + 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf + }; + guint32 retval = 0; + unsigned byte_index; + for (byte_index=0; byte_index<4; byte_index++) { + guint shiftA = byte_index*8; + guint shiftB = shiftA+4; + retval |= (nibble_rev[((val >> shiftA) & 0xf)] << shiftB); + retval |= (nibble_rev[((val >> shiftB) & 0xf)] << shiftA); + } + return retval; +} + static gint -dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *btle_item; proto_tree *btle_tree; @@ -223,27 +318,40 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ guint8 length; guint32 interface_id; tvbuff_t *next_tvb; + enum {CRC_INDETERMINATE, + CRC_CAN_BE_CALCULATED, + CRC_INCORRECT, + CRC_CORRECT} crc_status = CRC_INDETERMINATE; + guint32 crc_init = 0x555555; /* default to advertising channel's value */ + guint32 packet_crc; + const btle_context_t * btle_context = (const btle_context_t *) data; + + if (btle_context && btle_context->crc_checked_at_capture) { + crc_status = btle_context->crc_valid_at_capture ? CRC_CORRECT : CRC_INCORRECT; + } col_set_str(pinfo->cinfo, COL_PROTOCOL, "LE LL"); - switch (pinfo->p2p_dir) { - case P2P_DIR_SENT: - col_add_str(pinfo->cinfo, COL_INFO, "Sent "); - break; - case P2P_DIR_RECV: - col_add_str(pinfo->cinfo, COL_INFO, "Rcvd "); - break; - default: - col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ", - pinfo->p2p_dir); - break; - } - btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, ENC_NA); btle_tree = proto_item_add_subtree(btle_item, ett_btle); - proto_tree_add_item(btle_tree, hf_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + sub_item = proto_tree_add_item(btle_tree, hf_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); access_address = tvb_get_letohl(tvb, offset); + if (btle_context) { + switch(btle_context->aa_category) { + case E_AA_MATCHED: + expert_add_info(pinfo, sub_item, &ei_access_address_matched); + break; + case E_AA_ILLEGAL: + expert_add_info(pinfo, sub_item, &ei_access_address_illegal); + break; + case E_AA_BIT_ERRORS: + expert_add_info(pinfo, sub_item, &ei_access_address_bit_errors); + break; + default: + break; + } + } offset += 4; if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID) @@ -258,6 +366,11 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ proto_tree *link_layer_data_tree; guint8 pdu_type; + if (crc_status == CRC_INDETERMINATE) { + /* Advertising channel CRCs can aways be calculated, because CRCInit is always known. */ + crc_status = CRC_CAN_BE_CALCULATED; + } + advertising_header_item = proto_tree_add_item(btle_tree, hf_advertising_header, tvb, offset, 2, ENC_LITTLE_ENDIAN); advertising_header_tree = proto_item_add_subtree(advertising_header_item, ett_advertising_header); @@ -285,6 +398,7 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_2, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(advertising_header_tree, hf_advertising_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + length = tvb_get_guint8(tvb, offset) & 0x3f; offset += 1; switch (pdu_type) { @@ -604,10 +718,36 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ offset += tvb_length_remaining(tvb, offset) - 3; } } + + if ((crc_status == CRC_INDETERMINATE) && + btle_context && btle_context->connection_info_valid) { + /* the surrounding context has provided CRCInit */ + crc_init = btle_context->connection_info.CRCInit; + crc_status = CRC_CAN_BE_CALCULATED; + } } - proto_tree_add_item(btle_tree, hf_crc, tvb, offset, 3, ENC_LITTLE_ENDIAN); + /* BT spec Vol 6, Part B, Section 1.2: CRC is big endian and bits in byte are flipped */ + packet_crc = reverse_bits_per_byte(tvb_get_ntoh24(tvb, offset)); + sub_item = proto_tree_add_uint(btle_tree, hf_crc, tvb, offset, 3, packet_crc); offset += 3; + if (crc_status == CRC_CAN_BE_CALCULATED) { + guint32 crc = btle_crc(tvb, length, crc_init); + crc_status = (packet_crc == crc) ? CRC_CORRECT : CRC_INCORRECT; + } + switch(crc_status) { + case CRC_INDETERMINATE: + expert_add_info(pinfo, sub_item, &ei_crc_cannot_be_determined); + break; + case CRC_INCORRECT: + expert_add_info(pinfo, sub_item, &ei_crc_incorrect); + break; + case CRC_CORRECT: + expert_add_info(pinfo, sub_item, &ei_crc_correct); + break; + default: + break; + } return offset; } @@ -978,6 +1118,16 @@ proto_register_btle(void) static ei_register_info ei[] = { { &ei_unknown_data, { "btle.unknown_data", PI_PROTOCOL, PI_NOTE, "Unknown data", EXPFILL }}, + { &ei_access_address_matched, { "btle.access_address.matched", PI_PROTOCOL, PI_NOTE, + "matched at capture", EXPFILL }}, + { &ei_access_address_bit_errors, { "btle.access_address.bit_errors", PI_PROTOCOL, PI_WARN, + "but errors present at capture", EXPFILL }}, + { &ei_access_address_illegal, { "btle.access_address.illegal", PI_PROTOCOL, PI_ERROR, + "illegal value", EXPFILL }}, + { &ei_crc_cannot_be_determined, { "btle.crc.indeterminate", PI_PROTOCOL, PI_NOTE, + "unchecked, not all data available", EXPFILL }}, + { &ei_crc_correct, { "btle.crc.correct", PI_PROTOCOL, PI_CHAT, "correct", EXPFILL }}, + { &ei_crc_incorrect, { "btle.crc.incorrect", PI_PROTOCOL, PI_WARN, "incorrect", EXPFILL }}, }; static gint *ett[] = { diff --git a/epan/dissectors/packet-btle.h b/epan/dissectors/packet-btle.h new file mode 100644 index 0000000000..9d29d44346 --- /dev/null +++ b/epan/dissectors/packet-btle.h @@ -0,0 +1,76 @@ +/* packet-btle.h + * Structures for determining the dissection context for BTLE. + * + * Copyright 2014, Christopher D. Kilgour, techie at whiterocker dot com + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __PACKET_BTLE_H__ +#define __PACKET_BTLE_H__ + +/* + * These structures are meant to support the provision of contextual + * metadata to the BTLE dissector. + */ +typedef struct { + guint64 InitA; + guint64 AdvA; + guint32 LinkAA; + guint32 CRCInit; + guint8 WinSize; + guint16 WinOffset; + guint16 Interval; + guint16 Latency; + guint16 Timeout; + guint64 ChM; + guint8 Hop; + guint8 SCA; +} btle_CONNECT_REQ_t; + +typedef enum { + E_AA_NO_COMMENT = 0, + E_AA_MATCHED, + E_AA_BIT_ERRORS, + E_AA_ILLEGAL, +} btle_AA_category_t; + +typedef struct { + btle_AA_category_t aa_category; + btle_CONNECT_REQ_t connection_info; + gint connection_info_valid: 1; + gint crc_checked_at_capture: 1; + gint crc_valid_at_capture: 1; + gint mic_checked_at_capture: 1; + gint mic_valid_at_capture: 1; +} btle_context_t; + +#endif /* __PACKET_BTLE_H__ */ + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/dissectors/packet-btle_rf.c b/epan/dissectors/packet-btle_rf.c new file mode 100644 index 0000000000..282f8d9066 --- /dev/null +++ b/epan/dissectors/packet-btle_rf.c @@ -0,0 +1,376 @@ +/* packet-btle_rf.c + * http://www.whiterocker.com/bt/LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR.html + * + * Copyright 2014, Christopher D. Kilgour, techie at whiterocker dot com + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include + +#include "packet-btle.h" + +#define LE_DEWHITENED 0x0001 +#define LE_SIGPOWER_VALID 0x0002 +#define LE_NOISEPOWER_VALID 0x0004 +#define LE_PACKET_DECRYPTED 0x0008 +#define LE_REF_AA_VALID 0x0010 +#define LE_AA_OFFENSES_VALID 0x0020 +#define LE_CHANNEL_ALIASED 0x0040 +#define LE_CRC_CHECKED 0x0400 +#define LE_CRC_VALID 0x0800 +#define LE_MIC_CHECKED 0x1000 +#define LE_MIC_VALID 0x2000 + +#define BTLE_RF_OCTETS 10 + +static int proto_btle_rf = -1; + +static int hf_btle_rf_signed_byte_unused = -1; +static int hf_btle_rf_unsigned_byte_unused = -1; +static int hf_btle_rf_word_unused = -1; +static int hf_btle_rf_channel = -1; +static int hf_btle_rf_signal_dbm = -1; +static int hf_btle_rf_noise_dbm = -1; +static int hf_btle_rf_access_address_offenses = -1; +static int hf_btle_rf_reference_access_address = -1; +static int hf_btle_rf_flags = -1; +static int hf_btle_rf_dewhitened_flag = -1; +static int hf_btle_rf_sigpower_valid_flag = -1; +static int hf_btle_rf_noisepower_valid_flag = -1; +static int hf_btle_rf_packet_decrypted_flag = -1; +static int hf_btle_rf_ref_aa_valid_flag = -1; +static int hf_btle_rf_aa_offenses_valid_flag = -1; +static int hf_btle_rf_channel_aliased_flag = -1; +static int hf_btle_rf_flags_rfu_1 = -1; +static int hf_btle_rf_crc_checked_flag = -1; +static int hf_btle_rf_crc_valid_flag = -1; +static int hf_btle_rf_mic_checked_flag = -1; +static int hf_btle_rf_mic_valid_flag = -1; +static int hf_btle_rf_flags_rfu_2 = -1; + +static int ett_btle_rf = -1; +static int ett_btle_rf_flags = -1; + +static dissector_handle_t btle_rf_handle; +static dissector_handle_t btle_handle; + +void proto_register_btle_rf(void); +void proto_reg_handoff_btle_rf(void); + +static const char * +btle_rf_channel_type(guint8 rf_channel) +{ + if (rf_channel <= 39) { + switch(rf_channel) { + case 0: + case 12: + case 39: + return "Advertising channel"; + default: + return "Data channel"; + } + } + return "Illegal channel"; +} + +static guint8 +btle_rf_channel_index(guint8 rf_channel) +{ + if (rf_channel <= 39) { + if (rf_channel == 39) { + return 39; + } + else if (rf_channel >= 13) { + return rf_channel - 2; + } + else if (rf_channel == 12) { + return 38; + } + else if (rf_channel >= 1) { + return rf_channel - 1; + } + else { + return 37; + } + } + return (guint8) -1; +} + +static gint +dissect_btle_rf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BTLE RF"); + col_clear(pinfo->cinfo, COL_INFO); + + if (tree && (tvb_captured_length(tvb) >= BTLE_RF_OCTETS)) { + proto_item *ti = NULL; + proto_tree *btle_rf_tree = NULL; + proto_tree *btle_rf_flags_tree = NULL; + tvbuff_t *btle_tvb; + btle_context_t context; + guint8 rf_channel = tvb_get_guint8(tvb, 0); + guint8 aa_offenses = tvb_get_guint8(tvb, 3); + guint16 flags = tvb_get_letohs(tvb, 8); + + context.aa_category = E_AA_NO_COMMENT; + context.connection_info_valid = 0; /* TODO */ + context.crc_checked_at_capture = !!(flags & LE_CRC_CHECKED); + context.crc_valid_at_capture = !!(flags & LE_CRC_VALID); + context.mic_checked_at_capture = !!(flags & LE_MIC_CHECKED); + context.mic_valid_at_capture = !!(flags & LE_MIC_VALID); + + ti = proto_tree_add_item(tree, proto_btle_rf, tvb, 0, tvb_captured_length(tvb), ENC_NA); + btle_rf_tree = proto_item_add_subtree(ti, ett_btle_rf); + ti = proto_tree_add_item(btle_rf_tree, hf_btle_rf_channel, tvb, 0, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(ti, ", %d MHz, %s %d", 2402+2*rf_channel, + btle_rf_channel_type(rf_channel), + btle_rf_channel_index(rf_channel)); + if (flags & LE_CHANNEL_ALIASED) { + proto_item_append_text(ti, " [aliased]"); + } + if (flags & LE_SIGPOWER_VALID) { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_signal_dbm, tvb, 1, 1, ENC_LITTLE_ENDIAN); + } + else { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_signed_byte_unused, tvb, 1, 1, ENC_LITTLE_ENDIAN); + } + if (flags & LE_NOISEPOWER_VALID) { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_noise_dbm, tvb, 2, 1, ENC_LITTLE_ENDIAN); + } + else { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_signed_byte_unused, tvb, 2, 1, ENC_LITTLE_ENDIAN); + } + if (flags & LE_REF_AA_VALID) { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_reference_access_address, tvb, 4, 4, ENC_LITTLE_ENDIAN); + } + else { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_word_unused, tvb, 4, 4, ENC_LITTLE_ENDIAN); + } + if (flags & LE_AA_OFFENSES_VALID) { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_access_address_offenses, tvb, 3, 1, ENC_LITTLE_ENDIAN); + if (aa_offenses > 0) { + if (flags & LE_REF_AA_VALID) { + context.aa_category = E_AA_BIT_ERRORS; + } + else { + context.aa_category = E_AA_ILLEGAL; + } + } + else if (flags & LE_REF_AA_VALID) { + context.aa_category = E_AA_MATCHED; + } + } + else { + proto_tree_add_item(btle_rf_tree, hf_btle_rf_unsigned_byte_unused, tvb, 3, 1, ENC_LITTLE_ENDIAN); + } + ti = proto_tree_add_item(btle_rf_tree, hf_btle_rf_flags, tvb, 8, 2, ENC_LITTLE_ENDIAN); + btle_rf_flags_tree = proto_item_add_subtree(ti, ett_btle_rf_flags); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_dewhitened_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_sigpower_valid_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_noisepower_valid_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_packet_decrypted_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_ref_aa_valid_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_aa_offenses_valid_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_channel_aliased_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_flags_rfu_1, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_crc_checked_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_crc_valid_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_mic_checked_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_mic_valid_flag, tvb, 8, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_rf_flags_tree, hf_btle_rf_flags_rfu_2, tvb, 8, 2, ENC_LITTLE_ENDIAN); + + btle_tvb = tvb_new_subset_remaining(tvb, BTLE_RF_OCTETS); + return BTLE_RF_OCTETS+call_dissector_with_data(btle_handle, btle_tvb, pinfo, tree, &context); + } + return 0; +} + +void +proto_register_btle_rf(void) +{ + static hf_register_info hf[] = { + { &hf_btle_rf_signed_byte_unused, + { "Unused signed byte", "btle_rf.signed_byte_unused", + FT_INT8, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_unsigned_byte_unused, + { "Unused unsigned byte", "btle_rf.unsigned_byte_unused", + FT_UINT8, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_word_unused, + { "Unused word", "btle_rf.word_unused", + FT_UINT32, BASE_HEX, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_channel, + { "RF Channel", "btle_rf.channel", + FT_UINT8, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_signal_dbm, + { "Signal dBm", "btle_rf.signal_dbm", + FT_INT8, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_noise_dbm, + { "Noise dBm", "btle_rf.noise_dbm", + FT_INT8, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_access_address_offenses, + { "Access Address Offenses", "btle_rf.access_address_offenses", + FT_UINT8, BASE_DEC, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_reference_access_address, + { "Reference Access Address", "btle_rf.reference_access_address", + FT_UINT32, BASE_HEX, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_flags, + { "Flags", "btle_rf.flags", + FT_UINT16, BASE_HEX, + NULL, 0x0, + NULL, HFILL } + }, + { &hf_btle_rf_dewhitened_flag, + { "Dewhitened", "btle_rf.flags.dewhitened", + FT_BOOLEAN, 16, + NULL, LE_DEWHITENED, + NULL, HFILL } + }, + { &hf_btle_rf_sigpower_valid_flag, + { "Signal Power Valid", "btle_rf.flags.signal_dbm_valid", + FT_BOOLEAN, 16, + NULL, LE_SIGPOWER_VALID, + NULL, HFILL } + }, + { &hf_btle_rf_noisepower_valid_flag, + { "Noise Power Valid", "btle_rf.flags.noise_dbm_valid", + FT_BOOLEAN, 16, + NULL, LE_NOISEPOWER_VALID, + NULL, HFILL } + }, + { &hf_btle_rf_packet_decrypted_flag, + { "Decrypted", "btle_rf.flags.decrypted", + FT_BOOLEAN, 16, + NULL, LE_PACKET_DECRYPTED, + NULL, HFILL } + }, + { &hf_btle_rf_ref_aa_valid_flag, + { "Reference Access Address Valid", + "btle_rf.flags.reference_access_address_valid", + FT_BOOLEAN, 16, + NULL, LE_REF_AA_VALID, + NULL, HFILL } + }, + { &hf_btle_rf_aa_offenses_valid_flag, + { "Access Address Offenses Valid", + "btle_rf.flags.access_address_offenses_valid", + FT_BOOLEAN, 16, + NULL, LE_AA_OFFENSES_VALID, + NULL, HFILL } + }, + { &hf_btle_rf_channel_aliased_flag, + { "Channel Aliased", "btle_rf.flags.channel_aliased", + FT_BOOLEAN, 16, + NULL, LE_CHANNEL_ALIASED, + NULL, HFILL } + }, + { &hf_btle_rf_flags_rfu_1, + { "RFU", "btle_rf.flags.rfu.1", + FT_UINT16, BASE_DEC, NULL, 0x380, + NULL, HFILL } + }, + { &hf_btle_rf_crc_checked_flag, + { "CRC Checked", "btle_rf.flags.crc_checked", + FT_BOOLEAN, 16, + NULL, LE_CRC_CHECKED, + NULL, HFILL } + }, + { &hf_btle_rf_crc_valid_flag, + { "CRC Valid", "btle_rf.flags.crc_valid", + FT_BOOLEAN, 16, + NULL, LE_CRC_VALID, + NULL, HFILL } + }, + { &hf_btle_rf_mic_checked_flag, + { "MIC Checked", "btle_rf.flags.mic_checked", + FT_BOOLEAN, 16, + NULL, LE_MIC_CHECKED, + NULL, HFILL } + }, + { &hf_btle_rf_mic_valid_flag, + { "MIC Valid", "btle_rf.flags.mic_valid", + FT_BOOLEAN, 16, + NULL, LE_MIC_VALID, + NULL, HFILL } + }, + { &hf_btle_rf_flags_rfu_2, + { "RFU", "btle_rf.flags.rfu.2", + FT_UINT16, BASE_DEC, NULL, 0xc000, + NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_btle_rf, + &ett_btle_rf_flags, + }; + + proto_btle_rf = proto_register_protocol("Bluetooth Low Energy RF Info", + "BTLE RF", "btle_rf"); + proto_register_field_array(proto_btle_rf, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + btle_rf_handle = new_register_dissector("btle_rf", dissect_btle_rf, proto_btle_rf); +} + +void +proto_reg_handoff_btle_rf(void) +{ + dissector_add_uint("wtap_encap", WTAP_ENCAP_BLUETOOTH_LE_LL_WITH_PHDR, btle_rf_handle); + btle_handle = find_dissector("btle"); +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/wiretap/pcap-common.c b/wiretap/pcap-common.c index 393deb38f8..2fbdc61440 100644 --- a/wiretap/pcap-common.c +++ b/wiretap/pcap-common.c @@ -419,6 +419,11 @@ static const struct { { 253, WTAP_ENCAP_NETLINK }, /* Bluetooth Linux Monitor */ { 254, WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR }, + /* Bluetooth BR/EDR Baseband RF captures */ + { 255, WTAP_ENCAP_BLUETOOTH_BREDR_BB }, + /* Bluetooth Low Energy Link Layer RF captures */ + { 256, WTAP_ENCAP_BLUETOOTH_LE_LL_WITH_PHDR }, + /* * To repeat: * diff --git a/wiretap/wtap.c b/wiretap/wtap.c index ce9ff40591..07e5004bd1 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -697,6 +697,11 @@ static struct encap_type_info encap_table_base[] = { /* WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR */ { "Bluetooth Linux Monitor", "bluetooth-linux-monitor" }, + /* WTAP_ENCAP_BLUETOOTH_BREDR_BB */ + { "Bluetooth BR/EDR Baseband RF", "bluetooth-bredr-bb-rf" }, + + /* WTAP_ENCAP_BLUETOOTH_LE_LL_WITH_PHDR */ + { "Bluetooth Low Energy Link Layer RF", "bluetooth-le-ll-rf" }, }; WS_DLL_LOCAL diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 61cb2bff5f..1f18b1298e 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -251,6 +251,8 @@ extern "C" { #define WTAP_ENCAP_STANAG_5066_D_PDU 158 #define WTAP_ENCAP_NETLINK 159 #define WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR 160 +#define WTAP_ENCAP_BLUETOOTH_BREDR_BB 161 +#define WTAP_ENCAP_BLUETOOTH_LE_LL_WITH_PHDR 162 /* After adding new item here, please also add new item to encap_table_base array */ #define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types()