Bug Summary

File:builds/wireshark/wireshark/epan/dissectors/packet-trdp.c
Warning:line 1287, column 5
Potential leak of memory pointed to by 'endianenumvals'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-trdp.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-03-14-100340-3641-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-trdp.c
1/* packet-trdp.c
2 * Routines for trdp packet dissection
3 *
4 * The Train Real-Time Data Protocol (TRDP) is defined in IEC 61375-2-3. The
5 * protocol is used to exchange Train Communication Network (TCN) process data
6 * and message data.
7 *
8 * Copyright Bombardier Transportation Inc. or its subsidiaries and others, 2013. Florian Weispfenning
9 * Copyright Universität Rostock, 2019 (substantial changes leading to GLib-only version). Thorsten Schulz
10 * Copyright Stadler Deutschland GmbH, 2022-2025. Thorsten Schulz
11 *
12 * The new display-filter approach contains aspects and code
13 * snippets from the wimaxasncp dissector by Stephen Croll.
14 *
15 * Wireshark - Network traffic analyzer
16 * By Gerald Combs <[email protected]>
17 * Copyright 1998 Gerald Combs
18 *
19 * SPDX-License-Identifier: GPL-2.0-or-later
20 */
21
22#include <epan/packet.h>
23#include <epan/packet_info.h>
24#include <epan/prefs.h>
25#include <epan/crc32-tvb.h>
26#include <epan/column-utils.h>
27#include <epan/dissectors/packet-tcp.h>
28#include <epan/expert.h>
29#include <wsutil/report_message.h>
30#include <wsutil/filesystem.h>
31#include "packet-trdp-dict.h"
32
33
34/* packet-trdp-env.c */
35/*
36 * The SC-32 generator polynomial
37 */
38static const uint32_t sctab[256] = {
39 0x00000000U, 0xF4ACFB13U, 0x1DF50D35U, 0xE959F626U, 0x3BEA1A6AU,
40 0xCF46E179U, 0x261F175FU, 0xD2B3EC4CU, 0x77D434D4U, 0x8378CFC7U,
41 0x6A2139E1U, 0x9E8DC2F2U, 0x4C3E2EBEU, 0xB892D5ADU, 0x51CB238BU,
42 0xA567D898U, 0xEFA869A8U, 0x1B0492BBU, 0xF25D649DU, 0x06F19F8EU,
43 0xD44273C2U, 0x20EE88D1U, 0xC9B77EF7U, 0x3D1B85E4U, 0x987C5D7CU,
44 0x6CD0A66FU, 0x85895049U, 0x7125AB5AU, 0xA3964716U, 0x573ABC05U,
45 0xBE634A23U, 0x4ACFB130U, 0x2BFC2843U, 0xDF50D350U, 0x36092576U,
46 0xC2A5DE65U, 0x10163229U, 0xE4BAC93AU, 0x0DE33F1CU, 0xF94FC40FU,
47 0x5C281C97U, 0xA884E784U, 0x41DD11A2U, 0xB571EAB1U, 0x67C206FDU,
48 0x936EFDEEU, 0x7A370BC8U, 0x8E9BF0DBU, 0xC45441EBU, 0x30F8BAF8U,
49 0xD9A14CDEU, 0x2D0DB7CDU, 0xFFBE5B81U, 0x0B12A092U, 0xE24B56B4U,
50 0x16E7ADA7U, 0xB380753FU, 0x472C8E2CU, 0xAE75780AU, 0x5AD98319U,
51 0x886A6F55U, 0x7CC69446U, 0x959F6260U, 0x61339973U, 0x57F85086U,
52 0xA354AB95U, 0x4A0D5DB3U, 0xBEA1A6A0U, 0x6C124AECU, 0x98BEB1FFU,
53 0x71E747D9U, 0x854BBCCAU, 0x202C6452U, 0xD4809F41U, 0x3DD96967U,
54 0xC9759274U, 0x1BC67E38U, 0xEF6A852BU, 0x0633730DU, 0xF29F881EU,
55 0xB850392EU, 0x4CFCC23DU, 0xA5A5341BU, 0x5109CF08U, 0x83BA2344U,
56 0x7716D857U, 0x9E4F2E71U, 0x6AE3D562U, 0xCF840DFAU, 0x3B28F6E9U,
57 0xD27100CFU, 0x26DDFBDCU, 0xF46E1790U, 0x00C2EC83U, 0xE99B1AA5U,
58 0x1D37E1B6U, 0x7C0478C5U, 0x88A883D6U, 0x61F175F0U, 0x955D8EE3U,
59 0x47EE62AFU, 0xB34299BCU, 0x5A1B6F9AU, 0xAEB79489U, 0x0BD04C11U,
60 0xFF7CB702U, 0x16254124U, 0xE289BA37U, 0x303A567BU, 0xC496AD68U,
61 0x2DCF5B4EU, 0xD963A05DU, 0x93AC116DU, 0x6700EA7EU, 0x8E591C58U,
62 0x7AF5E74BU, 0xA8460B07U, 0x5CEAF014U, 0xB5B30632U, 0x411FFD21U,
63 0xE47825B9U, 0x10D4DEAAU, 0xF98D288CU, 0x0D21D39FU, 0xDF923FD3U,
64 0x2B3EC4C0U, 0xC26732E6U, 0x36CBC9F5U, 0xAFF0A10CU, 0x5B5C5A1FU,
65 0xB205AC39U, 0x46A9572AU, 0x941ABB66U, 0x60B64075U, 0x89EFB653U,
66 0x7D434D40U, 0xD82495D8U, 0x2C886ECBU, 0xC5D198EDU, 0x317D63FEU,
67 0xE3CE8FB2U, 0x176274A1U, 0xFE3B8287U, 0x0A977994U, 0x4058C8A4U,
68 0xB4F433B7U, 0x5DADC591U, 0xA9013E82U, 0x7BB2D2CEU, 0x8F1E29DDU,
69 0x6647DFFBU, 0x92EB24E8U, 0x378CFC70U, 0xC3200763U, 0x2A79F145U,
70 0xDED50A56U, 0x0C66E61AU, 0xF8CA1D09U, 0x1193EB2FU, 0xE53F103CU,
71 0x840C894FU, 0x70A0725CU, 0x99F9847AU, 0x6D557F69U, 0xBFE69325U,
72 0x4B4A6836U, 0xA2139E10U, 0x56BF6503U, 0xF3D8BD9BU, 0x07744688U,
73 0xEE2DB0AEU, 0x1A814BBDU, 0xC832A7F1U, 0x3C9E5CE2U, 0xD5C7AAC4U,
74 0x216B51D7U, 0x6BA4E0E7U, 0x9F081BF4U, 0x7651EDD2U, 0x82FD16C1U,
75 0x504EFA8DU, 0xA4E2019EU, 0x4DBBF7B8U, 0xB9170CABU, 0x1C70D433U,
76 0xE8DC2F20U, 0x0185D906U, 0xF5292215U, 0x279ACE59U, 0xD336354AU,
77 0x3A6FC36CU, 0xCEC3387FU, 0xF808F18AU, 0x0CA40A99U, 0xE5FDFCBFU,
78 0x115107ACU, 0xC3E2EBE0U, 0x374E10F3U, 0xDE17E6D5U, 0x2ABB1DC6U,
79 0x8FDCC55EU, 0x7B703E4DU, 0x9229C86BU, 0x66853378U, 0xB436DF34U,
80 0x409A2427U, 0xA9C3D201U, 0x5D6F2912U, 0x17A09822U, 0xE30C6331U,
81 0x0A559517U, 0xFEF96E04U, 0x2C4A8248U, 0xD8E6795BU, 0x31BF8F7DU,
82 0xC513746EU, 0x6074ACF6U, 0x94D857E5U, 0x7D81A1C3U, 0x892D5AD0U,
83 0x5B9EB69CU, 0xAF324D8FU, 0x466BBBA9U, 0xB2C740BAU, 0xD3F4D9C9U,
84 0x275822DAU, 0xCE01D4FCU, 0x3AAD2FEFU, 0xE81EC3A3U, 0x1CB238B0U,
85 0xF5EBCE96U, 0x01473585U, 0xA420ED1DU, 0x508C160EU, 0xB9D5E028U,
86 0x4D791B3BU, 0x9FCAF777U, 0x6B660C64U, 0x823FFA42U, 0x76930151U,
87 0x3C5CB061U, 0xC8F04B72U, 0x21A9BD54U, 0xD5054647U, 0x07B6AA0BU,
88 0xF31A5118U, 0x1A43A73EU, 0xEEEF5C2DU, 0x4B8884B5U, 0xBF247FA6U,
89 0x567D8980U, 0xA2D17293U, 0x70629EDFU, 0x84CE65CCU, 0x6D9793EAU,
90 0x993B68F9U };
91
92uint32_t trdp_sc32(const uint8_t buf[], uint32_t len, uint32_t sc) {
93 uint32_t i;
94
95 for (i = 0; i < len; i++) {
96 sc = sctab[((uint32_t)(sc >> 24) ^ buf[i]) & 0xff] ^ (sc << 8);
97 }
98 return sc;
99}
100
101int32_t trdp_dissect_width(uint32_t type) {
102 switch (type) {
103 case TRDP_BITSET81: // BITSET8 1
104 case TRDP_CHAR82: // CHAR8 2 char, can be used also as UTF8
105 case TRDP_INT84: // INT8 4 Signed integer, 8 bit
106 case TRDP_UINT88: // UINT8 8 Unsigned integer, 8 bit
107 return 1;
108 case TRDP_UTF163: // UTF16 3 Unicode UTF-16 character
109 case TRDP_INT165: // INT16 5 Signed integer, 16 bit
110 case TRDP_UINT169: // UINT16 9 Unsigned integer, 16 bit
111 return 2;
112 case TRDP_INT326: // INT32 6 Signed integer, 32 bit
113 case TRDP_UINT3210: // UINT32 10 Unsigned integer, 32 bit
114 case TRDP_REAL3212: // REAL32 12 Floating point real, 32 bit
115 case TRDP_TIMEDATE3214: // TIMEDATE32 14 32 bit UNIX time
116 case TRDP_SC3217: // SC32 17 SC-32, 32 bit
117 return 4;
118 case TRDP_INT647: // INT64 7 Signed integer, 64 bit
119 case TRDP_UINT6411: // UINT64 11 Unsigned integer, 64 bit
120 case TRDP_REAL6413: // REAL64 13 Floating point real, 64 bit
121 case TRDP_TIMEDATE6416: // TIMEDATE64 16 32 bit seconds and 32 bit
122 // microseconds
123 return 8;
124 case TRDP_TIMEDATE4815: // TIMEDATE48 15 48 bit TCN time (32 bit seconds
125 // and 16 bit ticks)
126 return 6;
127 case TRDP_UUID18: // UUID 18 UUID, not official but improves handling in WS
128 return 16;
129 default:
130 return -1;
131 }
132}
133/* end packet-trdp-env.c */
134
135#define API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 135, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 135, __FUNCTION__); } } while (0)
\
136 ws_noisy("%s:%d : %s\n", __FILE__, __LINE__, __FUNCTION__)do { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 136, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 136, __FUNCTION__); } } while (0)
137
138/* Reply status indication names
139 * Signed int: <0: NOK; 0: OK; >0: user reply status
140 * (taken from TRDP-EKE) */
141
142static const value_string reply_status_names[] = {
143 {-1, "Reserved"},
144 {-2, "Session abort"},
145 {-3, "No replier instance (at replier side)"},
146 {-4, "No memory (at replier side)"},
147 {-5, "No memory (local)"},
148 {-6, "No reply"},
149 {-7, "Not all replies"},
150 {-8, "No confirm"},
151 {-9, "Reserved"},
152 {-10, "Sending failed"},
153 {0, "Ok"},
154 {0, NULL((void*)0)}};
155
156/* TRDP-packet-type map */
157static const char *trdp_types[] = {
158 "Pr", "PD Request",
159 "Pp", "PD Reply ",
160 "Pe", "PD Error ",
161 "Pd", "PD Data ",
162 "Mn", "MD Notification (Req. w/o reply)",
163 "Mr", "MD Request with reply",
164 "Mp", "MD Reply ( w/o confrm)",
165 "Mq", "MD Reply (with confrm)",
166 "Mc", "MD Confirm",
167 "Me", "MD error ",
168 NULL((void*)0), "Unknown TRDP Type"
169};
170
171/* Initialize the protocol and registered fields */
172static int proto_trdp = -1;
173static dissector_handle_t trdp_handle;
174static dissector_handle_t trdp_TCP_handle;
175
176void proto_reg_handoff_trdp(void);
177void proto_register_trdp(void);
178
179/*For All*/
180static int hf_trdp_sequencecounter; /*uint32*/
181static int hf_trdp_protocolversion; /*uint16*/
182static int hf_trdp_type; /*uint16*/
183static int hf_trdp_etb_topocount; /*uint32*/
184static int hf_trdp_op_trn_topocount; /*uint32*/
185static int hf_trdp_comid; /*uint32*/
186static int hf_trdp_datasetlength; /*uint16*/
187static int hf_trdp_padding; /*bytes */
188
189/*For All (user data)*/
190static int hf_trdp_fcs_head; /*uint32*/
191static int hf_trdp_fcs_head_calc; /*uint32*/
192static int hf_trdp_userdata; /* userdata */
193
194/*needed only for PD messages*/
195static int hf_trdp_reserved; /*uint32*/
196static int hf_trdp_reply_comid; /*uint32*/ /*for MD-family only*/
197static int hf_trdp_reply_ipaddress; /*uint32*/
198
199/* needed only for MD messages*/
200static int hf_trdp_replystatus; /*uint32*/
201static int hf_trdp_sessionid; /*uuid*/
202static int hf_trdp_replytimeout; /*uint32*/
203static int hf_trdp_sourceURI; /*string*/
204static int hf_trdp_destinationURI; /*string*/
205
206/* Needed for dynamic content (Generated from convert_proto_tree_add_text.pl) */
207//static int hf_trdp_dataset_id;
208
209static bool_Bool g_basexml = TRUE(!(0));
210static const char *g_customTrdpDictionary; // XML Config Files String from ..Edit/Preference menu
211static unsigned int g_pd_port = TRDP_DEFAULT_UDP_PD_PORT17224;
212static unsigned int g_md_port = TRDP_DEFAULT_UDPTCP_MD_PORT17225;
213static bool_Bool g_scaled = TRUE(!(0));
214static bool_Bool g_strings_are_LE;
215static bool_Bool g_uids_are_LE;
216static bool_Bool g_char8_is_utf8 = TRUE(!(0));
217static bool_Bool g_0strings;
218static bool_Bool g_time_local = TRUE(!(0));
219static bool_Bool g_time_raw;
220static int g_bitset_subtype = TRDP_BITSUBTYPE_BOOL81;
221static int g_endian_subtype = TRDP_ENDSUBTYPE_BIG0;
222static unsigned int g_sid = TRDP_DEFAULT_SC32_SID0xFFFFFFFF;
223
224/* Initialize the subtree pointers */
225static int ett_trdp = -1;
226
227/* Expert fields */
228static expert_field ei_trdp_type_unkown;
229static expert_field ei_trdp_packet_small;
230static expert_field ei_trdp_userdata_empty;
231static expert_field ei_trdp_userdata_wrong;
232static expert_field ei_trdp_config_notparsed;
233static expert_field ei_trdp_padding_not_zero;
234static expert_field ei_trdp_array_wrong;
235static expert_field ei_trdp_faulty_antivalent;
236static expert_field ei_trdp_reserved_not_zero;
237static expert_field ei_trdp_sdtv2_safetycode;
238
239/* static container for dynamic fields and subtree handles */
240static struct {
241 wmem_array_t *hf;
242 wmem_array_t *ett;
243} trdp_build_dict;
244
245static TrdpDict *pTrdpParser;
246
247/******************************************************************************
248 * Local Functions
249 */
250
251/**
252 * @internal
253 * Compares the found CRC in a package with a calculated version
254 *
255 * @param tvb dissected package
256 * @param pinfo Necessary to mark status of this packet
257 * @param trdp_tree tree, where the information will be added as child
258 * @param offset the offset in the package where the (32bit) CRC is stored
259 * @param data_start start where the data begins, the CRC should be calculated from
260 * @param data_end end where the data stops, the CRC should be calculated from
261 */
262static void add_crc2tree(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *trdp_tree, uint32_t offset, uint32_t data_start, uint32_t data_end) {
263 uint32_t calced_crc, package_crc, length;
264 /* this must always fit */
265 if (data_start > data_end) return;
266
267 length = data_end - data_start;
268
269 package_crc = tvb_get_ntohl(tvb, offset);
270 calced_crc = g_ntohl(crc32_ccitt_tvb_offset(tvb, data_start, length))((((((guint32) ( (((guint32) (crc32_ccitt_tvb_offset(tvb, data_start
, length)) & (guint32) 0x000000ffU) << 24) | (((guint32
) (crc32_ccitt_tvb_offset(tvb, data_start, length)) & (guint32
) 0x0000ff00U) << 8) | (((guint32) (crc32_ccitt_tvb_offset
(tvb, data_start, length)) & (guint32) 0x00ff0000U) >>
8) | (((guint32) (crc32_ccitt_tvb_offset(tvb, data_start, length
)) & (guint32) 0xff000000U) >> 24)))))))
;
271
272 if (package_crc == calced_crc) {
273 proto_tree_add_uint_format_value(trdp_tree, hf_trdp_fcs_head, tvb, offset, 4, package_crc, "0x%04x [correct]", package_crc);
274 } else {
275 proto_tree_add_uint_format_value(trdp_tree, hf_trdp_fcs_head, tvb, offset, 4, package_crc, "0x%04x [mismatch]", package_crc);
276 proto_tree_add_uint_format_value(trdp_tree, hf_trdp_fcs_head_calc, tvb, offset, 4, calced_crc, "0x%04x [mismatch]", calced_crc);
277 }
278}
279
280/* @fn *static void checkPaddingAndOffset(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset)
281 *
282 * @brief Check for correct padding
283 *
284 * @param[in] tvb Buffer with the captured data
285 * @param[in] pinfo Necessary to mark status of this packet
286 * @param[in] tree The information is appended
287 * @param[in] offset Actual offset where the padding starts
288 *
289 * @return position in the buffer
290 */
291static int32_t checkPaddingAndOffset(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset) {
292 int32_t remainingBytes;
293 bool_Bool isPaddingZero = TRUE(!(0));
294
295 remainingBytes = tvb_reported_length_remaining(tvb, offset);
296 ws_noisy("The remaining bytes are %d (padding=%d)", remainingBytes, remainingBytes%4)do { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 296, __func__, "The remaining bytes are %d (padding=%d)", remainingBytes
, remainingBytes%4); } } while (0)
;
297
298 if (remainingBytes < 0) { /* There is no space for user data */
299 return offset;
300 } else if (remainingBytes > 0) {
301 for (int i = 0; i < remainingBytes; i++) {
302 if (tvb_get_uint8(tvb, offset + i) != 0) {
303 isPaddingZero = FALSE(0);
304 break;
305 }
306 }
307 proto_tree_add_bytes_format_value(tree, hf_trdp_padding, tvb, offset, remainingBytes, NULL((void*)0), "%s", (isPaddingZero ? "[ok]" : "not zero"));
308
309 /* Mark this packet in the statistics also as "not perfect" */
310 if (!isPaddingZero) expert_add_info_format(pinfo, tree, &ei_trdp_padding_not_zero, "Padding not zero");
311 }
312 return remainingBytes + TRDP_FCS_LENGTH4;
313}
314
315/** @fn uint32_t dissect_trdp_generic_body(tvbuff_t *tvb, packet_info *pinfo,
316 * proto_tree *trdp_tree, proto_tree *trdpRootNode, uint32_t trdp_comid, uint32_t
317 * offset, unsigned int clength, uint8_t dataset_level, const char *title, const int32_t
318 * arr_idx )
319 *
320 * @brief Extract all information from the userdata (uses the parsebody module for unmarshalling)
321 *
322 * @param tvb buffer
323 * @param pinfo info for the packet
324 * @param trdp_tree to which the information are added
325 * @param trdpRootNode Root node of the view of an TRDP packet (Necessary, as this function will be called recursively)
326 * @param trdp_comid the already extracted comId
327 * @param offset where the userdata starts in the TRDP packet
328 * @param clength Amount of bytes, that are transported for the users
329 * @param dataset_level is set to 0 for the beginning
330 * @param title presents the instance-name of the dataset for the sub-tree
331 * @param arr_idx index for presentation when a dataset occurs in an array element
332 *
333 * @return the actual offset in the packet
334 */
335// NOLINTNEXTLINE(misc-no-recursion) -- increment_dissection_depth() is used as guard
336static uint32_t dissect_trdp_generic_body(
337 tvbuff_t *tvb, packet_info *pinfo, proto_tree *trdp_tree, proto_tree *trdpRootNode, uint32_t trdp_comid,
338 uint32_t offset, unsigned int clength, uint8_t dataset_level, const char *title, const int32_t arr_idx)
339{
340
341 uint32_t start_offset = offset; /* mark beginning of the userdata in pkg */
342 int length;
343 const Dataset *ds = NULL((void*)0);
344 proto_tree *trdp_userdata = NULL((void*)0);
345 proto_tree *userdata_element = NULL((void*)0);
346 proto_item *pi = NULL((void*)0);
347 int array_index;
348 int element_count = 0;
349
350 /* make the userdata accessible for wireshark */
351 if (!dataset_level) {
352 if (!clength) return checkPaddingAndOffset(tvb, pinfo, trdp_tree, offset);
353
354 pi = proto_tree_add_item(trdp_tree, hf_trdp_userdata, tvb, offset, clength, ENC_NA0x00000000);
355
356 ws_debug("Searching for comid %u", trdp_comid)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 356, __func__, "Searching for comid %u", trdp_comid); } } while
(0)
;
357 const ComId *com = TrdpDict_lookup_ComId(pTrdpParser, trdp_comid);
358
359 if (!com) {
360 offset += clength;
361 return checkPaddingAndOffset(tvb, pinfo, trdp_tree, offset);
362 } else
363 ds = com->linkedDS;
364
365 /* so far, length was all userdata received, but this is not true for
366 * sub-datasets. */
367 /* but here we can check it works out */
368 length = ds ? ds->size : -1;
369
370 if (length < 0) { /* No valid configuration for this ComId available */
371 proto_tree_add_expert_format(trdp_userdata, pinfo, &ei_trdp_userdata_empty, tvb, offset, clength,
372 "Userdata should be empty or was incomplete, cannot parse. Check xml-config.");
373 ws_debug("No Dataset, %d byte of userdata -> end offset is %d [dataset-level: %d]", clength, offset, dataset_level)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 373, __func__, "No Dataset, %d byte of userdata -> end offset is %d [dataset-level: %d]"
, clength, offset, dataset_level); } } while (0)
;
374 offset += clength;
375 return checkPaddingAndOffset(tvb, pinfo, trdp_tree, offset);
376 }
377 } else {
378
379 ws_debug("Searching for dataset %u", trdp_comid)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 379, __func__, "Searching for dataset %u", trdp_comid); } }
while (0)
;
380 ds = TrdpDict_get_Dataset(pTrdpParser, trdp_comid /* <- datasetID */);
381
382 length = ds ? ds->size : -1;
383 if (length < 0) { /* this should actually not happen, ie. should be caught
384 in initial comID-round */
385 proto_tree_add_expert_format(trdp_userdata, pinfo, &ei_trdp_userdata_empty, tvb, offset, length,
386 "Userdata should be empty or was incomplete, cannot parse. Check xml-config.");
387 return offset;
388 }
389 }
390
391 ws_debug("%s aka %u ([%d] octets)", ds->name, ds->datasetId, length)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 391, __func__, "%s aka %u ([%d] octets)", ds->name, ds->
datasetId, length); } } while (0)
;
392 trdp_userdata = (arr_idx >= 0)
393 ? proto_tree_add_subtree_format(trdp_tree, tvb, offset, length ? length : -1, ds->ett_id, &pi, "%s.%d", title, arr_idx)
394 : (ds->source /* if custom, show its dataset-id*/
395 ? proto_tree_add_subtree_format(trdp_tree, tvb, offset, length ? length : -1, ds->ett_id, &pi, "%s: %s (%d)", title, ds->name, ds->datasetId)
396 : proto_tree_add_subtree_format(trdp_tree, tvb, offset, length ? length : -1, ds->ett_id, &pi, "%s: %s", title, ds->name));
397
398 array_index = 0;
399 int potential_array_size = -1;
400 for (Element *el = ds->listOfElements; el; el = el->next) {
401
402 ws_debug("[%d] Offset %5d ----> Element: type=%2d "do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 405, __func__, "[%d] Offset %5d ----> Element: type=%2d "
"%s\tname=%s\tarray-size=%d\tunit=%s\tscale=%f\toffset=%d", dataset_level
, offset, el->type.id, el->type.name, el->name, el->
array_size, el->unit, el->scale, el->offset); } } while
(0)
403 "%s\tname=%s\tarray-size=%d\tunit=%s\tscale=%f\toffset=%d",do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 405, __func__, "[%d] Offset %5d ----> Element: type=%2d "
"%s\tname=%s\tarray-size=%d\tunit=%s\tscale=%f\toffset=%d", dataset_level
, offset, el->type.id, el->type.name, el->name, el->
array_size, el->unit, el->scale, el->offset); } } while
(0)
404 dataset_level, offset, el->type.id, el->type.name, el->name,do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 405, __func__, "[%d] Offset %5d ----> Element: type=%2d "
"%s\tname=%s\tarray-size=%d\tunit=%s\tscale=%f\toffset=%d", dataset_level
, offset, el->type.id, el->type.name, el->name, el->
array_size, el->unit, el->scale, el->offset); } } while
(0)
405 el->array_size, el->unit, el->scale, el->offset)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 405, __func__, "[%d] Offset %5d ----> Element: type=%2d "
"%s\tname=%s\tarray-size=%d\tunit=%s\tscale=%f\toffset=%d", dataset_level
, offset, el->type.id, el->type.name, el->name, el->
array_size, el->unit, el->scale, el->offset); } } while
(0)
;
406
407 // at startup of a new item, check if it is an array or not
408 int remainder = 0;
409 element_count = el->array_size;
410
411 if (!element_count) { // handle variable element count
412
413 if (g_0strings && (el->type.id == TRDP_CHAR82 || el->type.id == TRDP_UTF163)) {
414 /* handle the special elements CHAR8 and UTF16: */
415
416 } else {
417 element_count = potential_array_size;
418
419 if (element_count < 1) {
420
421 if (element_count == 0) {
422 potential_array_size = -1;
423 continue; /* if, at the end of the day, the array is intentionally 0, skip the element */
424 } else {
425 expert_add_info_format(pinfo, trdp_tree, &ei_trdp_array_wrong, "%s : was introduced by an unsupported length field. (%d)", el->name, potential_array_size);
426 return 0; /* in this case, the whole packet is garbled */
427 }
428 } else {
429 ws_debug("[%d] Offset %5d Dynamic array, with %d elements found", dataset_level, offset, element_count)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 429, __func__, "[%d] Offset %5d Dynamic array, with %d elements found"
, dataset_level, offset, element_count); } } while (0)
;
430 }
431
432 // check if the specified amount could be found in the package
433 remainder = tvb_reported_length_remaining(tvb, offset);
434 if (remainder < TrdpDict_element_size(el, element_count)) {
435 expert_add_info_format(pinfo, trdp_tree, &ei_trdp_userdata_wrong, "%s : has %d elements [%d byte each], but only %d left", el->name, element_count, TrdpDict_element_size(el, 1), remainder);
436 element_count = 0;
437 }
438 }
439 }
440 if (element_count > 1) {
441 ws_debug("[%d] Offset %5d -- Array found, expecting %d elements using %d bytes", dataset_level, offset, element_count, TrdpDict_element_size(el, element_count))do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 441, __func__, "[%d] Offset %5d -- Array found, expecting %d elements using %d bytes"
, dataset_level, offset, element_count, TrdpDict_element_size
(el, element_count)); } } while (0)
;
442 }
443
444 /* For an array, inject a new node in the graphical dissector, tree (also the extracted dynamic information, see above are added) */
445 userdata_element = ((element_count == 1) || (el->type.id == TRDP_CHAR82) || (el->type.id == TRDP_UTF163)) /* for single line */
446 ? trdp_userdata /* take existing branch */
447 : proto_tree_add_subtree_format( trdp_userdata, tvb, offset,
448 TrdpDict_element_size(el, element_count),
449 el->ett_id, &pi,
450 "%s (%d) : %s[%d]", el->type.name, el->type.id, el->name, element_count);
451
452 do {
453 int64_t vals = 0;
454 uint64_t valu = 0;
455 const char *text = NULL((void*)0);
456 unsigned int slen = 0;
457 unsigned int bytelen = 0;
458 double real64 = 0;
459 nstime_t nstime = {0, 0};
460 char bits[TRDP_BITSUBTYPE_BITS8+1];
461 uint32_t package_crc = 0;
462 uint32_t calced_crc, buff_length;
463 uint8_t *pBuff;
464 e_guid_t guid;
465
466 switch (el->type.id) {
467
468 case TRDP_BITSET81:
469 switch (el->type.subtype) {
470 case TRDP_BITSUBTYPE_BOOL81:
471 valu = tvb_get_uint8(tvb, offset);
472 proto_tree_add_boolean(userdata_element, el->hf_id, tvb, offset, el->width, (uint32_t)valu);
473 offset += el->width;
474 break;
475 case TRDP_BITSUBTYPE_BITSET80:
476 if (!el->bitfields) {
477 valu = tvb_get_uint8(tvb, offset);
478 bits[sizeof(bits) - 1] = 0;
479 uint64_t v = valu;
480 for (int i = sizeof(bits) - 1; i--; v >>= 1) bits[i] = v & 1 ? '1' : '.';
481 proto_tree_add_uint_format_value(userdata_element, el->hf_id, tvb, offset, el->width, (uint32_t)valu,
482 "0x%#02x ( %s )", (uint32_t)valu, bits);
483 } else {
484 proto_tree_add_bitmask(userdata_element, tvb, offset, el->hf_id, el->bits_ett_id, el->bitfields, ENC_BIG_ENDIAN0x00000000);
485 }
486 offset += el->width;
487 break;
488 case TRDP_BITSUBTYPE_ANTIVALENT82:
489 valu = tvb_get_uint8(tvb, offset);
490 switch (valu) {
491 case 1:
492 proto_tree_add_boolean(userdata_element, el->hf_id, tvb, offset, el->width, (uint32_t)FALSE(0));
493 break;
494
495 case 2:
496 proto_tree_add_boolean(userdata_element, el->hf_id, tvb, offset, el->width, (uint32_t)TRUE(!(0)));
497 break;
498
499 default:
500 proto_tree_add_expert_format(userdata_element, pinfo, &ei_trdp_faulty_antivalent, tvb, offset, el->width,
501 "%#2x is an invalid ANTIVALENT8 value.", (uint32_t)valu);
502 break;
503 }
504 offset += el->width;
505 break;
506 }
507 break;
508
509 case TRDP_CHAR82:
510 bytelen = (element_count || !g_0strings) ? (unsigned int)element_count : tvb_strsize(tvb, offset);
511 slen = (element_count || !g_0strings) ? bytelen : (bytelen - 1);
512 text = (g_char8_is_utf8 && element_count > 1)
513 ? (const char *)tvb_get_string_enc(pinfo->pool, tvb, offset, slen, ENC_UTF_80x00000002)
514 : tvb_format_text(pinfo->pool, tvb, offset, slen);
515
516 if (element_count == 1)
517 proto_tree_add_string(userdata_element, el->hf_id, tvb, offset, bytelen, text);
518 else
519 proto_tree_add_string_format_value(userdata_element, el->hf_id, tvb, offset, bytelen, text, "[%d] \"%s\"", slen, text);
520 offset += bytelen;
521 element_count = 1;
522 break;
523
524 case TRDP_UTF163:
525 bytelen = (element_count || !g_0strings) ? (unsigned int)(2 * element_count) : tvb_unicode_strsize(tvb, offset);
526 slen = (element_count || !g_0strings) ? bytelen : (bytelen - 2);
527 text = (const char *)tvb_get_string_enc(pinfo->pool, tvb, offset, slen, ENC_UTF_160x00000004 | (g_strings_are_LE ? ENC_LITTLE_ENDIAN0x80000000 : ENC_BIG_ENDIAN0x00000000));
528 proto_tree_add_string_format_value(userdata_element, el->hf_id, tvb, offset, bytelen, text, "[%d] \"%s\"", slen / 2, text);
529 offset += bytelen;
530 element_count = 1;
531 break;
532
533 case TRDP_INT84:
534 vals = tvb_get_int8(tvb, offset);
535 break;
536
537 case TRDP_INT165:
538 vals = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohis(tvb, offset) : tvb_get_ntohis(tvb, offset);
539 break;
540
541 case TRDP_INT326:
542 vals = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohil(tvb, offset) : tvb_get_ntohil(tvb, offset);
543 break;
544
545 case TRDP_INT647:
546 vals = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohi64(tvb, offset) : tvb_get_ntohi64(tvb, offset);
547 break;
548
549 case TRDP_UINT88:
550 valu = tvb_get_uint8(tvb, offset);
551 break;
552
553 case TRDP_UINT169:
554 valu = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset);
555 break;
556
557 case TRDP_UINT3210:
558 valu = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset);
559 break;
560
561 case TRDP_UINT6411:
562 valu = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letoh64(tvb, offset) : tvb_get_ntoh64(tvb, offset);
563 break;
564
565 case TRDP_REAL3212:
566 real64 = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohieee_float(tvb, offset) : tvb_get_ntohieee_float(tvb, offset);
567 break;
568
569 case TRDP_REAL6413:
570 real64 = el->type.subtype == TRDP_ENDSUBTYPE_LIT1 ? tvb_get_letohieee_double(tvb, offset) : tvb_get_ntohieee_double(tvb, offset);
571 break;
572
573 case TRDP_TIMEDATE3214:
574 /* This should be time_t from general understanding, which is UNIX time,
575 * seconds since 1970 time_t is a signed long in modern POSIX ABIs, ie.
576 * often s64! However, vos_types.h defines this as u32, which may
577 * introduce some odd complications -- later. IEC61375-2-1 says for
578 * UNIX-time: SIGNED32 - ok, will respect!
579 */
580 vals = tvb_get_ntohil(tvb, offset);
581 nstime.secs = (long int)vals;
582 break;
583
584 case TRDP_TIMEDATE4815:
585 vals = tvb_get_ntohil(tvb, offset);
586 nstime.secs = (time_t)vals;
587 valu = tvb_get_ntohs(tvb, offset + 4);
588 nstime.nsecs = (int)(valu * (1000000000ULL / 256ULL)) / 256;
589 break;
590
591 case TRDP_TIMEDATE6416:
592 vals = tvb_get_ntohil(tvb, offset);
593 nstime.secs = (time_t)vals;
594 vals = tvb_get_ntohil(tvb, offset + 4);
595 nstime.nsecs = (int)vals * 1000;
596 break;
597
598 case TRDP_SC3217:
599 package_crc = tvb_get_ntohl(tvb, offset);
600 break;
601
602 case TRDP_UUID18:
603 tvb_get_guid(tvb, offset, &guid, (g_uids_are_LE ? ENC_LITTLE_ENDIAN0x80000000 : ENC_BIG_ENDIAN0x00000000));
604 break;
605
606 default:
607 ws_debug("Unique type %d for %s", el->type.id, el->name)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 607, __func__, "Unique type %d for %s", el->type.id, el->
name); } } while (0)
;
608 /* safe guard against excessive recursion of datasets.
609 * This should have been handled at dictionary reading. If it breaks here, it is some weired bug.
610 */
611 /* use wireshark's own protection. However, in the current dev-build of WS this value's (gui.max_tree_depth) default was much higher. */
612 /* be aware that each array introduces an extra level, as well as other protocol layers */
613 increment_dissection_depth(pinfo);
614
615 // NOLINTNEXTLINE(misc-no-recursion)
616 offset = dissect_trdp_generic_body( tvb, pinfo, userdata_element, trdpRootNode, el->type.id, offset, length - (offset - start_offset),
617 dataset_level + 1, el->name, (element_count != 1) ? array_index : -1);
618 decrement_dissection_depth(pinfo);
619
620 if (offset == 0) return offset; /* break dissecting, if things went sideways */
621 break;
622 }
623
624 switch (el->type.id) {
625
626 /* case TRDP_INT8 ... TRDP_INT64: */
627 case TRDP_INT84:
628 case TRDP_INT165:
629 case TRDP_INT326:
630 case TRDP_INT647:
631
632 if (g_ascii_strcasecmp(el->unit, "hide0") == 0) {
633 if (vals != 0) proto_tree_add_expert_format(userdata_element, pinfo, &ei_trdp_reserved_not_zero,
634 tvb, offset, el->width, "Element is not zero (%" G_GINT64_FORMAT"li" ").", vals);
635 } else if (el->scale && g_scaled) {
636 double formated_value = vals * el->scale + el->offset;
637 proto_tree_add_double_format_value(userdata_element, el->hf_id, tvb, offset, el->width, formated_value,
638 "%lg %s (raw=%" G_GINT64_FORMAT"li" ")", formated_value, el->unit, vals);
639 } else {
640 if (g_scaled) vals += el->offset;
641 proto_tree_add_int64(userdata_element, el->hf_id, tvb, offset, el->width, vals);
642 }
643 offset += el->width;
644 break;
645
646 /* case TRDP_UINT8 ... TRDP_UINT64: */
647 case TRDP_UINT88:
648 case TRDP_UINT169:
649 case TRDP_UINT3210:
650 case TRDP_UINT6411:
651 if (g_ascii_strcasecmp(el->unit, "hide0") == 0) {
652 if (valu != 0) proto_tree_add_expert_format(userdata_element, pinfo, &ei_trdp_reserved_not_zero,
653 tvb, offset, el->width, "Element is not zero (%" G_GUINT64_FORMAT"lu" ").", valu);
654 } else if (g_ascii_strcasecmp(el->unit, "version") == 0) {
655 proto_tree_add_uint_format_value(userdata_element, el->hf_id, tvb, offset, el->width, (uint32_t)valu, "%02"PRId64"l" "d"".%02"PRId64"l" "d""", (valu >> 8) & 0xff, (valu >> 0) & 0xff);
656 } else if (el->scale && g_scaled) {
657 double formated_value = valu * el->scale + el->offset;
658 proto_tree_add_double_format_value(userdata_element, el->hf_id, tvb, offset, el->width, formated_value,
659 "%lg %s (raw=%" G_GUINT64_FORMAT"lu" ")", formated_value, el->unit, valu);
660 } else {
661 if (g_scaled) valu += el->offset;
662 proto_tree_add_uint64(userdata_element, el->hf_id, tvb, offset, el->width, valu);
663 }
664 offset += el->width;
665 break;
666
667 case TRDP_REAL3212:
668 case TRDP_REAL6413:
669 if (el->scale && g_scaled) {
670 double formated_value = real64 * el->scale + el->offset;
671 proto_tree_add_double_format_value(userdata_element, el->hf_id, tvb, offset, el->width, formated_value,
672 "%lg %s (raw=%lf)", formated_value, el->unit, real64);
673 } else {
674 if (g_scaled) real64 += el->offset;
675 proto_tree_add_double(userdata_element, el->hf_id, tvb, offset, el->width, real64);
676 }
677 offset += el->width;
678 break;
679
680 /* case TRDP_TIMEDATE32 ... TRDP_TIMEDATE64: */
681 case TRDP_TIMEDATE3214:
682 case TRDP_TIMEDATE4815:
683 case TRDP_TIMEDATE6416:
684 /* Is it allowed to have offset / scale?? I am not going to scale
685 * seconds, but there could be use for an offset, esp. when misused as
686 * relative time. */
687 if (g_scaled) nstime.secs += el->offset;
688 if (g_time_raw) {
689 switch (el->type.id) {
690 case TRDP_TIMEDATE3214:
691 proto_tree_add_time_format_value(userdata_element, el->hf_id, tvb, offset, el->width, &nstime,
692 "%ld seconds", nstime.secs);
693 break;
694 case TRDP_TIMEDATE4815:
695 proto_tree_add_time_format_value(userdata_element, el->hf_id, tvb, offset, el->width, &nstime,
696 "%ld.%05ld seconds (=%" G_GUINT64_FORMAT"lu" " ticks)", nstime.secs, (nstime.nsecs + 5000L) / 10000L, valu);
697 break;
698 case TRDP_TIMEDATE6416:
699 proto_tree_add_time_format_value(userdata_element, el->hf_id, tvb, offset, el->width, &nstime,
700 "%ld.%06ld seconds", nstime.secs, nstime.nsecs / 1000L);
701 break;
702
703 }
704 } else
705 proto_tree_add_time(userdata_element, el->hf_id, tvb, offset, el->width, &nstime);
706
707 offset += el->width;
708 break;
709
710 case TRDP_SC3217:
711 buff_length = tvb_get_ntohl(tvb, TRDP_HEADER_OFFSET_DATASETLENGTH20) - TRDP_SC32_LENGTH4;
712 pBuff = (uint8_t *)g_malloc(buff_length);
713 if (pBuff != NULL((void*)0)) {
714 tvb_memcpy(tvb, pBuff, TRDP_HEADER_PD_OFFSET_DATA40, buff_length);
715 calced_crc = trdp_sc32(pBuff, buff_length, (uint32_t)(g_sid & 0xFFFFFFFF));
716 if (package_crc == calced_crc) {
717 proto_tree_add_uint_format_value(userdata_element, el->hf_id, tvb, offset, el->width, package_crc, "0x%04x [correct]", package_crc);
718 } else {
719 proto_tree_add_uint_format_value(userdata_element, el->hf_id, tvb, offset, el->width, package_crc, "0x%04x [incorrect, should be 0x%04x]", package_crc, calced_crc);
720 proto_tree_add_expert_format(userdata_element, pinfo, &ei_trdp_sdtv2_safetycode, tvb, offset, el->width, "0x%04x is an incorrect SC32 value.", (uint32_t)package_crc);
721 }
722 g_free(pBuff);
723 }
724 offset += el->width;
725 break;
726 case TRDP_UUID18:
727 proto_tree_add_guid(userdata_element, el->hf_id, tvb, offset, el->width, &guid);
728 offset += el->width;
729 break;
730 }
731
732 if (array_index || element_count != 1) {
733 /* handle arrays */
734 ws_debug( "[%d / %d]", array_index, element_count)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 734, __func__, "[%d / %d]", array_index, element_count); } }
while (0)
;
735 if (++array_index >= element_count) {
736 array_index = 0;
737 userdata_element = trdp_userdata;
738 }
739 potential_array_size = -1;
740 } else {
741 ws_debug("[%d / %d], (type=%d) val-u=%" G_GUINT64_FORMAT " val-s=%" G_GINT64_FORMAT ".", array_index, element_count, el->type.id, valu, vals)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 741, __func__, "[%d / %d], (type=%d) val-u=%" "lu" " val-s=%"
"li" ".", array_index, element_count, el->type.id, valu, vals
); } } while (0)
;
742
743 potential_array_size = (el->type.id < TRDP_INT84 || el->type.id > TRDP_UINT6411) ? -1 : (el->type.id >= TRDP_UINT88 ? (int)valu : (int)vals);
744 }
745
746 } while (array_index);
747 }
748
749 /* Check padding of the body */
750 if (!dataset_level) offset = checkPaddingAndOffset(tvb, pinfo, trdpRootNode, offset);
751
752 return offset;
753}
754
755static void add_dataset_reg_info(Dataset *ds);
756
757/**
758 * @internal
759 * Extract all information from the userdata (uses the parsebody module for
760 * unmarshalling)
761 *
762 * @param tvb buffer
763 * @param packet info for tht packet
764 * @param tree to which the information are added
765 * @param trdp_comid the already extracted comId
766 * @param offset where the userdata starts in the TRDP package
767 *
768 * @return size of the user data
769 */
770static uint32_t dissect_trdp_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *trdp_tree, uint32_t trdp_comid, uint32_t offset, uint32_t length) {
771 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 771, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 771, __FUNCTION__); } } while (0)
;
772 return dissect_trdp_generic_body(tvb, pinfo, trdp_tree, trdp_tree, trdp_comid, offset, length, 0 /* level of cascaded datasets*/, "dataset", -1);
773}
774
775/**
776 * @internal
777 * Build the special header for PD and MD datasets (and calls the function to extract the userdata)
778 *
779 * @param tvb buffer
780 * @param pinfo info for tht packet
781 * @param tree to which the information are added
782 * @param trdp_comid the already extracted comId
783 * @param offset where the userdata starts in the TRDP package
784 *
785 * @return size of the user data
786 */
787static uint32_t build_trdp_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item **ti_type, uint32_t trdp_comid, char *trdp_string) {
788 proto_item *ti = NULL((void*)0);
789 proto_tree *trdp_tree = NULL((void*)0);
790 proto_item *_ti_type_tmp = NULL((void*)0);
791 proto_item **pti_type = ti_type ? ti_type : &_ti_type_tmp;
792
793 uint32_t datasetlength = 0;
794 uint32_t pdu_size = 0;
795
796 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 796, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 796, __FUNCTION__); } } while (0)
;
797
798 /* when the package is big enough extract some data. */
799 if (tvb_reported_length_remaining(tvb, 0) > TRDP_HEADER_PD_OFFSET_RESERVED24) {
800 ti = proto_tree_add_item(tree, proto_trdp, tvb, 0, -1, ENC_NA0x00000000);
801 trdp_tree = proto_item_add_subtree(ti, ett_trdp);
802
803 proto_tree_add_item(trdp_tree, hf_trdp_sequencecounter, tvb, TRDP_HEADER_OFFSET_SEQCNT0, 4, ENC_BIG_ENDIAN0x00000000);
804 int verMain = tvb_get_uint8(tvb, TRDP_HEADER_OFFSET_PROTOVER4);
805 int verSub = tvb_get_uint8(tvb, (TRDP_HEADER_OFFSET_PROTOVER4 + 1));
806 proto_tree_add_bytes_format_value(trdp_tree, hf_trdp_protocolversion, tvb, 4, 2, NULL((void*)0), "%d.%d", verMain, verSub);
807
808 *pti_type = proto_tree_add_item(trdp_tree, hf_trdp_type, tvb, TRDP_HEADER_OFFSET_TYPE6, 2, ENC_ASCII0x00000000);
809 proto_tree_add_item(trdp_tree, hf_trdp_comid, tvb, TRDP_HEADER_OFFSET_COMID8, 4, ENC_BIG_ENDIAN0x00000000);
810 proto_tree_add_item(trdp_tree, hf_trdp_etb_topocount, tvb, TRDP_HEADER_OFFSET_ETB_TOPOCNT12, 4, ENC_BIG_ENDIAN0x00000000);
811 proto_tree_add_item(trdp_tree, hf_trdp_op_trn_topocount, tvb, TRDP_HEADER_OFFSET_OP_TRN_TOPOCNT16, 4, ENC_BIG_ENDIAN0x00000000);
812 proto_tree_add_item(trdp_tree, hf_trdp_datasetlength, tvb, TRDP_HEADER_OFFSET_DATASETLENGTH20, 4, ENC_BIG_ENDIAN0x00000000);
813 datasetlength = tvb_get_ntohl(tvb, TRDP_HEADER_OFFSET_DATASETLENGTH20);
814 } else {
815 expert_add_info_format(pinfo, tree, &ei_trdp_packet_small, "Packet too small for header information");
816 }
817
818 if (trdp_string) {
819 switch (trdp_string[0]) {
820 case 'P':
821 /* PD specific stuff */
822 proto_tree_add_item(trdp_tree, hf_trdp_reserved, tvb, TRDP_HEADER_PD_OFFSET_RESERVED24, 4, ENC_BIG_ENDIAN0x00000000);
823 proto_tree_add_item(trdp_tree, hf_trdp_reply_comid, tvb, TRDP_HEADER_PD_OFFSET_REPLY_COMID28, 4, ENC_BIG_ENDIAN0x00000000);
824 proto_tree_add_item(trdp_tree, hf_trdp_reply_ipaddress, tvb, TRDP_HEADER_PD_OFFSET_REPLY_IPADDR32, 4, ENC_BIG_ENDIAN0x00000000);
825 add_crc2tree(tvb, pinfo, trdp_tree, TRDP_HEADER_PD_OFFSET_FCSHEAD36, 0, TRDP_HEADER_PD_OFFSET_FCSHEAD36);
826 pdu_size = dissect_trdp_body(tvb, pinfo, trdp_tree, trdp_comid, TRDP_HEADER_PD_OFFSET_DATA40, datasetlength);
827 break;
828 case 'M':
829 /* MD specific stuff */
830 proto_tree_add_item(trdp_tree, hf_trdp_replystatus, tvb, TRDP_HEADER_MD_OFFSET_REPLY_STATUS24, 4, ENC_BIG_ENDIAN0x00000000);
831 proto_tree_add_item(trdp_tree, hf_trdp_sessionid, tvb, TRDP_HEADER_MD_SESSIONID028, 16, ENC_BIG_ENDIAN0x00000000);
832 proto_tree_add_item(trdp_tree, hf_trdp_replytimeout, tvb, TRDP_HEADER_MD_REPLY_TIMEOUT44, 4, ENC_BIG_ENDIAN0x00000000);
833 proto_tree_add_item(trdp_tree, hf_trdp_sourceURI, tvb, TRDP_HEADER_MD_SRC_URI48, 32, ENC_ASCII0x00000000);
834 proto_tree_add_item(trdp_tree, hf_trdp_destinationURI, tvb, TRDP_HEADER_MD_DEST_URI80, 32, ENC_ASCII0x00000000);
835 add_crc2tree(tvb, pinfo, trdp_tree, TRDP_HEADER_MD_OFFSET_FCSHEAD112, 0, TRDP_HEADER_MD_OFFSET_FCSHEAD112);
836 pdu_size = dissect_trdp_body(tvb, pinfo, trdp_tree, trdp_comid, TRDP_HEADER_MD_OFFSET_DATA116, datasetlength);
837 break;
838 default:
839 break;
840 }
841 }
842 return pdu_size;
843}
844
845int dissect_trdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused))) {
846 uint32_t trdp_comid = 0;
847 char *trdp_string = NULL((void*)0);
848 uint32_t parsed_size = 0U;
849 proto_item *ti_type = NULL((void*)0);
850
851 /* Load header fields and dictionary if not already done */
852 if (hf_trdp_type <= 0) {
853 proto_registrar_get_byname("trdp.type");
854 }
855
856 /* Make entries in Protocol column ... */
857 if (col_get_writable(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_TRDP"TRDP");
858
859 /* and "info" column on summary display */
860 if (col_get_writable(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO);
861
862 /* Read required values from the package: */
863 trdp_string = (char *)tvb_format_text(pinfo->pool, tvb, TRDP_HEADER_OFFSET_TYPE6, 2);
864 trdp_comid = tvb_get_ntohl(tvb, TRDP_HEADER_OFFSET_COMID8);
865
866 /* Telegram that fits into one packet, or the header of huge telegram, that was reassembled */
867 parsed_size = build_trdp_tree(tvb, pinfo, tree, &ti_type, trdp_comid, trdp_string);
868 if (tree == NULL((void*)0)) ws_debug("Dissector did not get a tree passed (type=%s, comid=%u, parsed=%u).", trdp_string, trdp_comid, parsed_size)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 868, __func__, "Dissector did not get a tree passed (type=%s, comid=%u, parsed=%u)."
, trdp_string, trdp_comid, parsed_size); } } while (0)
;
869
870 /* Append the packet type into the information description */
871 if (col_get_writable(pinfo->cinfo, COL_INFO)) {
872 /* Display a info line */
873 col_append_fstr(pinfo->cinfo, COL_INFO, "comId: %5u ", trdp_comid);
874
875 /* look-up the packet-type name */
876 const char **tt = trdp_types;
877 while (*tt && strcmp(trdp_string, *tt)) tt+=2;
878 col_append_str(pinfo->cinfo, COL_INFO, *(tt+1));
879 if (!*tt) expert_add_info_format(pinfo, ti_type, &ei_trdp_type_unkown, "Unknown TRDP Type: %s", trdp_string);
880
881 /* Help with high-level name of ComId / Dataset */
882 const ComId *comId = TrdpDict_lookup_ComId(pTrdpParser, trdp_comid);
883 if (comId) {
884 if (comId->name && *comId->name) {
885 col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", comId->name);
886 } else if (comId->linkedDS) {
887 if (*comId->linkedDS->name) {
888 col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%s]", comId->linkedDS->name);
889 } else {
890 col_append_fstr(pinfo->cinfo, COL_INFO, " -> [%u]", comId->linkedDS->datasetId);
891 }
892 }
893 } else {
894 const char* name = TrdpDict_lookup_ComId_Name(pTrdpParser, trdp_comid);
895 if (name) col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", name);
896 }
897 }
898 ws_debug("Returning a parsed_size=%d", parsed_size)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 898, __func__, "Returning a parsed_size=%d", parsed_size); }
} while (0)
; // tvb_captured_length(tvb)
899 return parsed_size;
900}
901
902/** @fn static unsigned int get_trdp_tcp_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
903 * @internal
904 * @brief retrieve the expected size of the transmitted packet.
905 */
906static unsigned int get_trdp_tcp_message_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, void *data _U___attribute__((unused))) {
907 unsigned int datasetlength = (unsigned int)tvb_get_ntohl(tvb, offset + TRDP_HEADER_OFFSET_DATASETLENGTH20);
908 unsigned int without_padding = datasetlength + TRDP_MD_HEADERLENGTH116/* + TRDP_FCS_LENGTH*/;
909 ws_debug("get_trdp_tcp_message_len (datasetlength=%d w/ padding=%d tvb_reported_length=%d / captured=%d)", datasetlength, (without_padding + 3) & (~3), tvb_reported_length(tvb), tvb_captured_length(tvb))do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 909, __func__, "get_trdp_tcp_message_len (datasetlength=%d w/ padding=%d tvb_reported_length=%d / captured=%d)"
, datasetlength, (without_padding + 3) & (~3), tvb_reported_length
(tvb), tvb_captured_length(tvb)); } } while (0)
;
910 return (without_padding + 3) & (~3); /* round up to add padding */
911}
912
913/**
914 * @internal
915 * Code to analyze the actual TRDP packet, transmitted via TCP
916 *
917 * @param tvb buffer
918 * @param pinfo info for the packet
919 * @param tree to which the information are added
920 * @param data Collected information
921 *
922 * @return length
923 */
924static int dissect_trdp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
925 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 925, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 925, __FUNCTION__); } } while (0)
;
926 if (!tvb_bytes_exist(tvb, 0, TRDP_MD_HEADERLENGTH116)) {
927 ws_debug("Missing enough bytes %d/%d", tvb_captured_length(tvb), TRDP_MD_HEADERLENGTH)do { if (1) { ws_log_full("", LOG_LEVEL_DEBUG, "epan/dissectors/packet-trdp.c"
, 927, __func__, "Missing enough bytes %d/%d", tvb_captured_length
(tvb), 116); } } while (0)
;
928 return 0;
929 }
930
931 tcp_dissect_pdus(tvb, pinfo, tree, TRUE(!(0)), TRDP_MD_HEADERLENGTH116, get_trdp_tcp_message_len, dissect_trdp, data);
932
933 return tvb_reported_length(tvb);
934}
935
936/* ========================================================================= */
937/* Register the protocol fields and subtrees with Wireshark
938 * (strongly inspired by the wimaxasncp plugin)
939 */
940
941/* ========================================================================= */
942/* Modify the given string to make a suitable display filter */
943/* copied from wimaxasncp plugin */
944static char *alnumerize(char *name) {
945 char *r = name; /* read pointer */
946 char *w = name; /* write pointer */
947 char c;
948
949 for (; (c = *r); ++r) {
950 if (g_ascii_isalnum(c)((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0) || c == '_' || c == '.') { /* These characters are fine - copy them */
951 *(w++) = c;
952 } else if (c == ' ' || c == '-' || c == '/') {
953 if (w == name) continue; /* Skip these others if haven't written any characters out yet */
954 if (*(w - 1) == '_') continue; /* Skip if we would produce multiple adjacent '_'s */
955
956 *(w++) = '_'; /* OK, replace with underscore */
957 }
958 /* Other undesirable characters are just skipped */
959 }
960 *w = '\0'; /* Terminate and return modified string */
961 return name;
962}
963
964/* ========================================================================= */
965
966static void add_reg_info(int *hf_ptr, const char *name, const char *abbrev, enum ftenum type, int display, int bitmask, const char *blurb) {
967
968 hf_register_info hf = {hf_ptr, {name, abbrev, type, display, NULL((void*)0), bitmask, blurb, HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}};
969
970 wmem_array_append_one(trdp_build_dict.hf, hf)wmem_array_append((trdp_build_dict.hf), &(hf), 1);
971}
972
973/* ========================================================================= */
974
975static void add_element_reg_info(const char *parentName, Element *el) {
976 char *name;
977 char *abbrev;
978 const char *blurb;
979 int *pett_id = &el->ett_id;
980
981 name = g_strdup(el->name)g_strdup_inline (el->name);
982 abbrev = alnumerize(g_strdup_printf(PROTO_FILTERNAME_TRDP_PDU"trdp" ".pdu" ".%s.%s", parentName, el->name));
983
984 if (el->scale || el->offset) {
985 blurb = g_strdup_printf("An element of type=%s(%u) scaling *%4g plus offset %+0d in unit %s",
986 el->type.name, el->type.id, el->scale ? el->scale : 1.0, el->offset, el->unit);
987 } else {
988 blurb = g_strdup_printf("An element of type=%s(%u) with unit %s",
989 el->type.name, el->type.id, el->unit);
990 }
991
992 if (!((el->array_size == 1) || (el->type.id == TRDP_CHAR82) || (el->type.id == TRDP_UTF163))) {
993 wmem_array_append_one(trdp_build_dict.ett, pett_id)wmem_array_append((trdp_build_dict.ett), &(pett_id), 1);
994 }
995
996 switch (el->type.id) {
997 case TRDP_BITSET81:
998 if (el->type.subtype == TRDP_BITSUBTYPE_BITSET80) {
999 /* TODO an Array of bitsets is currently not supported */
1000 if (el->bits /*&& el->array_size == 1*/) {
1001 int **bitfields = el->bitfields;
1002 int *pb_ett_id = &el->bits_ett_id;
1003 wmem_array_append_one(trdp_build_dict.ett, pb_ett_id)wmem_array_append((trdp_build_dict.ett), &(pb_ett_id), 1);
1004 for (int i=0;i<TRDP_BITSUBTYPE_BITS8;i++) {
1005 if (*el->bits[i].name) {
1006 char* abbrev2 = alnumerize(g_strdup_printf(PROTO_FILTERNAME_TRDP_PDU"trdp" ".pdu" ".%s.%s.%s", parentName, el->name, el->bits[i].name));
1007 add_reg_info( &el->bits[i].hf_id, el->bits[i].name, abbrev2, FT_BOOLEAN, 8, 1<<i, NULL((void*)0));
1008 *bitfields = &el->bits[i].hf_id;
1009 bitfields++;
1010 }
1011 }
1012 }
1013 add_reg_info(&el->hf_id, name, abbrev, FT_UINT8, BASE_HEX, 0, NULL((void*)0));
1014 } else {
1015 add_reg_info(&el->hf_id, name, abbrev, FT_BOOLEAN, 8, 0, blurb);
1016 }
1017 break;
1018 case TRDP_CHAR82:
1019 case TRDP_UTF163:
1020 add_reg_info(&el->hf_id, name, abbrev, el->array_size ? FT_STRING : FT_STRINGZ, BASE_NONE, 0, blurb);
1021 break;
1022
1023 /* case TRDP_INT8 ... TRDP_INT64: not supported in MSVC :( */
1024 case TRDP_INT84:
1025 case TRDP_INT165:
1026 case TRDP_INT326:
1027 case TRDP_INT647:
1028 if (el->scale && g_scaled) {
1029 add_reg_info(&el->hf_id, name, abbrev, FT_DOUBLE, BASE_NONE, 0, blurb);
1030 } else
1031 add_reg_info(&el->hf_id, name, abbrev, FT_INT64, BASE_DEC, 0, blurb);
1032 break;
1033
1034 /* case TRDP_UINT8 ... TRDP_UINT64: */
1035 case TRDP_UINT88:
1036 case TRDP_UINT169:
1037 case TRDP_UINT3210:
1038 case TRDP_UINT6411:
1039 if (g_ascii_strcasecmp(el->unit, "version") == 0) {
1040 add_reg_info(&el->hf_id, name, abbrev, FT_UINT16, BASE_HEX, 0, blurb);
1041 } else if (el->scale && g_scaled) {
1042 add_reg_info(&el->hf_id, name, abbrev, FT_DOUBLE, BASE_NONE, 0, blurb);
1043 } else
1044 add_reg_info(&el->hf_id, name, abbrev, FT_UINT64, BASE_DEC, 0, blurb);
1045 break;
1046
1047 case TRDP_REAL3212:
1048 case TRDP_REAL6413:
1049 add_reg_info(&el->hf_id, name, abbrev, FT_DOUBLE, BASE_NONE, 0, blurb);
1050 break;
1051
1052 /* case TRDP_TIMEDATE32 ... TRDP_TIMEDATE64:*/
1053 case TRDP_TIMEDATE3214:
1054 case TRDP_TIMEDATE4815:
1055 case TRDP_TIMEDATE6416:
1056 /* add_reg_info( &el->hf_id, name, abbrev, FT_DOUBLE, BASE_NONE, 0, blurb );*/
1057 add_reg_info(&el->hf_id, name, abbrev, g_time_raw ? FT_RELATIVE_TIME : FT_ABSOLUTE_TIME,
1058 g_time_raw ? 0 : (g_time_local ? ABSOLUTE_TIME_LOCAL : ABSOLUTE_TIME_UTC), 0, blurb);
1059 break;
1060
1061 case TRDP_SC3217:
1062 add_reg_info(&el->hf_id, name, abbrev, FT_UINT32, BASE_HEX, 0, blurb);
1063 break;
1064
1065 case TRDP_UUID18:
1066 add_reg_info(&el->hf_id, name, abbrev, FT_GUID, BASE_NONE, 0, blurb);
1067 break;
1068
1069 default:
1070 add_reg_info(&el->hf_id, name, abbrev, FT_BYTES, BASE_NONE, 0, blurb);
1071
1072 /* as long as I do not track the hierarchy, do not recurse */
1073 /* add_dataset_reg_info(el->linkedDS); */
1074 }
1075}
1076
1077static void add_dataset_reg_info(Dataset *ds) {
1078 int *pett_id = &ds->ett_id;
1079
1080 for (Element *el = ds->listOfElements; el; el = el->next) add_element_reg_info(ds->name, el);
1081
1082 if (ds->listOfElements) wmem_array_append_one(trdp_build_dict.ett, pett_id)wmem_array_append((trdp_build_dict.ett), &(pett_id), 1);
1083}
1084
1085static void register_trdp_fields(const char *prefix _U___attribute__((unused))) {
1086 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 1086, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 1086, __FUNCTION__); } } while (0)
;
1087
1088 /* List of header fields. */
1089 static hf_register_info hf_base[] = {
1090 /* All the general fields for the header */
1091 // clang-format off
1092 {&hf_trdp_sequencecounter, {"sequenceCounter", "trdp.sequencecounter", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1093 {&hf_trdp_protocolversion, {"protocolVersion", "trdp.protocolversion", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1094 {&hf_trdp_type, {"msgtype", "trdp.type", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1095 {&hf_trdp_comid, {"comId", "trdp.comid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1096 {&hf_trdp_etb_topocount, {"etbTopoCnt", "trdp.etbtopocnt", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1097 {&hf_trdp_op_trn_topocount,{"opTrnTopoCnt", "trdp.optrntopocnt", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1098 {&hf_trdp_datasetlength, {"datasetLength", "trdp.datasetlength", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1099 {&hf_trdp_padding, {"padding", "trdp.padding", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1100
1101 /* PD specific stuff */
1102 {&hf_trdp_reserved, {"reserved", "trdp.reserved", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1103 {&hf_trdp_reply_comid, {"replyComId", "trdp.replycomid", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}}, /* only in PD request */
1104 {&hf_trdp_reply_ipaddress, {"replyIpAddress", "trdp.replyip", FT_IPv4, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1105
1106 /* MD specific stuff */
1107 {&hf_trdp_replystatus, {"replyStatus", "trdp.replystatus", FT_INT32, BASE_DEC, VALS(reply_status_names)((0 ? (const struct _value_string*)0 : ((reply_status_names))
))
, 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1108 {&hf_trdp_sessionid, {"sessionUUID", "trdp.sessionid", FT_GUID, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1109 {&hf_trdp_replytimeout, {"replyTimeout", "trdp.replytimeout", FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1110 {&hf_trdp_sourceURI, {"sourceUri", "trdp.sourceUri", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1111 {&hf_trdp_destinationURI, {"destinationURI", "trdp.destinationUri", FT_STRING, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1112 {&hf_trdp_userdata, {"dataset", "trdp.rawdata", FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1113
1114 /* The checksum for the header (the trdp.fcsheadcalc is only set, if the
1115 calculated FCS differs) */
1116 {&hf_trdp_fcs_head, {"headerFcs", "trdp.fcshead", FT_UINT32, BASE_HEX, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1117 {&hf_trdp_fcs_head_calc, {"calculatedHeaderFcs", "trdp.fcsheadcalc", FT_UINT32, BASE_HEX, NULL((void*)0), 0x0, "", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
1118
1119 // clang-format on
1120 };
1121
1122 /* Setup protocol subtree array */
1123 static int *ett_base[] = {
1124 &ett_trdp,
1125 };
1126
1127 /* ------------------------------------------------------------------------
1128 * load the XML dictionary
1129 * ------------------------------------------------------------------------
1130 */
1131
1132 if (pTrdpParser != NULL((void*)0)) {
1133 /* currently the GUI callbacks are w/o effect, so always clear the filter expression */
1134// plugin_if_apply_filter("" /* empty filter */, TRUE /* apply immediately */);
1135 TrdpDict_delete(pTrdpParser, proto_trdp);
1136 proto_free_deregistered_fields();
1137 }
1138
1139 ws_info("TRDP custom dictionary is '%s' (proto=%d).", g_customTrdpDictionary, proto_trdp)do { if (1) { ws_log_full("", LOG_LEVEL_INFO, ((void*)0), -1,
((void*)0), "TRDP custom dictionary is '%s' (proto=%d).", g_customTrdpDictionary
, proto_trdp); } } while (0)
;
1140 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 1140, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 1140, __FUNCTION__); } } while (0)
;
1141
1142 GError *err = NULL((void*)0);
1143 char *basepath = g_basexml ? get_datafile_path("trdp", epan_get_environment_prefix()) : NULL((void*)0);
1144 pTrdpParser = TrdpDict_new(basepath, g_customTrdpDictionary, g_bitset_subtype, g_endian_subtype, &err);
1145
1146 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 1146, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 1146, __FUNCTION__); } } while (0)
;
1147 if (err) {
1148 report_failure("TRDP | XML input failed [%d]:\n%s", err->code, err->message);
1149 g_error_free(err);
1150 }
1151
1152 g_free(basepath);
1153
1154 /* ------------------------------------------------------------------------
1155 * build the hf and ett dictionary entries
1156 * ------------------------------------------------------------------------
1157 */
1158
1159 if (trdp_build_dict.hf) wmem_free(wmem_epan_scope(), trdp_build_dict.hf);
1160
1161 if (trdp_build_dict.ett) wmem_free(wmem_epan_scope(), trdp_build_dict.ett);
1162
1163 trdp_build_dict.hf = wmem_array_new(wmem_epan_scope(), sizeof(hf_register_info));
1164 trdp_build_dict.ett = wmem_array_new(wmem_epan_scope(), sizeof(int *));
1165
1166 if (hf_trdp_type <= 0) {
1167 proto_register_field_array(proto_trdp, hf_base, array_length(hf_base)(sizeof (hf_base) / sizeof (hf_base)[0]));
1168 proto_register_subtree_array(ett_base, array_length(ett_base)(sizeof (ett_base) / sizeof (ett_base)[0]));
1169 }
1170
1171 if (pTrdpParser) {
1172 /* arrays use the same hf */
1173 /* don't care about comID linkage, as I really want to index all datasets,
1174 * regardless of their hierarchy */
1175 for (Dataset *ds = pTrdpParser->mTableDataset; ds; ds = ds->next) add_dataset_reg_info(ds);
1176 }
1177
1178 /* Required function calls to register the header fields and subtrees used */
1179
1180 proto_register_field_array(proto_trdp, (hf_register_info *)wmem_array_get_raw(trdp_build_dict.hf), wmem_array_get_count(trdp_build_dict.hf));
1181
1182 proto_register_subtree_array((int **)wmem_array_get_raw(trdp_build_dict.ett), wmem_array_get_count(trdp_build_dict.ett));
1183}
1184
1185void proto_reg_handoff_trdp(void) {
1186 static bool_Bool initialized = FALSE(0);
1187 static unsigned int pd_port=0;
1188 static unsigned int md_port=0;
1189 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 1189, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 1189, __FUNCTION__); } } while (0)
;
1190
1191 if (initialized == FALSE(0)) {
1192 initialized = TRUE(!(0));
1193 } else {
1194 if (pd_port != g_pd_port) {
1195 dissector_delete_uint("udp.port", pd_port, trdp_handle);
1196 }
1197 if (md_port != g_md_port) {
1198 dissector_delete_uint("udp.port", md_port, trdp_handle);
1199 dissector_delete_uint("tcp.port", md_port, trdp_TCP_handle);
1200 }
1201 }
1202 if (pd_port != g_pd_port) {
1203 pd_port = g_pd_port;
1204 dissector_add_uint_with_preference("udp.port", pd_port, trdp_handle);
1205 }
1206 if (md_port != g_md_port) {
1207 md_port = g_md_port;
1208 dissector_add_uint_with_preference("udp.port", md_port, trdp_handle);
1209 dissector_add_uint_with_preference("tcp.port", md_port, trdp_TCP_handle);
1210 }
1211
1212 /* Reload header fields and dictionary but only, if it's been in use before */
1213 if (hf_trdp_type > 0) register_trdp_fields(NULL((void*)0));
1214}
1215
1216void proto_register_trdp(void) {
1217 module_t *trdp_module;
1218
1219 enum_val_t *bitsetenumvals;
1220 gsize bitset_offset = 0;
1221 gsize bitset_types = 0;
1222
1223 while (ElBasics[bitset_offset].id != TRDP_BITSET81) bitset_offset++;
1
Assuming field 'id' is equal to TRDP_BITSET8
2
Loop condition is false. Execution continues on line 1224
1224 while (ElBasics[bitset_offset+bitset_types].id == TRDP_BITSET81) bitset_types++;
3
Loop condition is true. Entering loop body
4
Assuming field 'id' is not equal to TRDP_BITSET8
5
Loop condition is false. Execution continues on line 1226
1225
1226 bitsetenumvals = g_new0(enum_val_t, bitset_types + 1)((enum_val_t *) g_malloc0_n ((bitset_types + 1), sizeof (enum_val_t
)))
;
1227 for (gsize i = 0; i < bitset_types; i++) {
6
Loop condition is true. Entering loop body
7
Loop condition is false. Execution continues on line 1233
1228 bitsetenumvals[i].description = ElBasics[i].name;
1229 bitsetenumvals[i].name = g_ascii_strdown(ElBasics[i].name, -1);
1230 bitsetenumvals[i].value = (int)ElBasics[i].subtype;
1231 }
1232
1233 enum_val_t *endianenumvals = g_new0(enum_val_t, 2 + 1)((enum_val_t *) g_malloc0_n ((2 + 1), sizeof (enum_val_t)));
8
Memory is allocated
1234 endianenumvals[0].description = "BE";
1235 endianenumvals[0].name = "be";
1236 endianenumvals[0].value = TRDP_ENDSUBTYPE_BIG0;
1237 endianenumvals[1].description = "LE (non-standard)";
1238 endianenumvals[1].name = "le";
1239 endianenumvals[1].value = TRDP_ENDSUBTYPE_LIT1;
1240
1241 API_TRACEdo { if (1) { ws_log_full("", LOG_LEVEL_NOISY, "epan/dissectors/packet-trdp.c"
, 1241, __func__, "%s:%d : %s\n", "epan/dissectors/packet-trdp.c"
, 1241, __FUNCTION__); } } while (0)
;
9
Taking true branch
10
Loop condition is false. Exiting loop
1242
1243 /* Register the protocol name and description */
1244 proto_trdp = proto_register_protocol(PROTO_NAME_TRDP"Train Real Time Data Protocol", PROTO_TAG_TRDP"TRDP", PROTO_FILTERNAME_TRDP"trdp");
1245 trdp_handle = register_dissector(PROTO_DISSECTORNAME_TRDP"TRDP", (dissector_t)dissect_trdp, proto_trdp);
1246 trdp_TCP_handle = register_dissector(PROTO_DISSECTORNAME_TRDPTCP"TRDP.tcp", (dissector_t)dissect_trdp_tcp, proto_trdp);
1247 /* Delay registration of com-id and dataset-id definitions */
1248 proto_register_prefix("trdp", register_trdp_fields);
1249
1250 trdp_module = prefs_register_protocol(proto_trdp, proto_reg_handoff_trdp);
1251
1252 /* Register the preference */
1253 prefs_register_static_text_preference( trdp_module, "dissector_summary",
1254 "Version 20251123",
1255 NULL((void*)0));
1256
1257 prefs_register_bool_preference( trdp_module, "basexml",
1258 "Load basic set of comIDs and dataset definitions",
1259 "When ticked, basic definitions of 61375-2-3 are loaded. If that conflicts with your use or your definitions "
1260 "- untick. If there's a bug or data missing, please file an issue.",
1261 &g_basexml);
1262
1263 prefs_register_filename_preference( trdp_module, "configfile",
1264 "Custom TRDP configuration file",
1265 "Custom TRDP configuration file",
1266 &g_customTrdpDictionary, FALSE(0));
1267
1268 prefs_set_preference_effect_fields(trdp_module, "configfile");
1269
1270 prefs_register_static_text_preference( trdp_module, "xml_summary",
1271 "If you need to include multiple files, chose a file, then manually remove the filename part above only leaving the folder path. You cannot choose a "
1272 "folder by itself in the dialog. Be sure, not to have conflicting versions of datasets or com-ids in that target folder - the file parser will be pesky.",
1273 NULL((void*)0));
1274
1275 prefs_register_enum_preference( trdp_module, "bitset.subtype",
1276 "Select default sub-type for TRDP-Element type 1",
1277 "Type 1 can be interpreted differently, as BOOL, ANTIVALENT or BITSET. Select the fallback, if the element type is not given literally.",
1278 &g_bitset_subtype, bitsetenumvals, FALSE(0));
1279
1280 prefs_set_preference_effect_fields( trdp_module, "bitset.subtype");
1281
1282 prefs_register_enum_preference( trdp_module, "numeric.subtype",
1283 "Select default byte-order for TRDP-Element types (5-7,9-13)",
1284 "Number types can be interpreted differently, as BE or LE (non-standard). Select the fallback, if the element type is not given literally.",
1285 &g_endian_subtype, endianenumvals, FALSE(0));
1286
1287 prefs_set_preference_effect_fields( trdp_module, "numeric.subtype");
11
Potential leak of memory pointed to by 'endianenumvals'
1288
1289 prefs_register_bool_preference( trdp_module, "time.local",
1290 "Display time-types as local time, untick for UTC / no offsets.",
1291 "Time types should be based on UTC. When ticked, Wireshark adds on local timezone offset. Untick if you like UTC to be displayed, or the source is not UTC.",
1292 &g_time_local);
1293
1294 prefs_register_bool_preference( trdp_module, "time.raw",
1295 "Display time-types as raw seconds, not absolute time.",
1296 "Time types should be absolute time since the UNIX-Epoch. When ticked, they are shown as seconds.",
1297 &g_time_raw);
1298
1299 prefs_register_bool_preference( trdp_module, "0strings",
1300 "Variable-length CHAR8 and UTF16 arrays are 0-terminated. (non-standard)",
1301 "When ticked, the length of a variable-length string (array-size=0) is calculated from searching for a terminator instead of using a previous length element.",
1302 &g_0strings);
1303
1304 prefs_register_bool_preference( trdp_module, "char8utf8",
1305 "Interpret CHAR8 arrays as UTF-8.",
1306 "When ticked, CHAR8 arrays are interpreted as UTF-8 string. If it fails, an exception is thrown. Untick if you need to see weird ASCII as C-escapes.",
1307 &g_char8_is_utf8);
1308
1309 prefs_register_bool_preference( trdp_module, "strings.le",
1310 "Interpret UTF-16 strings with Little-Endian wire format. (non-standard)",
1311 "When ticked, UTF16 arrays are interpreted as Little-Endian encoding.",
1312 &g_strings_are_LE);
1313
1314 prefs_register_bool_preference( trdp_module, "scaled",
1315 "Use scaled value for filter.",
1316 "When ticked, uses scaled values for filtering and display, otherwise the raw value.",
1317 &g_scaled);
1318
1319 prefs_register_uint_preference( trdp_module, "pd.udp.port",
1320 "PD message Port",
1321 "UDP port for PD messages (Default port is " TRDP_DEFAULT_STR_PD_PORT"17224" ")",
1322 10 /*base */, &g_pd_port);
1323
1324 prefs_register_uint_preference( trdp_module, "md.udptcp.port",
1325 "MD message Port",
1326 "UDP and TCP port for MD messages (Default port is " TRDP_DEFAULT_STR_MD_PORT"17225" ")",
1327 10 /*base */, &g_md_port);
1328
1329 prefs_register_uint_preference( trdp_module, "sdtv2.sid",
1330 "SDTv2 SID (SC-32 Initial Value)",
1331 "SDTv2 SID (Initial Value) for SC-32 calculation (Default is " TRDP_DEFAULT_STR_SC32_SID"0xFFFFFFFF" ")",
1332 16 /*base */, &g_sid);
1333
1334 /* abandon legacy prefs */
1335 prefs_register_obsolete_preference( trdp_module, "udp.port");
1336 prefs_register_obsolete_preference( trdp_module, "tcp.port");
1337
1338 /* Register expert information */
1339 expert_module_t *expert_trdp;
1340 static ei_register_info ei[] = {
1341 {&ei_trdp_type_unkown, {"trdp.type_unkown", PI_UNDECODED0x05000000, PI_WARN0x00600000, "TRDP type unkown", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1342 {&ei_trdp_packet_small, {"trdp.packet_size", PI_UNDECODED0x05000000, PI_WARN0x00600000, "TRDP packet too small", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1343 {&ei_trdp_userdata_empty, {"trdp.userdata_empty", PI_UNDECODED0x05000000, PI_WARN0x00600000, "TRDP user data is empty", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1344 {&ei_trdp_userdata_wrong, {"trdp.userdata_wrong", PI_UNDECODED0x05000000, PI_WARN0x00600000, "TRDP user data has wrong format", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1345 {&ei_trdp_config_notparsed, {"trdp.config_unparsable", PI_UNDECODED0x05000000, PI_WARN0x00600000, "TRDP XML configuration cannot be parsed", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1346 {&ei_trdp_padding_not_zero, {"trdp.padding_non_zero", PI_MALFORMED0x07000000, PI_WARN0x00600000, "TRDP Padding not filled with zero", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1347 {&ei_trdp_array_wrong, {"trdp.array", PI_MALFORMED0x07000000, PI_WARN0x00600000, "Dynamic array has unsupported datatype for length", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1348 {&ei_trdp_faulty_antivalent,{"trdp.faulty_antivalent", PI_MALFORMED0x07000000, PI_WARN0x00600000, "Data contains faulty antivalent value.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1349 {&ei_trdp_reserved_not_zero,{"trdp.reserved_non_zero", PI_MALFORMED0x07000000, PI_WARN0x00600000, "Reserved attribute is not zero", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1350 {&ei_trdp_sdtv2_safetycode, {"trdp.sdtv2_safetycode", PI_CHECKSUM0x01000000, PI_ERROR0x00800000, "SDTv2 SafetyCode check error.", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE
, BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE
, -1, ((void*)0)}}
}},
1351 };
1352
1353 expert_trdp = expert_register_protocol(proto_trdp);
1354 expert_register_field_array(expert_trdp, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
1355}