2 * Routines for nRF Sniffer for Bluetooth LE dissection
4 * Copyright (c) 2016-2018 Nordic Semiconductor.
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
13 /* nRF Sniffer for Bluetooth LE packet format: BoardID + Header + Payload
15 * +--------+--------+--------+--------+--------+--------+--------+--------+
16 * | BoardID (1 byte) |
17 * +--------+--------+--------+--------+--------+--------+--------+--------+
19 * Header version 0 (legacy):
20 * +--------+--------+--------+--------+--------+--------+--------+--------+
21 * | Packet ID (1 byte) |
22 * +--------+--------+--------+--------+--------+--------+--------+--------+
23 * | Packet counter (LSB) |
25 * +--------+--------+--------+--------+--------+--------+--------+--------+
28 * +--------+--------+--------+--------+--------+--------+--------+--------+
29 * | Length of payload (1 byte) |
30 * +--------+--------+--------+--------+--------+--------+--------+--------+
33 * +--------+--------+--------+--------+--------+--------+--------+--------+
34 * | Length of header (1 byte) |
35 * +--------+--------+--------+--------+--------+--------+--------+--------+
36 * | Length of payload (1 byte) |
37 * +--------+--------+--------+--------+--------+--------+--------+--------+
38 * | Protocol version (1 byte) |
39 * +--------+--------+--------+--------+--------+--------+--------+--------+
40 * | Packet counter (LSB) |
42 * +--------+--------+--------+--------+--------+--------+--------+--------+
43 * | Packet ID (1 byte) |
44 * +--------+--------+--------+--------+--------+--------+--------+--------+
47 * +--------+--------+--------+--------+--------+--------+--------+--------+
48 * | Length of payload (little endian) |
50 * +--------+--------+--------+--------+--------+--------+--------+--------+
51 * | Protocol version (1 byte) |
52 * +--------+--------+--------+--------+--------+--------+--------+--------+
53 * | Packet counter (little endian) |
55 * +--------+--------+--------+--------+--------+--------+--------+--------+
56 * | Packet ID (1 byte) |
57 * +--------+--------+--------+--------+--------+--------+--------+--------+
61 * Host tells the Sniffer to scan for Advertising from a specific
62 * address and follow all communication it has with other devices.
65 * Sniffer tells the Host that it has entered the FOLLOW state.
67 * 0x02 = EVENT_PACKET_ADVERTISING
68 * Sniffer tells the Host that it has received an advertising physical
71 * 0x05 = EVENT_CONNECT
72 * Sniffer tells the Host that someone has connected to the unit we
75 * 0x06 = EVENT_PACKET_DATA
76 * Protocol version < 3:
77 * Sniffer tells the host that it has received a packet on any physical
79 * Access address == 0x8e89bed6 Advertising physical channel PDU
80 * Access address != 0x8e89bed6 Data physical channel PDU
82 * Sniffer tells the Host that it has received a data physical
85 * 0x07 = REQ_SCAN_CONT
86 * Host tells the Sniffer to scan continuously for any advertising
87 * physical channel PDUs and send all packets received.
89 * 0x09 = EVENT_DISCONNECT
90 * Sniffer tells the Host that the connected address we were following
91 * has received a disconnect packet.
93 * 0x0C = SET_TEMPORARY_KEY
94 * Specify a temporary key (TK) to use on encryption.
95 * Only used for Legacy OOB and Legacy passkey pairing.
101 * 0x13 = SWITCH_BAUD_RATE_REQ
103 * 0x14 = SWITCH_BAUD_RATE_RESP
105 * 0x17 = SET_ADV_CHANNEL_HOP_SEQ
106 * Host tells the Sniffer which order to cycle through the channels
107 * when following an advertiser.
110 * Host tell the Sniffer to stop sending UART traffic and listen for
115 * Protocol version < 3:
116 * EVENT_PACKET (ID 0x06)
118 * Protocol version 3:
119 * EVENT_PACKET_ADVERTISING (ID 0x02)
120 * EVENT_PACKET_DATA (ID 0x06)
121 * +--------+--------+--------+--------+--------+--------+--------+--------+
122 * | Length of payload data (1 byte) |
123 * +--------+--------+--------+--------+--------+--------+--------+--------+
125 * +--------+--------+--------+--------+--------+--------+--------+--------+
126 * | Channel (1 byte) |
127 * +--------+--------+--------+--------+--------+--------+--------+--------+
128 * | RSSISample (dBm) (1 byte) |
129 * +--------+--------+--------+--------+--------+--------+--------+--------+
132 * +--------+--------+--------+--------+--------+--------+--------+--------+
133 * | Protocol version < 3: Delta time (us end to start) |
135 * | Protocol version 3: Firmware Timestamp (us) |
137 * +--------+--------+--------+--------+--------+--------+--------+--------+
139 * +--------+--------+--------+--------+--------+--------+--------+--------+
141 * | Bluetooth Low Energy Link Layer Packet (excluding preamble) |
144 * +--------+--------+--------+--------+--------+--------+--------+--------+
146 * Flags EVENT_PACKET_ADVERTISING (0x02)
147 * 0000000x = CRC (0 = Incorrect, 1 = OK)
150 * 00000xx0 = AUX_TYPE (channel < 37: 0 = AUX_ADV_IND, 1 = AUX_CHAIN_IND,
151 * 2 = AUX_SYNC_IND, 3 = AUX_SCAN_RSP)
153 * 0xxx0000 = PHY (0 = 1M, 1 = 2M, 2 = Coded, rest unused)
156 * Flags EVENT_PACKET_DATA (0x06)
157 * 0000000x = CRC (0 = Incorrect, 1 = OK)
158 * 000000x0 = Direction (0 = Peripheral -> Central, 1 = Central -> Peripheral)
159 * 00000x00 = Encrypted (0 = No, 1 = Yes)
160 * 0000x000 = MIC (0 = Incorrect, 1 = OK)
161 * 0xxx0000 = PHY (0 = 1M, 1 = 2M, 2 = Coded, rest unused)
165 * The channel index being used.
168 * RSSI sample raw value. The value of this register is read as a
169 * positive value while the actual received signal strength is a
170 * negative value. Actual received signal strength is therefore
171 * as follows: rssi = -RSSISAMPLE dBm
174 * This is the time in microseconds from the end of the previous received
175 * packet to the beginning of this packet.
177 * Firmware timestamp:
178 * Timestamp of the start of the received packet captured by the firmware
179 * timer with microsecond resolution.
184 #include <epan/packet.h>
185 #include <epan/expert.h>
186 #include <epan/proto_data.h>
188 #include <epan/tfs.h>
189 #include <epan/unit_strings.h>
191 #include <wsutil/array.h>
192 #include <wiretap/wtap.h>
194 #include "packet-btle.h"
196 /* Size of various UART Packet header fields */
197 #define UART_HEADER_LEN 6
198 #define EVENT_PACKET_LEN 10
200 #define US_PER_BYTE_1M_PHY 8
201 #define US_PER_BYTE_2M_PHY 4
203 #define US_PER_BYTE_CODED_PHY_S8 64
204 #define US_PER_BYTE_CODED_PHY_S2 16
206 #define PREAMBLE_LEN_1M_PHY 1
207 #define PREAMBLE_LEN_2M_PHY 2
209 /* Preamble + Access Address + CI + TERM1 */
210 #define FEC1_BLOCK_S8_US (80 + 256 + 16 + 24)
211 #define TERM2_S8_US 24
212 #define TERM2_S2_US 6
214 void proto_reg_handoff_nordic_ble(void);
215 void proto_register_nordic_ble(void);
217 static dissector_handle_t nordic_ble_handle
;
219 /* Initialize the protocol and registered fields */
220 static int proto_nordic_ble
;
222 /* Initialize the subtree pointers */
223 static int ett_nordic_ble
;
224 static int ett_packet_header
;
225 static int ett_flags
;
227 static int hf_nordic_ble_board_id
;
228 static int hf_nordic_ble_legacy_marker
;
229 static int hf_nordic_ble_header
;
230 static int hf_nordic_ble_header_length
;
231 static int hf_nordic_ble_payload_length
;
232 static int hf_nordic_ble_protover
;
233 static int hf_nordic_ble_packet_counter
;
234 static int hf_nordic_ble_packet_id
;
235 static int hf_nordic_ble_packet_length
;
236 static int hf_nordic_ble_flags
;
237 static int hf_nordic_ble_crcok
;
238 static int hf_nordic_ble_encrypted
;
239 static int hf_nordic_ble_micok
;
240 static int hf_nordic_ble_mic_not_relevant
;
241 static int hf_nordic_ble_aux_type
;
242 static int hf_nordic_ble_flag_reserved1
;
243 static int hf_nordic_ble_flag_reserved2
;
244 static int hf_nordic_ble_address_resolved
;
245 static int hf_nordic_ble_flag_reserved7
;
246 static int hf_nordic_ble_le_phy
;
247 static int hf_nordic_ble_direction
;
248 static int hf_nordic_ble_channel
;
249 static int hf_nordic_ble_rssi
;
250 static int hf_nordic_ble_event_counter
;
251 static int hf_nordic_ble_time
;
252 static int hf_nordic_ble_delta_time
;
253 static int hf_nordic_ble_delta_time_ss
;
254 static int hf_nordic_ble_packet_time
;
256 static expert_field ei_nordic_ble_bad_crc
;
257 static expert_field ei_nordic_ble_bad_mic
;
258 static expert_field ei_nordic_ble_bad_length
;
259 static expert_field ei_nordic_ble_unknown_version
;
261 static const true_false_string direction_tfs
=
263 "Central -> Peripheral",
264 "Peripheral -> Central"
267 static const value_string le_phys
[] =
283 static const value_string le_aux_ext_adv
[] = {
284 { 0, "AUX_ADV_IND" },
285 { 1, "AUX_CHAIN_IND" },
286 { 2, "AUX_SYNC_IND" },
287 { 3, "AUX_SCAN_RSP" },
295 uint16_t payload_length
;
296 uint16_t event_packet_length
;
297 } nordic_ble_context_t
;
300 static dissector_handle_t btle_dissector_handle
;
301 static dissector_handle_t debug_handle
;
304 dissect_lengths(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, nordic_ble_context_t
*nordic_ble_context
)
309 switch (nordic_ble_context
->protover
) {
310 case 0: /* Legacy version */
311 hlen
= 2 + UART_HEADER_LEN
; /* 2 bytes legacy marker + UART header */
312 item
= proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_payload_length
, tvb
, offset
, 1, ENC_NA
, &plen
);
317 proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_header_length
, tvb
, offset
, 1, ENC_NA
, &hlen
);
318 hlen
+= 1; /* Add one byte for board id */
321 item
= proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_payload_length
, tvb
, offset
, 1, ENC_NA
, &plen
);
325 default: /* Starting from version 2 */
326 hlen
= 1 + UART_HEADER_LEN
; /* Board ID + UART header */
327 item
= proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_payload_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &plen
);
332 if ((hlen
+ plen
) != tvb_captured_length(tvb
)) {
333 expert_add_info(pinfo
, item
, &ei_nordic_ble_bad_length
);
334 nordic_ble_context
->bad_length
= true;
337 nordic_ble_context
->payload_length
= plen
;
343 dissect_flags(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, nordic_ble_context_t
*nordic_ble_context
, btle_context_t
*context
)
345 uint8_t flags
, channel
;
347 proto_item
*flags_item
, *item
;
348 proto_tree
*flags_tree
;
350 flags
= tvb_get_uint8(tvb
, offset
);
351 channel
= tvb_get_uint8(tvb
, offset
+ 1);
353 if (nordic_ble_context
->protover
< 3) {
354 uint32_t access_address
;
356 access_address
= tvb_get_letohl(tvb
, offset
+ nordic_ble_context
->event_packet_length
- 1);
357 context
->pdu_type
= access_address
== ACCESS_ADDRESS_ADVERTISING
? BTLE_PDU_TYPE_ADVERTISING
: BTLE_PDU_TYPE_DATA
;
360 context
->crc_checked_at_capture
= 1;
361 context
->crc_valid_at_capture
= !!(flags
& 1);
363 if (context
->pdu_type
== BTLE_PDU_TYPE_DATA
) {
365 context
->mic_checked_at_capture
= !!(flags
& 4);
366 if (context
->mic_checked_at_capture
) {
367 context
->mic_valid_at_capture
= !!(flags
& 8);
371 nordic_ble_context
->phy
= (flags
>> 4) & 7;
372 context
->phy
= nordic_ble_context
->phy
;
374 if (context
->pdu_type
== BTLE_PDU_TYPE_DATA
) {
376 set_address(&pinfo
->src
, AT_STRINGZ
, 7, "Central");
377 set_address(&pinfo
->dst
, AT_STRINGZ
, 6, "Peripheral");
378 context
->direction
= BTLE_DIR_CENTRAL_PERIPHERAL
;
379 pinfo
->p2p_dir
= P2P_DIR_SENT
;
381 set_address(&pinfo
->src
, AT_STRINGZ
, 6, "Peripheral");
382 set_address(&pinfo
->dst
, AT_STRINGZ
, 7, "Central");
383 context
->direction
= BTLE_DIR_PERIPHERAL_CENTRAL
;
384 pinfo
->p2p_dir
= P2P_DIR_RECV
;
388 flags_item
= proto_tree_add_item(tree
, hf_nordic_ble_flags
, tvb
, offset
, 1, ENC_NA
);
389 flags_tree
= proto_item_add_subtree(flags_item
, ett_flags
);
390 item
= proto_tree_add_item(flags_tree
, hf_nordic_ble_crcok
, tvb
, offset
, 1, ENC_NA
);
391 if (!context
->crc_valid_at_capture
) {
393 expert_add_info(pinfo
, item
, &ei_nordic_ble_bad_crc
);
396 if (context
->pdu_type
== BTLE_PDU_TYPE_DATA
) {
397 proto_tree_add_item(flags_tree
, hf_nordic_ble_direction
, tvb
, offset
, 1, ENC_NA
);
398 proto_tree_add_item(flags_tree
, hf_nordic_ble_encrypted
, tvb
, offset
, 1, ENC_NA
);
399 if (context
->mic_checked_at_capture
) {
400 item
= proto_tree_add_item(flags_tree
, hf_nordic_ble_micok
, tvb
, offset
, 1, ENC_NA
);
401 if (!context
->mic_valid_at_capture
) {
403 expert_add_info(pinfo
, item
, &ei_nordic_ble_bad_mic
);
406 proto_tree_add_item(flags_tree
, hf_nordic_ble_mic_not_relevant
, tvb
, offset
, 1, ENC_NA
);
410 uint32_t aux_pdu_type
;
412 proto_tree_add_item_ret_uint(flags_tree
, hf_nordic_ble_aux_type
, tvb
, offset
, 1, ENC_NA
, &aux_pdu_type
);
413 context
->aux_pdu_type
= aux_pdu_type
;
414 context
->aux_pdu_type_valid
= true;
416 proto_tree_add_item(flags_tree
, hf_nordic_ble_flag_reserved1
, tvb
, offset
, 1, ENC_NA
);
417 proto_tree_add_item(flags_tree
, hf_nordic_ble_flag_reserved2
, tvb
, offset
, 1, ENC_NA
);
419 proto_tree_add_item(flags_tree
, hf_nordic_ble_address_resolved
, tvb
, offset
, 1, ENC_NA
);
422 proto_tree_add_item(flags_tree
, hf_nordic_ble_le_phy
, tvb
, offset
, 1, ENC_NA
);
423 proto_tree_add_item(flags_tree
, hf_nordic_ble_flag_reserved7
, tvb
, offset
, 1, ENC_NA
);
430 static uint16_t packet_time_get(nordic_ble_context_t
*nordic_ble_context
, uint8_t ci
)
432 /* Calculate packet time according to this packets PHY */
433 uint16_t ble_payload_length
= nordic_ble_context
->payload_length
- nordic_ble_context
->event_packet_length
;
435 switch (nordic_ble_context
->phy
) {
437 return US_PER_BYTE_1M_PHY
* (PREAMBLE_LEN_1M_PHY
+ ble_payload_length
);
439 return US_PER_BYTE_2M_PHY
* (PREAMBLE_LEN_2M_PHY
+ ble_payload_length
);
442 /* Subtract Access address and CI */
443 uint16_t fec2_block_len
= ble_payload_length
- 4 - 1;
447 return FEC1_BLOCK_S8_US
+ fec2_block_len
* US_PER_BYTE_CODED_PHY_S8
+ TERM2_S8_US
;
449 return FEC1_BLOCK_S8_US
+ fec2_block_len
* US_PER_BYTE_CODED_PHY_S2
+ TERM2_S2_US
;
454 return 0; /* Unknown */
460 uint32_t packet_start_time
;
461 uint32_t packet_end_time
;
465 bool first_frame_seen
;
466 /* Time information about previous packet times to calculate delta times */
467 uint32_t packet_time
;
468 uint32_t packet_start_time
;
469 uint32_t packet_end_time
;
470 } packet_time_context_t
;
472 static wmem_tree_t
*packet_time_context_tree
;
474 static packet_time_context_t
*packet_times_get(packet_info
*pinfo
)
476 uint32_t interface_id
= (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
) ? pinfo
->rec
->rec_header
.packet_header
.interface_id
: HCI_INTERFACE_DEFAULT
;
477 wmem_tree_t
*wmem_tree
;
478 wmem_tree_key_t keys
[2];
481 keys
[0].key
= &interface_id
;
485 wmem_tree
= (wmem_tree_t
*) wmem_tree_lookup32_array(packet_time_context_tree
, keys
);
487 return (packet_time_context_t
*) wmem_tree_lookup32_le(wmem_tree
, 0);
493 static packet_time_context_t
*packet_times_insert(packet_info
*pinfo
)
495 uint32_t interface_id
= (pinfo
->rec
->presence_flags
& WTAP_HAS_INTERFACE_ID
) ? pinfo
->rec
->rec_header
.packet_header
.interface_id
: HCI_INTERFACE_DEFAULT
;
497 wmem_tree_key_t keys
[3];
498 packet_time_context_t
*packet_times
;
501 keys
[0].key
= &interface_id
;
506 packet_times
= wmem_new0(wmem_file_scope(), packet_time_context_t
);
507 wmem_tree_insert32_array(packet_time_context_tree
, keys
, packet_times
);
513 dissect_ble_delta_time(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, nordic_ble_context_t
*nordic_ble_context
)
515 uint32_t delta_time
, delta_time_ss
, prev_packet_time
, packet_time
;
517 packet_time_context_t
*packet_times_context
;
519 packet_times_context
= packet_times_get(pinfo
);
520 if (!packet_times_context
) {
521 packet_times_context
= packet_times_insert(pinfo
);
525 proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_delta_time
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
, &delta_time
);
527 if (!pinfo
->fd
->visited
) {
528 /* First time visiting this packet, store previous BLE packet time */
529 p_add_proto_data(wmem_file_scope(), pinfo
, proto_nordic_ble
, 0, GUINT_TO_POINTER(packet_times_context
->packet_time
));
530 prev_packet_time
= packet_times_context
->packet_time
;
532 prev_packet_time
= GPOINTER_TO_UINT(p_get_proto_data(wmem_file_scope(), pinfo
, proto_nordic_ble
, 0));
535 if (!packet_times_context
->first_frame_seen
) {
536 delta_time_ss
= prev_packet_time
+ delta_time
;
537 pi
= proto_tree_add_uint(tree
, hf_nordic_ble_delta_time_ss
, tvb
, offset
, 4, delta_time_ss
);
538 proto_item_set_generated(pi
);
541 packet_time
= packet_time_get(nordic_ble_context
, 0 /* This version never supported Coded PHY */);
542 pi
= proto_tree_add_uint(tree
, hf_nordic_ble_packet_time
, tvb
, offset
, 4, packet_time
);
543 proto_item_set_generated(pi
);
547 if (!pinfo
->fd
->visited
) {
548 packet_times_context
->packet_time
= packet_time
;
549 packet_times_context
->first_frame_seen
= true;
556 dissect_ble_timestamp(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, nordic_ble_context_t
*nordic_ble_context
)
558 uint32_t delta_time
, delta_time_ss
, packet_time
;
559 uint32_t timestamp
, last_packet_end_time
, last_packet_start_time
;
561 packet_time_context_t
*packet_times_context
;
563 packet_times_context
= packet_times_get(pinfo
);
564 if (!packet_times_context
) {
565 packet_times_context
= packet_times_insert(pinfo
);
568 proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_time
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
, ×tamp
);
570 if (!pinfo
->fd
->visited
) {
571 packet_times_t
*saved_packet_times
= wmem_new0(wmem_file_scope(), packet_times_t
);
573 saved_packet_times
->packet_end_time
= packet_times_context
->packet_end_time
;
574 saved_packet_times
->packet_start_time
= packet_times_context
->packet_start_time
;
575 p_add_proto_data(wmem_file_scope(), pinfo
, proto_nordic_ble
, 0, saved_packet_times
);
577 /* First time visiting this packet, store previous BLE packet time */
578 last_packet_end_time
= packet_times_context
->packet_end_time
;
579 last_packet_start_time
= packet_times_context
->packet_start_time
;
581 packet_times_t
* saved_packet_times
= (packet_times_t
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_nordic_ble
, 0);
583 last_packet_end_time
= saved_packet_times
->packet_end_time
;
584 last_packet_start_time
= saved_packet_times
->packet_start_time
;
587 uint8_t ci
= tvb_get_uint8(tvb
, offset
+ 4 + 4);
588 packet_time
= packet_time_get(nordic_ble_context
, ci
);
589 item
= proto_tree_add_uint(tree
, hf_nordic_ble_packet_time
, tvb
, offset
, 4, packet_time
);
590 proto_item_set_generated(item
);
592 if (pinfo
->num
> 1) {
593 /* Calculated delta times are not valid for the first packet because we don't have the last packet times. */
594 delta_time
= timestamp
- last_packet_end_time
;
595 item
= proto_tree_add_uint(tree
, hf_nordic_ble_delta_time
, tvb
, offset
, 4, delta_time
);
596 proto_item_set_generated(item
);
598 delta_time_ss
= timestamp
- last_packet_start_time
;
599 item
= proto_tree_add_uint(tree
, hf_nordic_ble_delta_time_ss
, tvb
, offset
, 4, delta_time_ss
);
600 proto_item_set_generated(item
);
603 if (!pinfo
->fd
->visited
) {
605 packet_times_context
->packet_start_time
= timestamp
;
606 packet_times_context
->packet_end_time
= timestamp
+ packet_time
;
607 packet_times_context
->first_frame_seen
= true;
616 dissect_packet_counter(tvbuff_t
*tvb
, int offset
, proto_item
*item
, proto_tree
*tree
)
618 proto_item_append_text(item
, ", Packet counter: %u", tvb_get_uint16(tvb
, offset
, ENC_LITTLE_ENDIAN
));
619 proto_tree_add_item(tree
, hf_nordic_ble_packet_counter
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
626 dissect_packet_header(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, nordic_ble_context_t
*nordic_ble_context
, btle_context_t
*context
)
629 proto_tree
*header_tree
;
630 int start_offset
= offset
;
632 ti
= proto_tree_add_item(tree
, hf_nordic_ble_header
, tvb
, offset
, -1, ENC_NA
);
633 header_tree
= proto_item_add_subtree(ti
, ett_packet_header
);
634 proto_item_append_text(ti
, " Version: %u", nordic_ble_context
->protover
);
636 if (nordic_ble_context
->protover
== 0) {
637 proto_item
*item
= proto_tree_add_uint(header_tree
, hf_nordic_ble_protover
, tvb
, 0, 0, 0);
638 proto_item_set_generated(item
);
640 proto_tree_add_item(header_tree
, hf_nordic_ble_packet_id
, tvb
, offset
, 1, ENC_NA
);
643 offset
= dissect_packet_counter(tvb
, offset
, ti
, header_tree
);
645 offset
+= 2; // Two unused bytes
648 offset
= dissect_lengths(tvb
, offset
, pinfo
, header_tree
, nordic_ble_context
);
650 if (nordic_ble_context
->protover
!= 0) {
651 proto_item
*item
= proto_tree_add_item(header_tree
, hf_nordic_ble_protover
, tvb
, offset
, 1, ENC_NA
);
653 if (nordic_ble_context
->protover
> 3) {
654 expert_add_info(pinfo
, item
, &ei_nordic_ble_unknown_version
);
657 offset
= dissect_packet_counter(tvb
, offset
, ti
, header_tree
);
659 proto_tree_add_item(header_tree
, hf_nordic_ble_packet_id
, tvb
, offset
, 1, ENC_NA
);
661 if (nordic_ble_context
->protover
> 2) {
662 uint8_t id
= tvb_get_uint8(tvb
, offset
);
664 context
->pdu_type
= id
== 0x06 ? BTLE_PDU_TYPE_DATA
:
665 id
== 0x02 ? BTLE_PDU_TYPE_ADVERTISING
:
666 BTLE_PDU_TYPE_UNKNOWN
;
672 proto_item_set_len(ti
, offset
- start_offset
);
678 dissect_packet(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, nordic_ble_context_t
*nordic_ble_context
, btle_context_t
*context
)
681 uint32_t channel
, event_counter
;
683 if (nordic_ble_context
->protover
== 0) {
684 // Event packet length is fixed for the legacy version
685 nordic_ble_context
->event_packet_length
= EVENT_PACKET_LEN
;
688 proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_packet_length
, tvb
, offset
, 1, ENC_NA
, &plen
);
689 nordic_ble_context
->event_packet_length
= plen
;
693 offset
= dissect_flags(tvb
, offset
, pinfo
, tree
, nordic_ble_context
, context
);
695 proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_channel
, tvb
, offset
, 1, ENC_NA
, &channel
);
698 context
->channel
= channel
;
700 rssi
= (-1)*((int32_t)tvb_get_uint8(tvb
, offset
));
701 proto_tree_add_int(tree
, hf_nordic_ble_rssi
, tvb
, offset
, 1, rssi
);
704 proto_tree_add_item_ret_uint(tree
, hf_nordic_ble_event_counter
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &event_counter
);
707 context
->event_counter
= event_counter
;
708 context
->event_counter_valid
= 1;
710 if (nordic_ble_context
->protover
< 3) {
711 offset
= dissect_ble_delta_time(tvb
, offset
, pinfo
, tree
, nordic_ble_context
);
713 offset
= dissect_ble_timestamp(tvb
, offset
, pinfo
, tree
, nordic_ble_context
);
720 dissect_header(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, btle_context_t
*context
, bool *bad_length
)
723 proto_tree
*nordic_ble_tree
;
725 nordic_ble_context_t nordic_ble_context
;
727 memset(&nordic_ble_context
, 0, sizeof(nordic_ble_context
));
729 ti
= proto_tree_add_item(tree
, proto_nordic_ble
, tvb
, 0, -1, ENC_NA
);
730 nordic_ble_tree
= proto_item_add_subtree(ti
, ett_nordic_ble
);
732 if (tvb_get_uint16(tvb
, 0, ENC_BIG_ENDIAN
) == 0xBEEF) {
733 proto_tree_add_item(nordic_ble_tree
, hf_nordic_ble_legacy_marker
, tvb
, 0, 2, ENC_BIG_ENDIAN
);
736 nordic_ble_context
.protover
= 0; /* Legacy Version */
738 proto_tree_add_item(nordic_ble_tree
, hf_nordic_ble_board_id
, tvb
, 0, 1, ENC_NA
);
741 nordic_ble_context
.protover
= tvb_get_uint8(tvb
, offset
+ 2);
744 offset
= dissect_packet_header(tvb
, offset
, pinfo
, nordic_ble_tree
, &nordic_ble_context
, context
);
745 offset
= dissect_packet(tvb
, offset
, pinfo
, nordic_ble_tree
, &nordic_ble_context
, context
);
747 proto_item_set_len(ti
, offset
);
748 *bad_length
= nordic_ble_context
.bad_length
;
753 /* Main entry point for sniffer */
755 dissect_nordic_ble(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
757 tvbuff_t
*payload_tvb
;
758 btle_context_t
*context
;
760 bool bad_length
= false;
762 context
= wmem_new0(pinfo
->pool
, btle_context_t
);
764 offset
= dissect_header(tvb
, pinfo
, tree
, context
, &bad_length
);
765 payload_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, -1, tvb_captured_length(tvb
) - offset
);
768 call_dissector_with_data(btle_dissector_handle
, payload_tvb
, pinfo
, tree
, context
);
771 if ((context
->mic_checked_at_capture
) && (!context
->mic_valid_at_capture
)) {
772 col_set_str(pinfo
->cinfo
, COL_INFO
, "Encrypted packet decrypted incorrectly");
773 if (!context
->crc_valid_at_capture
) {
775 col_append_str(pinfo
->cinfo
, COL_INFO
, " (bad CRC)");
777 col_append_str(pinfo
->cinfo
, COL_INFO
, " (bad MIC)");
782 call_dissector(debug_handle
, payload_tvb
, pinfo
, tree
);
789 proto_register_nordic_ble(void)
791 static hf_register_info hf
[] = {
792 { &hf_nordic_ble_board_id
,
793 { "Board", "nordic_ble.board_id",
794 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
797 { &hf_nordic_ble_legacy_marker
,
798 { "Legacy marker", "nordic_ble.legacy_marker",
799 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
802 { &hf_nordic_ble_header
,
803 { "Header", "nordic_ble.header",
804 FT_NONE
, BASE_NONE
, NULL
, 0x0,
807 { &hf_nordic_ble_header_length
,
808 { "Length of header", "nordic_ble.hlen",
809 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
812 { &hf_nordic_ble_payload_length
,
813 { "Length of payload", "nordic_ble.plen",
814 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
817 { &hf_nordic_ble_protover
,
818 { "Protocol version", "nordic_ble.protover",
819 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
822 { &hf_nordic_ble_packet_counter
,
823 { "Packet counter", "nordic_ble.packet_counter",
824 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
825 "Global packet counter for packets sent on UART", HFILL
}
827 { &hf_nordic_ble_packet_id
,
828 { "Packet ID", "nordic_ble.packet_id",
829 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
832 { &hf_nordic_ble_packet_length
,
833 { "Length of packet", "nordic_ble.len",
834 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
837 { &hf_nordic_ble_flags
,
838 { "Flags", "nordic_ble.flags",
839 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
842 { &hf_nordic_ble_crcok
,
843 { "CRC", "nordic_ble.crcok",
844 FT_BOOLEAN
, 8, TFS(&tfs_ok_error
), 0x01,
845 "Cyclic Redundancy Check state", HFILL
}
847 { &hf_nordic_ble_direction
,
848 { "Direction", "nordic_ble.direction",
849 FT_BOOLEAN
, 8, TFS(&direction_tfs
), 0x02,
852 { &hf_nordic_ble_flag_reserved1
,
853 { "Reserved", "nordic_ble.flag_reserved1",
854 FT_UINT8
, BASE_DEC
, NULL
, 0x02,
857 { &hf_nordic_ble_encrypted
,
858 { "Encrypted", "nordic_ble.encrypted",
859 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), 0x04,
860 "Was the packet encrypted", HFILL
}
862 { &hf_nordic_ble_flag_reserved2
,
863 { "Reserved", "nordic_ble.flag_reserved2",
864 FT_UINT8
, BASE_DEC
, NULL
, 0x04,
867 { &hf_nordic_ble_aux_type
,
868 { "Aux Type", "nordic_ble.aux_type",
869 FT_UINT8
, BASE_DEC
, VALS(le_aux_ext_adv
), 0x06,
872 { &hf_nordic_ble_micok
,
873 { "MIC", "nordic_ble.micok",
874 FT_BOOLEAN
, 8, TFS(&tfs_ok_error
), 0x08,
875 "Message Integrity Check state", HFILL
}
877 { &hf_nordic_ble_mic_not_relevant
,
878 { "MIC (not relevant)", "nordic_ble.mic_not_relevant",
879 FT_UINT8
, BASE_DEC
, NULL
, 0x08,
880 "Message Integrity Check state is only relevant when encrypted", HFILL
}
882 { &hf_nordic_ble_address_resolved
,
883 { "Address Resolved", "nordic_ble.address_resolved",
884 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), 0x08,
887 { &hf_nordic_ble_le_phy
,
888 { "PHY", "nordic_ble.phy",
889 FT_UINT8
, BASE_DEC
, VALS(le_phys
), 0x70,
890 "Physical Layer", HFILL
}
892 { &hf_nordic_ble_flag_reserved7
,
893 { "Reserved", "nordic_ble.flag_reserved7",
894 FT_UINT8
, BASE_DEC
, NULL
, 0x80,
895 "Reserved for Future Use", HFILL
}
897 { &hf_nordic_ble_channel
,
898 { "Channel Index", "nordic_ble.channel",
899 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
902 { &hf_nordic_ble_rssi
,
903 { "RSSI", "nordic_ble.rssi",
904 FT_INT8
, BASE_DEC
| BASE_UNIT_STRING
, UNS(&units_dbm
), 0x0,
905 "Received Signal Strength Indicator", HFILL
}
907 { &hf_nordic_ble_event_counter
,
908 { "Event counter", "nordic_ble.event_counter",
909 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
912 { &hf_nordic_ble_time
,
913 { "Timestamp", "nordic_ble.time",
914 FT_UINT32
, BASE_DEC
| BASE_UNIT_STRING
, UNS(&units_microseconds
), 0x0,
915 "Firmware timestamp", HFILL
}
917 { &hf_nordic_ble_delta_time
,
918 { "Delta time (end to start)", "nordic_ble.delta_time",
919 FT_UINT32
, BASE_DEC
| BASE_UNIT_STRING
, UNS(&units_microseconds
), 0x0,
920 "Time since end of last reported packet", HFILL
}
922 { &hf_nordic_ble_delta_time_ss
,
923 { "Delta time (start to start)", "nordic_ble.delta_time_ss",
924 FT_UINT32
, BASE_DEC
| BASE_UNIT_STRING
, UNS(&units_microseconds
), 0x0,
925 "Time since start of last reported packet", HFILL
}
927 { &hf_nordic_ble_packet_time
,
928 { "Packet time (start to end)", "nordic_ble.packet_time",
929 FT_UINT32
, BASE_DEC
| BASE_UNIT_STRING
, UNS(&units_microseconds
), 0x0,
930 "Time of packet", HFILL
}
934 static int *ett
[] = {
940 static ei_register_info ei
[] = {
941 { &ei_nordic_ble_bad_crc
, { "nordic_ble.crc.bad", PI_CHECKSUM
, PI_ERROR
, "CRC is bad", EXPFILL
}},
942 { &ei_nordic_ble_bad_mic
, { "nordic_ble.mic.bad", PI_CHECKSUM
, PI_ERROR
, "MIC is bad", EXPFILL
}},
943 { &ei_nordic_ble_bad_length
, { "nordic_ble.length.bad", PI_MALFORMED
, PI_ERROR
, "Length is incorrect", EXPFILL
}},
944 { &ei_nordic_ble_unknown_version
, { "nordic_ble.protover.bad", PI_PROTOCOL
, PI_ERROR
, "Unknown version", EXPFILL
}},
947 expert_module_t
*expert_nordic_ble
;
949 packet_time_context_tree
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
951 proto_nordic_ble
= proto_register_protocol("nRF Sniffer for Bluetooth LE", "NORDIC_BLE", "nordic_ble");
953 nordic_ble_handle
= register_dissector("nordic_ble", dissect_nordic_ble
, proto_nordic_ble
);
955 expert_nordic_ble
= expert_register_protocol(proto_nordic_ble
);
956 expert_register_field_array(expert_nordic_ble
, ei
, array_length(ei
));
958 proto_register_field_array(proto_nordic_ble
, hf
, array_length(hf
));
959 proto_register_subtree_array(ett
, array_length(ett
));
963 proto_reg_handoff_nordic_ble(void)
965 btle_dissector_handle
= find_dissector("btle");
966 debug_handle
= find_dissector("nordic_debug");
968 dissector_add_for_decode_as_with_preference("udp.port", nordic_ble_handle
);
969 dissector_add_uint("wtap_encap", WTAP_ENCAP_NORDIC_BLE
, nordic_ble_handle
);
974 * Editor modelines - https://www.wireshark.org/tools/modelines.html
979 * indent-tabs-mode: nil
982 * vi: set shiftwidth =4 tabstop =8 expandtab:
983 * :indentSize =4:tabSize =8:noTabs =true: