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