epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-tpncp.c
blobbb99fae8a84079f2ade55a776ae8b779c18f8371
1 /* packet-tpncp.c
2 * Routines for Audiocodes TrunkPack Network Control Protocol (TPNCP) dissection
4 * Copyright (c) 2007 by Valery Sigalov <valery.sigalov@audiocodes.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.com>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 /*---------------------------------------------------------------------------*/
15 #define WS_LOG_DOMAIN "TPNCP"
16 #include "config.h"
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 <epan/wmem_scopes.h>
27 #include "packet-acdr.h"
28 #include "packet-tcp.h"
30 /*---------------------------------------------------------------------------*/
32 #define BASE_TPNCP_PORT 2424
33 #define HA_PORT_TPNCP_TRUNKPACK 2442
34 #define TCP_PORT_TPNCP_TRUNKPACK BASE_TPNCP_PORT
35 #define UDP_PORT_TPNCP_TRUNKPACK BASE_TPNCP_PORT
36 #define TCP_PORT_TPNCP_HOST BASE_TPNCP_PORT
37 #define UDP_PORT_TPNCP_HOST BASE_TPNCP_PORT
39 #define MAX_TPNCP_DB_ENTRY_LEN 3000
41 /*---------------------------------------------------------------------------*/
43 void proto_register_tpncp(void);
44 void proto_reg_handoff_tpncp(void);
46 enum SpecialFieldType {
47 TPNCP_NORMAL,
48 TPNCP_ADDRESS_FAMILY,
49 TPNCP_IP_ADDR,
50 TPNCP_OPEN_CHANNEL_START,
51 TPNCP_SECURITY_START,
52 TPNCP_SECURITY_OFFSET,
53 RTP_STATE_START,
54 RTP_STATE_OFFSET,
55 RTP_STATE_END,
56 TPNCP_CHANNEL_CONFIGURATION
59 /* The linked list for storing information about specific data fields. */
60 typedef struct tpncp_data_field_info
62 char *name;
63 int descr;
64 int ipv6_descr;
65 int array_dim;
66 enum SpecialFieldType special_type;
67 unsigned char size;
68 unsigned char sign;
69 int since;
70 struct tpncp_data_field_info *p_next;
71 } tpncp_data_field_info;
73 /*---------------------------------------------------------------------------
74 * Desegmentation of TPNCP over TCP */
75 static bool tpncp_desegment = true;
77 /* Database for storing information about all TPNCP events. */
78 static tpncp_data_field_info **tpncp_events_info_db;
79 unsigned tpncp_events_info_len;
81 /* Database for storing information about all TPNCP commands. */
82 static tpncp_data_field_info **tpncp_commands_info_db;
83 unsigned tpncp_commands_info_len;
85 /* Global variables for bitfields representation. */
86 static int bits[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
88 /* TPNCP packet header fields. */
89 static int proto_tpncp;
90 static int hf_tpncp_version;
91 static int hf_tpncp_length;
92 static int hf_tpncp_seq_number;
93 static int hf_tpncp_length_ext;
94 static int hf_tpncp_reserved;
95 static int hf_tpncp_command_id;
96 static int hf_tpncp_event_id;
97 static int hf_tpncp_cid;
99 static expert_field ei_tpncp_unknown_data;
101 /* TPNCP fields defining a subtree. */
102 static int ett_tpncp;
103 static int ett_tpncp_body;
105 static bool global_tpncp_load_db;
107 static dissector_handle_t tpncp_handle;
108 static dissector_handle_t tpncp_tcp_handle;
110 /* TODO: Runtime value_string_ext arrays should be used*/
111 static value_string *tpncp_commands_id_vals;
112 static value_string *tpncp_events_id_vals;
113 static value_string **tpncp_enums_id_vals;
114 static char **tpncp_enums_name_vals;
116 static int hf_size;
117 static int hf_allocated;
118 static hf_register_info *hf;
120 static bool db_initialized;
122 /*---------------------------------------------------------------------------*/
124 enum AddressFamily {
125 TPNCP_IPV4 = 2,
126 TPNCP_IPV6 = 10,
127 TPNCP_IPV6_PSOS = 28
130 static void
131 dissect_tpncp_data(unsigned data_id, packet_info *pinfo, tvbuff_t *tvb, proto_tree *ltree,
132 int *offset, tpncp_data_field_info **data_fields_info, int ver, unsigned encoding)
134 int8_t g_char;
135 uint8_t g_uchar;
136 int g_str_len, counter, bitshift, bitmask;
137 tpncp_data_field_info *field = NULL;
138 int bitindex = encoding == ENC_LITTLE_ENDIAN ? 7 : 0;
139 enum AddressFamily address_family = TPNCP_IPV4;
140 int open_channel_start = -1, security_offset = 0, rtp_state_offset = 0;
141 int channel_b_offset = 0, rtp_tx_state_offset = 0, rtp_state_size = 0;
142 const int initial_offset = *offset;
144 for (field = data_fields_info[data_id]; field; field = field->p_next) {
145 if (field->since > 0 && field->since > ver)
146 continue;
147 switch (field->special_type) {
148 case TPNCP_OPEN_CHANNEL_START:
149 open_channel_start = *offset;
150 break;
151 case TPNCP_SECURITY_OFFSET: {
152 const uint32_t sec_offset = tvb_get_uint32(tvb, *offset, encoding);
153 if (sec_offset > 0 && open_channel_start >= 0)
154 security_offset = open_channel_start + sec_offset;
155 break;
157 case TPNCP_SECURITY_START:
158 *offset = security_offset;
159 open_channel_start = -1;
160 security_offset = 0;
161 break;
162 case RTP_STATE_OFFSET:
163 rtp_state_offset = tvb_get_int32(tvb, *offset, encoding);
164 if (rtp_state_offset > 0)
165 rtp_state_offset += initial_offset + 4; /* The offset starts after CID */
166 break;
167 case RTP_STATE_START:
168 *offset = rtp_state_offset;
169 rtp_state_offset = 0;
170 if (rtp_tx_state_offset == 0) {
171 rtp_state_size = (tvb_reported_length_remaining(tvb, *offset) - 4) / 2;
172 rtp_tx_state_offset = *offset + rtp_state_size;
173 } else {
174 *offset = rtp_tx_state_offset;
175 rtp_tx_state_offset += rtp_state_size;
177 break;
178 case RTP_STATE_END:
179 rtp_tx_state_offset = 0;
180 break;
181 case TPNCP_CHANNEL_CONFIGURATION:
182 if (channel_b_offset == 0) {
183 int channel_configuration_size = tvb_reported_length_remaining(tvb, *offset) / 2;
184 channel_b_offset = *offset + channel_configuration_size;
185 } else {
186 *offset = channel_b_offset;
187 channel_b_offset = 0;
189 break;
190 case TPNCP_ADDRESS_FAMILY:
191 address_family = (enum AddressFamily)tvb_get_uint32(tvb, *offset, encoding);
192 // fall-through
193 default:
194 if (open_channel_start != -1 && security_offset > 0 && *offset >= security_offset)
195 continue;
196 if (rtp_state_offset > 0 && *offset >= rtp_state_offset)
197 continue;
198 if (rtp_tx_state_offset > 0 && *offset >= rtp_tx_state_offset)
199 continue;
200 if (channel_b_offset > 0 && *offset >= channel_b_offset)
201 continue;
202 break;
204 switch (field->size) {
205 case 1: case 2: case 3: case 4:
206 case 5: case 6: case 7: case 8:
207 /* add char array */
208 if ((g_str_len = field->array_dim)) {
209 g_str_len = MIN(g_str_len, tvb_reported_length_remaining(tvb, *offset));
210 proto_tree_add_item(ltree, field->descr, tvb, *offset, g_str_len, ENC_NA | ENC_ASCII);
211 (*offset) += g_str_len;
212 } else { /* add single char */
213 g_uchar = tvb_get_uint8(tvb, *offset);
215 /* bitfields */
217 if (field->size != 8) {
218 for (counter = 0, bitmask = 0x0, bitshift = bitindex;
219 counter < field->size;
220 counter++) {
221 bitmask |= bits[bitindex]; /* Bitmask of interesting bits. */
222 bitindex += encoding == ENC_LITTLE_ENDIAN ? -1 : 1;
224 g_uchar &= bitmask;
225 g_uchar >>= bitshift;
227 if (field->sign || field->size != 8) {
228 proto_tree_add_uint(ltree, field->descr, tvb, *offset, 1, g_uchar);
229 } else {
230 /* signed*/
231 g_char = (int8_t) g_uchar;
232 proto_tree_add_int(ltree, field->descr, tvb, *offset, 1, g_char);
234 if (((bitindex == 0 || bitindex == 8) && encoding == ENC_BIG_ENDIAN) ||
235 ((bitindex == -1 || bitindex == 7) && encoding == ENC_LITTLE_ENDIAN)) {
236 (*offset)++;
237 bitindex = encoding == ENC_LITTLE_ENDIAN ? 7 : 0;
240 break;
241 case 16:
242 proto_tree_add_item(ltree, field->descr, tvb, *offset, 2, encoding);
243 (*offset) += 2;
244 break;
245 case 32:
246 proto_tree_add_item(ltree, field->descr, tvb, *offset, 4, encoding);
247 (*offset) += 4;
248 break;
249 case 128:
250 if (field->special_type == TPNCP_IP_ADDR) {
251 if (address_family == TPNCP_IPV6 || address_family == TPNCP_IPV6_PSOS)
252 proto_tree_add_item(ltree, field->ipv6_descr, tvb, *offset, 16, encoding);
253 else
254 proto_tree_add_item(ltree, field->descr, tvb, *offset, 4, encoding);
255 address_family = TPNCP_IPV4;
257 (*offset) += 16;
258 break;
259 default:
260 break;
262 if (tvb_reported_length_remaining(tvb, *offset) <= 0)
263 break;
265 if ((g_str_len = tvb_reported_length_remaining(tvb, *offset)) > 0) {
266 expert_add_info_format(pinfo, ltree, &ei_tpncp_unknown_data, "TPNCP Unknown Data");
267 (*offset) += g_str_len;
271 /*---------------------------------------------------------------------------*/
272 static int
273 dissect_tpncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
275 proto_item *item = NULL;
276 proto_tree *tpncp_tree = NULL, *event_tree, *command_tree;
277 int offset = 0, cid = -1;
278 unsigned id;
279 unsigned seq_number, len, ver;
280 unsigned len_ext, reserved, encoding;
281 uint32_t fullLength;
283 if (!db_initialized)
284 return 0;
286 encoding = tvb_get_ntohs(tvb, 8) == 0 ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
288 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPNCP");
290 item = proto_tree_add_item(tree, proto_tpncp, tvb, 0, -1, ENC_NA);
291 tpncp_tree = proto_item_add_subtree(item, ett_tpncp);
293 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_version, tvb, 0, 2, encoding, &ver);
294 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_length, tvb, 2, 2, encoding, &len);
295 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_seq_number, tvb, 4, 2, encoding, &seq_number);
296 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_length_ext, tvb, 6, 1, encoding, &len_ext);
297 proto_tree_add_item_ret_uint(tpncp_tree, hf_tpncp_reserved, tvb, 7, 1, encoding, &reserved);
298 fullLength = 0xffff * len_ext + len;
300 id = tvb_get_uint32(tvb, 8, encoding);
301 if (len > 8)
302 cid = tvb_get_int32(tvb, 12, encoding);
303 if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK ||
304 pinfo->srcport == HA_PORT_TPNCP_TRUNKPACK) {
305 if (try_val_to_str(id, tpncp_events_id_vals)) {
306 proto_tree_add_uint(tpncp_tree, hf_tpncp_event_id, tvb, 8, 4, id);
307 if (len > 8)
308 proto_tree_add_int(tpncp_tree, hf_tpncp_cid, tvb, 12, 4, cid);
309 offset += 16;
310 if (id < tpncp_events_info_len && tpncp_events_info_db[id] != NULL && len > 12) {
311 event_tree = proto_tree_add_subtree_format(
312 tree, tvb, offset, -1, ett_tpncp_body, NULL,
313 "TPNCP Event: %s (%d)",
314 val_to_str_const(id, tpncp_events_id_vals, "Unknown"), id);
315 dissect_tpncp_data(id, pinfo, tvb, event_tree, &offset, tpncp_events_info_db,
316 ver, encoding);
319 col_add_fstr(pinfo->cinfo, COL_INFO,
320 "EvID=%s(%d), SeqNo=%d, CID=%d, Len=%d, Ver=%d",
321 val_to_str_const(id, tpncp_events_id_vals, "Unknown"),
322 id, seq_number, cid, fullLength, ver);
323 } else {
324 if (try_val_to_str(id, tpncp_commands_id_vals)) {
325 proto_tree_add_uint(tpncp_tree, hf_tpncp_command_id, tvb, 8, 4, id);
326 offset += 12;
327 if (id < tpncp_commands_info_len && tpncp_commands_info_db[id] != NULL && len > 8) {
328 command_tree = proto_tree_add_subtree_format(
329 tree, tvb, offset, -1, ett_tpncp_body, NULL,
330 "TPNCP Command: %s (%d)",
331 val_to_str_const(id, tpncp_commands_id_vals, "Unknown"), id);
332 dissect_tpncp_data(id, pinfo, tvb, command_tree, &offset, tpncp_commands_info_db,
333 ver, encoding);
336 col_add_fstr(pinfo->cinfo, COL_INFO,
337 "CmdID=%s(%d), SeqNo=%d, CID=%d, Len=%d, Ver=%d",
338 val_to_str_const(id, tpncp_commands_id_vals, "Unknown"),
339 id, seq_number, cid, fullLength, ver);
342 return tvb_reported_length(tvb);
345 /*---------------------------------------------------------------------------*/
347 static unsigned
348 get_tpncp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
350 uint32_t plen;
352 /* Get the length of the TPNCP packet. */
353 plen = tvb_get_ntohs(tvb, offset + 2) + 0xffff * tvb_get_uint8(tvb, offset + 6);
355 /* Length does not include the version+length field. */
356 plen += 4;
358 return plen;
361 /*---------------------------------------------------------------------------*/
363 static int
364 dissect_tpncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
366 if (!db_initialized)
367 return 0;
369 if (pinfo->can_desegment)
370 /* If desegmentation is enabled (TCP preferences) use the desegmentation API. */
371 tcp_dissect_pdus(tvb, pinfo, tree, tpncp_desegment, 4, get_tpncp_pdu_len,
372 dissect_tpncp, data);
373 else
374 /* Otherwise use the regular dissector (might not give correct dissection). */
375 dissect_tpncp(tvb, pinfo, tree, data);
377 return tvb_reported_length(tvb);
380 static int
381 dissect_acdr_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
383 int res = 0;
384 acdr_dissector_data_t *acdr_data = (acdr_dissector_data_t *) data;
385 uint32_t orig_port = pinfo->srcport;
387 if (acdr_data == NULL)
388 return 0;
390 // only on version 2+ events are sent with TPNCP header that enables using tpncp parser
391 if (acdr_data->version <= 1)
392 return 0;
394 // the TPNCP dissector uses the following statement to
395 // differentiate command from event:
396 // if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) -> Event
397 // so for proper dissection we want to imitate this behaviour
398 pinfo->srcport = UDP_PORT_TPNCP_TRUNKPACK;
399 res = dissect_tpncp(tvb, pinfo, tree, NULL);
400 pinfo->srcport = orig_port;
401 return res;
404 static int
405 dissect_acdr_tpncp_by_tracepoint(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
407 acdr_dissector_data_t *acdr_data = (acdr_dissector_data_t *) data;
408 uint32_t orig_port = pinfo->srcport;
409 int res = 0;
411 if (acdr_data == NULL)
412 return 0;
414 // the TPNCP dissector uses the following statement to
415 // differentiate command from event:
416 // if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) -> Event
417 // so for proper dissection we want to imitate this behaviour
419 if (acdr_data->trace_point == Host2Net) // event
420 pinfo->srcport = UDP_PORT_TPNCP_TRUNKPACK;
421 else // Net2Host ->command
422 pinfo->srcport = UDP_PORT_TPNCP_TRUNKPACK + 1;
424 res = dissect_tpncp(tvb, pinfo, tree, NULL);
425 pinfo->srcport = orig_port;
426 return res;
429 /*---------------------------------------------------------------------------*/
431 static bool
432 fgetline(char *buffer, int size, FILE *file)
434 if (!fgets(buffer, size, file))
435 return 0;
436 size_t last = strlen(buffer);
437 if (buffer[last - 1] == '\n')
438 buffer[last - 1] = 0;
439 return 1;
442 static int
443 fill_tpncp_id_vals(value_string **strings, FILE *file)
445 wmem_array_t *vs_arr;
446 char *line_in_file;
448 if (file == NULL) return -1;
450 line_in_file = (char *) g_malloc(MAX_TPNCP_DB_ENTRY_LEN);
451 vs_arr = wmem_array_new(NULL, sizeof **strings);
453 while (fgetline(line_in_file, MAX_TPNCP_DB_ENTRY_LEN, file) && !feof(file)) {
454 int tpncp_id = 0;
455 char tpncp_name[256];
457 if (!strncmp(line_in_file, "#####", 5))
458 break;
459 if (sscanf(line_in_file, "%255s %d", tpncp_name, &tpncp_id) == 2) {
460 value_string const string = {
461 .value = (uint32_t)tpncp_id,
462 .strptr = wmem_strdup(wmem_epan_scope(), tpncp_name)
464 wmem_array_append_one(vs_arr, string);
468 wmem_array_set_null_terminator(vs_arr);
469 *strings = wmem_array_finalize(vs_arr);
470 g_free(line_in_file);
472 return 0;
475 /*---------------------------------------------------------------------------*/
477 static int
478 fill_enums_id_vals(char ***enum_names, value_string ***enum_value_strings, FILE *file)
480 wmem_array_t *enum_name_arr, *enum_vs_arr, *enum_vs = NULL;
481 char *line_in_file;
482 char enum_type[256];
484 line_in_file = (char *) g_malloc(MAX_TPNCP_DB_ENTRY_LEN);
485 enum_type[0] = '\0';
487 enum_name_arr = wmem_array_new(NULL, sizeof **enum_names);
488 enum_vs_arr = wmem_array_new(NULL, sizeof **enum_value_strings);
490 while (fgetline(line_in_file, MAX_TPNCP_DB_ENTRY_LEN, file)) {
491 char enum_name[256], enum_str[256];
492 int enum_id;
494 if (!strncmp(line_in_file, "#####", 5))
495 break;
496 if (sscanf(line_in_file, "%255s %255s %d", enum_name, enum_str, &enum_id) == 3) {
497 if (strcmp(enum_type, enum_name) != 0) {
498 /* New record. */
499 if (enum_vs != NULL) {
500 /* The previous enum_vs is now complete. */
501 wmem_array_set_null_terminator(enum_vs);
502 value_string *new_enum_vs = wmem_array_finalize(enum_vs);
503 wmem_array_append_one(enum_vs_arr, new_enum_vs);
505 enum_vs = wmem_array_sized_new(NULL, sizeof ***enum_value_strings, 10);
507 char *enum_name_alloc = wmem_strdup(wmem_epan_scope(), enum_name);
508 wmem_array_append_one(enum_name_arr, enum_name_alloc);
509 g_strlcpy(enum_type, enum_name, sizeof enum_type);
511 value_string const vs = {
512 .value = enum_id,
513 .strptr = wmem_strdup(wmem_epan_scope(), enum_str)
515 wmem_array_append_one(enum_vs, vs);
519 if (enum_vs != NULL) {
520 /* The final enum_vs is now complete. */
521 wmem_array_set_null_terminator(enum_vs);
522 value_string *new_enum_vs = wmem_array_finalize(enum_vs);
523 wmem_array_append_one(enum_vs_arr, new_enum_vs);
526 wmem_array_set_null_terminator(enum_name_arr);
527 *enum_names = (char **)wmem_array_finalize(enum_name_arr);
529 wmem_array_set_null_terminator(enum_vs_arr);
530 *enum_value_strings = (value_string **)wmem_array_finalize(enum_vs_arr);
531 g_free(line_in_file);
533 return 0;
536 /*---------------------------------------------------------------------------*/
538 static int
539 get_enum_name_val(const char *enum_name)
541 int enum_val = 0;
543 while (tpncp_enums_name_vals[enum_val]) {
544 if (!strcmp(enum_name, tpncp_enums_name_vals[enum_val]))
545 return enum_val;
546 enum_val++;
549 return -1;
552 /*---------------------------------------------------------------------------*/
554 static bool add_hf(hf_register_info *hf_entr)
556 if (hf_size >= hf_allocated) {
557 void *newbuf;
558 hf_allocated += 1024;
559 newbuf = wmem_realloc(wmem_epan_scope(), hf, hf_allocated * sizeof (hf_register_info));
560 if (!newbuf)
561 return false;
562 hf = (hf_register_info *) newbuf;
564 memcpy(hf + hf_size, hf_entr, sizeof (hf_register_info));
565 hf_size++;
566 return true;
569 static int
570 init_tpncp_data_fields_info(tpncp_data_field_info ***data_fields_info, unsigned *data_fields_len, FILE *file)
572 static bool was_registered = false;
573 char tpncp_db_entry[MAX_TPNCP_DB_ENTRY_LEN];
574 char entry_copy[MAX_TPNCP_DB_ENTRY_LEN];
575 const char *name = NULL, *tmp = NULL;
576 int enum_val, data_id, current_data_id = -1, array_dim;
577 unsigned char size;
578 enum SpecialFieldType special_type;
579 bool sign, is_address_family;
580 unsigned idx, since, ip_addr_field;
581 tpncp_data_field_info *field = NULL;
582 hf_register_info hf_entr;
583 wmem_array_t *data_fields_info_arr;
585 hf_register_info hf_tpncp[] = {
587 &hf_tpncp_version,
589 "Version",
590 "tpncp.version",
591 FT_UINT16,
592 BASE_DEC,
593 NULL,
594 0x0,
595 NULL, HFILL
599 &hf_tpncp_length,
601 "Length",
602 "tpncp.length",
603 FT_UINT16,
604 BASE_DEC,
605 NULL,
606 0x0,
607 NULL, HFILL
611 &hf_tpncp_seq_number,
613 "Sequence number",
614 "tpncp.seq_number",
615 FT_UINT16,
616 BASE_DEC,
617 NULL,
618 0x0,
619 NULL, HFILL
623 &hf_tpncp_length_ext,
625 "Length Extension",
626 "tpncp.lengthextension",
627 FT_UINT8,
628 BASE_DEC,
629 NULL,
630 0x0,
631 NULL, HFILL
635 &hf_tpncp_reserved,
637 "Reserved",
638 "tpncp.reserved",
639 FT_UINT8,
640 BASE_DEC,
641 NULL,
642 0x0,
643 NULL, HFILL
647 &hf_tpncp_command_id,
649 "Command ID",
650 "tpncp.command_id",
651 FT_UINT32,
652 BASE_DEC,
653 VALS(tpncp_commands_id_vals),
654 0x0,
655 NULL, HFILL
659 &hf_tpncp_event_id,
661 "Event ID",
662 "tpncp.event_id",
663 FT_UINT32,
664 BASE_DEC,
665 VALS(tpncp_events_id_vals),
666 0x0,
667 NULL, HFILL
671 &hf_tpncp_cid,
673 "Channel ID",
674 "tpncp.channel_id",
675 FT_INT32,
676 BASE_DEC,
677 NULL,
678 0x0,
679 NULL, HFILL
684 /* Register common fields of hf_register_info structure. */
685 hf_entr.hfinfo.type = FT_NONE;
686 hf_entr.hfinfo.strings = NULL;
687 hf_entr.hfinfo.bitmask = 0x0;
688 hf_entr.hfinfo.blurb = NULL;
689 HFILL_INIT(hf_entr);
691 if (!was_registered) {
692 void *newbuf;
694 /* Register non-standard data should be done only once. */
695 hf_allocated = hf_size + (int) array_length(hf_tpncp);
696 newbuf = wmem_realloc(wmem_epan_scope(), hf, hf_allocated * sizeof (hf_register_info));
697 if (!newbuf)
698 return -1;
699 hf = (hf_register_info *) newbuf;
700 for (idx = 0; idx < array_length(hf_tpncp); idx++) {
701 memcpy(hf + hf_size, hf_tpncp + idx, sizeof (hf_register_info));
702 hf_size++;
704 was_registered = true;
707 is_address_family = false;
708 ip_addr_field = 0;
710 data_fields_info_arr = wmem_array_new(NULL, sizeof **data_fields_info);
712 /* Register standard data. */
713 while (fgetline(tpncp_db_entry, MAX_TPNCP_DB_ENTRY_LEN, file)) {
714 special_type = TPNCP_NORMAL;
715 since = 0;
716 snprintf(entry_copy, MAX_TPNCP_DB_ENTRY_LEN, "%s", tpncp_db_entry);
717 if (!strncmp(tpncp_db_entry, "#####", 5))
718 break;
720 /* Default to decimal display type */
721 hf_entr.hfinfo.display = BASE_DEC;
722 if ((tmp = strtok(tpncp_db_entry, " ")) == NULL) {
723 report_failure(
724 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
725 entry_copy);
726 continue;
728 data_id = (int) g_ascii_strtoll(tmp, NULL, 10);
729 if ((name = strtok(NULL, " ")) == NULL) {
730 report_failure(
731 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
732 entry_copy);
733 continue;
736 /* We happen to have a line without a name (57 0 32 0 0 primitive). Consider unnamed. */
737 if (g_ascii_isdigit(*name)) {
738 tmp = name;
739 name = "unnamed";
740 } else {
741 if ((tmp = strtok(NULL, " ")) == NULL) {
742 report_failure(
743 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
744 entry_copy);
745 continue;
748 if (name[0] == 'c' && !strcmp(name, "cmd_rev_lsb"))
749 special_type = TPNCP_OPEN_CHANNEL_START;
750 else if (name[0] == 'r' && !strcmp(name, "rtp_authentication_algorithm"))
751 special_type = TPNCP_SECURITY_START;
752 else if (name[0] == 's' && !strcmp(name, "security_cmd_offset"))
753 special_type = TPNCP_SECURITY_OFFSET;
754 else if (data_id != 1611 && name[0] == 's' && !strcmp(name, "ssrc"))
755 special_type = RTP_STATE_START;
756 else if (name[0] == 'r' && !strcmp(name, "rtp_tx_state_ssrc"))
757 special_type = RTP_STATE_START;
758 else if (name[0] == 'r' && !strcmp(name, "rtp_state_offset"))
759 special_type = RTP_STATE_OFFSET;
760 else if (name[0] == 's' && !strcmp(name, "state_update_time_stamp"))
761 special_type = RTP_STATE_END;
762 else if (data_id == 1611 && name[0] == 'c' && strstr(name, "configuration_type_updated"))
763 special_type = TPNCP_CHANNEL_CONFIGURATION;
764 else if ((data_id == 4 && strstr(name, "secondary_rtp_seq_num")) ||
765 (data_id == 1611 && strstr(name, "dtls_remote_fingerprint_alg"))) {
766 since = 7401;
768 sign = !!((bool) g_ascii_strtoll(tmp, NULL, 10));
769 if ((tmp = strtok(NULL, " ")) == NULL) {
770 report_failure(
771 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
772 entry_copy);
773 continue;
775 size = (unsigned char) g_ascii_strtoll(tmp, NULL, 10);
776 if ((tmp = strtok(NULL, " ")) == NULL) {
777 report_failure(
778 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
779 entry_copy);
780 continue;
782 array_dim = (int) g_ascii_strtoll(tmp, NULL, 10);
783 if ((tmp = strtok(NULL, " ")) == NULL) {
784 report_failure(
785 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
786 entry_copy);
787 continue;
789 if (sign && g_ascii_strtoll(tmp, NULL, 10))
790 special_type = TPNCP_IP_ADDR;
791 if ((tmp = strtok(NULL, "\n")) == NULL) {
792 report_failure(
793 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
794 entry_copy);
795 continue;
798 if (ip_addr_field > 0) {
799 // ip address that comes after address family has 4 fields: ip_addr_0, ip_addr_1, 2 and 3
800 // On these cases, ignore 1, 2 and 3 and enlarge the field size of 0 to 128
801 char *seq = (char*)name + strlen(name) - 2;
802 --ip_addr_field;
803 if (seq > name && *seq == '_') {
804 if (seq[1] >= '1' && seq[1] <= '3')
805 continue;
806 // relates to the *previous* field
807 if (is_address_family) {
808 *seq = 0;
809 size = 128;
810 special_type = TPNCP_IP_ADDR;
811 } else {
812 report_warning("Bad address form. Field name: %s", name);
813 ip_addr_field = 0;
818 is_address_family = false;
819 if (current_data_id != data_id) { /* new data */
820 tpncp_data_field_info **fp;
822 while (wmem_array_get_count(data_fields_info_arr) <= (unsigned)data_id) {
823 static const tpncp_data_field_info **empty = NULL;
824 wmem_array_append_one(data_fields_info_arr, empty);
826 fp = (tpncp_data_field_info **)wmem_array_index(data_fields_info_arr, data_id);
827 if (*fp != NULL) {
828 report_failure(
829 "ERROR! The data_id %d already registered. Cannot register two identical events/command",
830 data_id);
831 continue;
833 field = wmem_new0(wmem_epan_scope(), tpncp_data_field_info);
834 *fp = field;
835 current_data_id = data_id;
836 } else {
837 field->p_next = wmem_new(wmem_epan_scope(), tpncp_data_field_info);
838 if (!field->p_next)
839 return (-1);
840 field = field->p_next;
841 field->p_next = NULL;
844 /* Register specific fields of hf_register_info structure. */
845 if (strcmp(tmp, "primitive")) {
846 enum_val = get_enum_name_val(tmp);
847 if (enum_val == -1) {
848 hf_entr.hfinfo.strings = NULL;
849 } else {
850 hf_entr.hfinfo.strings = VALS(tpncp_enums_id_vals[enum_val]);
851 if (!strcmp(tmp, "AddressFamily")) {
852 is_address_family = true;
853 ip_addr_field = 4;
856 } else {
857 hf_entr.hfinfo.strings = NULL;
859 field->descr = -1;
860 field->ipv6_descr = -1;
861 hf_entr.p_id = &field->descr;
862 field->name = wmem_strdup_printf(wmem_epan_scope(), "tpncp.%s", name);
863 hf_entr.hfinfo.name = field->name;
864 hf_entr.hfinfo.abbrev = field->name;
865 switch (size) {
866 case 1: case 2: case 3: case 4:
867 case 5: case 6: case 7: case 8:
868 if (array_dim) {
869 hf_entr.hfinfo.type = FT_STRING;
870 hf_entr.hfinfo.display = BASE_NONE;
871 } else {
872 hf_entr.hfinfo.type = (sign) ? FT_UINT8 : FT_INT8;
874 break;
875 case 16:
876 hf_entr.hfinfo.type = (sign) ? FT_UINT16 : FT_INT16;
877 break;
878 case 32:
879 if (special_type == TPNCP_IP_ADDR) {
880 hf_entr.hfinfo.display = BASE_NONE;
881 hf_entr.hfinfo.type = FT_IPv4;
882 } else {
883 hf_entr.hfinfo.type = (sign) ? FT_UINT32 : FT_INT32;
885 break;
886 case 128:
887 if (special_type == TPNCP_IP_ADDR) {
888 hf_entr.hfinfo.display = BASE_NONE;
889 hf_entr.hfinfo.type = FT_IPv4;
890 if (!add_hf(&hf_entr))
891 return -1;
892 hf_entr.p_id = &field->ipv6_descr;
893 hf_entr.hfinfo.type = FT_IPv6;
895 break;
896 default:
897 break;
900 /* Register initialized hf_register_info in global database. */
901 if (!add_hf(&hf_entr))
902 return -1;
903 field->sign = sign;
904 field->size = size;
905 field->array_dim = array_dim;
906 field->special_type = is_address_family ? TPNCP_ADDRESS_FAMILY : special_type;
907 field->since = since;
910 *data_fields_len = wmem_array_get_count(data_fields_info_arr);
911 *data_fields_info = (tpncp_data_field_info **)wmem_array_finalize(data_fields_info_arr);
913 return 0;
916 /*---------------------------------------------------------------------------*/
918 static int
919 init_tpncp_db(void)
921 char tpncp_dat_file_path[MAX_TPNCP_DB_ENTRY_LEN];
922 FILE *file;
924 snprintf(tpncp_dat_file_path, MAX_TPNCP_DB_ENTRY_LEN,
925 "%s" G_DIR_SEPARATOR_S "tpncp" G_DIR_SEPARATOR_S "tpncp.dat", get_datafile_dir());
927 /* Open file with TPNCP data. */
928 if ((file = ws_fopen(tpncp_dat_file_path, "r")) == NULL)
929 return (-1);
930 fill_tpncp_id_vals(&tpncp_events_id_vals, file);
931 fill_tpncp_id_vals(&tpncp_commands_id_vals, file);
932 fill_enums_id_vals(&tpncp_enums_name_vals, &tpncp_enums_id_vals, file);
933 init_tpncp_data_fields_info(&tpncp_events_info_db, &tpncp_events_info_len, file);
934 init_tpncp_data_fields_info(&tpncp_commands_info_db, &tpncp_commands_info_len, file);
936 fclose(file);
937 return 0;
940 /*---------------------------------------------------------------------------*/
942 void
943 proto_reg_handoff_tpncp(void)
945 static bool initialized = false;
947 if (proto_tpncp <= 0) return;
949 if (!initialized) {
950 dissector_add_uint_with_preference("udp.port", UDP_PORT_TPNCP_TRUNKPACK, tpncp_handle);
951 dissector_add_uint_with_preference("tcp.port", TCP_PORT_TPNCP_TRUNKPACK, tpncp_tcp_handle);
952 dissector_add_uint("acdr.media_type", ACDR_PCIIF_COMMAND, tpncp_handle);
953 dissector_add_uint("acdr.media_type", ACDR_COMMAND, tpncp_handle);
954 dissector_add_uint("acdr.media_type", ACDR_Event, create_dissector_handle(dissect_acdr_event, proto_tpncp));
955 dissector_add_uint("acdr.media_type", ACDR_TPNCP,
956 create_dissector_handle(dissect_acdr_tpncp_by_tracepoint, proto_tpncp));
957 dissector_add_uint("acdr.tls_application", TLS_APP_TPNCP, tpncp_handle);
958 initialized = true;
960 /* If we weren't able to load the database (and thus the hf_ entries)
961 * do not attach to any ports (if we did then we'd get a "dissector bug"
962 * assertions every time a packet is handed to us and we tried to use the
963 * hf_ entry).
965 if (!global_tpncp_load_db)
966 return;
968 if (hf_allocated == 0 && init_tpncp_db() == -1) {
969 report_failure("tpncp: Could not load tpncp.dat file, tpncp dissector will not work");
970 return;
973 if (db_initialized)
974 return;
976 /* Rather than duplicating large quantities of code from
977 * proto_register_field_array() and friends to sanitize the tpncp.dat file
978 * when we read it, just catch any exceptions we get while registering and
979 * take them as a hint that the file is corrupt. Then move on, so that at
980 * least the rest of the protocol dissectors will still work.
982 TRY {
983 int idx;
984 /* The function proto_register_field_array does not work with dynamic
985 * arrays, so pass dynamic array elements one-by-one in the loop.
987 for (idx = 0; idx < hf_size; idx++)
988 proto_register_field_array(proto_tpncp, &hf[idx], 1);
991 CATCH_ALL {
992 report_failure("Corrupt tpncp.dat file, tpncp dissector will not work.");
995 ENDTRY;
996 db_initialized = true;
999 /*---------------------------------------------------------------------------*/
1001 void
1002 proto_register_tpncp(void)
1004 module_t *tpncp_module;
1005 expert_module_t* expert_tpncp;
1006 static int *ett[] = {
1007 &ett_tpncp,
1008 &ett_tpncp_body
1011 static ei_register_info ei[] = {
1012 { &ei_tpncp_unknown_data, { "tpncp.unknown_data", PI_UNDECODED, PI_WARN, "Unknown data", EXPFILL } },
1015 /* this dissector reads hf entries from a database
1016 * a boolean preference defines whether the database is loaded or not
1017 * we initialize the hf array in the handoff function when we have
1018 * access to the preference's value */
1020 proto_tpncp = proto_register_protocol("AudioCodes TPNCP (TrunkPack Network Control Protocol)",
1021 "TPNCP", "tpncp");
1023 tpncp_handle = register_dissector("tpncp", dissect_tpncp, proto_tpncp);
1024 tpncp_tcp_handle = register_dissector("tpncp.tcp", dissect_tpncp_tcp, proto_tpncp);
1026 tpncp_module = prefs_register_protocol(proto_tpncp, proto_reg_handoff_tpncp);
1028 proto_register_subtree_array(ett, array_length(ett));
1030 expert_tpncp = expert_register_protocol(proto_tpncp);
1031 expert_register_field_array(expert_tpncp, ei, array_length(ei));
1033 /* See https://gitlab.com/wireshark/wireshark/-/issues/9569 for some discussion on this as well */
1034 prefs_register_bool_preference(tpncp_module, "load_db",
1035 "Whether to load DB or not; if DB not loaded dissector is passive",
1036 "Whether to load the Database or not; not loading the DB"
1037 " disables the protocol; Wireshark has to be restarted for the"
1038 " setting to take effect.",
1039 &global_tpncp_load_db);
1043 * Editor modelines
1045 * Local Variables:
1046 * c-basic-offset: 4
1047 * tab-width: 8
1048 * indent-tabs-mode: nil
1049 * End:
1051 * ex: set shiftwidth=4 tabstop=8 expandtab:
1052 * :indentSize=4:tabSize=8:noTabs=true: