Coverage Report

Created: 2026-09-28 06:52

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