For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / 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  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.com>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <glib.h>
38
39 #include <wsutil/file_util.h>
40
41 #include <epan/packet.h>
42 #include <epan/prefs.h>
43 #include <epan/emem.h>
44 #include <epan/filesystem.h>
45 #include <epan/dissectors/packet-tcp.h>
46 #include <epan/strutil.h>
47
48 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
49
50 #define BASE_TPNCP_PORT 2424
51 #define TCP_PORT_TPNCP_TRUNKPACK BASE_TPNCP_PORT
52 #define UDP_PORT_TPNCP_TRUNKPACK BASE_TPNCP_PORT
53 #define TCP_PORT_TPNCP_HOST BASE_TPNCP_PORT
54 #define UDP_PORT_TPNCP_HOST BASE_TPNCP_PORT
55
56 #define BASE_TPNCP_DATA_LEN 256
57 #define MAX_TPNCP_DB_ENTRY_LEN BASE_TPNCP_DATA_LEN
58
59 #define MAX_TPNCP_DB_SIZE 3000
60 #define MAX_ENUMS_NUM 500
61 #define MAX_ENUM_ENTRIES 500
62
63 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
64
65 /* The linked list for storing information about specific data fields. */
66 typedef struct tpncp_data_field_info
67 {
68     gchar *tpncp_data_field_name;
69     gint tpncp_data_field_descr;
70     gint tpncp_data_field_sign;
71     gint tpncp_data_field_size;
72     gint tpncp_data_field_array_dim;
73     gint tpncp_data_field_is_ip_addr;
74     struct tpncp_data_field_info *p_next;
75 } tpncp_data_field_info;
76
77 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
78
79 /* Desegmentation of TPNCP over TCP */
80 static gboolean tpncp_desegment = TRUE;
81
82 /* Database for storing information about all TPNCP events. */
83 /* XXX: ToDo: allocate at runtime as needed */
84 static tpncp_data_field_info tpncp_events_info_db[MAX_TPNCP_DB_SIZE];
85
86 /* Database for storing information about all TPNCP commands. */
87 /* XXX: ToDo: allocate at runtime as needed */
88 static tpncp_data_field_info tpncp_commands_info_db[MAX_TPNCP_DB_SIZE];
89
90 /* Global variables for bitfields representation. */
91 static gint bits[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
92 static gint bitindex = 0;
93
94 /* TPNCP packet header fields. */
95 static gint proto_tpncp = -1,
96             hf_tpncp_version = -1,
97             hf_tpncp_length = -1,
98             hf_tpncp_seq_number = -1,
99             hf_tpncp_old_event_seq_number = -1,
100             hf_tpncp_reserved = -1,
101             hf_tpncp_command_id = -1,
102             hf_tpncp_old_command_id = -1,
103             hf_tpncp_event_id = -1,
104             hf_tpncp_cid = -1;
105
106 /* TPNCP fields defining a subtree. */
107 static gint ett_tpncp = -1,
108             ett_tpncp_body = -1;
109
110 static guint global_tpncp_trunkpack_tcp_port = TCP_PORT_TPNCP_TRUNKPACK,
111              global_tpncp_trunkpack_udp_port = UDP_PORT_TPNCP_TRUNKPACK,
112              global_tpncp_host_tcp_port = TCP_PORT_TPNCP_HOST,
113              global_tpncp_host_udp_port = UDP_PORT_TPNCP_HOST;
114
115 static guint trunkpack_tcp_port = 0,
116              trunkpack_udp_port = 0,
117              host_tcp_port = 0,
118              host_udp_port = 0;
119
120 /* XXX: ToDo: allocate at runtime as needed */
121 /*      The following allocates something on the order of 2M of static memory ! */
122 /*      Also: Runtime value_string_ext arrays should be used                    */
123 static value_string tpncp_commands_id_vals[MAX_TPNCP_DB_SIZE];
124 static value_string tpncp_events_id_vals[MAX_TPNCP_DB_SIZE];
125 static value_string tpncp_enums_id_vals[MAX_ENUMS_NUM][MAX_ENUM_ENTRIES];
126 static gchar *tpncp_enums_name_vals[MAX_ENUMS_NUM];
127
128 static gint hf_size = 1;
129 static gint hf_allocated = 0;
130 static hf_register_info *hf = NULL;
131
132 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
133
134 static void dissect_tpncp_data(gint data_id, tvbuff_t *tvb, proto_item *item,
135                                gint *offset, tpncp_data_field_info *data_fields_info) {
136     proto_tree *ltree = NULL;
137     proto_item *pi = NULL;
138     gint32 g_int;
139     gint16 g_short;
140     guint16 g_ushort;
141     gint8 g_char;
142     gchar *g_str = NULL;
143     gint g_str_len, counter, bitshift, bitmask;
144     tpncp_data_field_info *current_tpncp_data_field_info = NULL;
145
146     ltree = proto_item_add_subtree(item, ett_tpncp_body);
147     current_tpncp_data_field_info = &data_fields_info[data_id];
148
149     while (current_tpncp_data_field_info) {
150         switch(current_tpncp_data_field_info->tpncp_data_field_size) {
151             case 1: case 2: case 3: case 4:
152             case 5: case 6: case 7: case 8:
153                 if ((g_str_len = current_tpncp_data_field_info->tpncp_data_field_array_dim)) { /* add char array */
154                     g_str_len = MIN(g_str_len, tvb_length_remaining(tvb, *offset));
155                     g_str = g_malloc(g_str_len);
156                     tvb_memcpy(tvb, g_str, *offset, g_str_len);
157                     g_str[g_str_len-1] = '\0';
158                     proto_tree_add_string(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
159                                           tvb, *offset, g_str_len, g_str);
160                     (*offset) += g_str_len;
161                     g_free(g_str);
162                 }
163                 else { /* add single char */
164                     g_char = tvb_get_guint8(tvb, *offset);
165                     /* bitfields */
166                     if (current_tpncp_data_field_info->tpncp_data_field_size != 8) {
167                         for (counter = 0, bitmask = 0x0, bitshift = bitindex;
168                              counter < current_tpncp_data_field_info->tpncp_data_field_size;
169                              counter++)
170                             bitmask |= bits[bitindex++]; /* Bitmask of interesting bits. */
171                         g_char &= bitmask;
172                         g_char >>= bitshift;
173                     }
174                     if (current_tpncp_data_field_info->tpncp_data_field_sign) {
175                         proto_tree_add_uint(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
176                                             tvb, *offset, 1, g_char);
177                     }
178                     else {
179                         proto_tree_add_int(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
180                                            tvb, *offset, 1, g_char);
181                     }
182                     if ((bitindex == 0) || (bitindex == 8)) {
183                         (*offset)++;
184                         bitindex = 0;
185                     }
186                 }
187                 break;
188             case 16:
189                 if (current_tpncp_data_field_info->tpncp_data_field_sign) {
190                     g_ushort = tvb_get_ntohs(tvb, *offset);
191                     proto_tree_add_uint(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
192                                         tvb, *offset, 2, g_ushort);
193                 }
194                 else {
195                     g_short = tvb_get_ntohs(tvb, *offset);
196                     proto_tree_add_int(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
197                                        tvb, *offset, 2, g_short);
198                 }
199                 (*offset) += 2;
200                 break;
201             case 32:
202                 g_int = tvb_get_ntohl(tvb, *offset);
203                 if (current_tpncp_data_field_info->tpncp_data_field_sign) {
204                     pi = proto_tree_add_uint(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
205                                              tvb, *offset, 4, g_int);
206                 }
207                 else {
208                     pi = proto_tree_add_int(ltree, current_tpncp_data_field_info->tpncp_data_field_descr,
209                                             tvb, *offset, 4, g_int);
210                 }
211                 /* Add string representation for ip_address's field (if needed). */
212                 if (current_tpncp_data_field_info->tpncp_data_field_is_ip_addr) {
213                     proto_item_append_text(pi, " (%s)", tvb_ip_to_str(tvb, *offset));
214                 }
215                 (*offset) += 4;
216                 break;
217             default:
218                 break;
219         }
220         current_tpncp_data_field_info = current_tpncp_data_field_info->p_next;
221         if (tvb_length_remaining(tvb, *offset) <= 0) {
222             break;
223         }
224     }
225 }
226
227 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
228
229 static void dissect_tpncp_event(gint event_id, tvbuff_t *tvb,
230                                 proto_item *item, gint *offset) {
231     switch (event_id) {
232         /* Place non-standard events here. */
233         default:
234             dissect_tpncp_data(event_id, tvb, item, offset, tpncp_events_info_db);
235             break;
236     }
237 }
238
239 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
240
241 static void dissect_tpncp_command(gint command_id, tvbuff_t *tvb,
242                                   proto_item *item, gint *offset) {
243     switch (command_id) {
244         /* Place non-standard commands here. */
245         default:
246             dissect_tpncp_data(command_id, tvb, item, offset, tpncp_commands_info_db);
247             break;
248     }
249 }
250
251 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
252
253 static void dissect_tpncp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
254     proto_item *item = NULL, *tpncp_item = NULL;
255     proto_tree *tpncp_tree = NULL;
256     gint offset = 0;
257     guint32 id, cid = 0;
258     guint16 seq_number, len, ver, reserved;
259     gchar *tpncp_header;
260
261     ver = tvb_get_ntohs(tvb, 0);
262     len = tvb_get_ntohs(tvb, 2);
263     seq_number = tvb_get_ntohs(tvb, 4);
264     reserved = tvb_get_ntohs(tvb, 6);
265     id = tvb_get_ntohl(tvb, 8);
266
267     if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) /* Event */
268         cid = tvb_get_ntohl(tvb, 12 );
269
270     col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPNCP");
271
272     if (check_col(pinfo->cinfo, COL_INFO)) {
273         if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) {
274             col_add_fstr(pinfo->cinfo, COL_INFO,
275                          "EvID=%s(%d), SeqNo=%d, ChID=%d, Len=%d, Ver=%d",
276                          val_to_str(id, tpncp_events_id_vals, "Unknown"),
277                          id, seq_number, cid, len, ver);
278         } else {
279             col_add_fstr(pinfo->cinfo, COL_INFO,
280                          "CmdID=%s(%d), SeqNo=%d, Len=%d, Ver=%d",
281                          val_to_str(id, tpncp_commands_id_vals, "Unknown"),
282                          id, seq_number, len, ver);
283         }
284     }
285
286     if (tree) {
287         item = proto_tree_add_item(tree, proto_tpncp, tvb, 0, -1, ENC_NA);
288         tpncp_tree = proto_item_add_subtree(item, ett_tpncp);
289
290         proto_tree_add_uint(tpncp_tree, hf_tpncp_version, tvb, 0, 2, ver);
291         proto_tree_add_uint(tpncp_tree, hf_tpncp_length, tvb, 2, 2, len);
292         proto_tree_add_uint(tpncp_tree, hf_tpncp_seq_number, tvb, 4, 2, seq_number);
293         proto_tree_add_uint(tpncp_tree, hf_tpncp_reserved, tvb, 6, 2, reserved);
294
295         if (pinfo->srcport == UDP_PORT_TPNCP_TRUNKPACK) {
296             if (match_strval(id, tpncp_events_id_vals)) {
297                 proto_tree_add_uint(tpncp_tree, hf_tpncp_event_id, tvb, 8, 4, id);
298                 proto_tree_add_int(tpncp_tree, hf_tpncp_cid, tvb, 12, 4, cid);
299                 offset += 16;
300                 if (tpncp_events_info_db[id].tpncp_data_field_size) {
301                     tpncp_header = ep_strdup_printf("TPNCP Event: %s (%d)", val_to_str(id, tpncp_events_id_vals, "Unknown"), id);
302                     tpncp_item = proto_tree_add_text(tree, tvb, offset, -1, "%s", tpncp_header);
303                     dissect_tpncp_event(id, tvb, tpncp_item, &offset);
304                 }
305             }
306         }
307         else {
308             if (match_strval(id, tpncp_commands_id_vals)) {
309                 proto_tree_add_uint(tpncp_tree, hf_tpncp_command_id, tvb, 8, 4, id);
310                 offset += 12;
311                 if (tpncp_commands_info_db[id].tpncp_data_field_size) {
312                     tpncp_header = ep_strdup_printf("TPNCP Command: %s (%d)", val_to_str(id, tpncp_commands_id_vals, "Unknown"), id);
313                     tpncp_item = proto_tree_add_text(tree, tvb, offset, -1, "%s", tpncp_header);
314                     dissect_tpncp_command(id, tvb, tpncp_item, &offset);
315                 }
316             }
317         }
318     }
319 }
320
321 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
322
323 static guint get_tpncp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, gint offset) {
324   guint16 plen;
325
326   /* Get the length of the DNS packet. */
327   plen = tvb_get_ntohs(tvb, offset + 2);
328   /* Length does not include the version+length field. */
329   plen += 4;
330
331   return plen;
332 }
333
334 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
335
336 static void dissect_tpncp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
337     if (pinfo->can_desegment)
338         /* If desegmentation is enabled (TCP preferences) use the desegmentation API. */
339         tcp_dissect_pdus(tvb, pinfo, tree, tpncp_desegment, 4, get_tpncp_pdu_len, dissect_tpncp);
340     else
341         /* Otherwise use the regular dissector (might not give correct dissection). */
342         dissect_tpncp(tvb, pinfo, tree);
343 }
344
345 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
346
347 static gint fill_tpncp_id_vals(value_string string[], FILE *file) {
348     gint i = 0, tpncp_id = 0;
349     gchar *tpncp_name = NULL, *line_in_file = NULL;
350
351     line_in_file = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
352     line_in_file[0] = 0;
353     tpncp_name = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
354     tpncp_name[0] = 0;
355
356     while (fgets(line_in_file, MAX_TPNCP_DB_ENTRY_LEN, file) != NULL) {
357         if (!strncmp(line_in_file, "#####", 5)) {
358             break;
359         }
360         if (sscanf(line_in_file, "%255s %d", tpncp_name, &tpncp_id) == 2) {
361             string[i].strptr = g_strdup(tpncp_name);
362             string[i].value = tpncp_id;
363             if (i < (MAX_TPNCP_DB_SIZE-1)) {
364                 i++;
365             }
366             else {
367                 break;
368             }
369         }
370     }
371
372     return 0;
373 }
374
375 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
376
377 static gint fill_enums_id_vals(FILE *file) {
378     gint i = 0, enum_id = 0, enum_val = 0, first_entry = 1;
379     gchar *line_in_file = NULL, *enum_name = NULL,
380            *enum_type = NULL, *enum_str = NULL;
381
382     line_in_file = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
383     line_in_file[0] = 0;
384     enum_name = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
385     enum_name[0] = 0;
386     enum_type = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
387     enum_type[0] = 0;
388     enum_str = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
389     enum_str[0] = 0;
390
391     while (fgets(line_in_file, MAX_TPNCP_DB_ENTRY_LEN, file) != NULL) {
392         if (!strncmp(line_in_file, "#####", 5)) {
393             break;
394         }
395         if (sscanf(line_in_file, "%255s %255s %d", enum_name, enum_str, &enum_id) == 3) {
396             if (strcmp(enum_type, enum_name)) {
397                 if (!first_entry) {
398                     tpncp_enums_id_vals[enum_val][i].strptr = NULL;
399                     tpncp_enums_id_vals[enum_val][i].value = 0;
400                     if (enum_val < (MAX_ENUMS_NUM-1)) {
401                         enum_val++; i = 0;
402                     }
403                     else {
404                         break;
405                     }
406                 }
407                 else
408                     first_entry = 0;
409                 tpncp_enums_name_vals[enum_val] = g_strdup(enum_name);
410                 g_strlcpy(enum_type, enum_name, MAX_TPNCP_DB_ENTRY_LEN);
411             }
412             tpncp_enums_id_vals[enum_val][i].strptr = g_strdup(enum_str);
413             tpncp_enums_id_vals[enum_val][i].value = enum_id;
414             if (i < (MAX_ENUM_ENTRIES-1)) {
415                 i++;
416             }
417             else {
418                 break;
419             }
420         }
421     }
422
423     return 0;
424 }
425
426 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
427
428 static gint get_enum_name_val(gchar *enum_name) {
429     gint enum_val = 0;
430
431     while (tpncp_enums_name_vals[enum_val]) {
432         if (!strcmp(enum_name, tpncp_enums_name_vals[enum_val]))
433             return enum_val;
434         enum_val++;
435     }
436
437     return -1;
438 }
439
440 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
441
442 static gint init_tpncp_data_fields_info(tpncp_data_field_info *data_fields_info, FILE *file) {
443     static gboolean was_registered = FALSE;
444     gchar *tpncp_db_entry = NULL, *tpncp_data_field_name = NULL, *tmp = NULL;
445     gint enum_val, data_id, current_data_id = -1,
446          tpncp_data_field_sign, tpncp_data_field_size,
447          tpncp_data_field_array_dim, tpncp_data_field_is_ip_addr;
448     guint idx;
449     tpncp_data_field_info *current_tpncp_data_field_info = NULL;
450     hf_register_info hf_entr;
451
452     static hf_register_info hf_tpncp[] = {
453         {
454             &hf_tpncp_version,
455             {
456                 "Version",
457                 "tpncp.version",
458                 FT_UINT16,
459                 BASE_DEC,
460                 NULL,
461                 0x0,
462                 NULL, HFILL
463             }
464         },
465         {
466             &hf_tpncp_length,
467             {
468                 "Length",
469                 "tpncp.length",
470                 FT_UINT16,
471                 BASE_DEC,
472                 NULL,
473                 0x0,
474                 NULL, HFILL
475             }
476         },
477         {
478             &hf_tpncp_seq_number,
479             {
480                 "Sequence number",
481                 "tpncp.seq_number",
482                 FT_UINT16,
483                 BASE_DEC,
484                 NULL,
485                 0x0,
486                 NULL, HFILL
487             }
488         },
489         {
490             &hf_tpncp_old_event_seq_number,
491             {
492                 "Sequence number",
493                 "tpncp.old_event_seq_number",
494                 FT_UINT32,
495                 BASE_DEC,
496                 NULL,
497                 0x0,
498                 NULL, HFILL
499             }
500         },
501         {
502             &hf_tpncp_reserved,
503             {
504                 "Reserved",
505                 "tpncp.reserved",
506                 FT_UINT16,
507                 BASE_DEC,
508                 NULL,
509                 0x0,
510                 NULL, HFILL
511             }
512         },
513         {
514             &hf_tpncp_command_id,
515             {
516                 "Command ID",
517                 "tpncp.command_id",
518                 FT_UINT32,
519                 BASE_DEC,
520                 VALS(tpncp_commands_id_vals),
521                 0x0,
522                 NULL, HFILL
523             }
524         },
525         {
526             &hf_tpncp_old_command_id,
527             {
528                 "Command ID",
529                 "tpncp.old_command_id",
530                 FT_UINT16,
531                 BASE_DEC,
532                 VALS(tpncp_commands_id_vals),
533                 0x0,
534                 NULL, HFILL
535             }
536         },
537         {
538             &hf_tpncp_event_id,
539             {
540                 "Event ID",
541                 "tpncp.event_id",
542                 FT_UINT32,
543                 BASE_DEC,
544                 VALS(tpncp_events_id_vals),
545                 0x0,
546                 NULL, HFILL
547             }
548         },
549         {
550             &hf_tpncp_cid,
551             {
552                 "Channel ID",
553                 "tpncp.channel_id",
554                 FT_INT32,
555                 BASE_DEC,
556                 NULL,
557                 0x0,
558                 NULL, HFILL
559             }
560         }
561     };
562
563     tpncp_db_entry = ep_alloc(MAX_TPNCP_DB_ENTRY_LEN);
564     tpncp_db_entry[0] = 0;
565
566     /* Register common fields of hf_register_info struture. */
567     hf_entr.hfinfo.type           = 0;
568     hf_entr.hfinfo.strings        = NULL;
569     hf_entr.hfinfo.bitmask        = 0x0;
570     hf_entr.hfinfo.blurb          = NULL;
571     hf_entr.hfinfo.id             = 0;
572     hf_entr.hfinfo.parent         = 0;
573     hf_entr.hfinfo.ref_type       = HF_REF_TYPE_NONE;
574     hf_entr.hfinfo.bitshift       = 0;
575     hf_entr.hfinfo.same_name_next = NULL;
576     hf_entr.hfinfo.same_name_prev = NULL;
577
578     if (!was_registered) {
579         /* Register non-standard data should be done only once. */
580         hf_allocated = hf_size+array_length(hf_tpncp)-1;
581         if ((hf = (hf_register_info *)g_realloc(hf, hf_allocated * sizeof(hf_register_info))) == NULL)
582             return (-1);
583         for (idx = 0; idx < array_length(hf_tpncp); idx++) {
584             memcpy(hf + (hf_size - 1), hf_tpncp + idx, sizeof(hf_register_info));
585             hf_size++;
586         }
587         was_registered = TRUE;
588     }
589     else
590         hf_size++;
591     /* Register standard data. */
592     while (fgets(tpncp_db_entry, MAX_TPNCP_DB_ENTRY_LEN, file) != NULL) {
593         if (!strncmp(tpncp_db_entry, "#####", 5)) {
594             hf_size--;
595             break;
596         }
597
598         /* Default to decimal display type */
599         hf_entr.hfinfo.display = BASE_DEC;
600
601         if ((tmp = strtok(tpncp_db_entry, " ")) == NULL)
602             continue; /* Badly formed data base entry - skip corresponding field's registration. */
603         data_id = atoi(tmp);
604         if ((tpncp_data_field_name = strtok(NULL, " ")) == NULL)
605             continue; /* Badly formed data base entry - skip corresponding field's registration. */
606         if ((tmp = strtok(NULL, " ")) == NULL)
607             continue; /* Badly formed data base entry - skip corresponding field's registration. */
608         tpncp_data_field_sign = atoi(tmp);
609         if ((tmp = strtok(NULL, " ")) == NULL)
610             continue; /* Badly formed data base entry - skip corresponding field's registration. */
611         tpncp_data_field_size = atoi(tmp);
612         if ((tmp = strtok(NULL, " ")) == NULL)
613             continue; /* Badly formed data base entry - skip corresponding field's registration. */
614         tpncp_data_field_array_dim = atoi(tmp);
615         if ((tmp = strtok(NULL, " ")) == NULL)
616             continue; /* Badly formed data base entry - skip corresponding field's registration. */
617         tpncp_data_field_is_ip_addr = atoi(tmp);
618         if ((tmp = strtok(NULL, "\n")) == NULL)
619             continue; /* Badly formed data base entry - skip corresponding field's registration. */
620
621         if (current_data_id != data_id) { /* new data */
622             current_tpncp_data_field_info = &data_fields_info[data_id];
623             current_data_id = data_id;
624         }
625         else {
626             if ((current_tpncp_data_field_info->p_next =
627                 (tpncp_data_field_info *)g_malloc0(sizeof(tpncp_data_field_info)))
628                 == NULL)
629                 return (-1);
630             current_tpncp_data_field_info = current_tpncp_data_field_info->p_next;
631         }
632         /* Register specific fields of hf_register_info struture. */
633         if (strcmp(tmp, "primitive")) {
634             enum_val = get_enum_name_val(tmp);
635             if (enum_val == -1) {
636                 hf_entr.hfinfo.strings = NULL;
637             }
638             else {
639                 hf_entr.hfinfo.strings = VALS(tpncp_enums_id_vals[enum_val]);
640             }
641         }
642         else {
643             hf_entr.hfinfo.strings = NULL;
644         }
645         current_tpncp_data_field_info->tpncp_data_field_descr = -1;
646         hf_entr.p_id = &current_tpncp_data_field_info->tpncp_data_field_descr;
647         current_tpncp_data_field_info->tpncp_data_field_name = g_strdup_printf("tpncp.%s", tpncp_data_field_name);
648         hf_entr.hfinfo.name = current_tpncp_data_field_info->tpncp_data_field_name;
649         hf_entr.hfinfo.abbrev = current_tpncp_data_field_info->tpncp_data_field_name;
650         switch (tpncp_data_field_size) {
651             case 1: case 2: case 3: case 4:
652             case 5: case 6: case 7: case 8:
653                 if (tpncp_data_field_array_dim) {
654                     hf_entr.hfinfo.type = FT_STRING;
655                     hf_entr.hfinfo.display = BASE_NONE;
656                 }
657                 else
658                     hf_entr.hfinfo.type = (tpncp_data_field_sign)?FT_UINT8:FT_INT8;
659                 break;
660             case 16:
661                 hf_entr.hfinfo.type = (tpncp_data_field_sign)?FT_UINT16:FT_INT16;
662                 break;
663             case 32:
664                 hf_entr.hfinfo.type = (tpncp_data_field_sign)?FT_UINT32:FT_INT32;
665                 break;
666             default:
667                 break;
668         }
669         /* Register initialized hf_register_info in global database. */
670         if (hf_size > hf_allocated) {
671             hf_allocated += 1024;
672             if ((hf = (hf_register_info *)g_realloc(hf, hf_allocated * sizeof(hf_register_info))) == NULL)
673                 return (-1);
674         }
675         memcpy(hf + hf_size - 1, &hf_entr, sizeof(hf_register_info));
676         hf_size++;
677         current_tpncp_data_field_info->tpncp_data_field_sign = tpncp_data_field_sign;
678         current_tpncp_data_field_info->tpncp_data_field_size = tpncp_data_field_size;
679         current_tpncp_data_field_info->tpncp_data_field_array_dim = tpncp_data_field_array_dim;
680         current_tpncp_data_field_info->tpncp_data_field_is_ip_addr = tpncp_data_field_is_ip_addr;
681     }
682
683     return 0;
684 }
685
686 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
687
688 static gint init_tpncp_db(void) {
689     gchar *tpncp_dat_file_path;
690     FILE *file;
691
692     tpncp_dat_file_path = ep_strdup_printf("%s" G_DIR_SEPARATOR_S"tpncp" G_DIR_SEPARATOR_S "tpncp.dat", get_datafile_dir());
693
694     /* Open file with TPNCP data. */
695     if ((file = ws_fopen(tpncp_dat_file_path, "r")) == NULL)
696         return (-1);
697
698     fill_tpncp_id_vals(tpncp_events_id_vals, file);
699     fill_tpncp_id_vals(tpncp_commands_id_vals, file);
700     fill_enums_id_vals(file);
701     init_tpncp_data_fields_info(tpncp_events_info_db, file);
702     init_tpncp_data_fields_info(tpncp_commands_info_db, file);
703
704     fclose(file);
705
706     return 0;
707 }
708
709 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
710
711 void proto_reg_handoff_tpncp(void) {
712     static gint tpncp_prefs_initialized = FALSE;
713     static dissector_handle_t tpncp_udp_handle, tpncp_tcp_handle;
714
715     /*  If we weren't able to load the database (and thus the hf_ entries)
716      *  do not attach to any ports (if we did then we'd get a "dissector bug"
717      *  assertions every time a packet is handed to us and we tried to use the
718      *  hf_ entry).
719      */
720     if (proto_tpncp == -1)
721         return;
722
723     if (!tpncp_prefs_initialized) {
724         tpncp_udp_handle = create_dissector_handle(dissect_tpncp, proto_tpncp);
725         tpncp_tcp_handle = create_dissector_handle(dissect_tpncp_tcp, proto_tpncp);
726
727         tpncp_prefs_initialized = TRUE;
728     }
729     else {
730         dissector_delete_uint("tcp.port", trunkpack_tcp_port, tpncp_tcp_handle);
731         dissector_delete_uint("udp.port", trunkpack_udp_port, tpncp_udp_handle);
732         dissector_delete_uint("tcp.port", host_tcp_port,      tpncp_tcp_handle);
733         dissector_delete_uint("udp.port", host_udp_port,      tpncp_udp_handle);
734     }
735
736     trunkpack_tcp_port = global_tpncp_trunkpack_tcp_port;
737     trunkpack_udp_port = global_tpncp_trunkpack_udp_port;
738
739     host_tcp_port = global_tpncp_host_tcp_port;
740     host_udp_port = global_tpncp_host_udp_port;
741
742     dissector_add_uint("tcp.port", global_tpncp_trunkpack_tcp_port, tpncp_tcp_handle);
743     dissector_add_uint("udp.port", global_tpncp_trunkpack_udp_port, tpncp_udp_handle);
744 }
745
746 /*-------------------------------------------------------------------------------------------------------------------------------------------*/
747
748 void proto_register_tpncp(void) {
749     gint idx;
750     module_t *tpncp_module;
751     static gint *ett[] = {
752         &ett_tpncp,
753         &ett_tpncp_body
754     };
755
756     if (init_tpncp_db() == -1)
757         return;
758
759     proto_tpncp = proto_register_protocol("AudioCodes TPNCP (TrunkPack Network Control Protocol)",
760                                           "TPNCP", "tpncp");
761
762     /*
763      * The function proto_register_field_array can not work with dynamic arrays,
764      * so passing dynamic array elements one-by-one in the loop.
765      */
766     for(idx = 0; idx < hf_size; idx++) {
767         proto_register_field_array(proto_tpncp, &hf[idx], 1);
768     }
769
770     proto_register_subtree_array(ett, array_length(ett));
771
772     register_dissector("tpncp", dissect_tpncp, proto_tpncp);
773
774     tpncp_module = prefs_register_protocol(proto_tpncp, proto_reg_handoff_tpncp);
775
776     prefs_register_uint_preference(tpncp_module, "tcp.trunkpack_port",
777                                    "TPNCP \"well-known\" TrunkPack TCP Port",
778                                    "", 10, &global_tpncp_trunkpack_tcp_port);
779
780     prefs_register_uint_preference(tpncp_module, "udp.trunkpack_port",
781                                    "TPNCP \"well-known\" TrunkPack UDP Port",
782                                    "", 10, &global_tpncp_trunkpack_udp_port);
783 }