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"
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
{
50 TPNCP_OPEN_CHANNEL_START
,
52 TPNCP_SECURITY_OFFSET
,
56 TPNCP_CHANNEL_CONFIGURATION
59 /* The linked list for storing information about specific data fields. */
60 typedef struct tpncp_data_field_info
66 enum SpecialFieldType special_type
;
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
;
117 static int hf_allocated
;
118 static hf_register_info
*hf
;
120 static bool db_initialized
;
122 /*---------------------------------------------------------------------------*/
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
)
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
)
147 switch (field
->special_type
) {
148 case TPNCP_OPEN_CHANNEL_START
:
149 open_channel_start
= *offset
;
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
;
157 case TPNCP_SECURITY_START
:
158 *offset
= security_offset
;
159 open_channel_start
= -1;
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 */
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
;
174 *offset
= rtp_tx_state_offset
;
175 rtp_tx_state_offset
+= rtp_state_size
;
179 rtp_tx_state_offset
= 0;
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
;
186 *offset
= channel_b_offset
;
187 channel_b_offset
= 0;
190 case TPNCP_ADDRESS_FAMILY
:
191 address_family
= (enum AddressFamily
)tvb_get_uint32(tvb
, *offset
, encoding
);
194 if (open_channel_start
!= -1 && security_offset
> 0 && *offset
>= security_offset
)
196 if (rtp_state_offset
> 0 && *offset
>= rtp_state_offset
)
198 if (rtp_tx_state_offset
> 0 && *offset
>= rtp_tx_state_offset
)
200 if (channel_b_offset
> 0 && *offset
>= channel_b_offset
)
204 switch (field
->size
) {
205 case 1: case 2: case 3: case 4:
206 case 5: case 6: case 7: case 8:
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
);
217 if (field
->size
!= 8) {
218 for (counter
= 0, bitmask
= 0x0, bitshift
= bitindex
;
219 counter
< field
->size
;
221 bitmask
|= bits
[bitindex
]; /* Bitmask of interesting bits. */
222 bitindex
+= encoding
== ENC_LITTLE_ENDIAN
? -1 : 1;
225 g_uchar
>>= bitshift
;
227 if (field
->sign
|| field
->size
!= 8) {
228 proto_tree_add_uint(ltree
, field
->descr
, tvb
, *offset
, 1, g_uchar
);
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
)) {
237 bitindex
= encoding
== ENC_LITTLE_ENDIAN
? 7 : 0;
242 proto_tree_add_item(ltree
, field
->descr
, tvb
, *offset
, 2, encoding
);
246 proto_tree_add_item(ltree
, field
->descr
, tvb
, *offset
, 4, encoding
);
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
);
254 proto_tree_add_item(ltree
, field
->descr
, tvb
, *offset
, 4, encoding
);
255 address_family
= TPNCP_IPV4
;
262 if (tvb_reported_length_remaining(tvb
, *offset
) <= 0)
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 /*---------------------------------------------------------------------------*/
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;
279 unsigned seq_number
, len
, ver
;
280 unsigned len_ext
, reserved
, encoding
;
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
);
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
);
308 proto_tree_add_int(tpncp_tree
, hf_tpncp_cid
, tvb
, 12, 4, cid
);
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
,
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
);
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
);
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
,
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 /*---------------------------------------------------------------------------*/
348 get_tpncp_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
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. */
361 /*---------------------------------------------------------------------------*/
364 dissect_tpncp_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
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
);
374 /* Otherwise use the regular dissector (might not give correct dissection). */
375 dissect_tpncp(tvb
, pinfo
, tree
, data
);
377 return tvb_reported_length(tvb
);
381 dissect_acdr_event(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
384 acdr_dissector_data_t
*acdr_data
= (acdr_dissector_data_t
*) data
;
385 uint32_t orig_port
= pinfo
->srcport
;
387 if (acdr_data
== NULL
)
390 // only on version 2+ events are sent with TPNCP header that enables using tpncp parser
391 if (acdr_data
->version
<= 1)
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
;
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
;
411 if (acdr_data
== NULL
)
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
;
429 /*---------------------------------------------------------------------------*/
432 fgetline(char *buffer
, int size
, FILE *file
)
434 if (!fgets(buffer
, size
, file
))
436 size_t last
= strlen(buffer
);
437 if (buffer
[last
- 1] == '\n')
438 buffer
[last
- 1] = 0;
443 fill_tpncp_id_vals(value_string
**strings
, FILE *file
)
445 wmem_array_t
*vs_arr
;
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
)) {
455 char tpncp_name
[256];
457 if (!strncmp(line_in_file
, "#####", 5))
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
);
475 /*---------------------------------------------------------------------------*/
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
;
484 line_in_file
= (char *) g_malloc(MAX_TPNCP_DB_ENTRY_LEN
);
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];
494 if (!strncmp(line_in_file
, "#####", 5))
496 if (sscanf(line_in_file
, "%255s %255s %d", enum_name
, enum_str
, &enum_id
) == 3) {
497 if (strcmp(enum_type
, enum_name
) != 0) {
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
= {
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
);
536 /*---------------------------------------------------------------------------*/
539 get_enum_name_val(const char *enum_name
)
543 while (tpncp_enums_name_vals
[enum_val
]) {
544 if (!strcmp(enum_name
, tpncp_enums_name_vals
[enum_val
]))
552 /*---------------------------------------------------------------------------*/
554 static bool add_hf(hf_register_info
*hf_entr
)
556 if (hf_size
>= hf_allocated
) {
558 hf_allocated
+= 1024;
559 newbuf
= wmem_realloc(wmem_epan_scope(), hf
, hf_allocated
* sizeof (hf_register_info
));
562 hf
= (hf_register_info
*) newbuf
;
564 memcpy(hf
+ hf_size
, hf_entr
, sizeof (hf_register_info
));
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
;
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
[] = {
611 &hf_tpncp_seq_number
,
623 &hf_tpncp_length_ext
,
626 "tpncp.lengthextension",
647 &hf_tpncp_command_id
,
653 VALS(tpncp_commands_id_vals
),
665 VALS(tpncp_events_id_vals
),
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
;
691 if (!was_registered
) {
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
));
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
));
704 was_registered
= true;
707 is_address_family
= false;
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
;
716 snprintf(entry_copy
, MAX_TPNCP_DB_ENTRY_LEN
, "%s", tpncp_db_entry
);
717 if (!strncmp(tpncp_db_entry
, "#####", 5))
720 /* Default to decimal display type */
721 hf_entr
.hfinfo
.display
= BASE_DEC
;
722 if ((tmp
= strtok(tpncp_db_entry
, " ")) == NULL
) {
724 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
728 data_id
= (int) g_ascii_strtoll(tmp
, NULL
, 10);
729 if ((name
= strtok(NULL
, " ")) == NULL
) {
731 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
736 /* We happen to have a line without a name (57 0 32 0 0 primitive). Consider unnamed. */
737 if (g_ascii_isdigit(*name
)) {
741 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
743 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
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"))) {
768 sign
= !!((bool) g_ascii_strtoll(tmp
, NULL
, 10));
769 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
771 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
775 size
= (unsigned char) g_ascii_strtoll(tmp
, NULL
, 10);
776 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
778 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
782 array_dim
= (int) g_ascii_strtoll(tmp
, NULL
, 10);
783 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
785 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
789 if (sign
&& g_ascii_strtoll(tmp
, NULL
, 10))
790 special_type
= TPNCP_IP_ADDR
;
791 if ((tmp
= strtok(NULL
, "\n")) == NULL
) {
793 "ERROR! Badly formed data base entry: %s - corresponding field's registration is skipped.",
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;
803 if (seq
> name
&& *seq
== '_') {
804 if (seq
[1] >= '1' && seq
[1] <= '3')
806 // relates to the *previous* field
807 if (is_address_family
) {
810 special_type
= TPNCP_IP_ADDR
;
812 report_warning("Bad address form. Field name: %s", name
);
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
);
829 "ERROR! The data_id %d already registered. Cannot register two identical events/command",
833 field
= wmem_new0(wmem_epan_scope(), tpncp_data_field_info
);
835 current_data_id
= data_id
;
837 field
->p_next
= wmem_new(wmem_epan_scope(), tpncp_data_field_info
);
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
;
850 hf_entr
.hfinfo
.strings
= VALS(tpncp_enums_id_vals
[enum_val
]);
851 if (!strcmp(tmp
, "AddressFamily")) {
852 is_address_family
= true;
857 hf_entr
.hfinfo
.strings
= NULL
;
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
;
866 case 1: case 2: case 3: case 4:
867 case 5: case 6: case 7: case 8:
869 hf_entr
.hfinfo
.type
= FT_STRING
;
870 hf_entr
.hfinfo
.display
= BASE_NONE
;
872 hf_entr
.hfinfo
.type
= (sign
) ? FT_UINT8
: FT_INT8
;
876 hf_entr
.hfinfo
.type
= (sign
) ? FT_UINT16
: FT_INT16
;
879 if (special_type
== TPNCP_IP_ADDR
) {
880 hf_entr
.hfinfo
.display
= BASE_NONE
;
881 hf_entr
.hfinfo
.type
= FT_IPv4
;
883 hf_entr
.hfinfo
.type
= (sign
) ? FT_UINT32
: FT_INT32
;
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
))
892 hf_entr
.p_id
= &field
->ipv6_descr
;
893 hf_entr
.hfinfo
.type
= FT_IPv6
;
900 /* Register initialized hf_register_info in global database. */
901 if (!add_hf(&hf_entr
))
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
);
916 /*---------------------------------------------------------------------------*/
921 char tpncp_dat_file_path
[MAX_TPNCP_DB_ENTRY_LEN
];
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
)
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
);
940 /*---------------------------------------------------------------------------*/
943 proto_reg_handoff_tpncp(void)
945 static bool initialized
= false;
947 if (proto_tpncp
<= 0) return;
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
);
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
965 if (!global_tpncp_load_db
)
968 if (hf_allocated
== 0 && init_tpncp_db() == -1) {
969 report_failure("tpncp: Could not load tpncp.dat file, tpncp dissector will not work");
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.
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);
992 report_failure("Corrupt tpncp.dat file, tpncp dissector will not work.");
996 db_initialized
= true;
999 /*---------------------------------------------------------------------------*/
1002 proto_register_tpncp(void)
1004 module_t
*tpncp_module
;
1005 expert_module_t
* expert_tpncp
;
1006 static int *ett
[] = {
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)",
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
);
1048 * indent-tabs-mode: nil
1051 * ex: set shiftwidth=4 tabstop=8 expandtab:
1052 * :indentSize=4:tabSize=8:noTabs=true: