### 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

Show analyzer invocation
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

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

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 <gerald@wireshark.org>
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 | */
38 | static 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 |
92 | uint32_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 |
101 | int32_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 |
142 | static 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 */
157 | static 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 */
172 | static int proto_trdp = -1;
173 | static dissector_handle_t trdp_handle;
174 | static dissector_handle_t trdp_TCP_handle;
175 |
176 | void proto_reg_handoff_trdp(void);
177 | void proto_register_trdp(void);
178 |
179 | /*For All*/
180 | static int hf_trdp_sequencecounter; /*uint32*/
181 | static int hf_trdp_protocolversion; /*uint16*/
182 | static int hf_trdp_type; /*uint16*/
183 | static int hf_trdp_etb_topocount; /*uint32*/
184 | static int hf_trdp_op_trn_topocount; /*uint32*/
185 | static int hf_trdp_comid; /*uint32*/
186 | static int hf_trdp_datasetlength; /*uint16*/
187 | static int hf_trdp_padding; /*bytes */
188 |
189 | /*For All (user data)*/
190 | static int hf_trdp_fcs_head; /*uint32*/
191 | static int hf_trdp_fcs_head_calc; /*uint32*/
192 | static int hf_trdp_userdata; /* userdata */
193 |
194 | /*needed only for PD messages*/
195 | static int hf_trdp_reserved; /*uint32*/
196 | static int hf_trdp_reply_comid; /*uint32*/ /*for MD-family only*/
197 | static int hf_trdp_reply_ipaddress; /*uint32*/
198 |
199 | /* needed only for MD messages*/
200 | static int hf_trdp_replystatus; /*uint32*/
201 | static int hf_trdp_sessionid; /*uuid*/
202 | static int hf_trdp_replytimeout; /*uint32*/
203 | static int hf_trdp_sourceURI; /*string*/
204 | static 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 |
209 | static bool_Bool g_basexml = TRUE(!(0));
210 | static const char *g_customTrdpDictionary; // XML Config Files String from ..Edit/Preference menu
211 | static unsigned int g_pd_port = TRDP_DEFAULT_UDP_PD_PORT17224;
212 | static unsigned int g_md_port = TRDP_DEFAULT_UDPTCP_MD_PORT17225;
213 | static bool_Bool g_scaled = TRUE(!(0));
214 | static bool_Bool g_strings_are_LE;
215 | static bool_Bool g_uids_are_LE;
216 | static bool_Bool g_char8_is_utf8 = TRUE(!(0));
217 | static bool_Bool g_0strings;
218 | static bool_Bool g_time_local = TRUE(!(0));
219 | static bool_Bool g_time_raw;
220 | static int g_bitset_subtype = TRDP_BITSUBTYPE_BOOL81;
221 | static int g_endian_subtype = TRDP_ENDSUBTYPE_BIG0;
222 | static unsigned int g_sid = TRDP_DEFAULT_SC32_SID0xFFFFFFFF;
223 |
224 | /* Initialize the subtree pointers */
225 | static int ett_trdp = -1;
226 |
227 | /* Expert fields */
228 | static expert_field ei_trdp_type_unkown;
229 | static expert_field ei_trdp_packet_small;
230 | static expert_field ei_trdp_userdata_empty;
231 | static expert_field ei_trdp_userdata_wrong;
232 | static expert_field ei_trdp_config_notparsed;
233 | static expert_field ei_trdp_padding_not_zero;
234 | static expert_field ei_trdp_array_wrong;
235 | static expert_field ei_trdp_faulty_antivalent;
236 | static expert_field ei_trdp_reserved_not_zero;
237 | static expert_field ei_trdp_sdtv2_safetycode;
238 |
239 | /* static container for dynamic fields and subtree handles */
240 | static struct {
241 | wmem_array_t *hf;
242 | wmem_array_t *ett;
243 | } trdp_build_dict;
244 |
245 | static 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 | */
262 | static 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 | */
291 | static 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
336 | static 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 |
755 | static 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 | */
770 | static 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 | */
787 | static 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 |
845 | int 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 | */
906 | static 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 | */
924 | static 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 */
944 | static 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 |
966 | static 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 |
975 | static 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 |
1077 | static 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 |
1085 | static 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 |
1185 | void 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 |
1216 | void 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 | }