Coverage Report

Created: 2026-01-02 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-nordic_ble.c
Line
Count
Source
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 = 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)
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 <epan/tfs.h>
189
#include <epan/unit_strings.h>
190
191
#include <wsutil/array.h>
192
#include <wiretap/wtap.h>
193
194
#include "packet-btle.h"
195
196
/* Size of various UART Packet header fields */
197
11
#define UART_HEADER_LEN      6
198
2
#define EVENT_PACKET_LEN    10
199
200
2
#define US_PER_BYTE_1M_PHY   8
201
1
#define US_PER_BYTE_2M_PHY   4
202
203
2
#define US_PER_BYTE_CODED_PHY_S8 64
204
0
#define US_PER_BYTE_CODED_PHY_S2 16
205
206
2
#define PREAMBLE_LEN_1M_PHY  1
207
1
#define PREAMBLE_LEN_2M_PHY  2
208
209
/* Preamble + Access Address + CI + TERM1 */
210
2
#define FEC1_BLOCK_S8_US (80 + 256 + 16 + 24)
211
2
#define TERM2_S8_US      24
212
0
#define TERM2_S2_US       6
213
214
void proto_reg_handoff_nordic_ble(void);
215
void proto_register_nordic_ble(void);
216
217
static dissector_handle_t nordic_ble_handle;
218
219
/* Initialize the protocol and registered fields */
220
static int proto_nordic_ble;
221
222
/* Initialize the subtree pointers */
223
static int ett_nordic_ble;
224
static int ett_packet_header;
225
static int ett_flags;
226
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;
255
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;
260
261
static const true_false_string direction_tfs =
262
{
263
    "Central -> Peripheral",
264
    "Peripheral -> Central"
265
};
266
267
static const value_string le_phys[] =
268
{
269
    { 0, "LE 1M"    },
270
    { 1, "LE 2M"    },
271
    { 2, "LE Coded" },
272
    { 3, "Reserved" },
273
    { 4, "Reserved" },
274
    { 5, "Reserved" },
275
    { 6, "Reserved" },
276
    { 7, "Reserved" },
277
    { 0, NULL }
278
};
279
280
2
#define CI_S8 0
281
0
#define CI_S2 1
282
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" },
288
    { 0, NULL }
289
};
290
291
typedef struct {
292
    uint8_t protover;
293
    uint8_t phy;
294
    bool bad_length;
295
    uint16_t payload_length;
296
    uint16_t event_packet_length;
297
} nordic_ble_context_t;
298
299
/* next dissector */
300
static dissector_handle_t btle_dissector_handle;
301
static dissector_handle_t debug_handle;
302
303
static int
304
dissect_lengths(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context)
305
11
{
306
11
    uint32_t hlen, plen;
307
11
    proto_item* item;
308
309
11
    switch (nordic_ble_context->protover) {
310
2
    case 0:  /* Legacy version */
311
2
        hlen = 2 + UART_HEADER_LEN; /* 2 bytes legacy marker + UART header */
312
2
        item = proto_tree_add_item_ret_uint(tree, hf_nordic_ble_payload_length, tvb, offset, 1, ENC_BIG_ENDIAN, &plen);
313
2
        offset += 1;
314
2
        break;
315
316
0
    case 1:
317
0
        proto_tree_add_item_ret_uint(tree, hf_nordic_ble_header_length, tvb, offset, 1, ENC_NA, &hlen);
318
0
        hlen += 1; /* Add one byte for board id */
319
0
        offset += 1;
320
321
0
        item = proto_tree_add_item_ret_uint(tree, hf_nordic_ble_payload_length, tvb, offset, 1, ENC_BIG_ENDIAN, &plen);
322
0
        offset += 1;
323
0
        break;
324
325
9
    default: /* Starting from version 2 */
326
9
        hlen = 1 + UART_HEADER_LEN; /* Board ID + UART header */
327
9
        item = proto_tree_add_item_ret_uint(tree, hf_nordic_ble_payload_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &plen);
328
9
        offset += 2;
329
9
        break;
330
11
    }
331
332
11
    if ((hlen + plen) != tvb_captured_length(tvb)) {
333
11
        expert_add_info(pinfo, item, &ei_nordic_ble_bad_length);
334
11
        nordic_ble_context->bad_length = true;
335
11
    }
336
337
11
    nordic_ble_context->payload_length = plen;
338
339
11
    return offset;
340
11
}
341
342
static int
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)
344
11
{
345
11
    uint8_t flags, channel;
346
11
    bool dir;
347
11
    proto_item *flags_item, *item;
348
11
    proto_tree *flags_tree;
349
350
11
    flags = tvb_get_uint8(tvb, offset);
351
11
    channel = tvb_get_uint8(tvb, offset + 1);
352
353
11
    if (nordic_ble_context->protover < 3) {
354
3
        uint32_t access_address;
355
356
3
        access_address = tvb_get_letohl(tvb, offset + nordic_ble_context->event_packet_length - 1);
357
3
        context->pdu_type = access_address == ACCESS_ADDRESS_ADVERTISING ? BTLE_PDU_TYPE_ADVERTISING : BTLE_PDU_TYPE_DATA;
358
3
    }
359
360
11
    context->crc_checked_at_capture = 1;
361
11
    context->crc_valid_at_capture = !!(flags & 1);
362
363
11
    if (context->pdu_type == BTLE_PDU_TYPE_DATA) {
364
3
        dir = !!(flags & 2);
365
3
        context->mic_checked_at_capture = !!(flags & 4);
366
3
        if (context->mic_checked_at_capture) {
367
1
            context->mic_valid_at_capture = !!(flags & 8);
368
1
        }
369
3
    }
370
371
11
    nordic_ble_context->phy = (flags >> 4) & 7;
372
11
    context->phy = nordic_ble_context->phy;
373
374
11
    if (context->pdu_type == BTLE_PDU_TYPE_DATA) {
375
3
        if (dir) {
376
1
            set_address(&pinfo->src, AT_STRINGZ, 7, "Central");
377
1
            set_address(&pinfo->dst, AT_STRINGZ, 6, "Peripheral");
378
1
            context->direction = BTLE_DIR_CENTRAL_PERIPHERAL;
379
1
            pinfo->p2p_dir = P2P_DIR_SENT;
380
2
        } else {
381
2
            set_address(&pinfo->src, AT_STRINGZ, 6, "Peripheral");
382
2
            set_address(&pinfo->dst, AT_STRINGZ, 7, "Central");
383
2
            context->direction = BTLE_DIR_PERIPHERAL_CENTRAL;
384
2
            pinfo->p2p_dir = P2P_DIR_RECV;
385
2
        }
386
3
    }
387
388
11
    flags_item = proto_tree_add_item(tree, hf_nordic_ble_flags, tvb, offset, 1, ENC_NA);
389
11
    flags_tree = proto_item_add_subtree(flags_item, ett_flags);
390
11
    item = proto_tree_add_item(flags_tree, hf_nordic_ble_crcok, tvb, offset, 1, ENC_NA);
391
11
    if (!context->crc_valid_at_capture) {
392
        /* CRC is bad */
393
7
        expert_add_info(pinfo, item, &ei_nordic_ble_bad_crc);
394
7
    }
395
396
11
    if (context->pdu_type == BTLE_PDU_TYPE_DATA) {
397
3
        proto_tree_add_item(flags_tree, hf_nordic_ble_direction, tvb, offset, 1, ENC_NA);
398
3
        proto_tree_add_item(flags_tree, hf_nordic_ble_encrypted, tvb, offset, 1, ENC_NA);
399
3
        if (context->mic_checked_at_capture) {
400
1
            item = proto_tree_add_item(flags_tree, hf_nordic_ble_micok, tvb, offset, 1, ENC_NA);
401
1
            if (!context->mic_valid_at_capture) {
402
                /* MIC is bad */
403
1
                expert_add_info(pinfo, item, &ei_nordic_ble_bad_mic);
404
1
            }
405
2
        } else {
406
2
            proto_tree_add_item(flags_tree, hf_nordic_ble_mic_not_relevant, tvb, offset, 1, ENC_NA);
407
2
        }
408
8
    } else {
409
8
        if (channel < 37) {
410
2
            uint32_t aux_pdu_type;
411
412
2
            proto_tree_add_item_ret_uint(flags_tree, hf_nordic_ble_aux_type, tvb, offset, 1, ENC_NA, &aux_pdu_type);
413
2
            context->aux_pdu_type = aux_pdu_type;
414
2
            context->aux_pdu_type_valid = true;
415
6
        } else {
416
6
            proto_tree_add_item(flags_tree, hf_nordic_ble_flag_reserved1, tvb, offset, 1, ENC_NA);
417
6
            proto_tree_add_item(flags_tree, hf_nordic_ble_flag_reserved2, tvb, offset, 1, ENC_NA);
418
6
        }
419
8
        proto_tree_add_item(flags_tree, hf_nordic_ble_address_resolved, tvb, offset, 1, ENC_NA);
420
8
    }
421
422
11
    proto_tree_add_item(flags_tree, hf_nordic_ble_le_phy, tvb, offset, 1, ENC_NA);
423
11
    proto_tree_add_item(flags_tree, hf_nordic_ble_flag_reserved7, tvb, offset, 1, ENC_NA);
424
425
11
    offset++;
426
427
11
    return offset;
428
11
}
429
430
static uint16_t packet_time_get(nordic_ble_context_t *nordic_ble_context, uint8_t ci)
431
8
{
432
    /* Calculate packet time according to this packets PHY */
433
8
    uint16_t ble_payload_length = nordic_ble_context->payload_length - nordic_ble_context->event_packet_length;
434
435
8
    switch (nordic_ble_context->phy) {
436
2
        case LE_1M_PHY:
437
2
            return  US_PER_BYTE_1M_PHY * (PREAMBLE_LEN_1M_PHY + ble_payload_length);
438
1
        case LE_2M_PHY:
439
1
            return US_PER_BYTE_2M_PHY * (PREAMBLE_LEN_2M_PHY + ble_payload_length);
440
3
        case LE_CODED_PHY:
441
3
        {
442
            /* Subtract Access address and CI */
443
3
            uint16_t fec2_block_len = ble_payload_length - 4 - 1;
444
445
3
            switch (ci) {
446
2
                case CI_S8:
447
2
                    return FEC1_BLOCK_S8_US + fec2_block_len * US_PER_BYTE_CODED_PHY_S8 + TERM2_S8_US;
448
0
                case CI_S2:
449
0
                    return FEC1_BLOCK_S8_US + fec2_block_len * US_PER_BYTE_CODED_PHY_S2 + TERM2_S2_US;
450
3
            }
451
3
        }
452
        /* Fallthrough */
453
3
        default:
454
3
            return 0; /* Unknown */
455
8
    }
456
8
}
457
458
typedef struct
459
{
460
    uint32_t packet_start_time;
461
    uint32_t packet_end_time;
462
} packet_times_t;
463
464
typedef struct {
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;
471
472
static wmem_tree_t *packet_time_context_tree;
473
474
static packet_time_context_t *packet_times_get(packet_info *pinfo)
475
11
{
476
11
    uint32_t interface_id = (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) ? pinfo->rec->rec_header.packet_header.interface_id: HCI_INTERFACE_DEFAULT;
477
11
    wmem_tree_t *wmem_tree;
478
11
    wmem_tree_key_t keys[2];
479
480
11
    keys[0].length = 1;
481
11
    keys[0].key = &interface_id;
482
11
    keys[1].length = 0;
483
11
    keys[1].key = NULL;
484
485
11
    wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(packet_time_context_tree, keys);
486
11
    if (wmem_tree) {
487
10
        return (packet_time_context_t *) wmem_tree_lookup32_le(wmem_tree, 0);
488
10
    }
489
490
1
    return NULL;
491
11
}
492
493
static packet_time_context_t *packet_times_insert(packet_info *pinfo)
494
1
{
495
1
    uint32_t interface_id = (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) ? pinfo->rec->rec_header.packet_header.interface_id: HCI_INTERFACE_DEFAULT;
496
1
    uint32_t key = 0;
497
1
    wmem_tree_key_t keys[3];
498
1
    packet_time_context_t *packet_times;
499
500
1
    keys[0].length = 1;
501
1
    keys[0].key = &interface_id;
502
1
    keys[1].length = 1;
503
1
    keys[1].key = &key;
504
1
    keys[2].length = 0;
505
1
    keys[2].key = NULL;
506
1
    packet_times = wmem_new0(wmem_file_scope(), packet_time_context_t);
507
1
    wmem_tree_insert32_array(packet_time_context_tree, keys, packet_times);
508
509
1
    return packet_times;
510
1
}
511
512
static int
513
dissect_ble_delta_time(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context)
514
3
{
515
3
    uint32_t delta_time, delta_time_ss, prev_packet_time, packet_time;
516
3
    proto_item *pi;
517
3
    packet_time_context_t *packet_times_context;
518
519
3
    packet_times_context = packet_times_get(pinfo);
520
3
    if (!packet_times_context) {
521
0
        packet_times_context = packet_times_insert(pinfo);
522
0
    }
523
524
    /* end-to-start */
525
3
    proto_tree_add_item_ret_uint(tree, hf_nordic_ble_delta_time, tvb, offset, 4, ENC_LITTLE_ENDIAN, &delta_time);
526
527
3
    if (!pinfo->fd->visited) {
528
        /* First time visiting this packet, store previous BLE packet time */
529
3
        p_add_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0, GUINT_TO_POINTER(packet_times_context->packet_time));
530
3
        prev_packet_time = packet_times_context->packet_time;
531
3
    } else {
532
0
        prev_packet_time = GPOINTER_TO_UINT(p_get_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0));
533
0
    }
534
535
3
    if (!packet_times_context->first_frame_seen) {
536
1
        delta_time_ss = prev_packet_time + delta_time;
537
1
        pi = proto_tree_add_uint(tree, hf_nordic_ble_delta_time_ss, tvb, offset, 4, delta_time_ss);
538
1
        proto_item_set_generated(pi);
539
1
    }
540
541
3
    packet_time = packet_time_get(nordic_ble_context, 0 /* This version never supported Coded PHY */);
542
3
    pi = proto_tree_add_uint(tree, hf_nordic_ble_packet_time, tvb, offset, 4, packet_time);
543
3
    proto_item_set_generated(pi);
544
545
3
    offset += 4;
546
547
3
    if (!pinfo->fd->visited) {
548
3
        packet_times_context->packet_time = packet_time;
549
3
        packet_times_context->first_frame_seen = true;
550
3
    }
551
552
3
    return offset;
553
3
}
554
555
static int
556
dissect_ble_timestamp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, nordic_ble_context_t *nordic_ble_context)
557
8
{
558
8
    uint32_t delta_time, delta_time_ss, packet_time;
559
8
    uint32_t timestamp, last_packet_end_time, last_packet_start_time;
560
8
    proto_item *item;
561
8
    packet_time_context_t *packet_times_context;
562
563
8
    packet_times_context = packet_times_get(pinfo);
564
8
    if (!packet_times_context) {
565
1
        packet_times_context = packet_times_insert(pinfo);
566
1
    }
567
568
8
    proto_tree_add_item_ret_uint(tree, hf_nordic_ble_time, tvb, offset, 4, ENC_LITTLE_ENDIAN, &timestamp);
569
570
8
    if (!pinfo->fd->visited) {
571
5
        packet_times_t *saved_packet_times = wmem_new0(wmem_file_scope(), packet_times_t);
572
573
5
        saved_packet_times->packet_end_time = packet_times_context->packet_end_time;
574
5
        saved_packet_times->packet_start_time = packet_times_context->packet_start_time;
575
5
        p_add_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0, saved_packet_times);
576
577
        /* First time visiting this packet, store previous BLE packet time */
578
5
        last_packet_end_time = packet_times_context->packet_end_time;
579
5
        last_packet_start_time = packet_times_context->packet_start_time;
580
5
    } else {
581
3
        packet_times_t* saved_packet_times = (packet_times_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_nordic_ble, 0);
582
583
3
        last_packet_end_time = saved_packet_times->packet_end_time;
584
3
        last_packet_start_time = saved_packet_times->packet_start_time;
585
3
    }
586
587
8
    uint8_t ci = tvb_get_uint8(tvb, offset + 4 + 4);
588
8
    packet_time = packet_time_get(nordic_ble_context, ci);
589
8
    item = proto_tree_add_uint(tree, hf_nordic_ble_packet_time, tvb, offset, 4, packet_time);
590
8
    proto_item_set_generated(item);
591
592
8
    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
5
        delta_time = timestamp - last_packet_end_time;
595
5
        item = proto_tree_add_uint(tree, hf_nordic_ble_delta_time, tvb, offset, 4, delta_time);
596
5
        proto_item_set_generated(item);
597
598
5
        delta_time_ss = timestamp - last_packet_start_time;
599
5
        item = proto_tree_add_uint(tree, hf_nordic_ble_delta_time_ss, tvb, offset, 4, delta_time_ss);
600
5
        proto_item_set_generated(item);
601
5
    }
602
603
8
    if (!pinfo->fd->visited) {
604
605
5
        packet_times_context->packet_start_time = timestamp;
606
5
        packet_times_context->packet_end_time = timestamp + packet_time;
607
5
        packet_times_context->first_frame_seen = true;
608
5
    }
609
610
8
    offset += 4;
611
612
8
    return offset;
613
8
}
614
615
static int
616
dissect_packet_counter(tvbuff_t *tvb, int offset, proto_item *item, proto_tree *tree)
617
11
{
618
11
    proto_item_append_text(item, ", Packet counter: %u", tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN));
619
11
    proto_tree_add_item(tree, hf_nordic_ble_packet_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN);
620
11
    offset += 2;
621
622
11
    return offset;
623
11
}
624
625
static int
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)
627
11
{
628
11
    proto_item *ti;
629
11
    proto_tree *header_tree;
630
11
    int start_offset = offset;
631
632
11
    ti = proto_tree_add_item(tree, hf_nordic_ble_header, tvb, offset, -1, ENC_NA);
633
11
    header_tree = proto_item_add_subtree(ti, ett_packet_header);
634
11
    proto_item_append_text(ti, " Version: %u", nordic_ble_context->protover);
635
636
11
    if (nordic_ble_context->protover == 0) {
637
2
        proto_item *item = proto_tree_add_uint(header_tree, hf_nordic_ble_protover, tvb, 0, 0, 0);
638
2
        proto_item_set_generated(item);
639
640
2
        proto_tree_add_item(header_tree, hf_nordic_ble_packet_id, tvb, offset, 1, ENC_NA);
641
2
        offset += 1;
642
643
2
        offset = dissect_packet_counter(tvb, offset, ti, header_tree);
644
645
2
        offset += 2; // Two unused bytes
646
2
    }
647
648
11
    offset = dissect_lengths(tvb, offset, pinfo, header_tree, nordic_ble_context);
649
650
11
    if (nordic_ble_context->protover != 0) {
651
9
        proto_item *item = proto_tree_add_item(header_tree, hf_nordic_ble_protover, tvb, offset, 1, ENC_NA);
652
9
        offset += 1;
653
9
        if (nordic_ble_context->protover > 3) {
654
8
            expert_add_info(pinfo, item, &ei_nordic_ble_unknown_version);
655
8
        }
656
657
9
        offset = dissect_packet_counter(tvb, offset, ti, header_tree);
658
659
9
        proto_tree_add_item(header_tree, hf_nordic_ble_packet_id, tvb, offset, 1, ENC_NA);
660
661
9
        if (nordic_ble_context->protover > 2) {
662
8
            uint8_t id = tvb_get_uint8(tvb, offset);
663
664
8
            context->pdu_type = id == 0x06 ? BTLE_PDU_TYPE_DATA :
665
8
                                id == 0x02 ? BTLE_PDU_TYPE_ADVERTISING :
666
8
                                             BTLE_PDU_TYPE_UNKNOWN;
667
8
        }
668
669
9
        offset += 1;
670
9
    }
671
672
11
    proto_item_set_len(ti, offset - start_offset);
673
674
11
    return offset;
675
11
}
676
677
static int
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)
679
11
{
680
11
    int32_t rssi;
681
11
    uint32_t channel, event_counter;
682
683
11
    if (nordic_ble_context->protover == 0) {
684
        // Event packet length is fixed for the legacy version
685
2
        nordic_ble_context->event_packet_length = EVENT_PACKET_LEN;
686
9
    } else {
687
9
        uint32_t plen;
688
9
        proto_tree_add_item_ret_uint(tree, hf_nordic_ble_packet_length, tvb, offset, 1, ENC_NA, &plen);
689
9
        nordic_ble_context->event_packet_length = plen;
690
9
        offset += 1;
691
9
    }
692
693
11
    offset = dissect_flags(tvb, offset, pinfo, tree, nordic_ble_context, context);
694
695
11
    proto_tree_add_item_ret_uint(tree, hf_nordic_ble_channel, tvb, offset, 1, ENC_NA, &channel);
696
11
    offset += 1;
697
698
11
    context->channel = channel;
699
700
11
    rssi = (-1)*((int32_t)tvb_get_uint8(tvb, offset));
701
11
    proto_tree_add_int(tree, hf_nordic_ble_rssi, tvb, offset, 1, rssi);
702
11
    offset += 1;
703
704
11
    proto_tree_add_item_ret_uint(tree, hf_nordic_ble_event_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN, &event_counter);
705
11
    offset += 2;
706
707
11
    context->event_counter = event_counter;
708
11
    context->event_counter_valid = 1;
709
710
11
    if (nordic_ble_context->protover < 3) {
711
3
        offset = dissect_ble_delta_time(tvb, offset, pinfo, tree, nordic_ble_context);
712
8
    } else {
713
8
        offset = dissect_ble_timestamp(tvb, offset, pinfo, tree, nordic_ble_context);
714
8
    }
715
716
11
    return offset;
717
11
}
718
719
static int
720
dissect_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, btle_context_t *context, bool *bad_length)
721
11
{
722
11
    proto_item *ti;
723
11
    proto_tree *nordic_ble_tree;
724
11
    int offset = 0;
725
11
    nordic_ble_context_t nordic_ble_context;
726
727
11
    memset(&nordic_ble_context, 0, sizeof(nordic_ble_context));
728
729
11
    ti = proto_tree_add_item(tree, proto_nordic_ble, tvb, 0, -1, ENC_NA);
730
11
    nordic_ble_tree = proto_item_add_subtree(ti, ett_nordic_ble);
731
732
11
    if (tvb_get_uint16(tvb, 0, ENC_BIG_ENDIAN) == 0xBEEF) {
733
0
        proto_tree_add_item(nordic_ble_tree, hf_nordic_ble_legacy_marker, tvb, 0, 2, ENC_BIG_ENDIAN);
734
0
        offset += 2;
735
736
0
        nordic_ble_context.protover = 0; /* Legacy Version */
737
11
    } else {
738
11
        proto_tree_add_item(nordic_ble_tree, hf_nordic_ble_board_id, tvb, 0, 1, ENC_NA);
739
11
        offset += 1;
740
741
11
        nordic_ble_context.protover = tvb_get_uint8(tvb, offset + 2);
742
11
    }
743
744
11
    offset = dissect_packet_header(tvb, offset, pinfo, nordic_ble_tree, &nordic_ble_context, context);
745
11
    offset = dissect_packet(tvb, offset, pinfo, nordic_ble_tree, &nordic_ble_context, context);
746
747
11
    proto_item_set_len(ti, offset);
748
11
    *bad_length = nordic_ble_context.bad_length;
749
750
11
    return offset;
751
11
}
752
753
/* Main entry point for sniffer */
754
static int
755
dissect_nordic_ble(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
756
11
{
757
11
    tvbuff_t          *payload_tvb;
758
11
    btle_context_t    *context;
759
11
    int                offset;
760
11
    bool               bad_length = false;
761
762
11
    context = wmem_new0(pinfo->pool, btle_context_t);
763
764
11
    offset = dissect_header(tvb, pinfo, tree, context, &bad_length);
765
11
    payload_tvb = tvb_new_subset_remaining(tvb, offset);
766
767
11
    if (!bad_length) {
768
0
        call_dissector_with_data(btle_dissector_handle, payload_tvb, pinfo, tree, context);
769
0
    }
770
771
11
    if ((context->mic_checked_at_capture) && (!context->mic_valid_at_capture)) {
772
1
        col_set_str(pinfo->cinfo, COL_INFO, "Encrypted packet decrypted incorrectly");
773
1
        if (!context->crc_valid_at_capture) {
774
            /* CRC is bad */
775
0
            col_append_str(pinfo->cinfo, COL_INFO, " (bad CRC)");
776
1
        } else {
777
1
            col_append_str(pinfo->cinfo, COL_INFO, " (bad MIC)");
778
1
        }
779
1
    }
780
781
11
    if (debug_handle) {
782
0
        call_dissector(debug_handle, payload_tvb, pinfo, tree);
783
0
    }
784
785
11
    return offset;
786
11
}
787
788
void
789
proto_register_nordic_ble(void)
790
14
{
791
14
    static hf_register_info hf[] = {
792
14
        { &hf_nordic_ble_board_id,
793
14
            { "Board", "nordic_ble.board_id",
794
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
795
14
                NULL, HFILL }
796
14
        },
797
14
        { &hf_nordic_ble_legacy_marker,
798
14
            { "Legacy marker", "nordic_ble.legacy_marker",
799
14
                FT_UINT16, BASE_HEX, NULL, 0x0,
800
14
                NULL, HFILL }
801
14
        },
802
14
        { &hf_nordic_ble_header,
803
14
            { "Header", "nordic_ble.header",
804
14
                FT_NONE, BASE_NONE, NULL, 0x0,
805
14
                NULL, HFILL }
806
14
        },
807
14
        { &hf_nordic_ble_header_length,
808
14
            { "Length of header", "nordic_ble.hlen",
809
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
810
14
                NULL, HFILL }
811
14
        },
812
14
        { &hf_nordic_ble_payload_length,
813
14
            { "Length of payload", "nordic_ble.plen",
814
14
                FT_UINT16, BASE_DEC, NULL, 0x0,
815
14
                NULL, HFILL }
816
14
        },
817
14
        { &hf_nordic_ble_protover,
818
14
            { "Protocol version", "nordic_ble.protover",
819
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
820
14
                NULL, HFILL }
821
14
        },
822
14
        { &hf_nordic_ble_packet_counter,
823
14
            { "Packet counter", "nordic_ble.packet_counter",
824
14
                FT_UINT16, BASE_DEC, NULL, 0x0,
825
14
                "Global packet counter for packets sent on UART", HFILL }
826
14
        },
827
14
        { &hf_nordic_ble_packet_id,
828
14
            { "Packet ID", "nordic_ble.packet_id",
829
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
830
14
                NULL, HFILL }
831
14
        },
832
14
        { &hf_nordic_ble_packet_length,
833
14
            { "Length of packet", "nordic_ble.len",
834
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
835
14
                NULL, HFILL }
836
14
        },
837
14
        { &hf_nordic_ble_flags,
838
14
            { "Flags", "nordic_ble.flags",
839
14
                FT_UINT8, BASE_HEX, NULL, 0x0,
840
14
                NULL, HFILL }
841
14
        },
842
14
        { &hf_nordic_ble_crcok,
843
14
            { "CRC", "nordic_ble.crcok",
844
14
                FT_BOOLEAN, 8, TFS(&tfs_ok_error), 0x01,
845
14
                "Cyclic Redundancy Check state", HFILL }
846
14
        },
847
14
        { &hf_nordic_ble_direction,
848
14
            { "Direction", "nordic_ble.direction",
849
14
                FT_BOOLEAN, 8, TFS(&direction_tfs), 0x02,
850
14
                NULL, HFILL }
851
14
        },
852
14
        { &hf_nordic_ble_flag_reserved1,
853
14
            { "Reserved", "nordic_ble.flag_reserved1",
854
14
                FT_UINT8, BASE_DEC, NULL, 0x02,
855
14
                NULL, HFILL }
856
14
        },
857
14
        { &hf_nordic_ble_encrypted,
858
14
            { "Encrypted", "nordic_ble.encrypted",
859
14
                FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04,
860
14
                "Was the packet encrypted", HFILL }
861
14
        },
862
14
        { &hf_nordic_ble_flag_reserved2,
863
14
            { "Reserved", "nordic_ble.flag_reserved2",
864
14
                FT_UINT8, BASE_DEC, NULL, 0x04,
865
14
                NULL, HFILL }
866
14
        },
867
14
        { &hf_nordic_ble_aux_type,
868
14
            { "Aux Type", "nordic_ble.aux_type",
869
14
                FT_UINT8, BASE_DEC, VALS(le_aux_ext_adv), 0x06,
870
14
                NULL, HFILL }
871
14
        },
872
14
        { &hf_nordic_ble_micok,
873
14
            { "MIC", "nordic_ble.micok",
874
14
                FT_BOOLEAN, 8, TFS(&tfs_ok_error), 0x08,
875
14
                "Message Integrity Check state", HFILL }
876
14
        },
877
14
        { &hf_nordic_ble_mic_not_relevant,
878
14
            { "MIC (not relevant)", "nordic_ble.mic_not_relevant",
879
14
                FT_UINT8, BASE_DEC, NULL, 0x08,
880
14
                "Message Integrity Check state is only relevant when encrypted", HFILL }
881
14
        },
882
14
        { &hf_nordic_ble_address_resolved,
883
14
            { "Address Resolved", "nordic_ble.address_resolved",
884
14
                FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08,
885
14
                NULL, HFILL }
886
14
        },
887
14
        { &hf_nordic_ble_le_phy,
888
14
            { "PHY", "nordic_ble.phy",
889
14
                FT_UINT8, BASE_DEC, VALS(le_phys), 0x70,
890
14
                "Physical Layer", HFILL }
891
14
        },
892
14
        { &hf_nordic_ble_flag_reserved7,
893
14
            { "Reserved", "nordic_ble.flag_reserved7",
894
14
                FT_UINT8, BASE_DEC, NULL, 0x80,
895
14
                "Reserved for Future Use", HFILL }
896
14
        },
897
14
        { &hf_nordic_ble_channel,
898
14
            { "Channel Index", "nordic_ble.channel",
899
14
                FT_UINT8, BASE_DEC, NULL, 0x0,
900
14
                NULL, HFILL }
901
14
        },
902
14
        { &hf_nordic_ble_rssi,
903
14
            { "RSSI", "nordic_ble.rssi",
904
14
                FT_INT8, BASE_DEC | BASE_UNIT_STRING, UNS(&units_dbm), 0x0,
905
14
                "Received Signal Strength Indicator", HFILL }
906
14
        },
907
14
        { &hf_nordic_ble_event_counter,
908
14
            { "Event counter", "nordic_ble.event_counter",
909
14
                FT_UINT16, BASE_DEC, NULL, 0x0,
910
14
                NULL, HFILL }
911
14
        },
912
14
        { &hf_nordic_ble_time,
913
14
            { "Timestamp", "nordic_ble.time",
914
14
                FT_UINT32, BASE_DEC | BASE_UNIT_STRING, UNS(&units_microseconds), 0x0,
915
14
                "Firmware timestamp", HFILL }
916
14
        },
917
14
        { &hf_nordic_ble_delta_time,
918
14
            { "Delta time (end to start)", "nordic_ble.delta_time",
919
14
                FT_UINT32, BASE_DEC | BASE_UNIT_STRING, UNS(&units_microseconds), 0x0,
920
14
                "Time since end of last reported packet", HFILL }
921
14
        },
922
14
        { &hf_nordic_ble_delta_time_ss,
923
14
            { "Delta time (start to start)", "nordic_ble.delta_time_ss",
924
14
                FT_UINT32, BASE_DEC | BASE_UNIT_STRING, UNS(&units_microseconds), 0x0,
925
14
                "Time since start of last reported packet", HFILL }
926
14
        },
927
14
        { &hf_nordic_ble_packet_time,
928
14
            { "Packet time (start to end)", "nordic_ble.packet_time",
929
14
                FT_UINT32, BASE_DEC | BASE_UNIT_STRING, UNS(&units_microseconds), 0x0,
930
14
                "Time of packet", HFILL }
931
14
        },
932
14
    };
933
934
14
    static int *ett[] = {
935
14
        &ett_nordic_ble,
936
14
        &ett_packet_header,
937
14
        &ett_flags
938
14
    };
939
940
14
    static ei_register_info ei[] = {
941
14
        { &ei_nordic_ble_bad_crc, { "nordic_ble.crc.bad", PI_CHECKSUM, PI_ERROR, "CRC is bad", EXPFILL }},
942
14
        { &ei_nordic_ble_bad_mic, { "nordic_ble.mic.bad", PI_CHECKSUM, PI_ERROR, "MIC is bad", EXPFILL }},
943
14
        { &ei_nordic_ble_bad_length, { "nordic_ble.length.bad", PI_MALFORMED, PI_ERROR, "Length is incorrect", EXPFILL }},
944
14
        { &ei_nordic_ble_unknown_version, { "nordic_ble.protover.bad", PI_PROTOCOL, PI_ERROR, "Unknown version", EXPFILL }},
945
14
    };
946
947
14
    expert_module_t *expert_nordic_ble;
948
949
14
    packet_time_context_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
950
951
14
    proto_nordic_ble = proto_register_protocol("nRF Sniffer for Bluetooth LE", "NORDIC_BLE", "nordic_ble");
952
953
14
    nordic_ble_handle = register_dissector("nordic_ble", dissect_nordic_ble, proto_nordic_ble);
954
955
14
    expert_nordic_ble = expert_register_protocol(proto_nordic_ble);
956
14
    expert_register_field_array(expert_nordic_ble, ei, array_length(ei));
957
958
14
    proto_register_field_array(proto_nordic_ble, hf, array_length(hf));
959
14
    proto_register_subtree_array(ett, array_length(ett));
960
14
}
961
962
void
963
proto_reg_handoff_nordic_ble(void)
964
14
{
965
14
    btle_dissector_handle = find_dissector("btle");
966
14
    debug_handle = find_dissector("nordic_debug");
967
968
14
    dissector_add_for_decode_as_with_preference("udp.port", nordic_ble_handle);
969
14
    dissector_add_uint("wtap_encap", WTAP_ENCAP_NORDIC_BLE, nordic_ble_handle);
970
14
}
971
972
973
/*
974
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
975
 *
976
 * Local variables:
977
 * c-basic-offset: 4
978
 * tab-width: 8
979
 * indent-tabs-mode: nil
980
 * End:
981
 *
982
 * vi: set shiftwidth =4 tabstop =8 expandtab:
983
 * :indentSize =4:tabSize =8:noTabs =true:
984
 */