Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-silabs-dch.c
Line
Count
Source
1
/* packet-silabs-dch.c
2
 * Routines for Silicon Labs Debug Channel dissection
3
 * Copyright 2023, Dhruv Chandwani <dhchandw@silabs.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/*
13
 * Silabs Debug Channel is a protocol that is used for PTI (Packet Trace) data
14
 * to flow from the Silicon Labs chips, via the adapter firmware into the PC of a developer.
15
 *
16
 * Packet Trace (PTI) is a functionality of Silicon Labs radio chips, which allows
17
 * for the information about radio operation to be transferred to the observing
18
 * hardware via a dedicated PTI pin (or two) on the Silicon Labs Radio Microcontroller.
19
 *
20
 * Silabs Debug Channel can also be used for other event-based data transfer, but PTI is the primary use case.
21
 *
22
 * Spec - https://github.com/SiliconLabsSoftware/java-pti/blob/main/doc/debug-channel.md
23
 */
24
25
/* Include files */
26
#include "config.h"
27
#define WS_LOG_DOMAIN "silabs_dch"
28
#include <wireshark.h>
29
#include <wiretap/wtap.h>
30
#include <wsutil/bitswap.h>
31
#include <epan/packet.h> /* Required dissection API header */
32
#include <epan/exceptions.h>
33
#include <epan/show_exception.h>
34
#include <epan/expert.h> /* Include only as needed */
35
#include <epan/prefs.h>  /* Include only as needed */
36
#include <epan/proto_data.h>
37
#include "packet-ieee802154.h"
38
#include "packet-btle.h"
39
40
/* Protocol identifier, populated by registration */
41
static int proto_silabs_dch;
42
43
// Field identifiers, populated by registration.
44
/* Debug Channel Header */
45
static int hf_dch_version;
46
static int hf_dch_timestamp;
47
static int hf_dch_type;
48
static int hf_dch_flags;
49
static int hf_dch_sequence;
50
51
/* EFR32 */
52
static int hf_efr32;
53
static int hf_efr32_hwstart;
54
static int hf_efr32_phr;
55
static int hf_efr32_phr_packetlen;
56
static int hf_efr32_2bytephr;
57
static int hf_efr32_4bytephr;
58
static int hf_efr32_hwend;
59
static int hf_efr32_rssi;
60
static int hf_efr32_syncword;
61
static int hf_efr32_radiocfg;
62
static int hf_efr32_phyid;
63
static int hf_efr32_radiocfg_addedbytes;
64
static int hf_efr32_radiocfg_blephyid;
65
static int hf_efr32_radiocfg_regionid;
66
static int hf_efr32_radiocfg_2bytephr;
67
static int hf_efr32_radiocfg_softmodem;
68
static int hf_efr32_radiocfg_external;
69
static int hf_efr32_radiocfg_id;
70
static int hf_efr32_radioinfo;
71
static int hf_efr32_radioinfo_antenna;
72
static int hf_efr32_radioinfo_syncword;
73
static int hf_efr32_radioinfo_channel;
74
static int hf_efr32_channel;
75
static int hf_efr32_status;
76
static int hf_efr32_status_errorcode;
77
static int hf_efr32_status_protocolid;
78
static int hf_efr32_appendedinfocfg;
79
static int hf_efr32_appendedinfocfg_txrx;
80
static int hf_efr32_appendedinfocfg_length;
81
static int hf_efr32_appendedinfocfg_version;
82
83
/* Wi-SUN PHY Header */
84
static int hf_phr_fsk;
85
static int hf_phr_wisun_fsk_ms;
86
static int hf_phr_ofdm;
87
88
static int hf_phr_fsk_ms;
89
static int hf_phr_fsk_fcs;
90
static int hf_phr_fsk_dw;
91
static int hf_phr_fsk_length;
92
93
static int hf_phr_fsk_ms_checksum;
94
static int hf_phr_fsk_ms_parity;
95
96
static int hf_phr_wisun_fsk_ms_reserved;
97
static int hf_phr_wisun_fsk_ms_phymodeid;
98
99
static int hf_phr_ofdm_rate;
100
static int hf_phr_ofdm_length;
101
static int hf_phr_ofdm_scrambler;
102
103
/* Expert info fields - used for warnings and notes*/
104
static expert_field ei_silabs_dch_unsupported_type;
105
static expert_field ei_silabs_dch_unsupported_protocol;
106
static expert_field ei_silabs_dch_invalid_appendedinfolen;
107
108
/* Bit-mask for the EFR32 phr field */
109
16
#define EFR32_PHR_PACKETLEN_MASK 0xFF
110
111
/* Bit-masks for the EFR32 radio-cfg field */
112
16
#define EFR32_RADIOCFG_ADDEDBYTES_MASK 0xF8
113
16
#define EFR32_RADIOCFG_BLEPHYID_MASK 0x03
114
16
#define EFR32_RADIOCFG_REGIONID_MASK 0x1F
115
16
#define EFR32_RADIOCFG_2BYTEPHR_MASK 0x80
116
16
#define EFR32_RADIOCFG_SOFTMODEM_MASK 0x40
117
16
#define EFR32_RADIOCFG_EXTERNAL_MASK 0x10
118
16
#define EFR32_RADIOCFG_ID_MASK 0x07
119
120
/* Bit-masks for the EFR32 radio-info field */
121
16
#define EFR32_RADIOINFO_ANTENNA_MASK 0x80
122
16
#define EFR32_RADIOINFO_SYNCWORD_MASK 0x40
123
16
#define EFR32_RADIOINFO_CHANNEL_MASK 0x3F
124
125
/* Bit-masks for the EFR32 status field */
126
16
#define EFR32_STATUS_ERRORCODE_MASK 0xF0
127
16
#define EFR32_STATUS_PROTOCOLID_MASK 0x0F
128
129
/* Bit-masks for the EFR32 appended info cfg field */
130
16
#define EFR32_APPENDEDINFOCFG_TXRX_MASK 0x40
131
16
#define EFR32_APPENDEDINFOCFG_LENGTH_MASK 0x38
132
16
#define EFR32_APPENDEDINFOCFG_VERSION_MASK 0x07
133
134
/* BLE advertising PDU types (BT Core Spec Vol 6, Part B, 2.3) */
135
0
#define BLE_ADV_PDU_TYPE_CONNECT_IND 0x05
136
137
/* Bit-masks for Wi-SUN PHY Header */
138
16
#define PHR_FSK_MS 0x8000
139
16
#define PHR_FSK_FCS 0x1000
140
16
#define PHR_FSK_DW 0x0800
141
16
#define PHR_FSK_LENGTH 0x07ff
142
143
16
#define PHR_FSK_MS_CHECKSUM 0x001E
144
16
#define PHR_FSK_MS_PARITY 0x0001
145
146
16
#define PHR_WISUN_FSK_MS_RESERVED 0x6000
147
16
#define PHR_WISUN_FSK_MS_PHYMODEID 0x1FE0
148
149
16
#define PHR_OFDM_RATE 0xF80000
150
16
#define PHR_OFDM_LENGTH 0x03FF80
151
16
#define PHR_OFDM_SCRAMBLER 0x000018
152
153
// --------------------
154
155
/* Subtree identifiers, populated by registration */
156
static int ett_silabs_dch;
157
static int ett_silabs_efr32;
158
static int ett_silabs_efr32_radiocfg;
159
static int ett_silabs_efr32_radioinfo;
160
static int ett_silabs_efr32_status;
161
static int ett_silabs_efr32_appendedinfo;
162
static int ett_silabs_efr32_phr;
163
static int *ett[] = {
164
    &ett_silabs_dch,
165
    &ett_silabs_efr32,
166
    &ett_silabs_efr32_radiocfg,
167
    &ett_silabs_efr32_radioinfo,
168
    &ett_silabs_efr32_status,
169
    &ett_silabs_efr32_appendedinfo,
170
    &ett_silabs_efr32_phr,
171
};
172
173
// Structs and other types
174
typedef struct
175
{
176
  const char *title;
177
  int8_t crcLen;
178
} ProtocolInfo;
179
180
typedef struct
181
{
182
  uint8_t length;
183
  uint8_t version;
184
  bool isRx;
185
  bool hasRssi;
186
  bool hasSyncword;
187
  bool hasRadioCfg;
188
  uint8_t rssiLen;
189
  uint8_t syncwordLen;
190
  uint8_t radioCfgLen;
191
  bool isInvalid;
192
} Efr32AppendedInfo;
193
194
typedef enum
195
{
196
  PHR_RAW = 0,
197
  PHR_SUN_FSK = 6,
198
  PHR_SUN_OFDM = 7,
199
  PHR_WISUN_FSK_MS = 18,
200
} phr_type_t;
201
// --------------------
202
203
/* Silabs Debug Channel Dissector Handle */
204
static dissector_handle_t silabs_dch_handle;
205
206
/* Handoff dissector handles */
207
static dissector_handle_t ieee802154fcs_handle;
208
static dissector_handle_t ieee802154nofcs_handle;
209
static dissector_handle_t btle_handle;
210
211
/* BLE connection tracking for direction inference */
212
typedef struct {
213
    uint8_t device_role;  /* BTLE_DIR_CENTRAL_PERIPHERAL or BTLE_DIR_PERIPHERAL_CENTRAL */
214
} silabs_ble_connection_info_t;
215
216
static wmem_tree_t *silabs_ble_connections;
217
218
static bool pref_ble_sniffer_mode;
219
220
// Function declarations
221
/* Prototypes for required functions. */
222
void proto_reg_handoff_silabs_dch(void);
223
void proto_register_silabs_dch(void);
224
225
/* Dissector functions */
226
static int dissect_silabs_dch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
227
static int dissect_silabs_efr32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
228
static void dissect_silabs_ieee802154_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, int ota_payload_len, int crc_len);
229
static void dissect_silabs_ble_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, int ota_payload_len, const Efr32AppendedInfo *appended_info);
230
static int dissect_silabs_wisun_phr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, uint8_t phr_len, uint8_t phy_mode_id, int ota_payload_len, int *crc_len);
231
232
/* Helper functions */
233
static const Efr32AppendedInfo *get_efr32_appended_info(wmem_allocator_t *scope, uint8_t appended_info_cfg);
234
static const ProtocolInfo *get_protocol_info(wmem_allocator_t *scope, uint8_t protocol_id);
235
static int decode_wisun_phr_type(tvbuff_t *tvb, unsigned offset, uint8_t phr_len, uint8_t phy_mode_id, int ota_payload_len);
236
static int decode_channel_number(tvbuff_t *tvb, proto_tree *tree, unsigned offset, uint8_t radioinfo_channel, uint8_t radiocfg_id, uint8_t protocol_id);
237
static uint16_t reverse_bits_uint16(uint16_t value);
238
static uint8_t get_phr_length(uint8_t protocol_id, tvbuff_t *tvb, int last_index, uint8_t radioCfgLen);
239
static uint8_t get_phy_mode_id(uint8_t protocol_id, tvbuff_t *tvb, int last_index, uint8_t radioCfgLen);
240
241
/* BLE direction tracking helpers */
242
static void store_ble_connection_role(packet_info *pinfo, uint32_t interface_id, uint32_t access_address, uint8_t device_role);
243
static uint8_t lookup_ble_connection_role(uint32_t interface_id, uint32_t access_address);
244
// --------------------
245
246
/* Debug channel message types*/
247
static const value_string silabs_dch_message_types[] = {
248
    {0x0000, "Time synchronization notice"},
249
    {0x0001, "Reset notice"},
250
    {0x0002, "Application printf"},
251
    {0x0003, "API trace"},
252
    {0x0004, "Assertion notice"},
253
    {0x0005, "Core dump"},
254
    {0x0006, "Phy Rx"},
255
    {0x0007, "API Rx"},
256
    {0x0008, "Phy Tx"},
257
    {0x0009, "API Tx"},
258
    {0x000A, "Sniffer packet"},
259
    {0x000B, "Adapter error"},
260
    {0x000C, "Statistics"},
261
    {0x000D, "Time sync test"},
262
    {0x000E, "Radio reboot count"},
263
    {0x0011, "Virtual UART Tx"},
264
    {0x0012, "Virtual UART Rx"},
265
    {0x0020, "2420 Tx packet"},
266
    {0x0021, "2420 Rx packet"},
267
    {0x0022, "250 Tx packet"},
268
    {0x0023, "250 Rx packet"},
269
    {0x0024, "350 Tx packet"},
270
    {0x0025, "350 Rx packet"},
271
    {0x0026, "Pro2+ Tx packet"},
272
    {0x0027, "Pro2+ Rx packet"},
273
    {0x0028, "Pro2+ debug packet"},
274
    {0x0029, "EFR Tx packet"},
275
    {0x002A, "EFR Rx packet"},
276
    {0x002B, "EFR additional PTI data"},
277
    {0x0030, "Flash read request"},
278
    {0x0031, "Flash read response"},
279
    {0x0032, "EEPROM read request"},
280
    {0x0033, "EEPROM read response"},
281
    {0x0034, "EEPROM write request"},
282
    {0x0035, "EEPROM write response"},
283
    {0x0036, "RAM read request"},
284
    {0x0037, "RAM read response"},
285
    {0x0038, "RAM write request"},
286
    {0x0039, "RAM write response"},
287
    {0x003A, "Info request"},
288
    {0x003B, "Node information"},
289
    {0x003C, "EmberZNet serial protocol"},
290
    {0x003D, "ASH protocol"},
291
    {0x003E, "DAG trace"},
292
    {0x003F, "Simulated NCP callback ready"},
293
    {0x0040, "Simulated wakeup signal to NCP"},
294
    {0x0041, "Simulated signal to host that NCP is awake"},
295
    {0x0042, "Ember ZNet stack version"},
296
    {0x0043, "Ember IP stack version"},
297
    {0x0044, "Current time information"},
298
    {0x0045, "Memory use information"},
299
    {0x0046, "Mustang API message"},
300
    {0x0047, "Latency"},
301
    {0x0048, "TMSP"},
302
    {0x0050, "AEM sample"},
303
    {0x0051, "AEM counters snapshot"},
304
    {0x0060, "AEM request"},
305
    {0x0061, "AEM response"},
306
    {0x0062, "AEM current packet"},
307
    {0x0063, "AEM current packet v2"},
308
    {0x0064, "PC sample packet"},
309
    {0x0065, "Exception packet"},
310
    {0x0066, "Logic analyzer data"},
311
    {0x0070, "CPU usage"},
312
    {0x0080, "Configuration over SWO"},
313
    {0xFFFE, "User command"},
314
    {0xFFFF, "User response"},
315
    {0, NULL}};
316
317
/* Efr32 HW start values*/
318
static const value_string silabs_efr32_hwstart_values[] = {
319
    {0xF8, "Rx Start"},
320
    {0xFC, "Tx Start"},
321
    {0xF0, "DMP Protocol Switch"},
322
    {0, NULL}};
323
324
/* Efr32 HW end values*/
325
static const value_string silabs_efr32_hwend_values[] = {
326
    {0xF9, "Rx Success"},
327
    {0xFA, "Rx Abort"},
328
    {0xFD, "Tx Success"},
329
    {0xFE, "Tx Abort"},
330
    {0, NULL}};
331
332
/* Efr32 protocol id values*/
333
static const value_string silabs_efr32_status_protcolid_values[] = {
334
    {0x00, "Custom"},
335
    {0x01, "EmberPHY (Zigbee/Thread)"},
336
    {0x02, "Thread on RAIL"},
337
    {0x03, "BLE"},
338
    {0x04, "Connect on RAIL"},
339
    {0x05, "Zigbee on RAIL"},
340
    {0x06, "Z-Wave on RAIL"},
341
    {0x07, "Wi-SUN on RAIL"},
342
    {0x08, "Custom on 802.15.4 built-in PHY"},
343
    {0x09, "Amazon SideWalk"},
344
    {0x0A, "Bluetooth Classic"},
345
    {0, NULL}};
346
347
/* Efr32 tx/rx values*/
348
static const value_string silabs_efr32_appendedinfocfg_txrx_values[] = {
349
    {0x00, "Tx"},
350
    {0x01, "Rx"},
351
    {0, NULL}};
352
353
/* Wi-SUN PHR Values*/
354
static const value_string phr_wisun_phymodeid_values[] = {
355
    {1, "FSK #1a 50ksym/s mod-index 0.5"},
356
    {2, "FSK #1b 50ksym/s mod-index 1.0"},
357
    {3, "FSK #2a 100ksym/s mod-index 0.5"},
358
    {4, "FSK #2b 100ksym/s mod-index 1.0"},
359
    {5, "FSK #3 150ksym/s mod-index 0.5"},
360
    {6, "FSK #4a 200ksym/s mod-index 0.5"},
361
    {7, "FSK #4b 200ksym/s mod-index 1.0"},
362
    {8, "FSK #5 300ksym/s mod-index 0.5"},
363
    {17, "FSK with FEC #1a 50ksym/s mod-index 0.5"},
364
    {18, "FSK with FEC #1b 50ksym/s mod-index 1.0"},
365
    {19, "FSK with FEC #2a 100ksym/s mod-index 0.5"},
366
    {20, "FSK with FEC #2b 100ksym/s mod-index 1.0"},
367
    {21, "FSK with FEC #3 150ksym/s mod-index 0.5"},
368
    {22, "FSK with FEC #4a 200ksym/s mod-index 0.5"},
369
    {23, "FSK with FEC #4b 200ksym/s mod-index 1.0"},
370
    {24, "FSK with FEC #5 300ksym/s mod-index 0.5"},
371
    {34, "OFDM Option 1 MCS 2 400kbps"},
372
    {35, "OFDM Option 1 MCS 3 800kbps"},
373
    {36, "OFDM Option 1 MCS 4 1200kbps"},
374
    {37, "OFDM Option 1 MCS 5 1600kbps"},
375
    {38, "OFDM Option 1 MCS 6 2400kbps"},
376
    {51, "OFDM Option 2 MCS 3 400kbps"},
377
    {52, "OFDM Option 2 MCS 4 600kbps"},
378
    {53, "OFDM Option 2 MCS 5 800kbps"},
379
    {54, "OFDM Option 2 MCS 6 1200kbps"},
380
    {68, "OFDM Option 3 MCS 4 300kbps"},
381
    {69, "OFDM Option 3 MCS 5 400kbps"},
382
    {70, "OFDM Option 3 MCS 6 600kbps"},
383
    {84, "OFDM Option 4 MCS 4 150kbps"},
384
    {85, "OFDM Option 4 MCS 5 200kbps"},
385
    {86, "OFDM Option 4 MCS 6 300kbps"},
386
    {0, NULL}};
387
388
static const value_string phr_ofdm_rate_values[] = {
389
    {0, "MCS0"},
390
    {1, "MCS1"},
391
    {2, "MCS2"},
392
    {3, "MCS3"},
393
    {4, "MCS4"},
394
    {5, "MCS5"},
395
    {6, "MCS6"},
396
    {7, "MCS7"},
397
    {0, NULL}};
398
399
static const value_string phr_ofdm_scrambler_values[] = {
400
    {0, "000010111"},
401
    {1, "000011100"},
402
    {2, "101110111"},
403
    {3, "101111100"},
404
    {0, NULL}};
405
406
/**
407
 * Top-level dissector - dissects the debug channel header.
408
 *
409
 * @param tvb pointer to buffer containing raw packet.
410
 * @param pinfo pointer to packet information fields
411
 * @param tree pointer to data tree wireshark uses to display packet.
412
 * @param data data passed (unused)
413
 * @return offset after dissection
414
 *
415
 */
416
static int dissect_silabs_dch(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
417
0
{
418
0
  proto_item *dch_root = NULL;
419
0
  proto_tree *dch_tree = NULL;
420
0
  tvbuff_t *next_tvb;
421
0
  unsigned offset = 0;
422
0
  uint32_t dch_version, dch_message_type;
423
0
  const char *dch_message_type_str;
424
425
  // Create the top-level DCH subtree.
426
0
  dch_root = proto_tree_add_item(tree, proto_silabs_dch, tvb, offset, -1, ENC_NA);
427
0
  dch_tree = proto_item_add_subtree(dch_root, ett_silabs_dch);
428
429
  // Decode version, add it to DCH subtree.
430
0
  proto_tree_add_item_ret_uint(dch_tree, hf_dch_version, tvb, offset, 2, ENC_LITTLE_ENDIAN, &dch_version);
431
0
  offset += 2;
432
433
  // Decode timestamp, add it to DCH subtree. Timestamp is 8 bytes in later versions, but only 6 in version 2.
434
0
  if (dch_version > 2)
435
0
  {
436
0
    proto_tree_add_item(dch_tree, hf_dch_timestamp, tvb, offset, 8, ENC_TIME_NSECS | ENC_LITTLE_ENDIAN);
437
0
    offset += 8;
438
0
  }
439
0
  else
440
0
  {
441
0
    proto_tree_add_item(dch_tree, hf_dch_timestamp, tvb, offset, 6, ENC_TIME_USECS | ENC_LITTLE_ENDIAN);
442
0
    offset += 6;
443
0
  }
444
445
  // Decode message type, add it to DCH subtree. Use the message type descriptions
446
  // from the array above.
447
0
  proto_tree_add_item_ret_uint(dch_tree, hf_dch_type, tvb, offset, 2, ENC_LITTLE_ENDIAN, &dch_message_type);
448
0
  dch_message_type_str = val_to_str_const(dch_message_type, silabs_dch_message_types, "Unknown");
449
0
  offset += 2;
450
0
  col_add_fstr(pinfo->cinfo, COL_INFO, "Debug Message Type: %s", dch_message_type_str);
451
452
  // Decode flags (if exists) and sequence, honor differences between version 2 and version 3.
453
0
  if (dch_version > 2)
454
0
  {
455
0
    proto_tree_add_item(dch_tree, hf_dch_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN);
456
0
    offset += 4;
457
0
    proto_tree_add_item(dch_tree, hf_dch_sequence, tvb, offset, 2, ENC_LITTLE_ENDIAN);
458
0
    offset += 2;
459
0
  }
460
0
  else
461
0
  {
462
0
    proto_tree_add_item(dch_tree, hf_dch_sequence, tvb, offset, 1, ENC_LITTLE_ENDIAN);
463
0
    offset++;
464
0
  }
465
466
  // get debug message payload
467
0
  next_tvb = tvb_new_subset_remaining(tvb, offset);
468
469
  // Decode dch payload by dch message type
470
0
  switch (dch_message_type)
471
0
  {
472
0
  case 0x02A:
473
0
  case 0x029:
474
    // hand debug message payload to EFR32 dissector
475
0
    offset = dissect_silabs_efr32(next_tvb, pinfo, tree);
476
0
    break;
477
0
  default:
478
0
    proto_tree_add_expert_format_remaining(dch_tree, pinfo, &ei_silabs_dch_unsupported_type, tvb, offset, "Debug message type - %s not supported yet", dch_message_type_str);
479
0
    break;
480
0
  }
481
482
0
  return offset;
483
0
}
484
485
/**
486
 * Dissector for Efr32 radio info
487
 *
488
 * @param tvb pointer to buffer containing raw packet.
489
 * @param pinfo pointer to packet information fields
490
 * @param tree pointer to data tree wireshark uses to display packet.
491
 * @return offset after dissection
492
 *
493
 */
494
static int dissect_silabs_efr32(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
495
0
{
496
0
  proto_item *efr32_root;
497
0
  proto_tree *efr32_tree;
498
0
  unsigned offset = 0;
499
500
  // create the EFR32 subtree
501
0
  efr32_root = proto_tree_add_item(tree, hf_efr32, tvb, offset, -1, ENC_NA);
502
0
  efr32_tree = proto_item_add_subtree(efr32_root, ett_silabs_efr32);
503
504
  // decode hw start, add to subtree
505
0
  proto_tree_add_item(efr32_tree, hf_efr32_hwstart, tvb, offset, 1, ENC_LITTLE_ENDIAN);
506
0
  offset += 1;
507
508
0
  int last_index;
509
0
  uint8_t protocol_id;
510
0
  uint8_t appended_info_cfg;
511
0
  uint8_t status_byte;
512
0
  uint8_t phr_len;
513
0
  const ProtocolInfo *protocol;
514
0
  const Efr32AppendedInfo *appended_info;
515
516
  // decode radio appended info details
517
0
  last_index = offset + tvb_reported_length_remaining(tvb, offset) - 1;
518
0
  appended_info_cfg = tvb_get_uint8(tvb, last_index);
519
0
  appended_info = get_efr32_appended_info(pinfo->pool, appended_info_cfg);
520
521
  // check if appended info len is invalid
522
0
  if (appended_info->isInvalid)
523
0
  {
524
0
    proto_tree_add_expert_format_remaining(efr32_tree, pinfo, &ei_silabs_dch_invalid_appendedinfolen, tvb, offset, "Invalid Appended Info Length");
525
0
    return offset;
526
0
  }
527
528
  // decode protocol
529
0
  status_byte = tvb_get_uint8(tvb, last_index - 1);
530
0
  protocol_id = 0x0000000F & status_byte;
531
0
  protocol = get_protocol_info(pinfo->pool, protocol_id);
532
533
  // determine OTA Payload -> (PHR + Payload + CRC)
534
0
  int crc_len = (protocol->crcLen != -1) ? protocol->crcLen : 2; // Dynamic crc length (indicated by -1) not supported yet, default to 2
535
0
  int ota_payload_len = last_index + 1 - offset - appended_info->length - 1;
536
537
  // decode PHR Length and PHR
538
0
  phr_len = get_phr_length(protocol_id, tvb, last_index, appended_info->radioCfgLen);
539
0
  switch (protocol_id)
540
0
  {
541
0
  case 7:
542
0
  { // Further dissect Wi-SUN PHR
543
0
    uint8_t phy_mode_id = get_phy_mode_id(protocol_id, tvb, last_index, appended_info->radioCfgLen);
544
0
    phr_len = dissect_silabs_wisun_phr(tvb, pinfo, efr32_tree, offset, phr_len, phy_mode_id, ota_payload_len, &crc_len);
545
    // Adjust offset and ota_payload_len after PHR
546
0
    offset += phr_len;
547
0
    ota_payload_len -= phr_len;
548
0
    break;
549
0
  }
550
0
  case 2: // Thread on RAIL
551
0
  case 5: // Zigbee on RAIL
552
0
  case 8: // Custom on 802.15.4 built-in PHY
553
0
  {
554
0
    static int *const efr32_phr_fields[] = {
555
0
        &hf_efr32_phr_packetlen,
556
0
        NULL};
557
558
0
    switch (phr_len)
559
0
    {
560
0
    case 1:
561
0
      proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_phr, ett_silabs_efr32_phr, efr32_phr_fields, ENC_LITTLE_ENDIAN);
562
0
      break;
563
0
    case 2:
564
0
      proto_tree_add_item(efr32_tree, hf_efr32_2bytephr, tvb, offset, 2, ENC_LITTLE_ENDIAN);
565
0
      break;
566
0
    case 4:
567
0
      proto_tree_add_item(efr32_tree, hf_efr32_4bytephr, tvb, offset, 4, ENC_LITTLE_ENDIAN);
568
0
      break;
569
0
    default:
570
0
      break;
571
0
    }
572
    // Adjust offset and ota_payload_len after PHR
573
0
    offset += phr_len;
574
0
    ota_payload_len -= phr_len;
575
0
  }
576
0
  }
577
578
  // hand ota payload to protocol dissector
579
0
  if (ota_payload_len > 0)
580
0
  {
581
0
    switch (protocol_id)
582
0
    {
583
0
    case 2: // Thread on RAIL
584
0
    case 5: // Zigbee on RAIL
585
0
    case 7: // Wi-SUN on RAIL
586
0
    case 8: // Custom on 802.15.4 built-in PHY
587
0
      dissect_silabs_ieee802154_pdu(tvb, pinfo, tree, offset, ota_payload_len, crc_len);
588
0
      break;
589
0
    case 3: // BLE
590
0
      dissect_silabs_ble_pdu(tvb, pinfo, tree, offset, ota_payload_len, appended_info);
591
0
      break;
592
0
    default:
593
0
      proto_tree_add_expert_format_remaining(efr32_tree, pinfo, &ei_silabs_dch_unsupported_protocol, tvb, offset, "Protocol - %s not supported yet", protocol->title);
594
      // TODO: add support for the following protocols
595
      // case 1: // EFR32 EmberPHY (Zigbee/Thread)
596
      // case 4: // Connect on RAIL
597
      // case 6: // Z-Wave on RAIL
598
      // case 9: // Amazon SideWalk
599
0
      break;
600
0
    }
601
0
    offset += ota_payload_len;
602
0
  }
603
604
  // decode hw end, add to subtree
605
0
  proto_tree_add_item(efr32_tree, hf_efr32_hwend, tvb, offset, 1, ENC_LITTLE_ENDIAN);
606
0
  offset += 1;
607
608
  // decode rssi, add to subtree
609
0
  if (appended_info->hasRssi)
610
0
  {
611
0
    int8_t rssi = tvb_get_uint8(tvb, offset);
612
0
    rssi = (appended_info->version == 1) ? (rssi - 0x32) : rssi;
613
0
    proto_tree_add_int_format_value(efr32_tree, hf_efr32_rssi, tvb, offset, appended_info->rssiLen, rssi, "%d dBm", rssi);
614
0
    offset += appended_info->rssiLen;
615
0
  }
616
617
  // decode syncword, add to subtree
618
0
  if (appended_info->hasSyncword)
619
0
  {
620
0
    proto_tree_add_item(efr32_tree, hf_efr32_syncword, tvb, offset, appended_info->syncwordLen, ENC_LITTLE_ENDIAN);
621
0
    offset += appended_info->syncwordLen;
622
0
  }
623
624
  // decode radio cfg, add to subtree
625
0
  static int *const efr32_radiocfg_ble_fields[] = {
626
0
      &hf_efr32_radiocfg_addedbytes,
627
0
      &hf_efr32_radiocfg_blephyid,
628
0
      NULL};
629
0
  static int *const efr32_radiocfg_zwave_fields[] = {
630
0
      &hf_efr32_radiocfg_regionid,
631
0
      NULL};
632
0
  static int *const efr32_radiocfg_154_fields[] = {
633
0
      &hf_efr32_radiocfg_2bytephr,
634
0
      &hf_efr32_radiocfg_softmodem,
635
0
      &hf_efr32_radiocfg_external,
636
0
      &hf_efr32_radiocfg_id,
637
0
      NULL};
638
0
  uint8_t radiocfg_id = 0;
639
0
  if (appended_info->hasRadioCfg)
640
0
  {
641
0
    switch (protocol_id)
642
0
    {
643
0
    case 3: // BLE
644
0
      proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_radiocfg, ett_silabs_efr32_radiocfg, efr32_radiocfg_ble_fields, ENC_LITTLE_ENDIAN);
645
0
      break;
646
0
    case 6: // Z-Wave on RAIL
647
0
      proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_radiocfg, ett_silabs_efr32_radiocfg, efr32_radiocfg_zwave_fields, ENC_LITTLE_ENDIAN);
648
0
      break;
649
0
    case 1:
650
0
    case 2:
651
0
    case 5:
652
0
    case 7:
653
0
    case 8:
654
0
    {
655
0
      radiocfg_id = tvb_get_uint8(tvb, offset) & EFR32_RADIOCFG_ID_MASK;
656
0
      proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_radiocfg, ett_silabs_efr32_radiocfg, efr32_radiocfg_154_fields, ENC_LITTLE_ENDIAN);
657
0
      break;
658
0
    }
659
0
    default:
660
0
      proto_tree_add_item(efr32_tree, hf_efr32_radiocfg, tvb, offset, appended_info->radioCfgLen, ENC_LITTLE_ENDIAN);
661
0
      break;
662
0
    }
663
0
    offset += 1;
664
0
    if (appended_info->radioCfgLen == 2)
665
0
    {
666
0
      proto_tree_add_item(efr32_tree, hf_efr32_phyid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
667
0
      offset += 1;
668
0
    }
669
0
  }
670
671
  // decode radio info, add to subtree
672
0
  static int *const efr32_radioinfo_fields[] = {
673
0
      &hf_efr32_radioinfo_antenna,
674
0
      &hf_efr32_radioinfo_syncword,
675
0
      &hf_efr32_radioinfo_channel,
676
0
      NULL};
677
0
  uint8_t radioinfo_channel = tvb_get_uint8(tvb, offset) & EFR32_RADIOINFO_CHANNEL_MASK;
678
0
  proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_radioinfo, ett_silabs_efr32_radioinfo, efr32_radioinfo_fields, ENC_LITTLE_ENDIAN);
679
  // decode computed channel
680
0
  decode_channel_number(tvb, efr32_tree, offset, radioinfo_channel, radiocfg_id, protocol_id);
681
0
  offset += 1;
682
683
  // decode status, add to subtree
684
0
  static int *const efr32_status_fields[] = {
685
0
      &hf_efr32_status_errorcode,
686
0
      &hf_efr32_status_protocolid,
687
0
      NULL};
688
0
  proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_status, ett_silabs_efr32_status, efr32_status_fields, ENC_LITTLE_ENDIAN);
689
0
  offset += 1;
690
691
  // decode appended info cfg, add to subtree
692
0
  static int *const efr32_appendedinfocfg_fields[] = {
693
0
      &hf_efr32_appendedinfocfg_txrx,
694
0
      &hf_efr32_appendedinfocfg_length,
695
0
      &hf_efr32_appendedinfocfg_version,
696
0
      NULL};
697
0
  proto_tree_add_bitmask(efr32_tree, tvb, offset, hf_efr32_appendedinfocfg, ett_silabs_efr32_appendedinfo, efr32_appendedinfocfg_fields, ENC_LITTLE_ENDIAN);
698
0
  offset += 1;
699
700
0
  return offset;
701
0
}
702
703
/**
704
 * Dissect IEEE 802.15.4 OTA payload and hand off to the 802.15.4 dissector.
705
 *
706
 * @param tvb pointer to buffer containing raw packet.
707
 * @param pinfo pointer to packet information fields
708
 * @param tree pointer to data tree wireshark uses to display packet.
709
 * @param offset offset into tvb where the payload begins
710
 * @param ota_payload_len length of the OTA payload
711
 * @param crc_len length of the CRC (0 = no FCS, 2 = 16-bit, 4 = 32-bit)
712
 *
713
 */
714
static void
715
dissect_silabs_ieee802154_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
716
                             unsigned offset, int ota_payload_len, int crc_len)
717
0
{
718
0
  tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, ota_payload_len);
719
0
  TRY
720
0
  {
721
0
    if (crc_len > 0)
722
0
    {
723
0
      int fcs_type = crc_len == 2 ? IEEE802154_FCS_16_BIT : IEEE802154_FCS_32_BIT;
724
0
      call_dissector_with_data(ieee802154fcs_handle, next_tvb, pinfo, tree, &fcs_type);
725
0
    }
726
0
    else
727
0
    {
728
0
      call_dissector(ieee802154nofcs_handle, next_tvb, pinfo, tree);
729
0
    }
730
0
  }
731
0
  CATCH_NONFATAL_ERRORS
732
0
  {
733
0
    show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
734
0
  }
735
0
  ENDTRY;
736
0
}
737
738
/**
739
 * Dissect BLE OTA payload and hand off to the BTLE dissector.
740
 *
741
 * Builds a composite tvb from the syncword (in appended info) and the OTA
742
 * payload, infers BLE direction from connection tracking, and passes to
743
 * the BTLE dissector.
744
 *
745
 * @param tvb pointer to buffer containing raw packet.
746
 * @param pinfo pointer to packet information fields
747
 * @param tree pointer to data tree wireshark uses to display packet.
748
 * @param offset offset into tvb where the payload begins
749
 * @param ota_payload_len length of the OTA payload
750
 * @param appended_info pointer to appended info struct
751
 *
752
 */
753
static void
754
dissect_silabs_ble_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
755
                       unsigned offset, int ota_payload_len,
756
                       const Efr32AppendedInfo *appended_info)
757
0
{
758
0
  if (!appended_info->hasSyncword)
759
0
    return;
760
761
0
  bool is_tx = !appended_info->isRx;
762
763
  // syncword offset: after OTA payload, hwend (1 byte), and RSSI
764
0
  int syncword_offset = offset + ota_payload_len + 1 + appended_info->rssiLen;
765
0
  uint32_t access_address = tvb_get_letohl(tvb, syncword_offset);
766
0
  uint32_t interface_id = (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) ?
767
0
                          pinfo->rec->rec_header.packet_header.interface_id : 0;
768
769
  // build composite tvb: syncword + payload (BTLE dissector expects this)
770
0
  tvbuff_t *composite_tvb = tvb_new_composite();
771
0
  tvb_composite_append(composite_tvb, tvb_new_subset_length(tvb, syncword_offset, appended_info->syncwordLen));
772
0
  tvb_composite_append(composite_tvb, tvb_new_subset_length(tvb, offset, ota_payload_len));
773
0
  tvb_composite_finalize(composite_tvb);
774
775
0
  void *volatile dissector_data = NULL;
776
0
  btle_context_t context_storage;
777
778
0
  if (!pref_ble_sniffer_mode)
779
0
  {
780
    // track device role from CONNECT_IND for direction inference
781
0
    if (access_address == ACCESS_ADDRESS_ADVERTISING)
782
0
    {
783
0
      uint8_t pdu_type = tvb_get_uint8(composite_tvb, 4) & 0x0F;
784
0
      if (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_IND)
785
0
      {
786
        // conn access addr at AA(4)+hdr(2)+InitA(6)+AdvA(6)=18, need +4 to read
787
0
        if (tvb_captured_length(composite_tvb) >= 22)
788
0
        {
789
0
          uint32_t conn_access_addr = tvb_get_letohl(composite_tvb, 18);
790
0
          uint8_t device_role = is_tx ? BTLE_DIR_CENTRAL_PERIPHERAL : BTLE_DIR_PERIPHERAL_CENTRAL;
791
0
          store_ble_connection_role(pinfo, interface_id, conn_access_addr, device_role);
792
0
        }
793
0
      }
794
0
    }
795
796
    // pass NULL context for ADV so BTLE uses its default path;
797
    // a zero-init context triggers wrong value-table lookups
798
0
    if (access_address != ACCESS_ADDRESS_ADVERTISING)
799
0
    {
800
0
      memset(&context_storage, 0, sizeof(context_storage));
801
0
      uint8_t device_role;
802
      /* Keep the role found on the first pass for this frame, so that
803
         later passes do not see roles learned from later frames. */
804
0
      uint8_t *stored_role = (uint8_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_silabs_dch, 0);
805
0
      if (stored_role) {
806
0
        device_role = *stored_role;
807
0
      } else {
808
0
        device_role = lookup_ble_connection_role(interface_id, access_address);
809
0
        if (!PINFO_FD_VISITED(pinfo)) {
810
0
          stored_role = wmem_new(wmem_file_scope(), uint8_t);
811
0
          *stored_role = device_role;
812
0
          p_add_proto_data(wmem_file_scope(), pinfo, proto_silabs_dch, 0, stored_role);
813
0
        }
814
0
      }
815
0
      if (device_role != BTLE_DIR_UNKNOWN)
816
0
      {
817
0
        if (is_tx)
818
0
        {
819
0
          context_storage.direction = device_role;
820
0
          pinfo->p2p_dir = (device_role == BTLE_DIR_CENTRAL_PERIPHERAL) ? P2P_DIR_SENT : P2P_DIR_RECV;
821
0
        }
822
0
        else
823
0
        {
824
0
          context_storage.direction = (device_role == BTLE_DIR_CENTRAL_PERIPHERAL) ?
825
0
                                     BTLE_DIR_PERIPHERAL_CENTRAL : BTLE_DIR_CENTRAL_PERIPHERAL;
826
0
          pinfo->p2p_dir = (device_role == BTLE_DIR_CENTRAL_PERIPHERAL) ? P2P_DIR_RECV : P2P_DIR_SENT;
827
0
        }
828
0
      }
829
0
      dissector_data = &context_storage;
830
0
    }
831
0
  }
832
833
0
  add_new_data_source(pinfo, composite_tvb, "BLE Packet");
834
0
  TRY
835
0
  {
836
0
    call_dissector_with_data(btle_handle, composite_tvb, pinfo, tree, dissector_data);
837
0
  }
838
0
  CATCH_NONFATAL_ERRORS
839
0
  {
840
0
    show_exception(composite_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
841
0
  }
842
0
  ENDTRY;
843
0
}
844
845
/**
846
 * Dissect Wi-SUN PHY Header
847
 *
848
 * @param tvb pointer to buffer containing raw packet.
849
 * @param pinfo pointer to packet information fields
850
 * @param tree pointer to data tree wireshark uses to display packet.
851
 * @param offset offset in tvb
852
 * @param phr_len length of PHY Header
853
 * @param ota_payload_len length of OTA payload
854
 * @param crc_len pointer to length of CRC (updated by function)
855
 * @return offset after dissection
856
 *
857
 */
858
static int dissect_silabs_wisun_phr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, uint8_t phr_len, uint8_t phy_mode_id, int ota_payload_len, int *crc_len)
859
0
{
860
  // First byte after HW Start can be a garbage 0x0b or 0x00 byte
861
0
  bool can_be_garbage = (tvb_get_uint8(tvb, offset) == 0x0b) || (tvb_get_uint8(tvb, offset) == 0x00);
862
863
  // Get PHR Type
864
0
  uint8_t garbage_byte_len = 0;
865
0
  uint8_t phr_type = decode_wisun_phr_type(tvb, offset, phr_len, phy_mode_id, ota_payload_len);
866
  // if possible garbage byte is present, try skipping it
867
0
  if ((phr_type == PHR_RAW) & can_be_garbage)
868
0
  {
869
0
    phr_type = decode_wisun_phr_type(tvb, offset + 1, phr_len, phy_mode_id, ota_payload_len - 1);
870
0
    if (phr_type != PHR_RAW)
871
0
    {
872
0
      offset += 1;
873
0
      garbage_byte_len = 1;
874
0
    }
875
0
  }
876
877
  // Dissect PHR based of Type
878
0
  if (phr_type == PHR_SUN_FSK || phr_type == PHR_WISUN_FSK_MS)
879
0
  {
880
881
0
    uint8_t *datax = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, 2);
882
0
    bitswap_buf_inplace(datax, 2);
883
0
    tvbuff_t *reversed_tvb = tvb_new_child_real_data(tvb, datax, 2, 2);
884
    /* Add the reversed data to the data source list. */
885
0
    add_new_data_source(pinfo, reversed_tvb, "decoded_phr");
886
887
0
    if (phr_type == PHR_WISUN_FSK_MS)
888
0
    {
889
0
      static int *const phr_wisun_fsk_ms_fields[] = {
890
0
          &hf_phr_fsk_ms,
891
0
          &hf_phr_wisun_fsk_ms_reserved,
892
0
          &hf_phr_wisun_fsk_ms_phymodeid,
893
0
          &hf_phr_fsk_ms_checksum,
894
0
          &hf_phr_fsk_ms_parity,
895
0
          NULL};
896
0
      proto_tree_add_bitmask(tree, reversed_tvb, 0, hf_phr_wisun_fsk_ms, ett_silabs_efr32_phr, phr_wisun_fsk_ms_fields, ENC_BIG_ENDIAN);
897
0
      col_clear(pinfo->cinfo, COL_INFO);
898
0
      col_set_str(pinfo->cinfo, COL_INFO, "Wi-SUN FSK Mode Switch PHR");
899
0
      *crc_len = 0; // No CRC for Wi-SUN FSK MS since no payload
900
0
    }
901
0
    else
902
0
    {
903
0
      static int *const phr_fsk_fields[] = {
904
0
          &hf_phr_fsk_ms,
905
0
          &hf_phr_fsk_fcs,
906
0
          &hf_phr_fsk_dw,
907
0
          &hf_phr_fsk_length,
908
0
          NULL};
909
0
      proto_tree_add_bitmask(tree, reversed_tvb, 0, hf_phr_fsk, ett_silabs_efr32_phr, phr_fsk_fields, ENC_BIG_ENDIAN);
910
0
    }
911
0
  }
912
0
  else if (phr_type == PHR_SUN_OFDM)
913
0
  {
914
0
    offset += 1;
915
0
    *crc_len = 0; // No CRC for OFDM
916
0
    uint8_t *datax = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, 3);
917
0
    bitswap_buf_inplace(datax, 3);
918
0
    tvbuff_t *reversed_tvb = tvb_new_child_real_data(tvb, datax, 3, 3);
919
    /* Add the reversed data to the data source list. */
920
0
    add_new_data_source(pinfo, reversed_tvb, "decoded_phr");
921
922
0
    static int *const phr_ofdm_fields[] = {
923
0
        &hf_phr_ofdm_rate,
924
0
        &hf_phr_ofdm_length,
925
0
        &hf_phr_ofdm_scrambler,
926
0
        NULL};
927
0
    proto_tree_add_bitmask(tree, reversed_tvb, 0, hf_phr_ofdm, ett_silabs_efr32_phr, phr_ofdm_fields, ENC_BIG_ENDIAN);
928
0
  }
929
0
  else
930
0
  {
931
0
    proto_tree_add_item(tree, hf_efr32_phr, tvb, offset, phr_len, ENC_LITTLE_ENDIAN);
932
0
  }
933
0
  return phr_len + garbage_byte_len;
934
0
}
935
936
/**
937
 * Get Wi-SUN PHY Header Type
938
 *
939
 * @param tvb pointer to buffer containing raw packet.
940
 * @param offset offset in tvb
941
 * @param phr_len length of PHY Header
942
 * @param phy_mode_id PHY Mode ID
943
 * @param ota_payload_len length of OTA payload
944
 * @return Wi-SUN PHY Header Type
945
 *
946
 */
947
static int decode_wisun_phr_type(tvbuff_t *tvb, unsigned offset, uint8_t phr_len, uint8_t phy_mode_id, int ota_payload_len)
948
0
{
949
0
  uint8_t phr_type = PHR_RAW;
950
0
  if (phr_len == 2)
951
0
  {
952
    /* If PHR length is 2, PHR is either SUN FSK or WISUN FSK MS based on Mode Switch bit*/
953
0
    uint16_t phr = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN);
954
0
    if ((phr & 0x01) && (ota_payload_len == phr_len))
955
0
    {
956
0
      phr_type = PHR_WISUN_FSK_MS;
957
0
    }
958
0
    if ((ota_payload_len - phr_len) == reverse_bits_uint16(phr & 0xFFE0))
959
0
    {
960
0
      phr_type = PHR_SUN_FSK;
961
0
    }
962
0
  }
963
0
  if ((phr_len == 4) && (phy_mode_id >= 0x20))
964
0
  {
965
0
    uint32_t phr = tvb_get_uint24(tvb, offset + 1, ENC_LITTLE_ENDIAN);
966
0
    uint16_t frame_length = (uint16_t)((phr & 0x0001FFC0) >> 6);
967
0
    frame_length = reverse_bits_uint16(frame_length) >> 5;
968
0
    if ((ota_payload_len) == frame_length)
969
0
    {
970
0
      phr_type = PHR_SUN_OFDM;
971
0
    }
972
0
  }
973
0
  return phr_type;
974
0
}
975
976
/**
977
 * Decode and add computed channel number to the tree
978
 *
979
 * @param tvb pointer to buffer containing raw packet.
980
 * @param tree pointer to data tree wireshark uses to display packet.
981
 * @param offset offset in tvb
982
 * @param radioinfo_channel channel number from radio info
983
 * @param radiocfg_id radio configuration id
984
 * @param protocol_id protocol id
985
 * @return offset
986
 */
987
static int decode_channel_number(tvbuff_t *tvb, proto_tree *tree, unsigned offset, uint8_t radioinfo_channel, uint8_t radiocfg_id, uint8_t protocol_id)
988
0
{
989
0
  int center_freq;
990
0
  int formatted_channel = radioinfo_channel;
991
0
  proto_item *channel_item;
992
993
0
  switch (protocol_id)
994
0
  {
995
0
  case 3: // BLE
996
0
    center_freq = 2402 + (radioinfo_channel * 2);
997
0
    formatted_channel = radioinfo_channel;
998
0
    channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
999
0
    proto_item_append_text(channel_item, " (RF channel %d, %d MHz)", radioinfo_channel, center_freq);
1000
0
    break;
1001
1002
0
  case 1: // EMBER_PHY
1003
0
  case 2: // THREAD_ON_RAIL
1004
0
  case 5: // ZIGBEE_ON_RAIL
1005
0
  case 4: // CONNECT_ON_RAIL
1006
0
  case 8: // CUSTOM_ON_802_15_4
1007
0
    switch (radiocfg_id)
1008
0
    {
1009
0
    case 0: // OQPSK 2.4GHz
1010
0
      center_freq = 2405 + (5 * radioinfo_channel);
1011
0
      formatted_channel = radioinfo_channel + 11;
1012
0
      channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1013
0
      proto_item_append_text(channel_item, " (15.4 Cp0 channel %d, 2.%03d GHz)", formatted_channel, center_freq % 1000);
1014
0
      break;
1015
1016
0
    case 1: // BPSK 868MHz
1017
0
      channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1018
0
      proto_item_append_text(channel_item, " (15.4 Cp0 channel %d, 868.3 MHz)", radioinfo_channel);
1019
0
      break;
1020
1021
0
    case 2: // BPSK 915MHz
1022
0
      center_freq = 906 + (2 * radioinfo_channel);
1023
0
      channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1024
0
      proto_item_append_text(channel_item, " (15.4 Cp0 channel %d, %d MHz)", radioinfo_channel, center_freq);
1025
0
      break;
1026
1027
0
    case 5: // GFSK 863MHz GB868
1028
0
      center_freq = 863250 + (200 * radioinfo_channel);
1029
0
      if (radioinfo_channel < 27)
1030
0
      {
1031
0
        formatted_channel = radioinfo_channel;
1032
0
        channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1033
0
        proto_item_append_text(channel_item, " (15.4 Cp28 channel %d, %d.%03d MHz)", formatted_channel, center_freq / 1000, center_freq % 1000);
1034
0
      }
1035
0
      else if (radioinfo_channel < 35)
1036
0
      {
1037
0
        formatted_channel = radioinfo_channel - 27;
1038
0
        channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1039
0
        proto_item_append_text(channel_item, " (15.4 Cp29 channel %d, %d.%03d MHz)", formatted_channel, center_freq / 1000, center_freq % 1000);
1040
0
      }
1041
0
      else if (radioinfo_channel < 62)
1042
0
      {
1043
0
        formatted_channel = radioinfo_channel - 35;
1044
0
        channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1045
0
        proto_item_append_text(channel_item, " (15.4 Cp30 channel %d, %d.%03d MHz)", formatted_channel, center_freq / 1000, center_freq % 1000);
1046
0
      }
1047
0
      else
1048
0
      {
1049
0
        formatted_channel = 8 + radioinfo_channel - 62;
1050
0
        channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1051
0
        proto_item_append_text(channel_item, " (15.4 Cp29 channel %d, %d.%03d MHz)", formatted_channel, center_freq / 1000, center_freq % 1000);
1052
0
      }
1053
0
      break;
1054
1055
0
    case 6: // GFSK 915MHz GB868
1056
0
      center_freq = 915350 + (200 * radioinfo_channel);
1057
0
      channel_item = proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1058
0
      proto_item_append_text(channel_item, " (15.4 Cp31 channel %d, %d.%03d MHz)", radioinfo_channel, center_freq / 1000, center_freq % 1000);
1059
0
      break;
1060
1061
0
    default:
1062
0
      proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1063
0
      break;
1064
0
    }
1065
0
    break;
1066
1067
0
  case 7: // Wi-SUN
1068
0
  {
1069
0
    formatted_channel = (radiocfg_id << 6) + radioinfo_channel;
1070
0
    proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1071
0
    break;
1072
0
  }
1073
1074
0
  default:
1075
0
    proto_tree_add_uint(tree, hf_efr32_channel, tvb, offset, 1, formatted_channel);
1076
0
    break;
1077
0
  }
1078
1079
0
  return offset;
1080
0
}
1081
1082
/**
1083
 * Get protocol info based on protocol id
1084
 *
1085
 * @param protocol_id protocol id
1086
 * @return pointer to ProtocolInfo struct
1087
 *
1088
 */
1089
static const ProtocolInfo *get_protocol_info(wmem_allocator_t *scope, uint8_t protocol_id)
1090
0
{
1091
0
  ProtocolInfo *protocol_info = wmem_new(scope, ProtocolInfo);
1092
1093
0
  switch (protocol_id)
1094
0
  {
1095
0
  case 0:
1096
0
    *protocol_info = (ProtocolInfo){"Custom", 2};
1097
0
    break;
1098
0
  case 1:
1099
0
    *protocol_info = (ProtocolInfo){"EFR32 EmberPHY", 2};
1100
0
    break;
1101
0
  case 2:
1102
0
    *protocol_info = (ProtocolInfo){"Thread on RAIL", 2};
1103
0
    break;
1104
0
  case 3:
1105
0
    *protocol_info = (ProtocolInfo){"BLE", 3};
1106
0
    break;
1107
0
  case 4:
1108
0
    *protocol_info = (ProtocolInfo){"Connect on RAIL", 2};
1109
0
    break;
1110
0
  case 5:
1111
0
    *protocol_info = (ProtocolInfo){"ZigBee on RAIL", 2};
1112
0
    break;
1113
0
  case 6:
1114
0
    *protocol_info = (ProtocolInfo){"Z-Wave on RAIL", -1};
1115
0
    break;
1116
0
  case 7:
1117
0
    *protocol_info = (ProtocolInfo){"Wi-SUN", 4};
1118
0
    break;
1119
0
  default:
1120
0
    *protocol_info = (ProtocolInfo){"Unknown", 0};
1121
0
    break;
1122
0
  }
1123
1124
0
  return protocol_info;
1125
0
}
1126
1127
/**
1128
 * Get appended info details based on appended info cfg
1129
 *
1130
 * @param appended_info_cfg appended info cfg byte
1131
 * @return pointer to Efr32AppendedInfo struct
1132
 *
1133
 */
1134
static const Efr32AppendedInfo *get_efr32_appended_info(wmem_allocator_t *scope, uint8_t appended_info_cfg)
1135
0
{
1136
0
  Efr32AppendedInfo *appended_info = wmem_new(scope, Efr32AppendedInfo);
1137
0
  memset(appended_info, 0, sizeof(Efr32AppendedInfo)); // Initialize all fields to 0 or false
1138
0
  appended_info->isRx = (appended_info_cfg & EFR32_APPENDEDINFOCFG_TXRX_MASK) != 0;
1139
0
  uint8_t var_len = (appended_info_cfg & EFR32_APPENDEDINFOCFG_LENGTH_MASK) >> 3;
1140
0
  appended_info->length = var_len + 3;
1141
0
  appended_info->version = (appended_info_cfg & EFR32_APPENDEDINFOCFG_VERSION_MASK);
1142
0
  appended_info->isInvalid = false;
1143
0
  if (appended_info->isRx)
1144
0
  {
1145
0
    switch (var_len)
1146
0
    {
1147
0
    case 1:
1148
0
      appended_info->hasSyncword = false;
1149
0
      appended_info->hasRssi = true;
1150
0
      appended_info->hasRadioCfg = false;
1151
0
      break;
1152
0
    case 2:
1153
0
      appended_info->hasSyncword = false;
1154
0
      appended_info->hasRssi = true;
1155
0
      appended_info->hasRadioCfg = true;
1156
0
      break;
1157
0
    case 3:
1158
0
      appended_info->hasSyncword = false;
1159
0
      appended_info->hasRssi = true;
1160
0
      appended_info->hasRadioCfg = true;
1161
0
      break;
1162
0
    case 5:
1163
0
      appended_info->hasSyncword = true;
1164
0
      appended_info->hasRssi = true;
1165
0
      appended_info->hasRadioCfg = false;
1166
0
      break;
1167
0
    case 6:
1168
0
      appended_info->hasSyncword = true;
1169
0
      appended_info->hasRssi = true;
1170
0
      appended_info->hasRadioCfg = true;
1171
0
      break;
1172
0
    case 7:
1173
0
      appended_info->hasSyncword = true;
1174
0
      appended_info->hasRssi = true;
1175
0
      appended_info->hasRadioCfg = true;
1176
0
      break;
1177
0
    default:
1178
0
      appended_info->hasSyncword = false;
1179
0
      appended_info->hasRssi = false;
1180
0
      appended_info->hasRadioCfg = false;
1181
0
      appended_info->isInvalid = true;
1182
0
      break;
1183
0
    }
1184
0
  }
1185
0
  else
1186
0
  {
1187
0
    switch (var_len)
1188
0
    {
1189
0
    case 0:
1190
0
      appended_info->hasSyncword = false;
1191
0
      appended_info->hasRssi = false;
1192
0
      appended_info->hasRadioCfg = false;
1193
0
      break;
1194
0
    case 1:
1195
0
      appended_info->hasSyncword = false;
1196
0
      appended_info->hasRssi = false;
1197
0
      appended_info->hasRadioCfg = true;
1198
0
      break;
1199
0
    case 2:
1200
0
      appended_info->hasSyncword = false;
1201
0
      appended_info->hasRssi = false;
1202
0
      appended_info->hasRadioCfg = true;
1203
0
      break;
1204
0
    case 4:
1205
0
      appended_info->hasSyncword = true;
1206
0
      appended_info->hasRssi = false;
1207
0
      appended_info->hasRadioCfg = false;
1208
0
      break;
1209
0
    case 5:
1210
0
      appended_info->hasSyncword = true;
1211
0
      appended_info->hasRssi = false;
1212
0
      appended_info->hasRadioCfg = true;
1213
0
      break;
1214
0
    case 6:
1215
0
      appended_info->hasSyncword = true;
1216
0
      appended_info->hasRssi = false;
1217
0
      appended_info->hasRadioCfg = true;
1218
0
      break;
1219
0
    default:
1220
0
      appended_info->hasSyncword = false;
1221
0
      appended_info->hasRssi = false;
1222
0
      appended_info->hasRadioCfg = false;
1223
0
      appended_info->isInvalid = true;
1224
0
      break;
1225
0
    }
1226
0
  }
1227
0
  appended_info->rssiLen = appended_info->hasRssi ? 1 : 0;
1228
0
  appended_info->syncwordLen = appended_info->hasSyncword ? 4 : 0;
1229
0
  if (appended_info->hasRadioCfg)
1230
0
  {
1231
0
    if (appended_info->isRx)
1232
0
    {
1233
0
      appended_info->radioCfgLen = (var_len == 3 || var_len == 7) ? 2 : 1;
1234
0
    }
1235
0
    else
1236
0
    {
1237
0
      appended_info->radioCfgLen = (var_len == 2 || var_len == 6) ? 2 : 1;
1238
0
    }
1239
0
  }
1240
1241
0
  return appended_info;
1242
0
}
1243
1244
/**
1245
 * Get PHR Length
1246
 *
1247
 * @param protocol_id protocol id
1248
 * @param tvb pointer to buffer containing raw packet.
1249
 * @param last_index last index of tvb
1250
 * @param radioCfgLen radio cfg length
1251
 * @return PHR length
1252
 *
1253
 */
1254
static uint8_t get_phr_length(uint8_t protocol_id, tvbuff_t *tvb, int last_index, uint8_t radioCfgLen)
1255
0
{
1256
0
  uint8_t phr_len = 1;
1257
0
  if (radioCfgLen > 0)
1258
0
  {
1259
0
    switch (protocol_id)
1260
0
    {
1261
0
    case 1:
1262
0
    case 2:
1263
0
    case 5:
1264
0
    case 7:
1265
0
    case 8:
1266
0
    {
1267
0
      uint8_t radiocfg_byte = tvb_get_uint8(tvb, last_index - radioCfgLen - 2); // radio cfg byte is either 4th byte or 5th byte from the end (depends on existence of radio cfg ext)
1268
0
      if (radiocfg_byte & (1 << 6))
1269
0
      {
1270
0
        phr_len = 4; // if soft modem is used then PHR is always 4 bytes
1271
0
      }
1272
0
      else
1273
0
      {
1274
0
        phr_len = (radiocfg_byte & (1 << 7)) ? 2 : 1; // bit 7 indicates 2 byte PHR
1275
0
      }
1276
0
    }
1277
0
    break;
1278
0
    case 3:
1279
0
      phr_len = 2;
1280
0
      break;
1281
0
    default:
1282
0
      phr_len = 1;
1283
0
    }
1284
0
  }
1285
0
  return phr_len;
1286
0
}
1287
1288
/**
1289
 * Get PHY Mode ID
1290
 *
1291
 * @param protocol_id protocol id
1292
 * @param tvb pointer to buffer containing raw packet.
1293
 * @param last_index last index of tvb
1294
 * @param radioCfgLen radio cfg length
1295
 * @return PHY Mode ID
1296
 *
1297
 */
1298
static uint8_t get_phy_mode_id(uint8_t protocol_id, tvbuff_t *tvb, int last_index, uint8_t radioCfgLen)
1299
0
{
1300
0
  uint8_t phy_mode_id = 0;
1301
  // PHY Mode ID is present only in Radio Cfg Ext for 15.4
1302
0
  if (radioCfgLen == 2)
1303
0
  {
1304
0
    switch (protocol_id)
1305
0
    {
1306
0
    case 1:
1307
0
    case 2:
1308
0
    case 5:
1309
0
    case 7:
1310
0
    case 8:
1311
0
      phy_mode_id = tvb_get_uint8(tvb, last_index - radioCfgLen - 1);
1312
0
      break;
1313
0
    default:
1314
0
      phy_mode_id = 0;
1315
0
    }
1316
0
  }
1317
0
  return phy_mode_id;
1318
0
}
1319
1320
/**
1321
 * Reverse the bits of a uint16_t value.
1322
 *
1323
 * @param value The uint16_t value to reverse.
1324
 * @return The bit-reversed uint16_t value.
1325
 */
1326
static uint16_t reverse_bits_uint16(uint16_t value)
1327
0
{
1328
0
  value = ((value & 0x5555) << 1) | ((value & 0xAAAA) >> 1);
1329
0
  value = ((value & 0x3333) << 2) | ((value & 0xCCCC) >> 2);
1330
0
  value = ((value & 0x0F0F) << 4) | ((value & 0xF0F0) >> 4);
1331
0
  value = (value << 8) | (value >> 8);
1332
0
  return value;
1333
0
}
1334
1335
/**
1336
 * Store BLE connection role for direction tracking.
1337
 * Called when CONNECT_IND is detected to record whether this device is Central or Peripheral.
1338
 */
1339
static void store_ble_connection_role(packet_info *pinfo, uint32_t interface_id, uint32_t access_address, uint8_t device_role)
1340
0
{
1341
0
  if (pinfo->fd->visited)
1342
0
    return;
1343
1344
0
  wmem_tree_key_t key[3];
1345
0
  key[0].length = 1;
1346
0
  key[0].key = &interface_id;
1347
0
  key[1].length = 1;
1348
0
  key[1].key = &access_address;
1349
0
  key[2].length = 0;
1350
0
  key[2].key = NULL;
1351
1352
0
  silabs_ble_connection_info_t *conn_info = wmem_new(wmem_file_scope(), silabs_ble_connection_info_t);
1353
0
  conn_info->device_role = device_role;
1354
1355
0
  wmem_tree_insert32_array(silabs_ble_connections, key, conn_info);
1356
0
}
1357
1358
/**
1359
 * Lookup BLE connection role for a given access address.
1360
 * Returns BTLE_DIR_UNKNOWN if the connection hasn't been seen.
1361
 */
1362
static uint8_t lookup_ble_connection_role(uint32_t interface_id, uint32_t access_address)
1363
0
{
1364
0
  wmem_tree_key_t key[3];
1365
0
  key[0].length = 1;
1366
0
  key[0].key = &interface_id;
1367
0
  key[1].length = 1;
1368
0
  key[1].key = &access_address;
1369
0
  key[2].length = 0;
1370
0
  key[2].key = NULL;
1371
1372
0
  silabs_ble_connection_info_t *conn_info =
1373
0
      (silabs_ble_connection_info_t *)wmem_tree_lookup32_array(silabs_ble_connections, key);
1374
1375
0
  return conn_info ? conn_info->device_role : BTLE_DIR_UNKNOWN;
1376
0
}
1377
1378
// ********************************
1379
1380
/* Register the protocol with Wireshark.
1381
 *
1382
 * This format is required because a script is used to build the C function that
1383
 * calls all the protocol registration.
1384
 *
1385
 */
1386
void proto_register_silabs_dch(void)
1387
16
{
1388
16
  static hf_register_info hf[] = {
1389
      /* Debug Channel Header */
1390
16
      {&hf_dch_version,
1391
16
       {"Version", "silabs-dch.version", FT_UINT16, BASE_DEC, NULL, 0x0, "Debug Channel Version", HFILL}},
1392
16
      {&hf_dch_timestamp,
1393
16
       {"Timestamp", "silabs-dch.timestamp", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, "Debug Channel Timestamp", HFILL}},
1394
16
      {&hf_dch_type,
1395
16
       {"Type", "silabs-dch.type", FT_UINT16, BASE_HEX, VALS(silabs_dch_message_types), 0x0, "Debug Message Type", HFILL}},
1396
16
      {&hf_dch_flags,
1397
16
       {"Flags", "silabs-dch.flags", FT_UINT32, BASE_HEX, NULL, 0x0, "Debug Channel Flags", HFILL}},
1398
16
      {&hf_dch_sequence,
1399
16
       {"Sequence", "silabs-dch.seq", FT_UINT16, BASE_DEC, NULL, 0x0, "Debug Channel Sequence", HFILL}},
1400
1401
      /* EFR32 */
1402
16
      {&hf_efr32,
1403
16
       {"Silabs EFR32 Radio Info", "silabs-dch.efr32", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1404
16
      {&hf_efr32_hwstart,
1405
16
       {"HW Start", "silabs-dch.hwstart", FT_UINT8, BASE_HEX, VALS(silabs_efr32_hwstart_values), 0x0, "EFR32 HW Start", HFILL}},
1406
16
      {&hf_efr32_phr,
1407
16
       {"PHR", "silabs-dch.phr", FT_UINT8, BASE_DEC, NULL, 0x0, "EFR32 PHR", HFILL}},
1408
16
      {&hf_efr32_phr_packetlen,
1409
16
       {"Packet Length", "silabs-dch.phr_packetlen", FT_UINT8, BASE_DEC, NULL, EFR32_PHR_PACKETLEN_MASK, "EFR32 PHR Packet Length", HFILL}},
1410
16
      {&hf_efr32_2bytephr,
1411
16
       {"2-Byte PHR", "silabs-dch.phr_2bytephr", FT_UINT16, BASE_DEC, NULL, 0x0, "EFR32 PHR 2-Byte", HFILL}},
1412
16
      {&hf_efr32_4bytephr,
1413
16
       {"4-Byte PHR", "silabs-dch.phr_4bytephr", FT_UINT32, BASE_DEC, NULL, 0x0, "EFR32 PHR 4-Byte", HFILL}},
1414
16
      {&hf_efr32_hwend,
1415
16
       {"HW End", "silabs-dch.hwend", FT_UINT8, BASE_HEX, VALS(silabs_efr32_hwend_values), 0x0, "EFR32 HW End", HFILL}},
1416
16
      {&hf_efr32_rssi,
1417
16
       {"RSSI", "silabs-dch.rssi", FT_INT8, BASE_DEC, NULL, 0x0, "EFR32 RSSI", HFILL}},
1418
16
      {&hf_efr32_syncword,
1419
16
       {"Syncword", "silabs-dch.syncword", FT_UINT32, BASE_HEX, NULL, 0x0, "EFR32 Syncword", HFILL}},
1420
16
      {&hf_efr32_radiocfg,
1421
16
       {"Radio Config", "silabs-dch.radio_cfg", FT_UINT8, BASE_HEX, NULL, 0x0, "EFR32 Radio Config", HFILL}},
1422
16
      {&hf_efr32_phyid,
1423
16
       {"Phy ID", "silabs-dch.phy_id", FT_UINT8, BASE_HEX, NULL, 0x0, "EFR32 Phy ID", HFILL}},
1424
16
      {&hf_efr32_radiocfg_addedbytes,
1425
16
       {"Added Bytes", "silabs-dch.radio_cfg_addedbytes", FT_UINT8, BASE_HEX, NULL, EFR32_RADIOCFG_ADDEDBYTES_MASK, "EFR32 Radio Config Added Bytes", HFILL}},
1426
16
      {&hf_efr32_radiocfg_blephyid,
1427
16
       {"BLE PHY Id", "silabs-dch.radio_cfg_blephyid", FT_UINT8, BASE_HEX, NULL, EFR32_RADIOCFG_BLEPHYID_MASK, "EFR32 Radio Config BLE PHY Id", HFILL}},
1428
16
      {&hf_efr32_radiocfg_regionid,
1429
16
       {"Z-Wave Region ID", "silabs-dch.radio_cfg_regionid", FT_UINT8, BASE_HEX, NULL, EFR32_RADIOCFG_REGIONID_MASK, "EFR32 Radio Config Z-Wave Region ID", HFILL}},
1430
16
      {&hf_efr32_radiocfg_2bytephr,
1431
16
       {"2-Byte PHR", "silabs-dch.radio_cfg_2bytephr", FT_BOOLEAN, 8, NULL, EFR32_RADIOCFG_2BYTEPHR_MASK, "EFR32 Radio Config 2-Byte PHR", HFILL}},
1432
16
      {&hf_efr32_radiocfg_softmodem,
1433
16
       {"Soft Modem", "silabs-dch.radio_cfg_softmodem", FT_BOOLEAN, 8, NULL, EFR32_RADIOCFG_SOFTMODEM_MASK, "EFR32 Radio Config Soft Modem", HFILL}},
1434
16
      {&hf_efr32_radiocfg_external,
1435
16
       {"External Radio Config", "silabs-dch.radio_cfg_external", FT_BOOLEAN, 8, NULL, EFR32_RADIOCFG_EXTERNAL_MASK, "EFR32 Radio Config External", HFILL}},
1436
16
      {&hf_efr32_radiocfg_id,
1437
16
       {"Radio Config Id", "silabs-dch.radio_cfg_id", FT_UINT8, BASE_HEX, NULL, EFR32_RADIOCFG_ID_MASK, "EFR32 Radio Config ID", HFILL}},
1438
16
      {&hf_efr32_radioinfo,
1439
16
       {"Radio Info", "silabs-dch.radio_info", FT_UINT8, BASE_HEX, NULL, 0x0, "EFR32 Radio Info", HFILL}},
1440
16
      {&hf_efr32_radioinfo_antenna,
1441
16
       {"Antenna Select", "silabs-dch.radio_info_antenna", FT_UINT8, BASE_HEX, NULL, EFR32_RADIOINFO_ANTENNA_MASK, "EFR32 Radio Info Antenna", HFILL}},
1442
16
      {&hf_efr32_radioinfo_syncword,
1443
16
       {"Syncword Select", "silabs-dch.radio_info_syncword", FT_UINT8, BASE_HEX, NULL, EFR32_RADIOINFO_SYNCWORD_MASK, "EFR32 Radio Info Syncword", HFILL}},
1444
16
      {&hf_efr32_radioinfo_channel,
1445
16
       {"Radio Info Channel", "silabs-dch.radio_info_channel", FT_UINT8, BASE_DEC, NULL, EFR32_RADIOINFO_CHANNEL_MASK, "EFR32 Radio Info Channel", HFILL}},
1446
16
      {&hf_efr32_channel,
1447
16
       {"Channel", "silabs-dch.channel", FT_UINT16, BASE_DEC, NULL, 0x0, "EFR32 Channel", HFILL}},
1448
16
      {&hf_efr32_status,
1449
16
       {"Status", "silabs-dch.status", FT_UINT8, BASE_HEX, NULL, 0x0, "EFR32 Status", HFILL}},
1450
16
      {&hf_efr32_status_errorcode,
1451
16
       {"Error Code", "silabs-dch.status_errorcode", FT_UINT8, BASE_HEX, NULL, EFR32_STATUS_ERRORCODE_MASK, "EFR32 Status Error Code", HFILL}},
1452
16
      {&hf_efr32_status_protocolid,
1453
16
       {"Protocol", "silabs-dch.status_protocolid", FT_UINT8, BASE_HEX, VALS(silabs_efr32_status_protcolid_values), EFR32_STATUS_PROTOCOLID_MASK, "EFR32 Status Protocol ID", HFILL}},
1454
16
      {&hf_efr32_appendedinfocfg,
1455
16
       {"Appended Info Config", "silabs-dch.appended_info_cfg", FT_UINT8, BASE_HEX, NULL, 0x0, "EFR32 Appended Info Config", HFILL}},
1456
16
      {&hf_efr32_appendedinfocfg_txrx,
1457
16
       {"Tx/Rx", "silabs-dch.appended_info_cfg_txrx", FT_UINT8, BASE_HEX, VALS(silabs_efr32_appendedinfocfg_txrx_values), EFR32_APPENDEDINFOCFG_TXRX_MASK, "EFR32 Appended Info Config Tx/Rx", HFILL}},
1458
16
      {&hf_efr32_appendedinfocfg_length,
1459
16
       {"Appended Info Length", "silabs-dch.appended_info_cfg_length", FT_UINT8, BASE_DEC, NULL, EFR32_APPENDEDINFOCFG_LENGTH_MASK, "EFR32 Appended Info Config Length", HFILL}},
1460
16
      {&hf_efr32_appendedinfocfg_version,
1461
16
       {"Appended Info Version", "silabs-dch.appended_info_cfg_version", FT_UINT8, BASE_DEC, NULL, EFR32_APPENDEDINFOCFG_VERSION_MASK, "EFR32 Appended Info Config Version", HFILL}},
1462
1463
      /* Wi-SUN PHY Header */
1464
16
      {&hf_phr_fsk,
1465
16
       {"FSK PHR", "silabs-dch.phr_fsk", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1466
16
      {&hf_phr_wisun_fsk_ms,
1467
16
       {"Wi-SUN Mode Switch PHR", "silabs-dch.phr_wisun_fsk_ms", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1468
16
      {&hf_phr_ofdm,
1469
16
       {"OFDM PHR", "silabs-dch.phr_ofdm", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1470
16
      {&hf_phr_fsk_ms,
1471
16
       {"MS", "silabs-dch.phr_fsk.ms", FT_BOOLEAN, 16, NULL, PHR_FSK_MS, "PHR SunFSK MS", HFILL}},
1472
16
      {&hf_phr_fsk_fcs,
1473
16
       {"FCS Type", "silabs-dch.phr_fsk.fcs", FT_BOOLEAN, 16, NULL, PHR_FSK_FCS, "PHR SunFSK FCS", HFILL}},
1474
16
      {&hf_phr_fsk_dw,
1475
16
       {"DW", "silabs-dch.phr_fsk.dw", FT_BOOLEAN, 16, NULL, PHR_FSK_DW, "Data Whitening", HFILL}},
1476
16
      {&hf_phr_fsk_length,
1477
16
       {"Frame Length", "silabs-dch.phr_fsk.length", FT_UINT16, BASE_DEC, NULL, PHR_FSK_LENGTH, NULL, HFILL}},
1478
16
      {&hf_phr_fsk_ms_checksum,
1479
16
       {"Checksum", "silabs-dch.phr_fsk_ms.checksum", FT_UINT16, BASE_HEX, NULL, PHR_FSK_MS_CHECKSUM, "BCH(15,11) checksum", HFILL}},
1480
16
      {&hf_phr_fsk_ms_parity,
1481
16
       {"Parity", "silabs-dch.phr_fsk_ms.parity", FT_UINT16, BASE_HEX, NULL, PHR_FSK_MS_PARITY, "Parity Check bit", HFILL}},
1482
16
      {&hf_phr_wisun_fsk_ms_reserved,
1483
16
       {"Reserved", "silabs-dch.phr_wisun_fsk_ms.reserved", FT_UINT16, BASE_HEX, NULL, PHR_WISUN_FSK_MS_RESERVED, NULL, HFILL}},
1484
16
      {&hf_phr_wisun_fsk_ms_phymodeid,
1485
16
       {"PhyModeId", "silabs-dch.phr_wisun_fsk_ms.phymodeid", FT_UINT16, BASE_HEX, VALS(phr_wisun_phymodeid_values), PHR_WISUN_FSK_MS_PHYMODEID, "New Wi-SUN PhyModeId", HFILL}},
1486
16
      {&hf_phr_ofdm_rate,
1487
16
       {"Rate", "silabs-dch.phr_ofdm.rate", FT_UINT24, BASE_DEC, VALS(phr_ofdm_rate_values), PHR_OFDM_RATE, NULL, HFILL}},
1488
16
      {&hf_phr_ofdm_length,
1489
16
       {"Frame length", "silabs-dch.phr_ofdm.length", FT_UINT24, BASE_DEC, NULL, PHR_OFDM_LENGTH, NULL, HFILL}},
1490
16
      {&hf_phr_ofdm_scrambler,
1491
16
       {"Scrambling seed", "silabs-dch.phr_ofdm.scrambler", FT_UINT24, BASE_HEX, VALS(phr_ofdm_scrambler_values), PHR_OFDM_SCRAMBLER, NULL, HFILL}},
1492
1493
16
  };
1494
1495
16
  static ei_register_info ei[] = {
1496
16
      {&ei_silabs_dch_unsupported_type,
1497
16
       {"silabs-dch.unsupported_dch_msg_type", PI_COMMENTS_GROUP, PI_NOTE, "Unsupported Debug Channel Message Type", EXPFILL}},
1498
16
      {&ei_silabs_dch_unsupported_protocol,
1499
16
       {"silabs-dch.unsupported_protocol", PI_COMMENTS_GROUP, PI_NOTE, "Unsupported EFR32 Protocol", EXPFILL}},
1500
16
      {&ei_silabs_dch_invalid_appendedinfolen,
1501
16
       {"silabs-dch.invalid_appendedinfolen", PI_MALFORMED, PI_ERROR, "Invalid Appended Info Length", EXPFILL}},
1502
16
  };
1503
1504
  // Register the protocol
1505
16
  proto_silabs_dch = proto_register_protocol("Silabs Debug Channel", "Silabs DCH", "silabs-dch");
1506
1507
  // Register field header
1508
16
  proto_register_field_array(proto_silabs_dch, hf, array_length(hf));
1509
1510
  // Register subtrees
1511
16
  proto_register_subtree_array(ett, array_length(ett));
1512
1513
16
  expert_module_t *expert_silabs_dch;
1514
16
  expert_silabs_dch = expert_register_protocol(proto_silabs_dch);
1515
16
  expert_register_field_array(expert_silabs_dch, ei, array_length(ei));
1516
1517
  // Register the dissector, obtain a handle.
1518
16
  silabs_dch_handle = register_dissector(
1519
16
      "silabs_dch",
1520
16
      dissect_silabs_dch,
1521
16
      proto_silabs_dch);
1522
1523
  // Initialize BLE connection tracking tree
1524
16
  silabs_ble_connections = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
1525
1526
16
  module_t *silabs_dch_module = prefs_register_protocol(proto_silabs_dch, NULL);
1527
16
  prefs_register_bool_preference(silabs_dch_module, "ble_sniffer_mode",
1528
16
      "BLE Sniffer Mode",
1529
16
      "Enable when the capture source is a BLE sniffer. "
1530
16
      "This disables BLE connection role tracking which doesn't work in a sniffer context.",
1531
16
      &pref_ble_sniffer_mode);
1532
16
}
1533
1534
/**
1535
 * Register handoff link
1536
 *
1537
 */
1538
void proto_reg_handoff_silabs_dch(void)
1539
16
{
1540
  /* FCS is the IEEE 802.15.4 CRC, with a length determined by the protocol ID. */
1541
16
  ieee802154fcs_handle = find_dissector("wpan_fcs");
1542
16
  ieee802154nofcs_handle = find_dissector("wpan_nofcs");
1543
16
  btle_handle = find_dissector("btle");
1544
  // Register top-level handoff, so that the toplevel WTAP will be
1545
  // decoded by the silabs dch dissector.
1546
16
  dissector_add_uint(
1547
16
      "wtap_encap",
1548
16
      WTAP_ENCAP_SILABS_DEBUG_CHANNEL,
1549
16
      silabs_dch_handle);
1550
16
}
1551
1552
/*
1553
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1554
 *
1555
 * Local variables:
1556
 * c-basic-offset: 4
1557
 * tab-width: 8
1558
 * indent-tabs-mode: nil
1559
 * End:
1560
 *
1561
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1562
 * :indentSize=4:tabSize=8:noTabs=true:
1563
 */