Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-5co-legacy.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-5co-legacy.c
2
 * Routines for FiveCo's Legacy Register Access Protocol dissector
3
 * Copyright 2021, Antoine Gardiol <antoine.gardiol@fiveco.ch>
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
 * This protocol allows access to FiveCo's Ethernet products registers with old legacy
14
 * protocol. Product list can be found under https://www.fiveco.ch/bus-converter-products.html.
15
 * Protocol description can be found (by example) in FMod-TCP xx manual that can be dowloaded from
16
 * https://www.fiveco.ch/product-fmod-tcp-db.html.
17
 * Note that this protocol is a question-answer protocol. It's header is composed of:
18
 * - 16 bits type
19
 * - 16 bits frame id
20
 * - 16 bits length of parameters (n)
21
 * - n bytes of parameters (depends upon packet type)
22
 * - 16 bits IP like checksum
23
 *
24
 * This build-in dissector is replacing a plugin dissector available from Wireshark 1.8.
25
 */
26
27
#include <config.h>
28
#include <epan/packet.h>
29
#include <epan/proto_data.h>
30
#include <wsutil/array.h>
31
#include "packet-tcp.h"
32
#include <stdio.h>
33
#include <stdbool.h>
34
#include <stdint.h>
35
/* Prototypes */
36
void proto_reg_handoff_FiveCoLegacy(void);
37
void proto_register_FiveCoLegacy(void);
38
39
static dissector_handle_t FiveCoLegacy_handle;
40
41
/****************************************************************************/
42
/* Definition declaration */
43
/****************************************************************************/
44
45
// Protocol header length and frame minimum length
46
0
#define FIVECO_LEGACY_HEADER_LENGTH 6
47
0
#define FIVECO_LEGACY_MIN_LENGTH FIVECO_LEGACY_HEADER_LENGTH + 2 // Checksum is 16 bits
48
49
14
#define PSNAME "5co-legacy"
50
51
/* Global sample ports preferences */
52
14
#define FIVECO_PORT1 8010     /* TCP port of the FiveCo protocol */
53
14
#define FIVECO_PORT2 8004     /* TCP port of the FiveCo protocol for web page upload */
54
14
#define FIVECO_UDP_PORT1 7010 /* UDP port of the FiveCo protocol */
55
56
/* 16 bits type known available functions */
57
enum fiveco_functions
58
{
59
    I2C_READ = 0x0001,
60
    I2C_WRITE,
61
    I2C_READ_ANSWER,
62
    I2C_WRITE_ANSWER,
63
    I2C_SCAN,
64
    I2C_SCAN_ANSWER,
65
    I2C_READ_WRITE_ACK,
66
    I2C_READ_WRITE_ACK_ANSWER,
67
    I2C_READ_WRITE_ACK_ERROR,
68
    READ_REGISTER = 0x0021,
69
    WRITE_REGISTER,
70
    READ_REGISTER_ANSWER,
71
    WRITE_REGISTER_ANSWER,
72
    WRITE_REGISTER_QUIET,
73
    EASY_IP_ADDRESS_CONFIG = 0x002A,
74
    EASY_IP_ADDRESS_CONFIG_ANSWER,
75
    FLASH_AREA_ERASE = 0x0031,
76
    FLASH_AREA_LOAD,
77
    FLASH_AREA_ANSWER
78
};
79
80
/* Forward references to functions */
81
static uint16_t
82
checksum_fiveco(tvbuff_t * byte_tab, uint16_t start_offset, uint16_t size);
83
static int fiveco_hash_equal(const void *v, const void *w);
84
85
/* Register decoding functions prototypes */
86
static void dispType( char *result, uint32_t type);
87
static void dispVersion( char *result, uint32_t type);
88
static void dispMAC( char *result, uint64_t type);
89
static void dispIP( char *result, uint32_t type);
90
static void dispMask( char *result, uint32_t type);
91
static void dispTimeout( char *result, uint32_t type);
92
93
/* Initialize the protocol and registered fields */
94
static int proto_FiveCoLegacy; /* Wireshark ID of the FiveCo protocol */
95
96
/* static dissector_handle_t data_handle = NULL; */
97
static int hf_fiveco_header;       /* The following hf_* variables are used to hold the Wireshark IDs of */
98
static int hf_fiveco_fct;          /* our header fields; they are filled out when we call */
99
static int hf_fiveco_id;           /* proto_register_field_array() in proto_register_fiveco() */
100
static int hf_fiveco_length;
101
static int hf_fiveco_data;
102
static int hf_fiveco_cks;
103
static int hf_fiveco_i2cadd;
104
static int hf_fiveco_i2c2write;
105
static int hf_fiveco_i2cwrite;
106
static int hf_fiveco_i2c2read;
107
static int hf_fiveco_i2c2scan;
108
static int hf_fiveco_i2canswer;
109
static int hf_fiveco_i2cwriteanswer;
110
static int hf_fiveco_i2cscaned;
111
static int hf_fiveco_i2cerror;
112
static int hf_fiveco_i2cack;
113
static int hf_fiveco_regread;
114
static int hf_fiveco_regreadunknown;
115
static int hf_fiveco_regreaduk;
116
static int hf_fiveco_EasyIPMAC;
117
static int hf_fiveco_EasyIPIP;
118
static int hf_fiveco_EasyIPSM;
119
120
static int ett_fiveco_header; /* These are the ids of the subtrees that we may be creating */
121
static int ett_fiveco_data;   /* for the header fields. */
122
static int ett_fiveco;
123
static int ett_fiveco_checksum;
124
125
/* Constants declaration */
126
static const value_string packettypenames[] = {
127
    {I2C_READ, "I2C Read (deprecated)"},
128
    {I2C_READ_ANSWER, "I2C Read Answer (deprecated)"},
129
    {I2C_WRITE, "I2C Write (deprecated)"},
130
    {I2C_WRITE_ANSWER, "I2C Write Answer (deprecated)"},
131
    {I2C_SCAN, "I2C Scan"},
132
    {I2C_SCAN_ANSWER, "I2C Scan Answer"},
133
    {I2C_READ_WRITE_ACK, "I2C Read and write with ack"},
134
    {I2C_READ_WRITE_ACK_ANSWER, "I2C Read and write with ack Answer"},
135
    {I2C_READ_WRITE_ACK_ERROR, "I2C Read and write error"},
136
    {READ_REGISTER, "Read register"},
137
    {READ_REGISTER_ANSWER, "Read register Answer"},
138
    {WRITE_REGISTER, "Write register"},
139
    {WRITE_REGISTER_ANSWER, "Write register Answer"},
140
    {WRITE_REGISTER_QUIET, "Write register (no answer wanted)"},
141
    {EASY_IP_ADDRESS_CONFIG, "Easy IP address config"},
142
    {EASY_IP_ADDRESS_CONFIG_ANSWER, "Easy IP address config Acknowledge"},
143
    {FLASH_AREA_ERASE, "Flash area Erase"},
144
    {FLASH_AREA_LOAD, "Flash area Upload"},
145
    {FLASH_AREA_ANSWER, "Flash area Answer"},
146
    {0, NULL}};
147
148
/* Conversation request key structure */
149
typedef struct
150
{
151
    uint32_t conversation;
152
    uint64_t unInternalID;
153
    uint16_t usExpCmd;
154
} FCOSConvRequestKey;
155
156
/* Conversation request value structure */
157
typedef struct
158
{
159
    uint16_t usParaLen;
160
    uint16_t isReplied;
161
    uint8_t *pDataBuffer;
162
} FCOSConvRequestVal;
163
164
/* Conversation hash tables */
165
static wmem_map_t *FiveCo_requests_hash;
166
167
/* Internal unique ID (used to match answer with question
168
   since some software set always 0 as packet ID in protocol header)
169
*/
170
static uint64_t g_unInternalID;
171
172
/* Register definition structure (used to detect known registers when it is possible) */
173
typedef struct
174
{
175
    uint32_t unValue;                                        // Register address
176
    uint32_t unSize;                                         // Register size (in bytes)
177
    const char *name;                                       // Register name
178
    const char *abbrev;                                     // Abbreviation for header fill
179
    const enum ftenum ft;                                   // Field type
180
    int nsWsHeaderID;                                      // Wireshark ID for header fill
181
    const void *pFct;                                       // Conversion function
182
} FCOSRegisterDef;
183
184
/* Known (common on every product) registers */
185
static FCOSRegisterDef aRegisters[] = {
186
    {0x00, 4, "Register Type/Model", "5co_legacy.RegTypeModel", FT_UINT32, -1, CF_FUNC(dispType)},
187
    {0x01, 4, "Register Version", "5co_legacy.RegVersion", FT_UINT32, -1, CF_FUNC(dispVersion)},
188
    {0x02, 0, "Function Reset device", "5co_legacy.RegReset", FT_NONE, -1, NULL},
189
    {0x03, 0, "Function Save user parameters", "5co_legacy.RegSave", FT_NONE, -1, NULL},
190
    {0x04, 0, "Function Restore user parameters", "5co_legacy.RegRestore", FT_NONE, -1, NULL},
191
    {0x05, 0, "Function Restore factory parameters", "5co_legacy.RegRestoreFact", FT_NONE, -1, NULL},
192
    {0x06, 0, "Function Save factory parameters", "5co_legacy.SaveFact", FT_NONE, -1, NULL},
193
    {0x07, 0, "Register unknown", "5co_legacy.RegUnknown07", FT_NONE, -1, NULL},
194
    {0x08, 0, "Register unknown", "5co_legacy.RegUnknown08", FT_NONE, -1, NULL},
195
    {0x09, 0, "Register unknown", "5co_legacy.RegUnknown09", FT_NONE, -1, NULL},
196
    {0x0A, 0, "Register unknown", "5co_legacy.RegUnknown0A", FT_NONE, -1, NULL},
197
    {0x0B, 0, "Register unknown", "5co_legacy.RegUnknown0B", FT_NONE, -1, NULL},
198
    {0x0C, 0, "Register unknown", "5co_legacy.RegUnknown0C", FT_NONE, -1, NULL},
199
    {0x0D, 0, "Register unknown", "5co_legacy.RegUnknown0D", FT_NONE, -1, NULL},
200
    {0x0E, 0, "Register unknown", "5co_legacy.RegUnknown0E", FT_NONE, -1, NULL},
201
    {0x0F, 0, "Register unknown", "5co_legacy.RegUnknown0F", FT_NONE, -1, NULL},
202
    {0x10, 4, "Register Communication options", "5co_legacy.RegComOption", FT_UINT32, -1, NULL},
203
    {0x11, 6, "Register Ethernet MAC Address", "5co_legacy.RegMAC", FT_UINT48, -1, CF_FUNC(dispMAC)},
204
    {0x12, 4, "Register IP Address", "5co_legacy.RegIPAdd", FT_UINT32, -1, CF_FUNC(dispIP)},
205
    {0x13, 4, "Register IP Mask", "5co_legacy.RegIPMask", FT_UINT32, -1, CF_FUNC(dispMask)},
206
    {0x14, 1, "Register TCP Timeout", "5co_legacy.RegTCPTimeout", FT_UINT8, -1, CF_FUNC(dispTimeout)},
207
    {0x15, 16, "Register Module name", "5co_legacy.RegName", FT_STRING, -1, NULL}};
208
209
    /* List of static header fields */
210
static hf_register_info hf_base[] = {
211
    {&hf_fiveco_header, {"Header", "5co_legacy.header", FT_NONE, BASE_NONE, NULL, 0x0, "Header of the packet", HFILL}},
212
    {&hf_fiveco_fct, {"Function", "5co_legacy.fct", FT_UINT16, BASE_HEX, VALS(packettypenames), 0x0, "Function type", HFILL}},
213
    {&hf_fiveco_id, {"Frame ID", "5co_legacy.id", FT_UINT16, BASE_DEC, NULL, 0x0, "Packet ID", HFILL}},
214
    {&hf_fiveco_length, {"Data length", "5co_legacy.length", FT_UINT16, BASE_DEC, NULL, 0x0, "Parameters length of the packet", HFILL}},
215
    {&hf_fiveco_data, {"Data", "5co_legacy.data", FT_NONE, BASE_NONE, NULL, 0x0, "Data (parameters)", HFILL}},
216
    {&hf_fiveco_cks, {"Checksum", "5co_legacy.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, "Checksum of the packet", HFILL}},
217
    {&hf_fiveco_i2cadd, {"I2C Address", "5co_legacy.i2cadd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
218
    {&hf_fiveco_i2c2write, {"I2C number of bytes to write", "5co_legacy.i2c2write", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
219
    {&hf_fiveco_i2cwrite, {"I2C bytes to write", "5co_legacy.i2cwrite", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
220
    {&hf_fiveco_i2c2read, {"I2C number of bytes to read", "5co_legacy.i2c2read", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
221
    {&hf_fiveco_i2canswer, {"I2C bytes read", "5co_legacy.i2cread", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
222
    {&hf_fiveco_i2cwriteanswer, {"I2C bytes write", "5co_legacy.i2writeanswer", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
223
    {&hf_fiveco_i2cack, {"I2C ack state", "5co_legacy.i2cack", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
224
    {&hf_fiveco_i2c2scan, {"I2C addresses to scan", "5co_legacy.i2c2scan", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
225
    {&hf_fiveco_i2cscaned, {"I2C addresses present", "5co_legacy.i2cscaned", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
226
    {&hf_fiveco_i2cerror, {"I2C error", "5co_legacy.i2cerror", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
227
    {&hf_fiveco_regread, {"Read", "5co_legacy.regread", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
228
    {&hf_fiveco_regreadunknown, {"Read Register unknown", "5co_legacy.hf_fiveco_regreadunknown", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
229
    {&hf_fiveco_regreaduk, {"Data not decoded", "5co_legacy.regreaduk", FT_NONE, BASE_NONE, NULL, 0x0, "Data not decoded because there are unable to map to a known register", HFILL}},
230
    {&hf_fiveco_EasyIPMAC, {"MAC address", "5co_legacy.EasyIPMAC", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL}},
231
    {&hf_fiveco_EasyIPIP, {"New IP address", "5co_legacy.EasyIPIP", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL}},
232
    {&hf_fiveco_EasyIPSM, {"New subnet mask", "5co_legacy.EasyIPSM", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL}}
233
 };
234
235
/*****************************************************************************/
236
/* Code to actually dissect the packets                                      */
237
/* Callback function for reassembled packet                                  */
238
/*****************************************************************************/
239
static int
240
dissect_FiveCoLegacy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
241
0
{
242
0
    uint16_t checksum_cal, checksum_rx;
243
0
    uint16_t i, j, y;
244
0
    uint16_t tcp_data_offset = 0;
245
0
    uint32_t tcp_data_length = 0;
246
0
    uint16_t header_type = 0;
247
0
    uint16_t header_id = 0;
248
0
    uint16_t header_data_length = 0;
249
0
    uint8_t data_i2c_length = 0;
250
0
    proto_item *fiveco_item = NULL;
251
0
    proto_item *fiveco_header_item = NULL;
252
0
    proto_item *fiveco_data_item = NULL;
253
0
    proto_tree *fiveco_tree = NULL;
254
0
    proto_tree *fiveco_header_tree = NULL;
255
0
    proto_tree *fiveco_data_tree = NULL;
256
0
    conversation_t *conversation;
257
0
    bool isRequest = false;
258
0
    uint64_t *pulInternalID = NULL;
259
0
    FCOSConvRequestKey requestKey, *pNewRequestKey;
260
0
    FCOSConvRequestVal *pRequestVal = NULL;
261
0
    tvbuff_t *pRequestTvb = NULL;
262
0
    uint8_t ucAdd, ucBytesToWrite, ucBytesToRead;
263
0
    uint8_t ucRegAdd, ucRegSize;
264
0
    uint32_t unOffset;
265
0
    uint32_t unSize;
266
267
    /* Load protocol payload length (including checksum) */
268
0
    tcp_data_length = tvb_captured_length(tvb);
269
0
    if (tcp_data_length < FIVECO_LEGACY_MIN_LENGTH) // Check checksum presence
270
0
        return 0;
271
272
    /* Display fiveco in protocol column */
273
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
274
    /* Clear out stuff in the info column */
275
0
    col_clear(pinfo->cinfo, COL_INFO);
276
277
    /* Look for all future TCP conversations between the
278
    * requestiong server and the FiveCo device using the
279
    * same src & dest addr and ports.
280
    */
281
0
    conversation = find_or_create_conversation(pinfo);
282
0
    requestKey.conversation = conversation->conv_index;
283
284
    /* Loop because several fiveco packets can be present in one TCP packet */
285
0
    while (tcp_data_offset < tcp_data_length) {
286
287
        /* Check that header type is correct */
288
0
        header_type = tvb_get_ntohs(tvb, tcp_data_offset + 0);
289
0
        if (try_val_to_str(header_type, packettypenames) == NULL)
290
0
            return 0;
291
292
        /* Read packet ID */
293
0
        header_id = tvb_get_ntohs(tvb, tcp_data_offset + 2);
294
295
        /* Check that there's enough data versus prot data header_data_length */
296
0
        header_data_length = tvb_get_ntohs(tvb, tcp_data_offset + 4);
297
0
        if (header_data_length > tcp_data_length - tcp_data_offset - 8) {
298
0
            return 0;
299
0
        }
300
301
        /* Get/Set internal ID for this packet number */
302
0
        pulInternalID = (uint64_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_FiveCoLegacy, pinfo->num);
303
        /* If internal ID is not set (null), create it */
304
0
        if (!pulInternalID)
305
0
        {
306
            /* If it is a new request, increment internal ID */
307
0
            if ((header_type == I2C_READ) || (header_type == I2C_WRITE) || (header_type == I2C_SCAN) ||
308
0
                (header_type == I2C_READ_WRITE_ACK) || (header_type == READ_REGISTER) || (header_type == WRITE_REGISTER))
309
0
            {
310
0
                isRequest = true;
311
0
                g_unInternalID++;   // Increment unique request ID and record it in the new request
312
                /* Note: Since some software do not increment packet id located in frame header
313
                we use an internal ID to match answers to request. */
314
0
            }
315
0
            pulInternalID = wmem_new(wmem_file_scope(), uint64_t);
316
0
            *pulInternalID = g_unInternalID;
317
0
            p_add_proto_data(wmem_file_scope(), pinfo, proto_FiveCoLegacy, pinfo->num, pulInternalID);
318
0
        }
319
320
        /* Get info about the request */
321
0
        requestKey.usExpCmd = header_type;
322
0
        requestKey.unInternalID = *pulInternalID;
323
0
        pRequestVal = (FCOSConvRequestVal *)wmem_map_lookup(FiveCo_requests_hash, &requestKey);
324
0
        if ((!pinfo->fd->visited) && (!pRequestVal) && (isRequest))
325
0
        {
326
            /* If unknown and if it is a request, allocate new hash element that we want to handle later in answer */
327
0
            pNewRequestKey = wmem_new(wmem_file_scope(), FCOSConvRequestKey);
328
0
            *pNewRequestKey = requestKey;
329
0
            pNewRequestKey->unInternalID = g_unInternalID;
330
0
            switch (header_type)
331
0
            {
332
0
            case I2C_READ:
333
0
                pNewRequestKey->usExpCmd = I2C_READ_ANSWER;
334
0
                break;
335
0
            case I2C_WRITE:
336
0
                pNewRequestKey->usExpCmd = I2C_WRITE_ANSWER;
337
0
                break;
338
0
            case I2C_SCAN:
339
0
                pNewRequestKey->usExpCmd = I2C_SCAN_ANSWER;
340
0
                break;
341
0
            case I2C_READ_WRITE_ACK:
342
0
                pNewRequestKey->usExpCmd = I2C_READ_WRITE_ACK_ANSWER;
343
0
                break;
344
0
            case READ_REGISTER:
345
0
                pNewRequestKey->usExpCmd = READ_REGISTER_ANSWER;
346
0
                break;
347
0
            }
348
349
0
            pRequestVal = wmem_new(wmem_file_scope(), FCOSConvRequestVal);
350
0
            pRequestVal->usParaLen = header_data_length;
351
0
            pRequestVal->isReplied = false;
352
0
            pRequestVal->pDataBuffer = (uint8_t *)wmem_alloc(wmem_file_scope(), header_data_length);
353
0
            tvb_memcpy(tvb, pRequestVal->pDataBuffer, tcp_data_offset + 6, header_data_length);
354
355
0
            wmem_map_insert(FiveCo_requests_hash, pNewRequestKey, pRequestVal);
356
0
        }
357
358
0
        if (pRequestVal) {
359
0
            pRequestTvb = tvb_new_child_real_data(tvb, pRequestVal->pDataBuffer, pRequestVal->usParaLen, pRequestVal->usParaLen);
360
0
        }
361
362
        /* Compute checksum of the packet and read one received */
363
0
        checksum_cal = checksum_fiveco(tvb, tcp_data_offset, header_data_length + 6);
364
0
        checksum_rx = tvb_get_ntohs(tvb, tcp_data_offset + header_data_length + 6);
365
366
        /* Add text to info column */
367
        /* If the offset != 0 (not first fiveco frame in tcp packet) add a comma in info column */
368
0
        if (tcp_data_offset != 0)
369
0
        {
370
0
            col_append_fstr(pinfo->cinfo, COL_INFO, ", %s ID=%d Len=%d",
371
0
                val_to_str(header_type, packettypenames, "Unknown Type:0x%02x"), header_id, header_data_length);
372
0
        }
373
0
        else
374
0
        {
375
0
            col_append_fstr(pinfo->cinfo, COL_INFO, "%s ID=%d Len=%d",
376
0
                val_to_str(header_type, packettypenames, "Unknown Type:0x%02x"), header_id, header_data_length);
377
0
        }
378
379
0
        if (checksum_rx != checksum_cal)
380
0
        {
381
0
            col_append_str(pinfo->cinfo, COL_INFO, " [BAD CHECKSUM !!]");
382
0
        }
383
384
        /* Add FiveCo protocol in tree (after TCP or UDP entry) */
385
0
        fiveco_item = proto_tree_add_item(tree, proto_FiveCoLegacy, tvb, tcp_data_offset + 0,
386
0
                                        header_data_length + 8, ENC_NA); /* Add a new entry inside tree display */
387
0
        proto_item_append_text(fiveco_item, " (%s)", val_to_str(header_type, packettypenames, "Unknown Type:0x%02x"));
388
389
        /* Add fiveco Protocol tree and sub trees for Header, Data and Checksum */
390
0
        fiveco_tree = proto_item_add_subtree(fiveco_item, ett_fiveco); // FiveCo prot tree
391
0
        fiveco_header_item = proto_tree_add_item(fiveco_tree, hf_fiveco_header,
392
0
                                                tvb, tcp_data_offset + 0, 6, ENC_NA); // Header tree
393
0
        fiveco_header_tree = proto_item_add_subtree(fiveco_header_item, ett_fiveco_header);
394
0
        proto_tree_add_item(fiveco_header_tree, hf_fiveco_fct,
395
0
                                    tvb, tcp_data_offset + 0, 2, ENC_BIG_ENDIAN); // Packet type (function) in Header
396
0
        proto_tree_add_item(fiveco_header_tree, hf_fiveco_id,
397
0
                                    tvb, tcp_data_offset + 2, 2, ENC_BIG_ENDIAN); // Packet ID in Header
398
0
        proto_tree_add_item(fiveco_header_tree, hf_fiveco_length,
399
0
                                    tvb, tcp_data_offset + 4, 2, ENC_BIG_ENDIAN); // Length of para in Header
400
401
0
        tcp_data_offset += 6; // put offset on start of data (parameters)
402
403
        // If there are parameters (data) in packet, display them in data sub tree
404
0
        if (header_data_length > 0)
405
0
        {
406
0
            fiveco_data_item = proto_tree_add_item(fiveco_tree, hf_fiveco_data, tvb, tcp_data_offset,
407
0
                                                header_data_length, ENC_NA); // Data tree
408
0
            fiveco_data_tree = proto_item_add_subtree(fiveco_data_item, ett_fiveco_data);
409
0
            switch (header_type)
410
0
            {
411
0
            case I2C_READ:
412
0
            case I2C_READ_WRITE_ACK:
413
0
                i = 0;
414
0
                while (i < header_data_length)
415
0
                {
416
0
                    proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cadd, tvb, tcp_data_offset + i, 1, ENC_BIG_ENDIAN);
417
0
                    i += 1;
418
0
                    data_i2c_length = tvb_get_uint8(tvb, tcp_data_offset + i);
419
0
                    proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2c2write, tvb, tcp_data_offset + i, 1, ENC_BIG_ENDIAN);
420
0
                    i += 1;
421
0
                    fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cwrite,
422
0
                                                        tvb, tcp_data_offset + i, data_i2c_length, ENC_NA);
423
0
                    proto_item_append_text(fiveco_data_item, ": ");
424
0
                    for (j = 0; j < data_i2c_length; j++)
425
0
                    {
426
0
                        proto_item_append_text(fiveco_data_item, "0x%.2X ",
427
0
                                            tvb_get_uint8(tvb, tcp_data_offset + i));
428
0
                        i += 1;
429
0
                    }
430
0
                    proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2c2read, tvb, tcp_data_offset + i, 1, ENC_BIG_ENDIAN);
431
0
                    i += 1;
432
0
                }
433
0
                break;
434
0
            case I2C_WRITE:
435
0
                i = 0;
436
0
                while (i < header_data_length)
437
0
                {
438
0
                    proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cadd, tvb, tcp_data_offset + i, 1, ENC_BIG_ENDIAN);
439
0
                    i += 1;
440
0
                    data_i2c_length = tvb_get_uint8(tvb, tcp_data_offset + i);
441
0
                    proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2c2write, tvb, tcp_data_offset + i, 1, ENC_BIG_ENDIAN);
442
0
                    i += 1;
443
0
                    fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cwrite,
444
0
                                                        tvb, tcp_data_offset + i, data_i2c_length, ENC_NA);
445
0
                    proto_item_append_text(fiveco_data_item, ": ");
446
0
                    for (j = 0; j < data_i2c_length; j++)
447
0
                    {
448
0
                        proto_item_append_text(fiveco_data_item, "0x%.2X ",
449
0
                                            tvb_get_uint8(tvb, tcp_data_offset + i));
450
0
                        i += 1;
451
0
                    }
452
0
                }
453
0
                break;
454
0
            case I2C_SCAN:
455
0
                fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2c2scan,
456
0
                                                    tvb, tcp_data_offset + 0, header_data_length, ENC_NA);
457
0
                proto_item_append_text(fiveco_data_item, ": ");
458
                // If specific address exists in packet, display them
459
0
                for (i = 0; i < header_data_length; i++)
460
0
                {
461
0
                    proto_item_append_text(fiveco_data_item, "0x%.2X ",
462
0
                                        tvb_get_uint8(tvb, tcp_data_offset + i));
463
0
                }
464
0
                break;
465
0
            case I2C_SCAN_ANSWER:
466
0
                fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cscaned,
467
0
                                                    tvb, tcp_data_offset + 0, header_data_length, ENC_NA);
468
0
                proto_item_append_text(fiveco_data_item, ": ");
469
                // Display slave address presents in answer
470
0
                for (i = 0; i < header_data_length; i++)
471
0
                {
472
0
                    proto_item_append_text(fiveco_data_item, "0x%.2X ",
473
0
                                        tvb_get_uint8(tvb, tcp_data_offset + i));
474
0
                }
475
0
                break;
476
0
            case I2C_READ_WRITE_ACK_ERROR:
477
0
                fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cerror,
478
0
                                                    tvb, tcp_data_offset + 0, header_data_length, ENC_NA);
479
0
                proto_item_append_text(fiveco_data_item, ": ");
480
0
                proto_item_append_text(fiveco_data_item, "0x%.2X ",
481
0
                                    tvb_get_uint8(tvb, tcp_data_offset));
482
0
                break;
483
0
            case READ_REGISTER:
484
                // List registers asked for read
485
0
                for (i = 0; i < header_data_length; i++)
486
0
                {
487
0
                    ucRegAdd = tvb_get_uint8(tvb, tcp_data_offset + i);
488
0
                    if ((ucRegAdd < array_length(aRegisters)) &&
489
0
                        (aRegisters[ucRegAdd].unValue == ucRegAdd))
490
0
                    {
491
0
                        fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_regread,
492
0
                                                                tvb, tcp_data_offset + i, 0, ENC_NA);
493
0
                        proto_item_append_text(fiveco_data_item, " %s", aRegisters[ucRegAdd].name);
494
0
                    }
495
0
                    else
496
0
                    {
497
0
                        fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_regreadunknown,
498
0
                            tvb, tcp_data_offset + i, 0, ENC_NA);
499
0
                    }
500
0
                    proto_item_append_text(fiveco_data_item, " (0x%.2X)", ucRegAdd);
501
0
                }
502
0
                break;
503
0
            case WRITE_REGISTER:
504
0
            case WRITE_REGISTER_QUIET:
505
                // List register asked to write with data to fill in until an unknown one is found
506
0
                for (i = tcp_data_offset; i < tcp_data_offset + header_data_length;)
507
0
                {
508
0
                    ucRegAdd = tvb_get_uint8(tvb, i++);
509
                    // If register address is known & found
510
0
                    if ((ucRegAdd < array_length(aRegisters)) &&
511
0
                        (aRegisters[ucRegAdd].unValue == ucRegAdd))
512
0
                    {
513
0
                        ucRegSize = aRegisters[ucRegAdd].unSize;
514
                        // If a display function is defined, call it
515
0
                        if (aRegisters[ucRegAdd].pFct != NULL)
516
0
                        {
517
0
                            proto_tree_add_item(fiveco_data_tree, aRegisters[ucRegAdd].nsWsHeaderID,
518
0
                                                    tvb, i, ucRegSize, ENC_NA);
519
0
                            i += ucRegSize;
520
0
                        }
521
                        // else if register type is string, display it as string
522
0
                        else if (aRegisters[ucRegAdd].ft == FT_STRING)
523
0
                        {
524
0
                            fiveco_data_item = proto_tree_add_item(fiveco_data_tree,
525
0
                                aRegisters[ucRegAdd].nsWsHeaderID,
526
0
                                tvb, i, ucRegSize,
527
0
                                ENC_NA);
528
0
                            proto_item_append_text(fiveco_data_item, ": %s", tvb_format_text(pinfo->pool, tvb, i, ucRegSize));
529
0
                            i += ucRegSize;
530
0
                        }
531
                        // else display raw data in hex
532
0
                        else
533
0
                        {
534
0
                            fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_regread,
535
0
                                tvb, i, ucRegSize, ENC_NA);
536
0
                            proto_item_append_text(fiveco_data_item, " %s (Add: 0x%.2X, Size: %d bytes): ",
537
0
                                aRegisters[ucRegAdd].name, ucRegAdd, ucRegSize);
538
0
                            for (j = 0; j < ucRegSize; j++)
539
0
                            {
540
0
                                proto_item_append_text(fiveco_data_item, "0x%.2X ", tvb_get_uint8(tvb, i++));
541
0
                            }
542
0
                        }
543
0
                    }
544
                    // Else tell user that data cannot be interpreted
545
0
                    else
546
0
                    {
547
0
                        fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_regreaduk,
548
0
                                                            tvb, i, tcp_data_offset + header_data_length - i, ENC_NA);
549
0
                        proto_item_append_text(fiveco_data_item, " (Interpretation depends on product type)");
550
0
                        break;
551
0
                    }
552
0
                }
553
0
                break;
554
0
            case EASY_IP_ADDRESS_CONFIG:
555
0
                proto_tree_add_item(fiveco_data_tree, hf_fiveco_EasyIPMAC, tvb, tcp_data_offset + 0, 6, ENC_NA);
556
0
                proto_tree_add_item(fiveco_data_tree, hf_fiveco_EasyIPIP, tvb, tcp_data_offset + 6, 4, ENC_BIG_ENDIAN);
557
0
                proto_tree_add_item(fiveco_data_tree, hf_fiveco_EasyIPSM, tvb, tcp_data_offset + 10, 4, ENC_BIG_ENDIAN);
558
0
                break;
559
0
            case I2C_READ_ANSWER:
560
0
            case I2C_WRITE_ANSWER:
561
0
            case I2C_READ_WRITE_ACK_ANSWER:
562
0
                if (pRequestVal)
563
0
                {
564
0
                    if (pRequestVal->isReplied != 0)
565
0
                    {
566
0
                        proto_item_append_text(fiveco_data_item,
567
0
                                            " WARNING : Answer already found ! Maybe packets ID not incremented.");
568
0
                    }
569
0
                    else
570
0
                    {
571
0
                        i = tcp_data_offset; // Answer index
572
0
                        y = 0;               // Request index
573
0
                        while ((y < pRequestVal->usParaLen) && (i < tcp_data_offset + header_data_length))
574
0
                        {
575
                            // I2C address in first byte of request
576
0
                            ucAdd = tvb_get_uint8(pRequestTvb, y++);
577
                            // Read number of bytes to write
578
0
                            ucBytesToWrite = tvb_get_uint8(pRequestTvb, y);
579
                            // Skip number of bytes to write and those bytes
580
0
                            y += 1 + ucBytesToWrite;
581
                            // Read number of bytes to read
582
0
                            ucBytesToRead = tvb_get_uint8(pRequestTvb, y++);
583
0
                            if (ucBytesToRead > 0)
584
0
                            {
585
0
                                fiveco_data_item = proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2canswer,
586
0
                                                                    tvb, i, ucBytesToRead, ENC_NA);
587
0
                                proto_item_append_text(fiveco_data_item,
588
0
                                                    " from address %d (%d bytes written) : ",
589
0
                                                    ucAdd, ucBytesToWrite);
590
0
                                for (j = 0; j < ucBytesToRead; j++)
591
0
                                {
592
0
                                    proto_item_append_text(fiveco_data_item, "0x%.2X ",
593
0
                                                        tvb_get_uint8(tvb, i++));
594
0
                                }
595
0
                                if (header_type == 0x08)
596
0
                                    proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cack, tvb, i++, 1, ENC_BIG_ENDIAN);
597
0
                            }
598
0
                            else if (header_type == I2C_READ_WRITE_ACK_ANSWER)
599
0
                            {
600
                                // if it's an answer to a write but with ack, display it
601
0
                                fiveco_data_item = proto_tree_add_item(fiveco_data_tree,
602
0
                                                                    hf_fiveco_i2cwriteanswer, tvb, i,
603
0
                                                                    ucBytesToRead, ENC_NA);
604
0
                                proto_item_append_text(fiveco_data_item, " to address %d (%d bytes written)",
605
0
                                                    ucAdd, ucBytesToWrite);
606
0
                                proto_tree_add_item(fiveco_data_tree, hf_fiveco_i2cack, tvb, i++, 1, ENC_BIG_ENDIAN);
607
0
                            }
608
0
                        }
609
0
                    }
610
0
                    break;
611
0
                }
612
0
                else {
613
0
                    proto_item_append_text(fiveco_data_item, " (Interpretation depends on product type)");
614
0
                }
615
0
                break;
616
0
            case READ_REGISTER_ANSWER:
617
0
                if (pRequestVal)
618
0
                {
619
0
                    if (pRequestVal->isReplied != 0)
620
0
                    {
621
0
                        proto_item_append_text(fiveco_data_item,
622
0
                                            " WARNING : Answer already found ! Maybe packets ID not incremented.");
623
0
                    }
624
0
                    else
625
0
                    {
626
0
                        i = tcp_data_offset; // Answer index
627
0
                        y = 0;               // Request index
628
                        // For each request stored in the last read request of the conversation
629
0
                        while ((y < pRequestVal->usParaLen) && (i < tcp_data_offset + header_data_length))
630
0
                        {
631
                            // Register address in first byte of request
632
0
                            ucRegAdd = tvb_get_uint8(pRequestTvb, y++);
633
                            // If register address is known & found in answer
634
0
                            if ((ucRegAdd < array_length(aRegisters)) &&
635
0
                                (aRegisters[ucRegAdd].unValue == ucRegAdd) &&
636
0
                                (ucRegAdd == tvb_get_uint8(tvb, i++)))
637
0
                            {
638
                                // Retrieve register size and display it with address
639
0
                                ucRegSize = aRegisters[ucRegAdd].unSize;
640
                                // If a display function is defined, call it
641
0
                                if (aRegisters[ucRegAdd].pFct != NULL)
642
0
                                {
643
0
                  proto_tree_add_item(fiveco_data_tree, aRegisters[ucRegAdd].nsWsHeaderID,
644
0
                                tvb, i, ucRegSize, ENC_NA);
645
0
                                    i += ucRegSize;
646
0
                                }
647
                                // else if register type is string, display it as string
648
0
                                else if (aRegisters[ucRegAdd].ft == FT_STRING)
649
0
                                {
650
0
                  fiveco_data_item = proto_tree_add_item(fiveco_data_tree,
651
0
                                aRegisters[ucRegAdd].nsWsHeaderID,
652
0
                                tvb, i, ucRegSize,
653
0
                                                            ENC_NA);
654
0
                                    proto_item_append_text(fiveco_data_item, ": %s", tvb_format_text(pinfo->pool, tvb, i, ucRegSize));
655
0
                                    i += ucRegSize;
656
0
                                }
657
                                // else display raw data in hex
658
0
                                else
659
0
                                {
660
0
                  fiveco_data_item = proto_tree_add_item(fiveco_data_tree,
661
0
                              hf_fiveco_regread, tvb, i, ucRegSize, ENC_NA);
662
0
                                    proto_item_append_text(fiveco_data_item,
663
0
                                                        " %s (Add: 0x%.2X, Size: %d bytes): ",
664
0
                                                        aRegisters[ucRegAdd].name, ucRegAdd, ucRegSize);
665
0
                                    for (j = 0; j < ucRegSize; j++)
666
0
                                    {
667
0
                                        proto_item_append_text(fiveco_data_item,
668
0
                                                            "0x%.2X ", tvb_get_uint8(tvb, i++));
669
0
                                    }
670
0
                                }
671
0
                            }
672
                            // Else tell user that data cannot be interpreted
673
0
                            else
674
0
                            {
675
0
                                fiveco_data_item = proto_tree_add_item(fiveco_data_tree,
676
0
                                                                    hf_fiveco_regreaduk, tvb, i,
677
0
                                                                    tcp_data_offset + header_data_length - i,
678
0
                                                                    ENC_NA);
679
0
                                proto_item_append_text(fiveco_data_item,
680
0
                                                    " (Interpretation depends on product type)");
681
0
                                break;
682
0
                            }
683
0
                        }
684
0
                    }
685
0
                }
686
0
                break;
687
0
            case FLASH_AREA_LOAD:
688
0
                unOffset = tvb_get_uint24(tvb, tcp_data_offset, ENC_BIG_ENDIAN);
689
0
                unSize = tvb_get_uint24(tvb, tcp_data_offset + 3, ENC_BIG_ENDIAN);
690
0
                proto_item_append_text(fiveco_data_item,
691
0
                                    " (%d bytes to load into flash at offset %d)", unSize, unOffset);
692
0
                break;
693
0
            case FLASH_AREA_ANSWER:
694
0
                if ( header_data_length > 1 ) {
695
0
                    proto_item_append_text(fiveco_data_item, " (%s)", tvb_format_text(pinfo->pool, tvb, tcp_data_offset, header_data_length - 1));
696
0
                }
697
0
                break;
698
699
0
            case WRITE_REGISTER_ANSWER:
700
0
            case FLASH_AREA_ERASE:
701
0
            case EASY_IP_ADDRESS_CONFIG_ANSWER:
702
0
                proto_item_append_text(fiveco_data_item, " (ERROR: No data should be present with that packet type !!)");
703
0
                break;
704
705
0
            default:
706
0
                proto_item_append_text(fiveco_data_item, " (Interpretation depends on product type)");
707
0
                break;
708
0
            }
709
0
        }
710
711
        // Checksum validation and sub tree
712
0
        proto_tree_add_checksum(fiveco_tree, tvb, tcp_data_offset + header_data_length, hf_fiveco_cks, -1, NULL, NULL,
713
0
            checksum_cal, ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
714
715
0
        tcp_data_offset += header_data_length + 2 ; /* jump to next packet if exists */
716
0
    } /*while (tcp_data_offset < tcp_data_length) */
717
718
0
    return tvb_captured_length(tvb);
719
0
}
720
721
/*****************************************************************************/
722
/* This function returns the calculated checksum (IP based)                  */
723
/*****************************************************************************/
724
static uint16_t checksum_fiveco(tvbuff_t *byte_tab, uint16_t start_offset, uint16_t size)
725
0
{
726
0
  uint32_t Sum      = 0;
727
0
  uint8_t AddHighByte = 1;
728
0
  uint32_t ChecksumCalculated;
729
0
  uint16_t i;
730
0
  uint8_t temp;
731
732
0
  for (i = 0; i < size; i++)
733
0
    {
734
0
        tvb_memcpy(byte_tab, (uint8_t *)&temp, start_offset + i, 1);
735
0
        if (AddHighByte)
736
0
        {
737
0
            Sum += (temp << 8) ^ 0xFF00;
738
0
            AddHighByte = 0;
739
0
        }
740
0
        else
741
0
        {
742
0
            Sum += (temp) ^ 0x00FF;
743
0
            AddHighByte = 1;
744
0
        }
745
0
    }
746
747
0
    if (AddHighByte == 0)
748
0
        Sum += 0xFF;
749
750
0
    ChecksumCalculated = ((Sum >> 16) & 0xFFFF) + (Sum & 0xFFFF);
751
0
    ChecksumCalculated = ((ChecksumCalculated >> 16) & 0xFFFF) + (ChecksumCalculated & 0xFFFF);
752
0
    return (uint16_t)ChecksumCalculated;
753
0
}
754
755
/*****************************************************************************/
756
/* Compute an unique hash value                                              */
757
/*****************************************************************************/
758
static unsigned fiveco_hash(const void *v)
759
0
{
760
0
    const FCOSConvRequestKey *key = (const FCOSConvRequestKey *)v;
761
0
    unsigned val;
762
763
0
    val = key->conversation + (((key->usExpCmd) & 0xFFFF) << 16) +
764
0
            (key->unInternalID & 0xFFFFFFFF) + ((key->unInternalID >>32) & 0xFFFFFFFF);
765
766
0
    return val;
767
0
}
768
769
/*****************************************************************************/
770
/* Check hash equal                                                          */
771
/*****************************************************************************/
772
static int fiveco_hash_equal(const void *v, const void *w)
773
0
{
774
0
    const FCOSConvRequestKey *v1 = (const FCOSConvRequestKey *)v;
775
0
    const FCOSConvRequestKey *v2 = (const FCOSConvRequestKey *)w;
776
777
0
    if (v1->conversation == v2->conversation &&
778
0
        v1->usExpCmd == v2->usExpCmd &&
779
0
        v1->unInternalID == v2->unInternalID)
780
0
    {
781
0
        return 1;
782
0
    }
783
0
    return 0;
784
0
}
785
786
/*****************************************************************************/
787
/* Register the protocol with Wireshark.
788
 *
789
 * This format is required because a script is used to build the C function that
790
 * calls all the protocol registration.
791
 */
792
/*****************************************************************************/
793
void proto_register_FiveCoLegacy(void)
794
14
{
795
    /* Setup list of header fields (based on static table and specific table) */
796
14
    static hf_register_info hf[array_length(hf_base) + array_length(aRegisters)];
797
322
    for (uint32_t i = 0; i < array_length(hf_base); i++) {
798
308
        hf[i] = hf_base[i];
799
308
    }
800
322
    for (uint32_t i = 0; i < array_length(aRegisters); i++) {
801
308
        if (aRegisters[i].pFct != NULL){
802
84
            hf_register_info hfx = { &(aRegisters[i].nsWsHeaderID),{aRegisters[i].name, aRegisters[i].abbrev, aRegisters[i].ft, BASE_CUSTOM, aRegisters[i].pFct, 0x0, NULL, HFILL}};
803
84
            hf[array_length(hf_base) + i] = hfx;
804
224
        } else {
805
224
            hf_register_info hfx = { &(aRegisters[i].nsWsHeaderID),{aRegisters[i].name, aRegisters[i].abbrev, FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}};
806
224
            hf[array_length(hf_base) + i] = hfx;
807
224
        }
808
308
    }
809
810
    /* Setup protocol subtree array */
811
14
    static int *ett[] = {
812
14
        &ett_fiveco_header,
813
14
        &ett_fiveco_data,
814
14
        &ett_fiveco,
815
14
        &ett_fiveco_checksum};
816
817
    /* Register the protocol name and description */
818
14
    proto_FiveCoLegacy = proto_register_protocol("FiveCo's Legacy Register Access Protocol",
819
14
                                                 PSNAME, "5co_legacy");
820
821
    /* Required function calls to register the header fields and subtrees */
822
14
    proto_register_field_array(proto_FiveCoLegacy, hf, array_length(hf));
823
14
    proto_register_subtree_array(ett, array_length(ett));
824
825
    /* Register the dissector */
826
14
    FiveCoLegacy_handle = register_dissector("5co_legacy", dissect_FiveCoLegacy,
827
14
                                                    proto_FiveCoLegacy);
828
829
14
    FiveCo_requests_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), fiveco_hash, fiveco_hash_equal);
830
831
    /* Set preference callback to NULL since it is not used */
832
14
    prefs_register_protocol(proto_FiveCoLegacy, NULL);
833
14
}
834
835
/* If this dissector uses sub-dissector registration add a registration routine.
836
 * This exact format is required because a script is used to find these
837
 * routines and create the code that calls these routines.
838
 *
839
 * Simpler form of proto_reg_handoff_FiveCoLegacy which can be used if there are
840
 * no prefs-dependent registration function calls. */
841
void proto_reg_handoff_FiveCoLegacy(void)
842
14
{
843
14
    static bool initialized = false;
844
845
14
    if (!initialized)
846
14
    {
847
14
        dissector_add_uint("tcp.port", FIVECO_PORT1, FiveCoLegacy_handle);
848
14
        dissector_add_uint("tcp.port", FIVECO_PORT2, FiveCoLegacy_handle);
849
14
        dissector_add_uint("udp.port", FIVECO_UDP_PORT1, FiveCoLegacy_handle);
850
14
        initialized = true;
851
14
    }
852
14
}
853
854
/*****************************************************************************/
855
/* Registers decoding functions                                              */
856
/*****************************************************************************/
857
static void
858
dispType( char *result, uint32_t type)
859
0
{
860
0
    int nValueH = (type>>16) & 0xFFFF;
861
0
    int nValueL = (type & 0xFFFF);
862
0
    snprintf( result, ITEM_LABEL_LENGTH, "%d.%d (%.4X.%.4X)", nValueH, nValueL, nValueH, nValueL);
863
0
}
864
865
static void
866
dispVersion( char *result, uint32_t version)
867
0
{
868
0
    if ((version & 0xFF000000) == 0)
869
0
    {
870
0
        int nValueH = (version>>16) & 0xFFFF;
871
0
        int nValueL = (version & 0xFFFF);
872
0
        snprintf( result, ITEM_LABEL_LENGTH, "FW: %d.%d", nValueH, nValueL);
873
0
    }
874
0
    else
875
0
    {
876
0
        int nHWHigh = (version>>24) & 0xFF;
877
0
        int nHWLow = (version>>16) & 0xFF;
878
0
        int nFWHigh = (version>>8) & 0xFF;
879
0
        int nFWLow = (version>>8) & 0xFF;
880
0
        snprintf( result, ITEM_LABEL_LENGTH, "HW: %d.%d / FW: %d.%d", nHWHigh, nHWLow, nFWHigh, nFWLow);
881
0
    }
882
0
}
883
884
static void dispMAC( char *result, uint64_t mac)
885
0
{
886
0
    uint8_t *pData = (uint8_t*)(&mac);
887
888
0
    snprintf( result, ITEM_LABEL_LENGTH, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X", pData[5], pData[4], pData[3], pData[2],
889
0
                           pData[1], pData[0]);
890
0
}
891
892
static void dispIP( char *result, uint32_t ip)
893
0
{
894
0
    uint8_t *pData = (uint8_t*)(&ip);
895
896
0
    snprintf( result, ITEM_LABEL_LENGTH, "%d.%d.%d.%d", pData[3], pData[2], pData[1], pData[0]);
897
0
}
898
899
static void dispMask( char *result, uint32_t mask)
900
0
{
901
0
    uint8_t *pData = (uint8_t*)(&mask);
902
903
0
    snprintf( result, ITEM_LABEL_LENGTH, "%d.%d.%d.%d", pData[3], pData[2], pData[1], pData[0]);
904
0
}
905
906
static void dispTimeout( char *result, uint32_t timeout)
907
0
{
908
0
    if (timeout != 0)
909
0
        snprintf( result, ITEM_LABEL_LENGTH, "%d seconds", timeout);
910
0
    else
911
0
        snprintf( result, ITEM_LABEL_LENGTH, "Disabled");
912
0
}
913
914
/*
915
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
916
 *
917
 * Local variables:
918
 * c-basic-offset: 4
919
 * tab-width: 8
920
 * indent-tabs-mode: nil
921
 * End:
922
 *
923
 * vi: set shiftwidth=4 tabstop=8 expandtab:
924
 * :indentSize=4:tabSize=8:noTabs=true:
925
 */