Bug Summary

File:epan/dissectors/packet-tpncp.c
Warning:line 435, column 10
Read function called when stream is in EOF state. Function has no effect

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-tpncp.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-truncation -Wno-format-nonliteral -Wno-pointer-sign -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/2025-11-05-100318-3623-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-tpncp.c
1/* packet-tpncp.c
2 * Routines for Audiocodes TrunkPack Network Control Protocol (TPNCP) dissection
3 *
4 * Copyright (c) 2007 by Valery Sigalov <valery.sigalov@audiocodes.com>
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.com>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13/*---------------------------------------------------------------------------*/
14
15#define WS_LOG_DOMAIN"TPNCP" "TPNCP"
16#include "config.h"
17
18#include <epan/packet.h>
19#include <epan/exceptions.h>
20#include <epan/expert.h>
21#include <epan/prefs.h>
22#include <wsutil/filesystem.h>
23#include <wsutil/file_util.h>
24#include <wsutil/report_message.h>
25#include <wsutil/strtoi.h>
26#include <wsutil/application_flavor.h>
27#include <epan/wmem_scopes.h>
28#include "packet-acdr.h"
29#include "packet-tcp.h"
30
31/*---------------------------------------------------------------------------*/
32
33#define BASE_TPNCP_PORT2424 2424
34#define HA_PORT_TPNCP_TRUNKPACK2442 2442
35#define TCP_PORT_TPNCP_TRUNKPACK2424 BASE_TPNCP_PORT2424
36#define UDP_PORT_TPNCP_TRUNKPACK2424 BASE_TPNCP_PORT2424
37#define TCP_PORT_TPNCP_HOST2424 BASE_TPNCP_PORT2424
38#define UDP_PORT_TPNCP_HOST2424 BASE_TPNCP_PORT2424
39
40#define MAX_TPNCP_DB_ENTRY_LEN3000 3000
41
42/*---------------------------------------------------------------------------*/
43
44void proto_register_tpncp(void);
45void proto_reg_handoff_tpncp(void);
46
47enum SpecialFieldType {
48 TPNCP_NORMAL,
49 TPNCP_ADDRESS_FAMILY,
50 TPNCP_IP_ADDR,
51 TPNCP_OPEN_CHANNEL_START,
52 TPNCP_SECURITY_START,
53 TPNCP_SECURITY_OFFSET,
54 RTP_STATE_START,
55 RTP_STATE_OFFSET,
56 RTP_STATE_END,
57 TPNCP_CHANNEL_CONFIGURATION
58};
59
60/* The linked list for storing information about specific data fields. */
61typedef struct tpncp_data_field_info
62{
63 char *name;
64 int descr;
65 int ipv6_descr;
66 int array_dim;
67 enum SpecialFieldType special_type;
68 unsigned char size;
69 unsigned char sign;
70 int since;
71 struct tpncp_data_field_info *p_next;
72} tpncp_data_field_info;
73
74/*---------------------------------------------------------------------------
75 * Desegmentation of TPNCP over TCP */
76static bool_Bool tpncp_desegment = true1;
77
78/* Database for storing information about all TPNCP events. */
79static tpncp_data_field_info **tpncp_events_info_db;
80unsigned tpncp_events_info_len;
81
82/* Database for storing information about all TPNCP commands. */
83static tpncp_data_field_info **tpncp_commands_info_db;
84unsigned tpncp_commands_info_len;
85
86/* Global variables for bitfields representation. */
87/* TPNCP packet header fields. */
88static int proto_tpncp;
89static int hf_tpncp_version;
90static int hf_tpncp_length;
91static int hf_tpncp_seq_number;
92static int hf_tpncp_length_ext;
93static int hf_tpncp_reserved;
94static int hf_tpncp_command_id;
95static int hf_tpncp_event_id;
96static int hf_tpncp_cid;
97
98static expert_field ei_tpncp_unknown_data;
99
100/* TPNCP fields defining a subtree. */
101static int ett_tpncp;
102static int ett_tpncp_body;
103
104static bool_Bool global_tpncp_load_db;
105
106static dissector_handle_t tpncp_handle;
107static dissector_handle_t tpncp_tcp_handle;
108
109/* TODO: Runtime value_string_ext arrays should be used*/
110static value_string *tpncp_commands_id_vals;
111static value_string *tpncp_events_id_vals;
112static value_string **tpncp_enums_id_vals;
113static char **tpncp_enums_name_vals;
114
115static int hf_size;
116static int hf_allocated;
117static hf_register_info *hf;
118
119static bool_Bool db_initialized;
120
121/*---------------------------------------------------------------------------*/
122
123enum AddressFamily {
124 TPNCP_IPV4 = 2,
125 TPNCP_IPV6 = 10,
126 TPNCP_IPV6_PSOS = 28
127};
128
129static void
130dissect_tpncp_data(unsigned data_id, packet_info *pinfo, tvbuff_t *tvb, proto_tree *ltree,
131 int *offset, tpncp_data_field_info **data_fields_info, int ver, unsigned encoding)
132{
133 int g_str_len;
134 tpncp_data_field_info *field = NULL((void*)0);
135 int bitindex = encoding == ENC_LITTLE_ENDIAN0x80000000 ? 7 : 0;
136 enum AddressFamily address_family = TPNCP_IPV4;
137 int open_channel_start = -1, security_offset = 0, rtp_state_offset = 0;
138 int channel_b_offset = 0, rtp_tx_state_offset = 0, rtp_state_size = 0;
139 const int initial_offset = *offset;
140
141 for (field = data_fields_info[data_id]; field; field = field->p_next) {
142 if (field->since > 0 && field->since > ver)
143 continue;
144 switch (field->special_type) {
145 case TPNCP_OPEN_CHANNEL_START:
146 open_channel_start = *offset;
147 break;
148 case TPNCP_SECURITY_OFFSET: {
149 const uint32_t sec_offset = tvb_get_uint32(tvb, *offset, encoding);
150 if (sec_offset > 0 && open_channel_start >= 0)
151 security_offset = open_channel_start + sec_offset;
152 break;
153 }
154 case TPNCP_SECURITY_START:
155 *offset = security_offset;
156 open_channel_start = -1;
157 security_offset = 0;
158 break;
159 case RTP_STATE_OFFSET:
160 rtp_state_offset = tvb_get_int32(tvb, *offset, encoding);
161 if (rtp_state_offset > 0)
162 rtp_state_offset += initial_offset + 4; /* The offset starts after CID */
163 break;
164 case RTP_STATE_START:
165 *offset = rtp_state_offset;
166 rtp_state_offset = 0;
167 if (rtp_tx_state_offset == 0) {
168 rtp_state_size = (tvb_reported_length_remaining(tvb, *offset) - 4) / 2;
169 rtp_tx_state_offset = *offset + rtp_state_size;
170 } else {
171 *offset = rtp_tx_state_offset;
172 rtp_tx_state_offset += rtp_state_size;
173 }
174 break;
175 case RTP_STATE_END:
176 rtp_tx_state_offset = 0;
177 break;
178 case TPNCP_CHANNEL_CONFIGURATION:
179 if (channel_b_offset == 0) {
180 int channel_configuration_size = tvb_reported_length_remaining(tvb, *offset) / 2;
181 channel_b_offset = *offset + channel_configuration_size;
182 } else {
183 *offset = channel_b_offset;
184 channel_b_offset = 0;
185 }
186 break;
187 case TPNCP_ADDRESS_FAMILY:
188 address_family = (enum AddressFamily)tvb_get_uint32(tvb, *offset, encoding);
189 // fall-through
190 default:
191 if (open_channel_start != -1 && security_offset > 0 && *offset >= security_offset)
192 continue;
193 if (rtp_state_offset > 0 && *offset >= rtp_state_offset)
194 continue;
195 if (rtp_tx_state_offset > 0 && *offset >= rtp_tx_state_offset)
196 continue;
197 if (channel_b_offset > 0 && *offset >= channel_b_offset)
198 continue;
199 break;
200 }
201 switch (field->size) {
202 case 1: case 2: case 3: case 4:
203 case 5: case 6: case 7: case 8:
204 /* add char array */
205 if ((g_str_len = field->array_dim)) {
206 g_str_len = MIN(g_str_len, tvb_reported_length_remaining(tvb, *offset))(((g_str_len) < (tvb_reported_length_remaining(tvb, *offset
))) ? (g_str_len) : (tvb_reported_length_remaining(tvb, *offset
)))
;
207 proto_tree_add_item(ltree, field->descr, tvb, *offset, g_str_len, ENC_NA0x00000000 | ENC_ASCII0x00000000);
208 (*offset) += g_str_len;
209 } else { /* add single char */
210 /* Output only the numeric value for 8-bit fields, considering sign, with no extra formatting. */
211 if (field->size == 8) {
212 uint8_t g_uchar = tvb_get_uint8(tvb, *offset);
213 if (field->sign)
214 proto_tree_add_uint(ltree, field->descr, tvb, *offset, 1, g_uchar);
215 else
216 proto_tree_add_int(ltree, field->descr, tvb, *offset, 1, (int8_t)g_uchar);
217 (*offset)++;
218 } else { /* unsigned bitfield <8 */
219 unsigned bit_offset;
220
221 /*
222 * tpncp.dat always lists bitfields in little-endian (LSB-first) order, regardless of encoding.
223 * Wireshark's proto_tree_add_bits_item with ENC_LITTLE_ENDIAN matches this order.
224 *
225 * Therefore, we always use ENC_LITTLE_ENDIAN for bitfield extraction, regardless of the packet encoding.
226 *
227 * bit_offset is simply (*offset) * 8 + bitindex, and bitindex increments by field->size.
228 */
229 bit_offset = (*offset) * 8 + bitindex;
230 proto_tree_add_bits_item(ltree, field->descr, tvb, bit_offset, field->size, ENC_LITTLE_ENDIAN0x80000000);
231
232 bitindex += field->size;
233 (*offset) += bitindex / 8;
234 bitindex %= 8;
235 }
236 }
237 break;
238 case 16:
239 proto_tree_add_item(ltree, field->descr, tvb, *offset, 2, encoding);
240 (*offset) += 2;
241 break;
242 case 32:
243 proto_tree_add_item(ltree, field->descr, tvb, *offset, 4, encoding);
244 (*offset) += 4;
245 break;
246 case 64:
247 proto_tree_add_item(ltree, field->descr, tvb, *offset, 8, encoding);
248 (*offset) += 8;
249 break;
250 case 128:
251 if (field->special_type == TPNCP_IP_ADDR) {
252 if (address_family == TPNCP_IPV6 || address_family == TPNCP_IPV6_PSOS)
253 proto_tree_add_item(ltree, field->ipv6_descr, tvb, *offset, 16, encoding);
254 else
255 proto_tree_add_item(ltree, field->descr, tvb, *offset, 4, encoding);
256 address_family = TPNCP_IPV4;
257 }
258 (*offset) += 16;
259 break;
260 default:
261 break;
262 }
263 if (tvb_reported_length_remaining(tvb, *offset) <= 0)
264 break;
265 }
266 if ((g_str_len = tvb_reported_length_remaining(tvb, *offset)) > 0) {
267 expert_add_info_format(pinfo, ltree, &ei_tpncp_unknown_data, "TPNCP Unknown Data");
268 (*offset) += g_str_len;
269 }
270}
271
272/*---------------------------------------------------------------------------*/
273static int
274dissect_tpncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U___attribute__((unused)))
275{
276 proto_item *item = NULL((void*)0);
277 proto_tree *tpncp_tree = NULL((void*)0), *event_tree, *command_tree;
278 int offset = 0, cid = -1;
279 unsigned id;
280 unsigned seq_number, len, ver;
281 unsigned len_ext, reserved, encoding;
282 uint32_t fullLength;
283
284 if (!db_initialized)
285 return 0;
286
287 encoding = tvb_get_ntohs(tvb, 8) == 0 ? ENC_BIG_ENDIAN0x00000000 : ENC_LITTLE_ENDIAN0x80000000;
288
289 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPNCP");
290
291 item = proto_tree_add_item(tree, proto_tpncp, tvb, 0, -1, ENC_NA0x00000000);
292 tpncp_tree = proto_item_add_subtree(item, ett_tpncp);
293
294 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_version, tvb, 0, 2, encoding, &ver);
295 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_length, tvb, 2, 2, encoding, &len);
296 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_seq_number, tvb, 4, 2, encoding, &seq_number);
297 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_length_ext, tvb, 6, 1, encoding, &len_ext);
298 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_reserved, tvb, 7, 1, encoding, &reserved);
299 fullLength = 0xffff * len_ext + len;
300
301 id = tvb_get_uint32(tvb, 8, encoding);
302 if (len > 8)
303 cid = tvb_get_int32(tvb, 12, encoding);
304 if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK2424 ||
305 pinfo->srcport == HA_PORT_TPNCP_TRUNKPACK2442) {
306 if (try_val_to_str(id, tpncp_events_id_vals)) {
307 proto_tree_add_uint(tpncp_tree, hf_tpncp_event_id, tvb, 8, 4, id);
308 if (len > 8)
309 proto_tree_add_int(tpncp_tree, hf_tpncp_cid, tvb, 12, 4, cid);
310 offset += 16;
311 if (id < tpncp_events_info_len && tpncp_events_info_db[id] != NULL((void*)0) && len > 12) {
312 event_tree = proto_tree_add_subtree_format(
313 tree, tvb, offset, -1, ett_tpncp_body, NULL((void*)0),
314 "TPNCP Event: %s (%d)",
315 val_to_str_const(id, tpncp_events_id_vals, "Unknown"), id);
316 dissect_tpncp_data(id, pinfo, tvb, event_tree, &offset, tpncp_events_info_db,
317 ver, encoding);
318 }
319 }
320 col_add_fstr(pinfo->cinfo, COL_INFO,
321 "EvID=%s(%d), SeqNo=%d, CID=%d, Len=%d, Ver=%d",
322 val_to_str_const(id, tpncp_events_id_vals, "Unknown"),
323 id, seq_number, cid, fullLength, ver);
324 } else {
325 if (try_val_to_str(id, tpncp_commands_id_vals)) {
326 proto_tree_add_uint(tpncp_tree, hf_tpncp_command_id, tvb, 8, 4, id);
327 offset += 12;
328 if (id < tpncp_commands_info_len && tpncp_commands_info_db[id] != NULL((void*)0) && len > 8) {
329 command_tree = proto_tree_add_subtree_format(
330 tree, tvb, offset, -1, ett_tpncp_body, NULL((void*)0),
331 "TPNCP Command: %s (%d)",
332 val_to_str_const(id, tpncp_commands_id_vals, "Unknown"), id);
333 dissect_tpncp_data(id, pinfo, tvb, command_tree, &offset, tpncp_commands_info_db,
334 ver, encoding);
335 }
336 }
337 col_add_fstr(pinfo->cinfo, COL_INFO,
338 "CmdID=%s(%d), SeqNo=%d, CID=%d, Len=%d, Ver=%d",
339 val_to_str_const(id, tpncp_commands_id_vals, "Unknown"),
340 id, seq_number, cid, fullLength, ver);
341 }
342
343 return tvb_reported_length(tvb);
344}
345
346/*---------------------------------------------------------------------------*/
347
348static unsigned
349get_tpncp_pdu_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, void *data _U___attribute__((unused)))
350{
351 uint32_t plen;
352
353 /* Get the length of the TPNCP packet. */
354 plen = tvb_get_ntohs(tvb, offset + 2) + 0xffff * tvb_get_uint8(tvb, offset + 6);
355
356 /* Length does not include the version+length field. */
357 plen += 4;
358
359 return plen;
360}
361
362/*---------------------------------------------------------------------------*/
363
364static int
365dissect_tpncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
366{
367 if (!db_initialized)
368 return 0;
369
370 if (pinfo->can_desegment)
371 /* If desegmentation is enabled (TCP preferences) use the desegmentation API. */
372 tcp_dissect_pdus(tvb, pinfo, tree, tpncp_desegment, 4, get_tpncp_pdu_len,
373 dissect_tpncp, data);
374 else
375 /* Otherwise use the regular dissector (might not give correct dissection). */
376 dissect_tpncp(tvb, pinfo, tree, data);
377
378 return tvb_reported_length(tvb);
379}
380
381static int
382dissect_acdr_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
383{
384 int res = 0;
385 acdr_dissector_data_t *acdr_data = (acdr_dissector_data_t *) data;
386 uint32_t orig_port = pinfo->srcport;
387
388 if (acdr_data == NULL((void*)0))
389 return 0;
390
391 // only on version 2+ events are sent with TPNCP header that enables using tpncp parser
392 if (acdr_data->version <= 1)
393 return 0;
394
395 // the TPNCP dissector uses the following statement to
396 // differentiate command from event:
397 // if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) -> Event
398 // so for proper dissection we want to imitate this behaviour
399 pinfo->srcport = UDP_PORT_TPNCP_TRUNKPACK2424;
400 res = dissect_tpncp(tvb, pinfo, tree, NULL((void*)0));
401 pinfo->srcport = orig_port;
402 return res;
403}
404
405static int
406dissect_acdr_tpncp_by_tracepoint(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
407{
408 acdr_dissector_data_t *acdr_data = (acdr_dissector_data_t *) data;
409 uint32_t orig_port = pinfo->srcport;
410 int res = 0;
411
412 if (acdr_data == NULL((void*)0))
413 return 0;
414
415 // the TPNCP dissector uses the following statement to
416 // differentiate command from event:
417 // if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) -> Event
418 // so for proper dissection we want to imitate this behaviour
419
420 if (acdr_data->trace_point == Host2Net) // event
421 pinfo->srcport = UDP_PORT_TPNCP_TRUNKPACK2424;
422 else // Net2Host ->command
423 pinfo->srcport = UDP_PORT_TPNCP_TRUNKPACK2424 + 1;
424
425 res = dissect_tpncp(tvb, pinfo, tree, NULL((void*)0));
426 pinfo->srcport = orig_port;
427 return res;
428}
429
430/*---------------------------------------------------------------------------*/
431
432static bool_Bool
433fgetline(char *buffer, int size, FILE *file)
434{
435 if (!fgets(buffer, size, file))
11
Assuming stream reaches end-of-file here
12
Taking true branch
18
Read function called when stream is in EOF state. Function has no effect
436 return 0;
437 size_t last = strlen(buffer);
438 if (buffer[last - 1] == '\n')
439 buffer[last - 1] = 0;
440 return 1;
441}
442
443static int
444fill_tpncp_id_vals(value_string **strings, FILE *file)
445{
446 wmem_array_t *vs_arr;
447 char *line_in_file;
448
449 if (file
8.1
'file' is not equal to NULL
15.1
'file' is not equal to NULL
== NULL((void*)0)) return -1;
9
Taking false branch
16
Taking false branch
450
451 line_in_file = (char *) g_malloc(MAX_TPNCP_DB_ENTRY_LEN3000);
452 vs_arr = wmem_array_new(NULL((void*)0), sizeof **strings);
453
454 while (fgetline(line_in_file, MAX_TPNCP_DB_ENTRY_LEN3000, file) && !feof(file)) {
10
Calling 'fgetline'
13
Returning from 'fgetline'
17
Calling 'fgetline'
455 int tpncp_id = 0;
456 char tpncp_name[256];
457
458 if (!strncmp(line_in_file, "#####", 5))
459 break;
460 if (sscanf(line_in_file, "%255s %d", tpncp_name, &tpncp_id) == 2) {
461 value_string const string = {
462 .value = (uint32_t)tpncp_id,
463 .strptr = wmem_strdup(wmem_epan_scope(), tpncp_name)
464 };
465 wmem_array_append_one(vs_arr, string)wmem_array_append((vs_arr), &(string), 1);
466 }
467 }
468
469 wmem_array_set_null_terminator(vs_arr);
470 *strings = wmem_array_finalize(vs_arr);
471 g_free(line_in_file);
472
473 return 0;
474}
475
476/*---------------------------------------------------------------------------*/
477
478static int
479fill_enums_id_vals(char ***enum_names, value_string ***enum_value_strings, FILE *file)
480{
481 wmem_array_t *enum_name_arr, *enum_vs_arr, *enum_vs = NULL((void*)0);
482 char *line_in_file;
483 char enum_type[256];
484
485 line_in_file = (char *) g_malloc(MAX_TPNCP_DB_ENTRY_LEN3000);
486 enum_type[0] = '\0';
487
488 enum_name_arr = wmem_array_new(NULL((void*)0), sizeof **enum_names);
489 enum_vs_arr = wmem_array_new(NULL((void*)0), sizeof **enum_value_strings);
490
491 while (fgetline(line_in_file, MAX_TPNCP_DB_ENTRY_LEN3000, file)) {
492 char enum_name[256], enum_str[256];
493 int enum_id;
494
495 if (!strncmp(line_in_file, "#####", 5))
496 break;
497 if (sscanf(line_in_file, "%255s %255s %d", enum_name, enum_str, &enum_id) == 3) {
498 if (strcmp(enum_type, enum_name) != 0) {
499 /* New record. */
500 if (enum_vs != NULL((void*)0)) {
501 /* The previous enum_vs is now complete. */
502 wmem_array_set_null_terminator(enum_vs);
503 value_string *new_enum_vs = wmem_array_finalize(enum_vs);
504 wmem_array_append_one(enum_vs_arr, new_enum_vs)wmem_array_append((enum_vs_arr), &(new_enum_vs), 1);
505 }
506 enum_vs = wmem_array_sized_new(NULL((void*)0), sizeof ***enum_value_strings, 10);
507
508 char *enum_name_alloc = wmem_strdup(wmem_epan_scope(), enum_name);
509 wmem_array_append_one(enum_name_arr, enum_name_alloc)wmem_array_append((enum_name_arr), &(enum_name_alloc), 1);
510 g_strlcpy(enum_type, enum_name, sizeof enum_type);
511 }
512 value_string const vs = {
513 .value = enum_id,
514 .strptr = wmem_strdup(wmem_epan_scope(), enum_str)
515 };
516 wmem_array_append_one(enum_vs, vs)wmem_array_append((enum_vs), &(vs), 1);
517 }
518 }
519
520 if (enum_vs != NULL((void*)0)) {
521 /* The final enum_vs is now complete. */
522 wmem_array_set_null_terminator(enum_vs);
523 value_string *new_enum_vs = wmem_array_finalize(enum_vs);
524 wmem_array_append_one(enum_vs_arr, new_enum_vs)wmem_array_append((enum_vs_arr), &(new_enum_vs), 1);
525 }
526
527 wmem_array_set_null_terminator(enum_name_arr);
528 *enum_names = (char **)wmem_array_finalize(enum_name_arr);
529
530 wmem_array_set_null_terminator(enum_vs_arr);
531 *enum_value_strings = (value_string **)wmem_array_finalize(enum_vs_arr);
532 g_free(line_in_file);
533
534 return 0;
535}
536
537/*---------------------------------------------------------------------------*/
538
539static int
540get_enum_name_val(const char *enum_name)
541{
542 int enum_val = 0;
543
544 while (tpncp_enums_name_vals[enum_val]) {
545 if (!strcmp(enum_name, tpncp_enums_name_vals[enum_val]))
546 return enum_val;
547 enum_val++;
548 }
549
550 return -1;
551}
552
553/*---------------------------------------------------------------------------*/
554
555static bool_Bool add_hf(hf_register_info *hf_entr)
556{
557 if (hf_size >= hf_allocated) {
558 void *newbuf;
559 hf_allocated += 1024;
560 newbuf = wmem_realloc(wmem_epan_scope(), hf, hf_allocated * sizeof (hf_register_info));
561 if (!newbuf)
562 return false0;
563 hf = (hf_register_info *) newbuf;
564 }
565 memcpy(hf + hf_size, hf_entr, sizeof (hf_register_info));
566 hf_size++;
567 return true1;
568}
569
570static int
571init_tpncp_data_fields_info(tpncp_data_field_info ***data_fields_info, unsigned *data_fields_len, FILE *file)
572{
573 static bool_Bool was_registered = false0;
574 char tpncp_db_entry[MAX_TPNCP_DB_ENTRY_LEN3000];
575 char entry_copy[MAX_TPNCP_DB_ENTRY_LEN3000];
576 const char *name = NULL((void*)0), *tmp = NULL((void*)0);
577 int enum_val, data_id, current_data_id = -1, array_dim;
578 unsigned char size;
579 enum SpecialFieldType special_type;
580 bool_Bool sign, is_address_family;
581 unsigned idx, since, ip_addr_field;
582 tpncp_data_field_info *field = NULL((void*)0);
583 hf_register_info hf_entr;
584 wmem_array_t *data_fields_info_arr;
585
586 hf_register_info hf_tpncp[] = {
587 {
588 &hf_tpncp_version,
589 {
590 "Version",
591 "tpncp.version",
592 FT_UINT16,
593 BASE_DEC,
594 NULL((void*)0),
595 0x0,
596 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
597 }
598 },
599 {
600 &hf_tpncp_length,
601 {
602 "Length",
603 "tpncp.length",
604 FT_UINT16,
605 BASE_DEC,
606 NULL((void*)0),
607 0x0,
608 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
609 }
610 },
611 {
612 &hf_tpncp_seq_number,
613 {
614 "Sequence number",
615 "tpncp.seq_number",
616 FT_UINT16,
617 BASE_DEC,
618 NULL((void*)0),
619 0x0,
620 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
621 }
622 },
623 {
624 &hf_tpncp_length_ext,
625 {
626 "Length Extension",
627 "tpncp.lengthextension",
628 FT_UINT8,
629 BASE_DEC,
630 NULL((void*)0),
631 0x0,
632 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
633 }
634 },
635 {
636 &hf_tpncp_reserved,
637 {
638 "Reserved",
639 "tpncp.reserved",
640 FT_UINT8,
641 BASE_DEC,
642 NULL((void*)0),
643 0x0,
644 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
645 }
646 },
647 {
648 &hf_tpncp_command_id,
649 {
650 "Command ID",
651 "tpncp.command_id",
652 FT_UINT32,
653 BASE_DEC,
654 VALS(tpncp_commands_id_vals)((0 ? (const struct _value_string*)0 : ((tpncp_commands_id_vals
))))
,
655 0x0,
656 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
657 }
658 },
659 {
660 &hf_tpncp_event_id,
661 {
662 "Event ID",
663 "tpncp.event_id",
664 FT_UINT32,
665 BASE_DEC,
666 VALS(tpncp_events_id_vals)((0 ? (const struct _value_string*)0 : ((tpncp_events_id_vals
))))
,
667 0x0,
668 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
669 }
670 },
671 {
672 &hf_tpncp_cid,
673 {
674 "Channel ID",
675 "tpncp.channel_id",
676 FT_INT32,
677 BASE_DEC,
678 NULL((void*)0),
679 0x0,
680 NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)
681 }
682 }
683 };
684
685 /* Register common fields of hf_register_info structure. */
686 hf_entr.hfinfo.type = FT_NONE;
687 hf_entr.hfinfo.strings = NULL((void*)0);
688 hf_entr.hfinfo.bitmask = 0x0;
689 hf_entr.hfinfo.blurb = NULL((void*)0);
690 HFILL_INIT(hf_entr)(hf_entr).hfinfo.id = -1; (hf_entr).hfinfo.parent = 0; (hf_entr
).hfinfo.ref_type = HF_REF_TYPE_NONE; (hf_entr).hfinfo.same_name_prev_id
= -1; (hf_entr).hfinfo.same_name_next = ((void*)0);
;
691
692 if (!was_registered) {
693 void *newbuf;
694
695 /* Register non-standard data should be done only once. */
696 hf_allocated = hf_size + (int) array_length(hf_tpncp)(sizeof (hf_tpncp) / sizeof (hf_tpncp)[0]);
697 newbuf = wmem_realloc(wmem_epan_scope(), hf, hf_allocated * sizeof (hf_register_info));
698 if (!newbuf)
699 return -1;
700 hf = (hf_register_info *) newbuf;
701 for (idx = 0; idx < array_length(hf_tpncp)(sizeof (hf_tpncp) / sizeof (hf_tpncp)[0]); idx++) {
702 memcpy(hf + hf_size, hf_tpncp + idx, sizeof (hf_register_info));
703 hf_size++;
704 }
705 was_registered = true1;
706 }
707
708 is_address_family = false0;
709 ip_addr_field = 0;
710
711 data_fields_info_arr = wmem_array_new(NULL((void*)0), sizeof **data_fields_info);
712
713 /* Register standard data. */
714 while (fgetline(tpncp_db_entry, MAX_TPNCP_DB_ENTRY_LEN3000, file)) {
715 special_type = TPNCP_NORMAL;
716 since = 0;
717 snprintf(entry_copy, MAX_TPNCP_DB_ENTRY_LEN3000, "%s", tpncp_db_entry);
718 if (!strncmp(tpncp_db_entry, "#####", 5))
719 break;
720
721 /* Default to decimal display type */
722 hf_entr.hfinfo.display = BASE_DEC;
723 if ((tmp = strtok(tpncp_db_entry, " ")) == NULL((void*)0)) {
724 report_failure(
725 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
726 entry_copy);
727 continue;
728 }
729 data_id = (int) g_ascii_strtoll(tmp, NULL((void*)0), 10);
730 if ((name = strtok(NULL((void*)0), " ")) == NULL((void*)0)) {
731 report_failure(
732 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
733 entry_copy);
734 continue;
735 }
736
737 /* We happen to have a line without a name (57 0 32 0 0 primitive). Consider unnamed. */
738 if (g_ascii_isdigit(*name)((g_ascii_table[(guchar) (*name)] & G_ASCII_DIGIT) != 0)) {
739 tmp = name;
740 name = "unnamed";
741 } else {
742 if ((tmp = strtok(NULL((void*)0), " ")) == NULL((void*)0)) {
743 report_failure(
744 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
745 entry_copy);
746 continue;
747 }
748 }
749 if (name[0] == 'c' && !strcmp(name, "cmd_rev_lsb"))
750 special_type = TPNCP_OPEN_CHANNEL_START;
751 else if (name[0] == 'r' && !strcmp(name, "rtp_authentication_algorithm"))
752 special_type = TPNCP_SECURITY_START;
753 else if (name[0] == 's' && !strcmp(name, "security_cmd_offset"))
754 special_type = TPNCP_SECURITY_OFFSET;
755 else if (data_id != 1611 && name[0] == 's' && !strcmp(name, "ssrc"))
756 special_type = RTP_STATE_START;
757 else if (name[0] == 'r' && !strcmp(name, "rtp_tx_state_ssrc"))
758 special_type = RTP_STATE_START;
759 else if (name[0] == 'r' && !strcmp(name, "rtp_state_offset"))
760 special_type = RTP_STATE_OFFSET;
761 else if (name[0] == 's' && !strcmp(name, "state_update_time_stamp"))
762 special_type = RTP_STATE_END;
763 else if (data_id == 1611 && name[0] == 'c' && strstr(name, "configuration_type_updated"))
764 special_type = TPNCP_CHANNEL_CONFIGURATION;
765 else if ((data_id == 4 && strstr(name, "secondary_rtp_seq_num")) ||
766 (data_id == 1611 && strstr(name, "dtls_remote_fingerprint_alg"))) {
767 since = 7401;
768 }
769 sign = !!((bool_Bool) g_ascii_strtoll(tmp, NULL((void*)0), 10));
770 if ((tmp = strtok(NULL((void*)0), " ")) == NULL((void*)0)) {
771 report_failure(
772 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
773 entry_copy);
774 continue;
775 }
776 size = (unsigned char) g_ascii_strtoll(tmp, NULL((void*)0), 10);
777 if ((tmp = strtok(NULL((void*)0), " ")) == NULL((void*)0)) {
778 report_failure(
779 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
780 entry_copy);
781 continue;
782 }
783 array_dim = (int) g_ascii_strtoll(tmp, NULL((void*)0), 10);
784 if ((tmp = strtok(NULL((void*)0), " ")) == NULL((void*)0)) {
785 report_failure(
786 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
787 entry_copy);
788 continue;
789 }
790 if (sign && g_ascii_strtoll(tmp, NULL((void*)0), 10))
791 special_type = TPNCP_IP_ADDR;
792 if ((tmp = strtok(NULL((void*)0), "\n")) == NULL((void*)0)) {
793 report_failure(
794 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
795 entry_copy);
796 continue;
797 }
798
799 if (ip_addr_field > 0) {
800 // ip address that comes after address family has 4 fields: ip_addr_0, ip_addr_1, 2 and 3
801 // On these cases, ignore 1, 2 and 3 and enlarge the field size of 0 to 128
802 char *seq = (char*)name + strlen(name) - 2;
803 --ip_addr_field;
804 if (seq > name && *seq == '_') {
805 if (seq[1] >= '1' && seq[1] <= '3')
806 continue;
807 // relates to the *previous* field
808 if (is_address_family) {
809 *seq = 0;
810 size = 128;
811 special_type = TPNCP_IP_ADDR;
812 } else {
813 report_warning("Bad address form. Field name: %s", name);
814 ip_addr_field = 0;
815 }
816 }
817 }
818
819 is_address_family = false0;
820 if (current_data_id != data_id) { /* new data */
821 tpncp_data_field_info **fp;
822
823 while (wmem_array_get_count(data_fields_info_arr) <= (unsigned)data_id) {
824 static const tpncp_data_field_info **empty = NULL((void*)0);
825 wmem_array_append_one(data_fields_info_arr, empty)wmem_array_append((data_fields_info_arr), &(empty), 1);
826 }
827 fp = (tpncp_data_field_info **)wmem_array_index(data_fields_info_arr, data_id);
828 if (*fp != NULL((void*)0)) {
829 report_failure(
830 "ERROR! The data_id %d already registered. Cannot register two identical events/command",
831 data_id);
832 continue;
833 }
834 field = wmem_new0(wmem_epan_scope(), tpncp_data_field_info)((tpncp_data_field_info*)wmem_alloc0((wmem_epan_scope()), sizeof
(tpncp_data_field_info)))
;
835 *fp = field;
836 current_data_id = data_id;
837 } else {
838 field->p_next = wmem_new(wmem_epan_scope(), tpncp_data_field_info)((tpncp_data_field_info*)wmem_alloc((wmem_epan_scope()), sizeof
(tpncp_data_field_info)))
;
839 if (!field->p_next)
840 return (-1);
841 field = field->p_next;
842 field->p_next = NULL((void*)0);
843 }
844
845 /* Register specific fields of hf_register_info structure. */
846 if (strcmp(tmp, "primitive")) {
847 enum_val = get_enum_name_val(tmp);
848 if (enum_val == -1) {
849 hf_entr.hfinfo.strings = NULL((void*)0);
850 } else {
851 if (special_type == TPNCP_IP_ADDR)
852 special_type = TPNCP_NORMAL;
853 hf_entr.hfinfo.strings = VALS(tpncp_enums_id_vals[enum_val])((0 ? (const struct _value_string*)0 : ((tpncp_enums_id_vals[
enum_val]))))
;
854 if (!strcmp(tmp, "AddressFamily")) {
855 is_address_family = true1;
856 ip_addr_field = 4;
857 }
858 }
859 } else {
860 hf_entr.hfinfo.strings = NULL((void*)0);
861 }
862 field->descr = -1;
863 field->ipv6_descr = -1;
864 hf_entr.p_id = &field->descr;
865 field->name = wmem_strdup_printf(wmem_epan_scope(), "tpncp.%s", name);
866 hf_entr.hfinfo.name = field->name;
867 hf_entr.hfinfo.abbrev = field->name;
868 switch (size) {
869 case 1:
870 hf_entr.hfinfo.type = FT_BOOLEAN;
871 break;
872 case 2: case 3: case 4:
873 case 5: case 6: case 7: case 8:
874 if (array_dim) {
875 hf_entr.hfinfo.type = FT_STRING;
876 hf_entr.hfinfo.display = BASE_NONE;
877 } else {
878 hf_entr.hfinfo.type = (sign) ? FT_UINT8 : FT_INT8;
879 }
880 break;
881 case 16:
882 hf_entr.hfinfo.type = (sign) ? FT_UINT16 : FT_INT16;
883 break;
884 case 32:
885 if (special_type == TPNCP_IP_ADDR) {
886 hf_entr.hfinfo.display = BASE_NONE;
887 hf_entr.hfinfo.type = FT_IPv4;
888 } else {
889 hf_entr.hfinfo.type = (sign) ? FT_UINT32 : FT_INT32;
890 }
891 break;
892 case 64:
893 hf_entr.hfinfo.type = (sign) ? FT_UINT64 : FT_INT64;
894 break;
895 case 128:
896 if (special_type == TPNCP_IP_ADDR) {
897 hf_entr.hfinfo.display = BASE_NONE;
898 hf_entr.hfinfo.type = FT_IPv4;
899 if (!add_hf(&hf_entr))
900 return -1;
901 hf_entr.p_id = &field->ipv6_descr;
902 hf_entr.hfinfo.type = FT_IPv6;
903 }
904 break;
905 default:
906 break;
907 }
908
909 /* Register initialized hf_register_info in global database. */
910 if (!add_hf(&hf_entr))
911 return -1;
912 field->sign = sign;
913 field->size = size;
914 field->array_dim = array_dim;
915 field->special_type = is_address_family ? TPNCP_ADDRESS_FAMILY : special_type;
916 field->since = since;
917 }
918
919 *data_fields_len = wmem_array_get_count(data_fields_info_arr);
920 *data_fields_info = (tpncp_data_field_info **)wmem_array_finalize(data_fields_info_arr);
921
922 return 0;
923}
924
925/*---------------------------------------------------------------------------*/
926
927static int
928init_tpncp_db(void)
929{
930 char tpncp_dat_file_path[MAX_TPNCP_DB_ENTRY_LEN3000];
931 FILE *file;
932
933 snprintf(tpncp_dat_file_path, MAX_TPNCP_DB_ENTRY_LEN3000,
934 "%s" G_DIR_SEPARATOR_S"/" "tpncp" G_DIR_SEPARATOR_S"/" "tpncp.dat", get_datafile_dir(application_configuration_environment_prefix()));
935
936 /* Open file with TPNCP data. */
937 if ((file = ws_fopenfopen(tpncp_dat_file_path, "r")) == NULL((void*)0))
7
Taking false branch
938 return (-1);
939 fill_tpncp_id_vals(&tpncp_events_id_vals, file);
8
Calling 'fill_tpncp_id_vals'
14
Returning from 'fill_tpncp_id_vals'
940 fill_tpncp_id_vals(&tpncp_commands_id_vals, file);
15
Calling 'fill_tpncp_id_vals'
941 fill_enums_id_vals(&tpncp_enums_name_vals, &tpncp_enums_id_vals, file);
942 init_tpncp_data_fields_info(&tpncp_events_info_db, &tpncp_events_info_len, file);
943 init_tpncp_data_fields_info(&tpncp_commands_info_db, &tpncp_commands_info_len, file);
944
945 fclose(file);
946 return 0;
947}
948
949/*---------------------------------------------------------------------------*/
950
951void
952proto_reg_handoff_tpncp(void)
953{
954 static bool_Bool initialized = false0;
955
956 if (proto_tpncp <= 0) return;
1
Assuming 'proto_tpncp' is > 0
2
Taking false branch
957
958 if (!initialized
2.1
'initialized' is false
) {
3
Taking true branch
959 dissector_add_uint_with_preference("udp.port", UDP_PORT_TPNCP_TRUNKPACK2424, tpncp_handle);
960 dissector_add_uint_with_preference("tcp.port", TCP_PORT_TPNCP_TRUNKPACK2424, tpncp_tcp_handle);
961 dissector_add_uint("acdr.media_type", ACDR_PCIIF_COMMAND, tpncp_handle);
962 dissector_add_uint("acdr.media_type", ACDR_COMMAND, tpncp_handle);
963 dissector_add_uint("acdr.media_type", ACDR_Event, create_dissector_handle(dissect_acdr_event, proto_tpncp));
964 dissector_add_uint("acdr.media_type", ACDR_TPNCP,
965 create_dissector_handle(dissect_acdr_tpncp_by_tracepoint, proto_tpncp));
966 dissector_add_uint("acdr.tls_application", TLS_APP_TPNCP, tpncp_handle);
967 initialized = true1;
968 }
969 /* If we weren't able to load the database (and thus the hf_ entries)
970 * do not attach to any ports (if we did then we'd get a "dissector bug"
971 * assertions every time a packet is handed to us and we tried to use the
972 * hf_ entry).
973 */
974 if (!global_tpncp_load_db)
4
Assuming 'global_tpncp_load_db' is true
975 return;
976
977 if (hf_allocated == 0 && init_tpncp_db() == -1) {
5
Assuming 'hf_allocated' is equal to 0
6
Calling 'init_tpncp_db'
978 report_failure("tpncp: Could not load tpncp.dat file, tpncp dissector will not work");
979 return;
980 }
981
982 if (db_initialized)
983 return;
984
985 /* Rather than duplicating large quantities of code from
986 * proto_register_field_array() and friends to sanitize the tpncp.dat file
987 * when we read it, just catch any exceptions we get while registering and
988 * take them as a hint that the file is corrupt. Then move on, so that at
989 * least the rest of the protocol dissectors will still work.
990 */
991 TRY{ except_t *volatile exc; volatile int except_state = 0; static
const except_id_t catch_spec[] = { { 1, 0 } }; { struct except_stacknode
except_sn; struct except_catch except_ch; except_setup_try(&
except_sn, &except_ch, catch_spec, 1); if (_setjmp (except_ch
.except_jmp)) *(&exc) = &except_ch.except_obj; else *
(&exc) = 0; if(except_state & 1) except_state |= 2; except_state
&= ~1; if (except_state == 0 && exc == 0)
{
992 int idx;
993 /* The function proto_register_field_array does not work with dynamic
994 * arrays, so pass dynamic array elements one-by-one in the loop.
995 */
996 for (idx = 0; idx < hf_size; idx++)
997 proto_register_field_array(proto_tpncp, &hf[idx], 1);
998 }
999
1000 CATCH_ALLif (except_state == 0 && exc != 0 && (except_state
|=1))
{
1001 report_failure("Corrupt tpncp.dat file, tpncp dissector will not work.");
1002 }
1003
1004 ENDTRYif(!(except_state&1) && exc != 0) except_rethrow(
exc); except_free(except_ch.except_obj.except_dyndata); except_pop
(); };}
;
1005 db_initialized = true1;
1006}
1007
1008/*---------------------------------------------------------------------------*/
1009
1010void
1011proto_register_tpncp(void)
1012{
1013 module_t *tpncp_module;
1014 expert_module_t* expert_tpncp;
1015 static int *ett[] = {
1016 &ett_tpncp,
1017 &ett_tpncp_body
1018 };
1019
1020 static ei_register_info ei[] = {
1021 { &ei_tpncp_unknown_data, { "tpncp.unknown_data", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Unknown data", 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)}}
} },
1022 };
1023
1024 /* this dissector reads hf entries from a database
1025 * a boolean preference defines whether the database is loaded or not
1026 * we initialize the hf array in the handoff function when we have
1027 * access to the preference's value */
1028
1029 proto_tpncp = proto_register_protocol("TPNCP (TrunkPack Network Control Protocol)",
1030 "TPNCP", "tpncp");
1031
1032 tpncp_handle = register_dissector("tpncp", dissect_tpncp, proto_tpncp);
1033 tpncp_tcp_handle = register_dissector("tpncp.tcp", dissect_tpncp_tcp, proto_tpncp);
1034
1035 tpncp_module = prefs_register_protocol(proto_tpncp, proto_reg_handoff_tpncp);
1036
1037 proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
1038
1039 expert_tpncp = expert_register_protocol(proto_tpncp);
1040 expert_register_field_array(expert_tpncp, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
1041
1042 /* See https://gitlab.com/wireshark/wireshark/-/issues/9569 for some discussion on this as well */
1043 prefs_register_bool_preference(tpncp_module, "load_db",
1044 "Whether to load DB or not; if DB not loaded dissector is passive",
1045 "Whether to load the Database or not; not loading the DB"
1046 " disables the protocol; Wireshark has to be restarted for the"
1047 " setting to take effect.",
1048 &global_tpncp_load_db);
1049}
1050
1051/*
1052 * Editor modelines
1053 *
1054 * Local Variables:
1055 * c-basic-offset: 4
1056 * tab-width: 8
1057 * indent-tabs-mode: nil
1058 * End:
1059 *
1060 * ex: set shiftwidth=4 tabstop=8 expandtab:
1061 * :indentSize=4:tabSize=8:noTabs=true:
1062 */