1 /* packet-nordic_ble.c
2 * Routines for nRF Sniffer for Bluetooth LE dissection
3 *
4 * Copyright (c) 2016-2018 Nordic Semiconductor.
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 /* nRF Sniffer for Bluetooth LE packet format: BoardID + Header + Payload
14 *
15 * +--------+--------+--------+--------+--------+--------+--------+--------+
16 * | BoardID (1 byte) |
17 * +--------+--------+--------+--------+--------+--------+--------+--------+
18 *
19 * Header version 0 (legacy):
20 * +--------+--------+--------+--------+--------+--------+--------+--------+
21 * | Packet ID (1 byte) |
22 * +--------+--------+--------+--------+--------+--------+--------+--------+
23 * | Packet counter (LSB) |
24 * | (2 bytes) |
25 * +--------+--------+--------+--------+--------+--------+--------+--------+
26 * | Unused |
27 * | (2 bytes) |
28 * +--------+--------+--------+--------+--------+--------+--------+--------+
29 * | Length of payload (1 byte) |
30 * +--------+--------+--------+--------+--------+--------+--------+--------+
31 *
32 * Header version 1:
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) |
41 * | (2 bytes) |
42 * +--------+--------+--------+--------+--------+--------+--------+--------+
43 * | Packet ID (1 byte) |
44 * +--------+--------+--------+--------+--------+--------+--------+--------+
45 *
46 * Header version > 1:
47 * +--------+--------+--------+--------+--------+--------+--------+--------+
48 * | Length of payload (little endian) |
49 * | (2 bytes) |
50 * +--------+--------+--------+--------+--------+--------+--------+--------+
51 * | Protocol version (1 byte) |
52 * +--------+--------+--------+--------+--------+--------+--------+--------+
53 * | Packet counter (little endian) |
54 * | (2 bytes) |
55 * +--------+--------+--------+--------+--------+--------+--------+--------+
56 * | Packet ID (1 byte) |
57 * +--------+--------+--------+--------+--------+--------+--------+--------+
58 *
59 * Packet ID:
60 * 0x00 = REQ_FOLLOW
61 * Host tells the Sniffer to scan for Advertising from a specific
62 * address and follow all communication it has with other devices.
63 *
64 * 0x01 = EVENT_FOLLOW
65 * Sniffer tells the Host that it has entered the FOLLOW state.
66 *
67 * 0x02 = EVENT_PACKET_ADVERTISING
68 * Sniffer tells the Host that it has received an advertising physical
69 * channel PDU.
70 *
71 * 0x05 = EVENT_CONNECT
72 * Sniffer tells the Host that someone has connected to the unit we
73 * are following.
74 *
75 * 0x06 = EVENT_PACKET_DATA
76 * Protocol version < 3:
77 * Sniffer tells the host that it has received a packet on any physical
78 * channel.
79 * Access address == 0x8e89bed6 Advertising physical channel PDU
80 * Access address != 0x8e89bed6 Data physical channel PDU
81 * Protocol version 3:
82 * Sniffer tells the Host that it has received a data physical
83 * channel PDU.
84 *
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.
88 *
89 * 0x09 = EVENT_DISCONNECT
90 * Sniffer tells the Host that the connected address we were following
91 * has received a disconnect packet.
92 *
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.
96 *
97 * 0x0D = PING_REQ
98 *
99 * 0x0E = PING_RESP
100 *
101 * 0x13 = SWITCH_BAUD_RATE_REQ
102 *
103 * 0x14 = SWITCH_BAUD_RATE_RESP
104 *
105 * 0x17 = SET_ADV_CHANNEL_HOP_SEQ
106 * Host tells the Sniffer which order to cycle through the channels
107 * when following an advertiser.
108 *
109 * 0xFE = GO_IDLE
110 * Host tell the Sniffer to stop sending UART traffic and listen for
111 * new commands.
112 *
113 * Payloads:
114 *
115 * Protocol version < 3:
116 * EVENT_PACKET (ID 0x06)
117 *
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 * +--------+--------+--------+--------+--------+--------+--------+--------+
124 * | Flags (1 byte) |
125 * +--------+--------+--------+--------+--------+--------+--------+--------+
126 * | Channel (1 byte) |
127 * +--------+--------+--------+--------+--------+--------+--------+--------+
128 * | RSSISample (dBm) (1 byte) |
129 * +--------+--------+--------+--------+--------+--------+--------+--------+
130 * | Event counter |
131 * | (2 bytes) |
132 * +--------+--------+--------+--------+--------+--------+--------+--------+
133 * | Protocol version < 3: Delta time (us end to start) |
134 * | (4 bytes) |
135 * | Protocol version 3: Firmware Timestamp (us) |
136 * | (4 bytes) |
137 * +--------+--------+--------+--------+--------+--------+--------+--------+
138 *
139 * +--------+--------+--------+--------+--------+--------+--------+--------+
140 * | |
141 * | Bluetooth Low Energy Link Layer Packet (excluding preamble) |
142 * | ... |
143 * | |
144 * +--------+--------+--------+--------+--------+--------+--------+--------+
145 *
146 * Flags EVENT_PACKET_ADVERTISING (0x02)
147 * 0000000x = CRC (0 = Incorrect, 1 = OK)
148 * 000000x0 = RFU
149 * 00000x00 = RFU
150 * 00000xx0 = AUX_TYPE (channel < 37: 0 = AUX_ADV_IND, 1 = AUX_CHAIN_IND,
151 * 2 = AUX_SYNC_IND, 3 = AUX_SCAN_RSP)
152 * 0000x000 = RFU
153 * 0xxx0000 = PHY (0 = 1M, 1 = 2M, 2 = Coded, rest unused)
154 * x0000000 = RFU
155 *
156 * Flags EVENT_PACKET_DATA (0x06)
157 * 0000000x = CRC (0 = Incorrect, 1 = OK)
158 * 000000x0 = Direction (0 = Slave -> Master, 1 = Master -> Slave)
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)
162 * x0000000 = RFU
163 *
164 * Channel:
165 * The channel index being used.
166 *
167 * RSSIsample:
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
172 *
173 * Delta time:
174 * This is the time in microseconds from the end of the previous received
175 * packet to the beginning of this packet.
176 *
177 * Firmware timestamp:
178 * Timestamp of the start of the received packet captured by the firmware
179 * timer with microsecond resolution.
180 */
181
182 #include "config.h"
183
184 #include <epan/packet.h>
185 #include <epan/expert.h>
186 #include <epan/proto_data.h>
187
188 #include <wsutil/utf8_entities.h>
189 #include <wiretap/wtap.h>
190
191 #include "packet-btle.h"
192
193 /* Size of various UART Packet header fields */
194 #define UART_HEADER_LEN 6
195 #define EVENT_PACKET_LEN 10
196
197 #define US_PER_BYTE_1M_PHY 8
198 #define US_PER_BYTE_2M_PHY 4
199
200 #define US_PER_BYTE_CODED_PHY_S8 64
201 #define US_PER_BYTE_CODED_PHY_S2 16
202
203 #define PREAMBLE_LEN_1M_PHY 1
204 #define PREAMBLE_LEN_2M_PHY 2
205
206 /* Preamble + Access Address + CI + TERM1 */
207 #define FEC1_BLOCK_S8_US (80 + 256 + 16 + 24)
208 #define TERM2_S8_US 24
209 #define TERM2_S2_US 6
210
211 void proto_reg_handoff_nordic_ble(void);
212 void proto_register_nordic_ble(void);
213
214 /* Initialize the protocol and registered fields */
215 static int proto_nordic_ble = -1;
216
217 /* Initialize the subtree pointers */
218 static gint ett_nordic_ble = -1;
219 static gint ett_packet_header = -1;
220 static gint ett_flags = -1;
221
222 static int hf_nordic_ble_board_id = -1;
223 static int hf_nordic_ble_legacy_marker = -1;
224 static int hf_nordic_ble_header = -1;
225 static int hf_nordic_ble_header_length = -1;
226 static int hf_nordic_ble_payload_length = -1;
227 static int hf_nordic_ble_protover = -1;
228 static int hf_nordic_ble_packet_counter = -1;
229 static int hf_nordic_ble_packet_id = -1;
230 static int hf_nordic_ble_packet_length = -1;
231 static int hf_nordic_ble_flags = -1;
232 static int hf_nordic_ble_crcok = -1;
233 static int hf_nordic_ble_encrypted = -1;
234 static int hf_nordic_ble_micok = -1;
235 static int hf_nordic_ble_mic_not_relevant = -1;
236 static int hf_nordic_ble_aux_type = -1;
237 static int hf_nordic_ble_flag_reserved1 = -1;
238 static int hf_nordic_ble_flag_reserved2 = -1;
239 static int hf_nordic_ble_address_resolved = -1;
240 static int hf_nordic_ble_flag_reserved7 = -1;
241 static int hf_nordic_ble_le_phy = -1;
242 static int hf_nordic_ble_direction = -1;
243 static int hf_nordic_ble_channel = -1;
244 static int hf_nordic_ble_rssi = -1;
245 static int hf_nordic_ble_event_counter = -1;
246 static int hf_nordic_ble_time = -1;
247 static int hf_nordic_ble_delta_time = -1;
248 static int hf_nordic_ble_delta_time_ss = -1;
249 static int hf_nordic_ble_packet_time = -1;
250
251 static expert_field ei_nordic_ble_bad_crc = EI_INIT;
252 static expert_field ei_nordic_ble_bad_mic = EI_INIT;
253 static expert_field ei_nordic_ble_bad_length = EI_INIT;
254 static expert_field ei_nordic_ble_unknown_version = EI_INIT;
255
256 static const true_false_string direction_tfs =
257 {
258 "Master -> Slave",
259 "Slave -> Master"
260 };
261
262 static const value_string le_phys[] =
263 {
264 { 0, "LE 1M" },
265 { 1, "LE 2M" },
266 { 2, "LE Coded" },
267 { 3, "Reserved" },
268 { 4, "Reserved" },
269 { 5, "Reserved" },
270 { 6, "Reserved" },
271 { 7, "Reserved" },
272 { 0, NULL }
273 };
274
275 #define CI_S8 0
276 #define CI_S2 1
277
278 static const value_string le_aux_ext_adv[] = {
279 { 0, "AUX_ADV_IND" },
280 { 1, "AUX_CHAIN_IND" },
281 { 2, "AUX_SYNC_IND" },
282 { 3, "AUX_SCAN_RSP" },
283 { 0, NULL }
284 };
285
286 typedef struct {
287 guint8 protover;
288 guint8 phy;
289 gboolean bad_length;
290 guint16 payload_length;
291 guint16 event_packet_length;
292 } nordic_ble_context_t;
293
294 /* next dissector */
295 static dissector_handle_t btle_dissector_handle = NULL;
296 static dissector_handle_t debug_handle = NULL;
297
298 static gint
dissect_lengths(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,nordic_ble_context_t * nordic_ble_context)299 dissect_lengths(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context)
300 {
301 guint32 hlen, plen;
302 proto_item* item;
303
304 switch (nordic_ble_context->protover) {
305 case 0: /* Legacy version */
306 hlen = 2 + UART_HEADER_LEN; /* 2 bytes legacy marker + UART header */
307 item = proto_tree_add_item_ret_uint(tree, hf_nordic_ble_payload_length, tvb, offset, 1, ENC_NA, &plen);
308 offset += 1;
309 break;
310
311 case 1:
312 proto_tree_add_item_ret_uint(tree, hf_nordic_ble_header_length, tvb, offset, 1, ENC_NA, &hlen);
313 hlen += 1; /* Add one byte for board id */
314 offset += 1;
315
316 item = proto_tree_add_item_ret_uint(tree, hf_nordic_ble_payload_length, tvb, offset, 1, ENC_NA, &plen);
317 offset += 1;
318 break;
319
320 default: /* Starting from version 2 */
321 hlen = 1 + UART_HEADER_LEN; /* Board ID + UART header */
322 item = proto_tree_add_item_ret_uint(tree, hf_nordic_ble_payload_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &plen);
323 offset += 2;
324 break;
325 }
326
327 if ((hlen + plen) != tvb_captured_length(tvb)) {
328 expert_add_info(pinfo, item, &ei_nordic_ble_bad_length);
329 nordic_ble_context->bad_length = TRUE;
330 }
331
332 nordic_ble_context->payload_length = plen;
333
334 return offset;
335 }
336
337 static gint
dissect_flags(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,nordic_ble_context_t * nordic_ble_context,btle_context_t * context)338 dissect_flags(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context, btle_context_t *context)
339 {
340 guint8 flags, channel;
341 gboolean dir;
342 proto_item *flags_item, *item;
343 proto_tree *flags_tree;
344
345 flags = tvb_get_guint8(tvb, offset);
346 channel = tvb_get_guint8(tvb, offset + 1);
347
348 if (nordic_ble_context->protover < 3) {
349 guint32 access_address;
350
351 access_address = tvb_get_letohl(tvb, offset + nordic_ble_context->event_packet_length - 1);
352 context->pdu_type = access_address == ACCESS_ADDRESS_ADVERTISING ? BTLE_PDU_TYPE_ADVERTISING : BTLE_PDU_TYPE_DATA;
353 }
354
355 context->crc_checked_at_capture = 1;
356 context->crc_valid_at_capture = !!(flags & 1);
357
358 if (context->pdu_type == BTLE_PDU_TYPE_DATA) {
359 dir = !!(flags & 2);
360 context->mic_checked_at_capture = !!(flags & 4);
361 if (context->mic_checked_at_capture) {
362 context->mic_valid_at_capture = !!(flags & 8);
363 }
364 }
365
366 nordic_ble_context->phy = (flags >> 4) & 7;
367 context->phy = nordic_ble_context->phy;
368
369 if (context->pdu_type == BTLE_PDU_TYPE_DATA) {
370 if (dir) {
371 set_address(&pinfo->src, AT_STRINGZ, 7, "Master");
372 set_address(&pinfo->dst, AT_STRINGZ, 6, "Slave");
373 context->direction = BTLE_DIR_MASTER_SLAVE;
374 pinfo->p2p_dir = P2P_DIR_SENT;
375 } else {
376 set_address(&pinfo->src, AT_STRINGZ, 6, "Slave");
377 set_address(&pinfo->dst, AT_STRINGZ, 7, "Master");
378 context->direction = BTLE_DIR_SLAVE_MASTER;
379 pinfo->p2p_dir = P2P_DIR_RECV;
380 }
381 }
382
383 flags_item = proto_tree_add_item(tree, hf_nordic_ble_flags, tvb, offset, 1, ENC_NA);
384 flags_tree = proto_item_add_subtree(flags_item, ett_flags);
385 item = proto_tree_add_item(flags_tree, hf_nordic_ble_crcok, tvb, offset, 1, ENC_NA);
386 if (!context->crc_valid_at_capture) {
387 /* CRC is bad */
388 expert_add_info(pinfo, item, &ei_nordic_ble_bad_crc);
389 }
390
391 if (context->pdu_type == BTLE_PDU_TYPE_DATA) {
392 proto_tree_add_item(flags_tree, hf_nordic_ble_direction, tvb, offset, 1, ENC_NA);
393 proto_tree_add_item(flags_tree, hf_nordic_ble_encrypted, tvb, offset, 1, ENC_NA);
394 if (context->mic_checked_at_capture) {
395 item = proto_tree_add_item(flags_tree, hf_nordic_ble_micok, tvb, offset, 1, ENC_NA);
396 if (!context->mic_valid_at_capture) {
397 /* MIC is bad */
398 expert_add_info(pinfo, item, &ei_nordic_ble_bad_mic);
399 }
400 } else {
401 proto_tree_add_item(flags_tree, hf_nordic_ble_mic_not_relevant, tvb, offset, 1, ENC_NA);
402 }
403 } else {
404 if (channel < 37) {
405 guint32 aux_pdu_type;
406
407 proto_tree_add_item_ret_uint(flags_tree, hf_nordic_ble_aux_type, tvb, offset, 1, ENC_NA, &aux_pdu_type);
408 context->aux_pdu_type = aux_pdu_type;
409 context->aux_pdu_type_valid = TRUE;
410 } else {
411 proto_tree_add_item(flags_tree, hf_nordic_ble_flag_reserved1, tvb, offset, 1, ENC_NA);
412 proto_tree_add_item(flags_tree, hf_nordic_ble_flag_reserved2, tvb, offset, 1, ENC_NA);
413 }
414 proto_tree_add_item(flags_tree, hf_nordic_ble_address_resolved, tvb, offset, 1, ENC_NA);
415 }
416
417 proto_tree_add_item(flags_tree, hf_nordic_ble_le_phy, tvb, offset, 1, ENC_NA);
418 proto_tree_add_item(flags_tree, hf_nordic_ble_flag_reserved7, tvb, offset, 1, ENC_NA);
419
420 offset++;
421
422 return offset;
423 }
424
packet_time_get(nordic_ble_context_t * nordic_ble_context,guint8 ci)425 static guint16 packet_time_get(nordic_ble_context_t *nordic_ble_context, guint8 ci)
426 {
427 /* Calculate packet time according to this packets PHY */
428 guint16 ble_payload_length = nordic_ble_context->payload_length - nordic_ble_context->event_packet_length;
429
430 switch (nordic_ble_context->phy) {
431 case LE_1M_PHY:
432 return US_PER_BYTE_1M_PHY * (PREAMBLE_LEN_1M_PHY + ble_payload_length);
433 case LE_2M_PHY:
434 return US_PER_BYTE_2M_PHY * (PREAMBLE_LEN_2M_PHY + ble_payload_length);
435 case LE_CODED_PHY:
436 {
437 /* Subtract Access address and CI */
438 guint16 fec2_block_len = ble_payload_length - 4 - 1;
439
440 switch (ci) {
441 case CI_S8:
442 return FEC1_BLOCK_S8_US + fec2_block_len * US_PER_BYTE_CODED_PHY_S8 + TERM2_S8_US;
443 case CI_S2:
444 return FEC1_BLOCK_S8_US + fec2_block_len * US_PER_BYTE_CODED_PHY_S2 + TERM2_S2_US;
445 }
446 }
447 /* Fallthrough */
448 default:
449 return 0; /* Unknown */
450 }
451 }
452
453 typedef struct
454 {
455 guint32 packet_start_time;
456 guint32 packet_end_time;
457 } packet_times_t;
458
459 typedef struct {
460 gboolean first_frame_seen;
461 /* Time information about previous packet times to calculate delta times */
462 guint32 packet_time;
463 guint32 packet_start_time;
464 guint32 packet_end_time;
465 } packet_time_context_t;
466
467 static wmem_tree_t *packet_time_context_tree;
468
packet_times_get(packet_info * pinfo)469 static packet_time_context_t *packet_times_get(packet_info *pinfo)
470 {
471 guint32 interface_id = (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) ? pinfo->rec->rec_header.packet_header.interface_id: HCI_INTERFACE_DEFAULT;
472 wmem_tree_t *wmem_tree;
473 wmem_tree_key_t keys[2];
474
475 keys[0].length = 1;
476 keys[0].key = &interface_id;
477 keys[1].length = 0;
478 keys[1].key = NULL;
479
480 wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(packet_time_context_tree, keys);
481 if (wmem_tree) {
482 return (packet_time_context_t *) wmem_tree_lookup32_le(wmem_tree, 0);
483 }
484
485 return NULL;
486 }
487
packet_times_insert(packet_info * pinfo)488 static packet_time_context_t *packet_times_insert(packet_info *pinfo)
489 {
490 guint32 interface_id = (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) ? pinfo->rec->rec_header.packet_header.interface_id: HCI_INTERFACE_DEFAULT;
491 guint32 key = 0;
492 wmem_tree_key_t keys[3];
493 packet_time_context_t *packet_times;
494
495 keys[0].length = 1;
496 keys[0].key = &interface_id;
497 keys[1].length = 1;
498 keys[1].key = &key;
499 keys[2].length = 0;
500 keys[2].key = NULL;
501 packet_times = wmem_new0(wmem_file_scope(), packet_time_context_t);
502 wmem_tree_insert32_array(packet_time_context_tree, keys, packet_times);
503
504 return packet_times;
505 }
506
507 static gint
dissect_ble_delta_time(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,nordic_ble_context_t * nordic_ble_context)508 dissect_ble_delta_time(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context)
509 {
510 guint32 delta_time, delta_time_ss, prev_packet_time, packet_time;
511 proto_item *pi;
512 packet_time_context_t *packet_times_context;
513
514 packet_times_context = packet_times_get(pinfo);
515 if (!packet_times_context) {
516 packet_times_context = packet_times_insert(pinfo);
517 }
518
519 /* end-to-start */
520 proto_tree_add_item_ret_uint(tree, hf_nordic_ble_delta_time, tvb, offset, 4, ENC_LITTLE_ENDIAN, &delta_time);
521
522 if (!pinfo->fd->visited) {
523 /* First time visiting this packet, store previous BLE packet time */
524 p_add_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0, GUINT_TO_POINTER(packet_times_context->packet_time));
525 prev_packet_time = packet_times_context->packet_time;
526 } else {
527 prev_packet_time = GPOINTER_TO_UINT(p_get_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0));
528 }
529
530 if (!packet_times_context->first_frame_seen) {
531 delta_time_ss = prev_packet_time + delta_time;
532 pi = proto_tree_add_uint(tree, hf_nordic_ble_delta_time_ss, tvb, offset, 4, delta_time_ss);
533 proto_item_set_generated(pi);
534 }
535
536 packet_time = packet_time_get(nordic_ble_context, 0 /* This version never supported Coded PHY */);
537 pi = proto_tree_add_uint(tree, hf_nordic_ble_packet_time, tvb, offset, 4, packet_time);
538 proto_item_set_generated(pi);
539
540 offset += 4;
541
542 if (!pinfo->fd->visited) {
543 packet_times_context->packet_time = packet_time;
544 packet_times_context->first_frame_seen = TRUE;
545 }
546
547 return offset;
548 }
549
550 static gint
dissect_ble_timestamp(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,nordic_ble_context_t * nordic_ble_context)551 dissect_ble_timestamp(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context)
552 {
553 guint32 delta_time, delta_time_ss, packet_time;
554 guint32 timestamp, last_packet_end_time, last_packet_start_time;
555 proto_item *item;
556 packet_time_context_t *packet_times_context;
557
558 packet_times_context = packet_times_get(pinfo);
559 if (!packet_times_context) {
560 packet_times_context = packet_times_insert(pinfo);
561 }
562
563 proto_tree_add_item_ret_uint(tree, hf_nordic_ble_time, tvb, offset, 4, ENC_LITTLE_ENDIAN, ×tamp);
564
565 if (!pinfo->fd->visited) {
566 packet_times_t *saved_packet_times = wmem_new0(wmem_file_scope(), packet_times_t);
567
568 saved_packet_times->packet_end_time = packet_times_context->packet_end_time;
569 saved_packet_times->packet_start_time = packet_times_context->packet_start_time;
570 p_add_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0, saved_packet_times);
571
572 /* First time visiting this packet, store previous BLE packet time */
573 last_packet_end_time = packet_times_context->packet_end_time;
574 last_packet_start_time = packet_times_context->packet_start_time;
575 } else {
576 packet_times_t* saved_packet_times = (packet_times_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0);
577
578 last_packet_end_time = saved_packet_times->packet_end_time;
579 last_packet_start_time = saved_packet_times->packet_start_time;
580 }
581
582 guint8 ci = tvb_get_guint8(tvb, offset + 4 + 4);
583 packet_time = packet_time_get(nordic_ble_context, ci);
584 item = proto_tree_add_uint(tree, hf_nordic_ble_packet_time, tvb, offset, 4, packet_time);
585 proto_item_set_generated(item);
586
587 if (pinfo->num > 1) {
588 /* Calculated delta times are not valid for the first packet because we don't have the last packet times. */
589 delta_time = timestamp - last_packet_end_time;
590 item = proto_tree_add_uint(tree, hf_nordic_ble_delta_time, tvb, offset, 4, delta_time);
591 proto_item_set_generated(item);
592
593 delta_time_ss = timestamp - last_packet_start_time;
594 item = proto_tree_add_uint(tree, hf_nordic_ble_delta_time_ss, tvb, offset, 4, delta_time_ss);
595 proto_item_set_generated(item);
596 }
597
598 if (!pinfo->fd->visited) {
599
600 packet_times_context->packet_start_time = timestamp;
601 packet_times_context->packet_end_time = timestamp + packet_time;
602 packet_times_context->first_frame_seen = TRUE;
603 }
604
605 offset += 4;
606
607 return offset;
608 }
609
610 static gint
dissect_packet_counter(tvbuff_t * tvb,gint offset,proto_item * item,proto_tree * tree)611 dissect_packet_counter(tvbuff_t *tvb, gint offset, proto_item *item, proto_tree *tree)
612 {
613 proto_item_append_text(item, ", Packet counter: %u", tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN));
614 proto_tree_add_item(tree, hf_nordic_ble_packet_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN);
615 offset += 2;
616
617 return offset;
618 }
619
620 static gint
dissect_packet_header(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,nordic_ble_context_t * nordic_ble_context,btle_context_t * context)621 dissect_packet_header(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context, btle_context_t *context)
622 {
623 proto_item *ti;
624 proto_tree *header_tree;
625 gint start_offset = offset;
626
627 ti = proto_tree_add_item(tree, hf_nordic_ble_header, tvb, offset, -1, ENC_NA);
628 header_tree = proto_item_add_subtree(ti, ett_packet_header);
629 proto_item_append_text(ti, " Version: %u", nordic_ble_context->protover);
630
631 if (nordic_ble_context->protover == 0) {
632 proto_item *item = proto_tree_add_uint(header_tree, hf_nordic_ble_protover, tvb, 0, 0, 0);
633 proto_item_set_generated(item);
634
635 proto_tree_add_item(header_tree, hf_nordic_ble_packet_id, tvb, offset, 1, ENC_NA);
636 offset += 1;
637
638 offset = dissect_packet_counter(tvb, offset, ti, header_tree);
639
640 offset += 2; // Two unused bytes
641 }
642
643 offset = dissect_lengths(tvb, offset, pinfo, header_tree, nordic_ble_context);
644
645 if (nordic_ble_context->protover != 0) {
646 proto_item *item = proto_tree_add_item(header_tree, hf_nordic_ble_protover, tvb, offset, 1, ENC_NA);
647 offset += 1;
648 if (nordic_ble_context->protover > 3) {
649 expert_add_info(pinfo, item, &ei_nordic_ble_unknown_version);
650 }
651
652 offset = dissect_packet_counter(tvb, offset, ti, header_tree);
653
654 proto_tree_add_item(header_tree, hf_nordic_ble_packet_id, tvb, offset, 1, ENC_NA);
655
656 if (nordic_ble_context->protover > 2) {
657 guint8 id = tvb_get_guint8(tvb, offset);
658
659 context->pdu_type = id == 0x06 ? BTLE_PDU_TYPE_DATA :
660 id == 0x02 ? BTLE_PDU_TYPE_ADVERTISING :
661 BTLE_PDU_TYPE_UNKNOWN;
662 }
663
664 offset += 1;
665 }
666
667 proto_item_set_len(ti, offset - start_offset);
668
669 return offset;
670 }
671
672 static gint
dissect_packet(tvbuff_t * tvb,gint offset,packet_info * pinfo,proto_tree * tree,nordic_ble_context_t * nordic_ble_context,btle_context_t * context)673 dissect_packet(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context, btle_context_t *context)
674 {
675 gint32 rssi;
676 guint32 channel, event_counter;
677
678 if (nordic_ble_context->protover == 0) {
679 // Event packet length is fixed for the legacy version
680 nordic_ble_context->event_packet_length = EVENT_PACKET_LEN;
681 } else {
682 guint32 plen;
683 proto_tree_add_item_ret_uint(tree, hf_nordic_ble_packet_length, tvb, offset, 1, ENC_NA, &plen);
684 nordic_ble_context->event_packet_length = plen;
685 offset += 1;
686 }
687
688 offset = dissect_flags(tvb, offset, pinfo, tree, nordic_ble_context, context);
689
690 proto_tree_add_item_ret_uint(tree, hf_nordic_ble_channel, tvb, offset, 1, ENC_NA, &channel);
691 offset += 1;
692
693 context->channel = channel;
694
695 rssi = (-1)*((gint32)tvb_get_guint8(tvb, offset));
696 proto_tree_add_int(tree, hf_nordic_ble_rssi, tvb, offset, 1, rssi);
697 offset += 1;
698
699 proto_tree_add_item_ret_uint(tree, hf_nordic_ble_event_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN, &event_counter);
700 offset += 2;
701
702 context->event_counter = event_counter;
703 context->event_counter_valid = 1;
704
705 if (nordic_ble_context->protover < 3) {
706 offset = dissect_ble_delta_time(tvb, offset, pinfo, tree, nordic_ble_context);
707 } else {
708 offset = dissect_ble_timestamp(tvb, offset, pinfo, tree, nordic_ble_context);
709 }
710
711 return offset;
712 }
713
714 static gint
dissect_header(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,btle_context_t * context,gboolean * bad_length)715 dissect_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, btle_context_t *context, gboolean *bad_length)
716 {
717 proto_item *ti;
718 proto_tree *nordic_ble_tree;
719 gint offset = 0;
720 nordic_ble_context_t nordic_ble_context;
721
722 memset(&nordic_ble_context, 0, sizeof(nordic_ble_context));
723
724 ti = proto_tree_add_item(tree, proto_nordic_ble, tvb, 0, -1, ENC_NA);
725 nordic_ble_tree = proto_item_add_subtree(ti, ett_nordic_ble);
726
727 if (tvb_get_guint16(tvb, 0, ENC_BIG_ENDIAN) == 0xBEEF) {
728 proto_tree_add_item(nordic_ble_tree, hf_nordic_ble_legacy_marker, tvb, 0, 2, ENC_BIG_ENDIAN);
729 offset += 2;
730
731 nordic_ble_context.protover = 0; /* Legacy Version */
732 } else {
733 proto_tree_add_item(nordic_ble_tree, hf_nordic_ble_board_id, tvb, 0, 1, ENC_NA);
734 offset += 1;
735
736 nordic_ble_context.protover = tvb_get_guint8(tvb, offset + 2);
737 }
738
739 offset = dissect_packet_header(tvb, offset, pinfo, nordic_ble_tree, &nordic_ble_context, context);
740 offset = dissect_packet(tvb, offset, pinfo, nordic_ble_tree, &nordic_ble_context, context);
741
742 proto_item_set_len(ti, offset);
743 *bad_length = nordic_ble_context.bad_length;
744
745 return offset;
746 }
747
748 /* Main entry point for sniffer */
749 static int
dissect_nordic_ble(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)750 dissect_nordic_ble(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
751 {
752 tvbuff_t *payload_tvb;
753 btle_context_t *context;
754 gint offset;
755 gboolean bad_length = FALSE;
756
757 context = wmem_new0(pinfo->pool, btle_context_t);
758
759 offset = dissect_header(tvb, pinfo, tree, context, &bad_length);
760 payload_tvb = tvb_new_subset_length_caplen(tvb, offset, -1, tvb_captured_length(tvb) - offset);
761
762 if (!bad_length) {
763 call_dissector_with_data(btle_dissector_handle, payload_tvb, pinfo, tree, context);
764 }
765
766 if ((context->mic_checked_at_capture) && (!context->mic_valid_at_capture)) {
767 col_set_str(pinfo->cinfo, COL_INFO, "Encrypted packet decrypted incorrectly");
768 if (!context->crc_valid_at_capture) {
769 /* CRC is bad */
770 col_append_str(pinfo->cinfo, COL_INFO, " (bad CRC)");
771 } else {
772 col_append_str(pinfo->cinfo, COL_INFO, " (bad MIC)");
773 }
774 }
775
776 if (debug_handle) {
777 call_dissector(debug_handle, payload_tvb, pinfo, tree);
778 }
779
780 return offset;
781 }
782
783 void
proto_register_nordic_ble(void)784 proto_register_nordic_ble(void)
785 {
786 static hf_register_info hf[] = {
787 { &hf_nordic_ble_board_id,
788 { "Board", "nordic_ble.board_id",
789 FT_UINT8, BASE_DEC, NULL, 0x0,
790 NULL, HFILL }
791 },
792 { &hf_nordic_ble_legacy_marker,
793 { "Legacy marker", "nordic_ble.legacy_marker",
794 FT_UINT16, BASE_HEX, NULL, 0x0,
795 NULL, HFILL }
796 },
797 { &hf_nordic_ble_header,
798 { "Header", "nordic_ble.header",
799 FT_NONE, BASE_NONE, NULL, 0x0,
800 NULL, HFILL }
801 },
802 { &hf_nordic_ble_header_length,
803 { "Length of header", "nordic_ble.hlen",
804 FT_UINT8, BASE_DEC, NULL, 0x0,
805 NULL, HFILL }
806 },
807 { &hf_nordic_ble_payload_length,
808 { "Length of payload", "nordic_ble.plen",
809 FT_UINT16, BASE_DEC, NULL, 0x0,
810 "Payload length", HFILL }
811 },
812 { &hf_nordic_ble_protover,
813 { "Protocol version", "nordic_ble.protover",
814 FT_UINT8, BASE_DEC, NULL, 0x0,
815 NULL, HFILL }
816 },
817 { &hf_nordic_ble_packet_counter,
818 { "Packet counter", "nordic_ble.packet_counter",
819 FT_UINT16, BASE_DEC, NULL, 0x0,
820 "Global packet counter for packets sent on UART", HFILL }
821 },
822 { &hf_nordic_ble_packet_id,
823 { "Packet ID", "nordic_ble.packet_id",
824 FT_UINT8, BASE_DEC, NULL, 0x0,
825 NULL, HFILL }
826 },
827 { &hf_nordic_ble_packet_length,
828 { "Length of packet", "nordic_ble.len",
829 FT_UINT16, BASE_DEC, NULL, 0x0,
830 NULL, HFILL }
831 },
832 { &hf_nordic_ble_flags,
833 { "Flags", "nordic_ble.flags",
834 FT_UINT8, BASE_HEX, NULL, 0x0,
835 NULL, HFILL }
836 },
837 { &hf_nordic_ble_crcok,
838 { "CRC", "nordic_ble.crcok",
839 FT_BOOLEAN, 8, TFS(&tfs_ok_error), 0x01,
840 "Cyclic Redundancy Check state", HFILL }
841 },
842 { &hf_nordic_ble_direction,
843 { "Direction", "nordic_ble.direction",
844 FT_BOOLEAN, 8, TFS(&direction_tfs), 0x02,
845 NULL, HFILL }
846 },
847 { &hf_nordic_ble_flag_reserved1,
848 { "Reserved", "nordic_ble.flag_reserved1",
849 FT_UINT8, BASE_DEC, NULL, 0x02,
850 NULL, HFILL }
851 },
852 { &hf_nordic_ble_encrypted,
853 { "Encrypted", "nordic_ble.encrypted",
854 FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04,
855 "Was the packet encrypted", HFILL }
856 },
857 { &hf_nordic_ble_flag_reserved2,
858 { "Reserved", "nordic_ble.flag_reserved2",
859 FT_UINT8, BASE_DEC, NULL, 0x04,
860 NULL, HFILL }
861 },
862 { &hf_nordic_ble_aux_type,
863 { "Aux Type", "nordic_ble.aux_type",
864 FT_UINT8, BASE_DEC, VALS(le_aux_ext_adv), 0x06,
865 NULL, HFILL }
866 },
867 { &hf_nordic_ble_micok,
868 { "MIC", "nordic_ble.micok",
869 FT_BOOLEAN, 8, TFS(&tfs_ok_error), 0x08,
870 "Message Integrity Check state", HFILL }
871 },
872 { &hf_nordic_ble_mic_not_relevant,
873 { "MIC (not relevant)", "nordic_ble.mic_not_relevant",
874 FT_UINT8, BASE_DEC, NULL, 0x08,
875 "Message Integrity Check state is only relevant when encrypted", HFILL }
876 },
877 { &hf_nordic_ble_address_resolved,
878 { "Address Resolved", "nordic_ble.address_resolved",
879 FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08,
880 NULL, HFILL }
881 },
882 { &hf_nordic_ble_le_phy,
883 { "PHY", "nordic_ble.phy",
884 FT_UINT8, BASE_DEC, VALS(le_phys), 0x70,
885 "Physical Layer", HFILL }
886 },
887 { &hf_nordic_ble_flag_reserved7,
888 { "Reserved", "nordic_ble.flag_reserved7",
889 FT_UINT8, BASE_DEC, NULL, 0x80,
890 "Reserved for Future Use", HFILL }
891 },
892 { &hf_nordic_ble_channel,
893 { "Channel Index", "nordic_ble.channel",
894 FT_UINT8, BASE_DEC, NULL, 0x0,
895 NULL, HFILL }
896 },
897 { &hf_nordic_ble_rssi,
898 { "RSSI", "nordic_ble.rssi",
899 FT_INT8, BASE_DEC | BASE_UNIT_STRING, &units_dbm, 0x0,
900 "Received Signal Strength Indicator", HFILL }
901 },
902 { &hf_nordic_ble_event_counter,
903 { "Event counter", "nordic_ble.event_counter",
904 FT_UINT16, BASE_DEC, NULL, 0x0,
905 NULL, HFILL }
906 },
907 { &hf_nordic_ble_time,
908 { "Timestamp", "nordic_ble.time",
909 FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_microseconds, 0x0,
910 "Firmware timestamp", HFILL }
911 },
912 { &hf_nordic_ble_delta_time,
913 { "Delta time (end to start)", "nordic_ble.delta_time",
914 FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_microseconds, 0x0,
915 "Time since end of last reported packet", HFILL }
916 },
917 { &hf_nordic_ble_delta_time_ss,
918 { "Delta time (start to start)", "nordic_ble.delta_time_ss",
919 FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_microseconds, 0x0,
920 "Time since start of last reported packet", HFILL }
921 },
922 { &hf_nordic_ble_packet_time,
923 { "Packet time (start to end)", "nordic_ble.packet_time",
924 FT_UINT32, BASE_DEC | BASE_UNIT_STRING, &units_microseconds, 0x0,
925 "Time of packet", HFILL }
926 },
927 };
928
929 static gint *ett[] = {
930 &ett_nordic_ble,
931 &ett_packet_header,
932 &ett_flags
933 };
934
935 static ei_register_info ei[] = {
936 { &ei_nordic_ble_bad_crc, { "nordic_ble.crc.bad", PI_CHECKSUM, PI_ERROR, "CRC is bad", EXPFILL }},
937 { &ei_nordic_ble_bad_mic, { "nordic_ble.mic.bad", PI_CHECKSUM, PI_ERROR, "MIC is bad", EXPFILL }},
938 { &ei_nordic_ble_bad_length, { "nordic_ble.length.bad", PI_MALFORMED, PI_ERROR, "Length is incorrect", EXPFILL }},
939 { &ei_nordic_ble_unknown_version, { "nordic_ble.protover.bad", PI_PROTOCOL, PI_ERROR, "Unknown version", EXPFILL }},
940 };
941
942 expert_module_t *expert_nordic_ble;
943
944 packet_time_context_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
945
946 proto_nordic_ble = proto_register_protocol("nRF Sniffer for Bluetooth LE", "NORDIC_BLE", "nordic_ble");
947
948 register_dissector("nordic_ble", dissect_nordic_ble, proto_nordic_ble);
949
950 expert_nordic_ble = expert_register_protocol(proto_nordic_ble);
951 expert_register_field_array(expert_nordic_ble, ei, array_length(ei));
952
953 proto_register_field_array(proto_nordic_ble, hf, array_length(hf));
954 proto_register_subtree_array(ett, array_length(ett));
955 }
956
957 void
proto_reg_handoff_nordic_ble(void)958 proto_reg_handoff_nordic_ble(void)
959 {
960 dissector_handle_t nordic_ble_handle;
961
962 nordic_ble_handle = create_dissector_handle(dissect_nordic_ble, proto_nordic_ble);
963
964 btle_dissector_handle = find_dissector("btle");
965 debug_handle = find_dissector("nordic_debug");
966
967 dissector_add_for_decode_as_with_preference("udp.port", nordic_ble_handle);
968 dissector_add_uint("wtap_encap", WTAP_ENCAP_NORDIC_BLE, nordic_ble_handle);
969 }
970
971
972 /*
973 * Editor modelines - https://www.wireshark.org/tools/modelines.html
974 *
975 * Local variables:
976 * c-basic-offset: 4
977 * tab-width: 8
978 * indent-tabs-mode: nil
979 * End:
980 *
981 * vi: set shiftwidth =4 tabstop =8 expandtab:
982 * :indentSize =4:tabSize =8:noTabs =true:
983 */
984