/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, ×tamp); |
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 | | */ |