Fix byte-count of IPv6 addresses.
[obnox/wireshark/wip.git] / proto.c
1 /* proto.c
2  * Routines for protocol tree
3  *
4  * $Id: proto.c,v 1.36 1999/10/12 19:47:44 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifndef _STDIO_H
35 #include <stdio.h>
36 #endif
37
38 #include <stdarg.h>
39
40 #ifndef _STRING_H
41 #include <string.h>
42 #endif
43
44 #ifdef NEED_SNPRINTF_H
45 # include "snprintf.h"
46 #endif
47
48 #ifndef __G_LIB_H__
49 #include <glib.h>
50 #endif
51
52 #ifndef __PROTO_H__
53 #include "proto.h"
54 #endif
55
56 #ifndef __PACKET_H__
57 #include "packet.h"
58 #endif
59
60 #ifndef __RESOLV_H__
61 #include "resolv.h"
62 #endif
63
64 #include "packet-ipv6.h"
65
66 #define cVALS(x) (const value_string*)(x)
67
68 #if defined(HAVE_UCD_SNMP_SNMP_H)
69 # define WITH_SNMP_UCD 1
70 #elif defined(HAVE_SNMP_SNMP_H)
71 # define WITH_SNMP_CMU 1
72 #endif
73
74 static gboolean
75 proto_tree_free_node(GNode *node, gpointer data);
76
77 static struct header_field_info*
78 find_hfinfo_record(int hfindex);
79
80 static proto_item *
81 proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
82         gint length, int include_format, int visible, va_list ap);
83
84 static void fill_label_boolean(field_info *fi, gchar *label_str);
85 static void fill_label_uint(field_info *fi, gchar *label_str);
86 static void fill_label_enumerated_uint(field_info *fi, gchar *label_str);
87 static void fill_label_enumerated_bitfield(field_info *fi, gchar *label_str);
88 static void fill_label_numeric_bitfield(field_info *fi, gchar *label_str);
89
90 static int hfinfo_bitwidth(header_field_info *hfinfo);
91 static char* hfinfo_uint_vals_format(header_field_info *hfinfo);
92 static char* hfinfo_uint_format(header_field_info *hfinfo);
93
94 static gboolean check_for_protocol_or_field_id(GNode *node, gpointer data);
95 static gboolean check_for_field_within_protocol(GNode *node, gpointer data);
96
97 static int proto_register_field_init(header_field_info *hfinfo, int parent);
98
99 /* centralization of registration functions */
100 void proto_register_aarp(void);
101 void proto_register_arp(void);
102 void proto_register_ascend(void);
103 void proto_register_atalk(void);
104 void proto_register_atm(void);
105 void proto_register_bootp(void);
106 void proto_register_bpdu(void);
107 void proto_register_cdp(void);
108 void proto_register_clnp(void);
109 void proto_register_cotp(void);
110 void proto_register_data(void);
111 void proto_register_dns(void);
112 void proto_register_eth(void);
113 void proto_register_fddi(void);
114 void proto_register_frame(void);
115 void proto_register_ftp(void);
116 void proto_register_giop(void);
117 void proto_register_gre(void);
118 void proto_register_http(void);
119 void proto_register_icmp(void);
120 void proto_register_icmpv6(void);
121 void proto_register_icp(void);
122 void proto_register_igmp(void);
123 void proto_register_ip(void);
124 void proto_register_ipp(void);
125 void proto_register_ipsec(void);
126 void proto_register_ipv6(void);
127 void proto_register_ipx(void);
128 void proto_register_isakmp(void);
129 void proto_register_lapb(void);
130 void proto_register_llc(void);
131 void proto_register_mp(void);
132 void proto_register_nbipx(void);
133 void proto_register_nbt(void);
134 void proto_register_ncp(void);
135 void proto_register_netbios(void);
136 void proto_register_nntp(void);
137 void proto_register_null(void);
138 void proto_register_ospf(void);
139 void proto_register_pop(void);
140 void proto_register_ppp(void);
141 void proto_register_radius(void);
142 void proto_register_rip(void);
143 void proto_register_rsvp(void);
144 void proto_register_rtsp(void);
145 void proto_register_sdp(void);
146 void proto_register_smb(void);
147 void proto_register_sna(void);
148 #if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
149 void proto_register_snmp(void);
150 #endif
151 void proto_register_telnet(void);
152 void proto_register_tftp(void);
153 void proto_register_tcp(void);
154 void proto_register_tr(void);
155 void proto_register_trmac(void);
156 void proto_register_udp(void);
157 void proto_register_x25(void);
158
159 /* special-case header field used within proto.c */
160 int hf_text_only = 1;
161
162 /* Contains information about protocols and header fields. Used when
163  * dissectors register their data */
164 GMemChunk *gmc_hfinfo = NULL;
165
166 /* Contains information about a field when a dissector calls
167  * proto_tree_add_item.  */
168 GMemChunk *gmc_field_info = NULL;
169
170 /* String space for protocol and field items for the GUI */
171 GMemChunk *gmc_item_labels = NULL;
172
173 /* List which stores protocols and fields that have been registered */
174 GPtrArray *gpa_hfinfo = NULL;
175
176 /* Is the parsing being done for a visible proto_tree or an invisible one?
177  * By setting this correctly, the proto_tree creation is sped up by not
178  * having to call vsnprintf and copy strings around.
179  */
180 gboolean proto_tree_is_visible = TRUE;
181
182 /* initialize data structures and register protocols and fields */
183 void
184 proto_init(void)
185 {
186         static hf_register_info hf[] = {
187                 { &hf_text_only,
188                 { "Text",       "text", FT_TEXT_ONLY, BASE_NONE, NULL, 0x0,
189                         "" }},
190         };
191
192         if (gmc_hfinfo)
193                 g_mem_chunk_destroy(gmc_hfinfo);
194         if (gmc_field_info)
195                 g_mem_chunk_destroy(gmc_field_info);
196         if (gmc_item_labels)
197                 g_mem_chunk_destroy(gmc_item_labels);
198         if (gpa_hfinfo)
199                 g_ptr_array_free(gpa_hfinfo, FALSE);
200
201         gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
202                 sizeof(struct header_field_info), 50 * sizeof(struct 
203                 header_field_info), G_ALLOC_ONLY);
204         gmc_field_info = g_mem_chunk_new("gmc_field_info",
205                 sizeof(struct field_info), 200 * sizeof(struct field_info),
206                 G_ALLOC_AND_FREE);
207         gmc_item_labels = g_mem_chunk_new("gmc_item_labels",
208                 ITEM_LABEL_LENGTH, 20 * ITEM_LABEL_LENGTH,
209                 G_ALLOC_AND_FREE);
210         gpa_hfinfo = g_ptr_array_new();
211
212         /* Have each dissector register its protocols and fields. The
213          * order doesn't matter. Put the calls in alphabetical order
214          * just to make it easy. */
215         proto_register_aarp();
216         proto_register_arp();
217         proto_register_ascend();
218         proto_register_atalk();
219         proto_register_atm();
220         proto_register_bootp();
221         proto_register_bpdu();
222         proto_register_cdp();
223         proto_register_clnp();
224         proto_register_cotp();
225         proto_register_data();
226         proto_register_dns();
227         proto_register_eth();
228         proto_register_fddi();
229         proto_register_frame();
230         proto_register_ftp();
231         proto_register_giop();
232         proto_register_gre();
233         proto_register_http();
234         proto_register_icmp();
235         proto_register_icmpv6();
236         proto_register_icp();
237         proto_register_igmp();
238         proto_register_ip();
239         proto_register_ipp();
240         proto_register_ipsec();
241         proto_register_ipv6();
242         proto_register_ipx();
243         proto_register_isakmp();
244         proto_register_lapb();
245         proto_register_llc();
246         proto_register_mp();
247         proto_register_nbipx();
248         proto_register_nbt();
249         proto_register_ncp();
250         proto_register_netbios();
251         proto_register_nntp();
252         proto_register_null();
253         proto_register_ospf();
254         proto_register_pop();
255         proto_register_ppp();
256         proto_register_radius();
257         proto_register_rip();
258         proto_register_rsvp();
259         proto_register_rtsp();
260         proto_register_sdp();
261         proto_register_smb();
262         proto_register_sna();
263 #if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
264         proto_register_snmp();
265 #endif
266         proto_register_telnet();
267         proto_register_tftp();
268         proto_register_tcp();
269         proto_register_tr();
270         proto_register_trmac();
271         proto_register_udp();
272         proto_register_x25();
273
274         /* Register one special-case FT_TEXT_ONLY field for use when
275                 converting ethereal to new-style proto_tree. These fields
276                 are merely strings on the GUI tree; they are not filterable */
277         proto_register_field_array(-1, hf, array_length(hf));
278 }
279
280 void
281 proto_cleanup(void)
282 {
283         if (gmc_hfinfo)
284                 g_mem_chunk_destroy(gmc_hfinfo);
285         if (gmc_field_info)
286                 g_mem_chunk_destroy(gmc_field_info);
287         if (gmc_item_labels)
288                 g_mem_chunk_destroy(gmc_item_labels);
289         if (gpa_hfinfo)
290                 g_ptr_array_free(gpa_hfinfo, FALSE);
291 }
292
293 /* frees the resources that the dissection a proto_tree uses */
294 void
295 proto_tree_free(proto_tree *tree)
296 {
297         g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, -1,
298                 proto_tree_free_node, NULL);
299         g_node_destroy((GNode*)tree);
300 }
301
302 static gboolean
303 proto_tree_free_node(GNode *node, gpointer data)
304 {
305         field_info *fi = (field_info*) (node->data);
306
307         if (fi != NULL) {
308                 if (fi->representation)
309                         g_mem_chunk_free(gmc_item_labels, fi->representation);
310                 if (fi->hfinfo->type == FT_STRING)
311                         g_free(fi->value.string);
312                 else if (fi->hfinfo->type == FT_BYTES) 
313                         g_free(fi->value.bytes);
314                 g_mem_chunk_free(gmc_field_info, fi);
315         }
316         return FALSE; /* FALSE = do not end traversal of GNode tree */
317 }       
318
319 /* Finds a record in the hf_info_records array. */
320 static struct header_field_info*
321 find_hfinfo_record(int hfindex)
322 {
323         g_assert(hfindex >= 0 && hfindex < gpa_hfinfo->len);
324         return g_ptr_array_index(gpa_hfinfo, hfindex);
325 }
326
327 proto_item *
328 proto_tree_add_item(proto_tree *tree, int hfindex, gint start, gint length, ...)
329 {
330         proto_item      *pi;
331         va_list         ap;
332
333         va_start(ap, length);
334         pi = proto_tree_add_item_value(tree, hfindex, start, length, 0, 1, ap);
335         va_end(ap);
336
337         return pi;
338 }
339
340 proto_item *
341 proto_tree_add_item_hidden(proto_tree *tree, int hfindex, gint start, gint length, ...)
342 {
343         proto_item      *pi;
344         va_list         ap;
345
346         va_start(ap, length);
347         pi = proto_tree_add_item_value(tree, hfindex, start, length, 0, 0, ap);
348         va_end(ap);
349
350         return pi;
351 }
352
353 proto_item *
354 proto_tree_add_item_format(proto_tree *tree, int hfindex, gint start, gint length, ...)
355 {
356         proto_item      *pi;
357         va_list         ap;
358
359         va_start(ap, length);
360         pi = proto_tree_add_item_value(tree, hfindex, start, length, 1, 1, ap);
361         va_end(ap);
362
363         return pi;
364 }
365
366 proto_item *
367 proto_tree_add_text(proto_tree *tree, gint start, gint length, ...)
368 {
369         proto_item      *pi;
370         va_list         ap;
371
372         va_start(ap, length);
373         pi = proto_tree_add_item_value(tree, hf_text_only, start, length, 1, 1, ap);
374         va_end(ap);
375
376         return pi;
377 }
378
379 static proto_item *
380 proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
381         gint length, int include_format, int visible, va_list ap)
382 {
383         proto_item      *pi;
384         field_info      *fi;
385         char            *junk, *format;
386         header_field_info *hfinfo;
387
388         if (!tree)
389                 return(NULL);
390
391         /* either visibility flag can nullify the other */
392         visible = proto_tree_is_visible && visible;
393
394         fi = g_mem_chunk_alloc(gmc_field_info);
395
396         fi->hfinfo = find_hfinfo_record(hfindex);
397         g_assert(fi->hfinfo != NULL);
398         fi->start = start;
399         fi->length = length;
400         fi->tree_type = ETT_NONE;
401         fi->visible = visible;
402
403         /* for convenience */
404
405         hfinfo = fi->hfinfo;
406 /* from the stdarg man page on Solaris 2.6:
407 NOTES
408      It is up to the calling routine to specify  in  some  manner
409      how  many arguments there are, since it is not always possi-
410      ble to determine the number  of  arguments  from  the  stack
411      frame.   For example, execl is passed a zero pointer to sig-
412      nal the end of the list.  printf can tell how many arguments
413      there  are  by  the format.  It is non-portable to specify a
414      second argument of char, short, or float to va_arg,  because
415      arguments  seen  by the called function are not char, short,
416      or float.  C converts char and short arguments  to  int  and
417      converts  float arguments to double before passing them to a
418      function.
419 */
420         switch(hfinfo->type) {
421                 case FT_NONE:
422                         junk = va_arg(ap, guint8*);
423                         break;
424
425                 case FT_BYTES:
426                         /* This g_malloc'ed memory is freed in
427                            proto_tree_free_node() */
428                         fi->value.bytes = (guint8 *)g_malloc(length);
429                         memcpy(fi->value.bytes, va_arg(ap, guint8*), length);
430                         break;
431
432                 case FT_BOOLEAN:
433                 case FT_UINT8:
434                 case FT_UINT16:
435                 case FT_UINT24:
436                 case FT_UINT32:
437                 case FT_INT8:
438                 case FT_INT16:
439                 case FT_INT24:
440                 case FT_INT32:
441                         fi->value.numeric = va_arg(ap, unsigned int);
442                         if (hfinfo->bitmask) {
443                                 /* Mask out irrelevant portions */
444                                 fi->value.numeric &= hfinfo->bitmask;
445
446                                 /* Shift bits */
447                                 if (hfinfo->bitshift > 0) {
448                                         fi->value.numeric >>= hfinfo->bitshift;
449                                 }
450                         }
451                         break;
452
453                 case FT_IPv4:
454                 case FT_IPXNET:
455                         fi->value.numeric = va_arg(ap, unsigned int);
456                         break;
457
458                 case FT_IPv6:
459                         memcpy(fi->value.ipv6, va_arg(ap, guint8*), 16);
460                         break;
461
462                 case FT_DOUBLE:
463                         fi->value.floating = va_arg(ap, double);
464                         break;
465
466                 case FT_ETHER:
467                         memcpy(fi->value.ether, va_arg(ap, guint8*), 6);
468                         break;
469
470                 case FT_ABSOLUTE_TIME:
471                 case FT_RELATIVE_TIME:
472                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
473                                 sizeof(struct timeval));
474                         break;
475
476                 case FT_STRING:
477                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
478                         fi->value.string = g_strdup(va_arg(ap, char*));
479                         break;
480
481                 case FT_TEXT_ONLY:
482                         ; /* nothing */
483                         break;
484
485                 default:
486                         g_error("hfinfo->type %d not handled\n", hfinfo->type);
487                         break;
488         }
489
490         pi = (proto_item*) g_node_new(fi);
491         g_node_append((GNode*)tree, (GNode*)pi);
492
493         /* are there any formatting arguments? */
494         if (visible && include_format) {
495                 fi->representation = g_mem_chunk_alloc(gmc_item_labels);
496                 format = va_arg(ap, char*);
497                 vsnprintf(fi->representation, ITEM_LABEL_LENGTH,
498                                 format, ap);
499         }
500         else {
501                 fi->representation = NULL;
502         }
503
504         return pi;
505 }
506
507 void
508 proto_item_set_len(proto_item *pi, gint length)
509 {
510         field_info *fi = (field_info*) (((GNode*)pi)->data);
511         fi->length = length;
512 }
513
514 proto_tree*
515 proto_tree_create_root(void)
516 {
517         return (proto_tree*) g_node_new(NULL);
518 }
519
520 proto_tree*
521 proto_item_add_subtree(proto_item *pi,  gint idx) {
522         field_info *fi = (field_info*) (((GNode*)pi)->data);
523         fi->tree_type = idx;
524         return (proto_tree*) pi;
525 }
526
527
528 int
529 proto_register_protocol(char *name, char *abbrev)
530 {
531         struct header_field_info *hfinfo;
532
533         /* Here we do allocate a new header_field_info struct */
534         hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
535         hfinfo->name = name;
536         hfinfo->abbrev = abbrev;
537         hfinfo->type = FT_NONE;
538         hfinfo->strings = NULL;
539         hfinfo->bitmask = 0;
540         hfinfo->bitshift = 0;
541         hfinfo->blurb = "";
542         hfinfo->parent = -1; /* this field differentiates protos and fields */
543
544         return proto_register_field_init(hfinfo, hfinfo->parent);
545 }
546
547 /* for use with static arrays only, since we don't allocate our own copies
548 of the header_field_info struct contained withing the hf_register_info struct */
549 void
550 proto_register_field_array(int parent, hf_register_info *hf, int num_records)
551 {
552         int                     field_id, i;
553         hf_register_info        *ptr = hf;
554
555         for (i = 0; i < num_records; i++, ptr++) {
556                 field_id = proto_register_field_init(&ptr->hfinfo, parent);
557                 *ptr->p_id = field_id;
558         }
559 }
560
561 static int
562 proto_register_field_init(header_field_info *hfinfo, int parent)
563 {
564         /* These types of fields are allowed to have value_strings or true_false_strings */
565         g_assert((hfinfo->strings == NULL) || (
566                         (hfinfo->type == FT_UINT8) ||
567                         (hfinfo->type == FT_UINT16) ||
568                         (hfinfo->type == FT_UINT24) ||
569                         (hfinfo->type == FT_UINT32) ||
570                         (hfinfo->type == FT_INT8) ||
571                         (hfinfo->type == FT_INT16) ||
572                         (hfinfo->type == FT_INT24) ||
573                         (hfinfo->type == FT_INT32) ||
574                         (hfinfo->type == FT_BOOLEAN) ));
575
576         /* if this is a bitfield, compure bitshift */
577         if (hfinfo->bitmask) {
578                 while ((hfinfo->bitmask & (1 << hfinfo->bitshift)) == 0)
579                         hfinfo->bitshift++;
580         }
581
582         hfinfo->parent = parent;
583
584         /* if we always add and never delete, then id == len - 1 is correct */
585         g_ptr_array_add(gpa_hfinfo, hfinfo);
586         hfinfo->id = gpa_hfinfo->len - 1;
587         return hfinfo->id;
588 }
589
590 void
591 proto_item_fill_label(field_info *fi, gchar *label_str)
592 {
593         struct header_field_info        *hfinfo = fi->hfinfo;
594
595         switch(hfinfo->type) {
596                 case FT_NONE:
597                         snprintf(label_str, ITEM_LABEL_LENGTH,
598                                 "%s", hfinfo->name);
599                         break;
600
601                 case FT_BOOLEAN:
602                         fill_label_boolean(fi, label_str);
603                         break;
604
605                 case FT_BYTES:
606                         snprintf(label_str, ITEM_LABEL_LENGTH,
607                                 "%s: %s", hfinfo->name, 
608                                  bytes_to_str(fi->value.bytes, fi->length));
609                         break;
610
611                 /* Four types of integers to take care of:
612                  *      Bitfield, with val_string
613                  *      Bitfield, w/o val_string
614                  *      Non-bitfield, with val_string
615                  *      Non-bitfield, w/o val_string
616                  */
617                 case FT_UINT8:
618                 case FT_UINT16:
619                 case FT_UINT32:
620                 case FT_INT8:
621                 case FT_INT16:
622                 case FT_INT32:
623                         if (hfinfo->bitmask) {
624                                 if (hfinfo->strings) {
625                                         fill_label_enumerated_bitfield(fi, label_str);
626                                 }
627                                 else {
628                                         fill_label_numeric_bitfield(fi, label_str);
629                                 }
630                         }
631                         else {
632                                 if (hfinfo->strings) {
633                                         fill_label_enumerated_uint(fi, label_str);
634                                 }
635                                 else {
636                                         fill_label_uint(fi, label_str);
637                                 }
638                         }
639                         break;
640
641                 case FT_DOUBLE:
642                         snprintf(label_str, ITEM_LABEL_LENGTH,
643                                 "%s: %g", fi->hfinfo->name,
644                                 fi->value.floating);
645                         break;
646
647                 case FT_ABSOLUTE_TIME:
648                         snprintf(label_str, ITEM_LABEL_LENGTH,
649                                 "%s: %s", fi->hfinfo->name,
650                                 abs_time_to_str(&fi->value.time));
651                         break;
652
653                 case FT_RELATIVE_TIME:
654                         snprintf(label_str, ITEM_LABEL_LENGTH,
655                                 "%s: %s seconds", fi->hfinfo->name,
656                                 rel_time_to_str(&fi->value.time));
657                         break;
658
659                 case FT_IPXNET:
660                         snprintf(label_str, ITEM_LABEL_LENGTH,
661                                 "%s: 0x%08X", fi->hfinfo->name, fi->value.numeric);
662                         break;
663
664                 case FT_ETHER:
665                         snprintf(label_str, ITEM_LABEL_LENGTH,
666                                 "%s: %s (%s)", fi->hfinfo->name,
667                                 ether_to_str(fi->value.ether),
668                                 get_ether_name(fi->value.ether));
669                         break;
670
671                 case FT_IPv4:
672                         snprintf(label_str, ITEM_LABEL_LENGTH,
673                                 "%s: %s (%s)", fi->hfinfo->name,
674                                 get_hostname(fi->value.numeric),
675                                 ip_to_str((guint8*)&fi->value.numeric));
676                         break;
677
678                 case FT_IPv6:
679                         snprintf(label_str, ITEM_LABEL_LENGTH,
680                                 "%s: %s (%s)", fi->hfinfo->name,
681                                 get_hostname6((struct e_in6_addr *)fi->value.ipv6),
682                                 ip6_to_str((struct e_in6_addr*)fi->value.ipv6));
683                         break;
684         
685                 case FT_STRING:
686                         snprintf(label_str, ITEM_LABEL_LENGTH,
687                                 "%s: %s", fi->hfinfo->name, fi->value.string);
688                         break;
689
690                 default:
691                         g_error("hfinfo->type %d not handled\n", fi->hfinfo->type);
692                         break;
693         }
694 }
695
696 static void
697 fill_label_boolean(field_info *fi, gchar *label_str)
698 {
699         char *p = label_str;
700         int bitfield_byte_length = 0, bitwidth;
701         guint32 unshifted_value;
702
703         struct header_field_info        *hfinfo = fi->hfinfo;
704         struct true_false_string        default_tf = { "True", "False" };
705         struct true_false_string        *tfstring = &default_tf;
706
707         if (hfinfo->strings) {
708                 tfstring = (struct true_false_string*) hfinfo->strings;
709         }
710
711         if (hfinfo->bitmask) {
712                 /* Figure out the bit width */
713                 bitwidth = hfinfo_bitwidth(hfinfo);
714
715                 /* Un-shift bits */
716                 unshifted_value = fi->value.numeric;
717                 if (hfinfo->bitshift > 0) {
718                         unshifted_value <<= hfinfo->bitshift;
719                 }
720
721                 /* Create the bitfield first */
722                 p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
723                 bitfield_byte_length = p - label_str;
724         }
725
726         /* Fill in the textual info */
727         snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
728                 "%s: %s",  hfinfo->name,
729                 fi->value.numeric ? tfstring->true_string : tfstring->false_string);
730 }
731
732
733 /* Fills data for bitfield ints with val_strings */
734 static void
735 fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
736 {
737         char *format = NULL, *p;
738         int bitfield_byte_length, bitwidth;
739         guint32 unshifted_value;
740
741         struct header_field_info        *hfinfo = fi->hfinfo;
742
743         /* Figure out the bit width */
744         bitwidth = hfinfo_bitwidth(hfinfo);
745
746         /* Pick the proper format string */
747         format = hfinfo_uint_vals_format(hfinfo);
748
749         /* Un-shift bits */
750         unshifted_value = fi->value.numeric;
751         if (hfinfo->bitshift > 0) {
752                 unshifted_value <<= hfinfo->bitshift;
753         }
754
755         /* Create the bitfield first */
756         p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
757         bitfield_byte_length = p - label_str;
758
759         /* Fill in the textual info using stored (shifted) value */
760         snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
761                         format,  hfinfo->name,
762                         val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
763                         fi->value.numeric);
764 }
765
766 static void
767 fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
768 {
769         char *format = NULL, *p;
770         int bitfield_byte_length, bitwidth;
771         guint32 unshifted_value;
772
773         struct header_field_info        *hfinfo = fi->hfinfo;
774
775         /* Figure out the bit width */
776         bitwidth = hfinfo_bitwidth(hfinfo);
777
778         /* Pick the proper format string */
779         format = hfinfo_uint_format(hfinfo);
780
781         /* Un-shift bits */
782         unshifted_value = fi->value.numeric;
783         if (hfinfo->bitshift > 0) {
784                 unshifted_value <<= hfinfo->bitshift;
785         }
786
787         /* Create the bitfield using */
788         p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
789         bitfield_byte_length = p - label_str;
790
791         /* Fill in the textual info using stored (shifted) value */
792         snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
793                         format,  hfinfo->name, fi->value.numeric);
794 }
795
796 static void
797 fill_label_enumerated_uint(field_info *fi, gchar *label_str)
798 {
799         char *format = NULL;
800         struct header_field_info        *hfinfo = fi->hfinfo;
801
802         /* Pick the proper format string */
803         format = hfinfo_uint_vals_format(hfinfo);
804
805         /* Fill in the textual info */
806         snprintf(label_str, ITEM_LABEL_LENGTH,
807                         format,  hfinfo->name,
808                         val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
809                         fi->value.numeric);
810 }
811
812 static void
813 fill_label_uint(field_info *fi, gchar *label_str)
814 {
815         char *format = NULL;
816         struct header_field_info        *hfinfo = fi->hfinfo;
817
818         /* Pick the proper format string */
819         format = hfinfo_uint_format(hfinfo);
820
821         /* Fill in the textual info */
822         snprintf(label_str, ITEM_LABEL_LENGTH,
823                         format,  hfinfo->name, fi->value.numeric);
824 }
825
826 static int
827 hfinfo_bitwidth(header_field_info *hfinfo)
828 {
829         int bitwidth = 0;
830
831         if (!hfinfo->bitmask) {
832                 return 0;
833         }
834
835         switch(hfinfo->type) {
836                 case FT_UINT8:
837                 case FT_INT8:
838                         bitwidth = 8;
839                         break;
840                 case FT_UINT16:
841                 case FT_INT16:
842                         bitwidth = 16;
843                         break;
844                 case FT_UINT24:
845                 case FT_INT24:
846                         bitwidth = 24;
847                         break;
848                 case FT_UINT32:
849                 case FT_INT32:
850                         bitwidth = 32;
851                         break;
852                 case FT_BOOLEAN:
853                         bitwidth = hfinfo->display; /* hacky? :) */
854                         break;
855                 default:
856                         g_assert_not_reached();
857                         ;
858         }
859         return bitwidth;
860 }
861
862 static char*
863 hfinfo_uint_vals_format(header_field_info *hfinfo)
864 {
865         char *format = NULL;
866
867         switch(hfinfo->display) {
868                 case BASE_DEC:
869                 case BASE_NONE:
870                 case BASE_OCT: /* I'm lazy */
871                 case BASE_BIN: /* I'm lazy */
872                         format = "%s: %s (%u)";
873                         break;
874                 case BASE_HEX:
875                         switch(hfinfo->type) {
876                                 case FT_UINT8:
877                                 case FT_INT8:
878                                         format = "%s: %s (0x%02x)";
879                                         break;
880                                 case FT_UINT16:
881                                 case FT_INT16:
882                                         format = "%s: %s (0x%04x)";
883                                         break;
884                                 case FT_UINT24:
885                                 case FT_INT24:
886                                         format = "%s: %s (0x%06x)";
887                                         break;
888                                 case FT_UINT32:
889                                 case FT_INT32:
890                                         format = "%s: %s (0x%08x)";
891                                         break;
892                                 default:
893                                         g_assert_not_reached();
894                                         ;
895                         }
896                         break;
897                 default:
898                         g_assert_not_reached();
899                         ;
900         }
901         return format;
902 }
903
904 static char*
905 hfinfo_uint_format(header_field_info *hfinfo)
906 {
907         char *format = NULL;
908
909         /* Pick the proper format string */
910         switch(hfinfo->display) {
911                 case BASE_DEC:
912                 case BASE_NONE:
913                 case BASE_OCT: /* I'm lazy */
914                 case BASE_BIN: /* I'm lazy */
915                         format = "%s: %u";
916                         break;
917                 case BASE_HEX:
918                         switch(hfinfo->type) {
919                                 case FT_UINT8:
920                                 case FT_INT8:
921                                         format = "%s: 0x%02x";
922                                         break;
923                                 case FT_UINT16:
924                                 case FT_INT16:
925                                         format = "%s: 0x%04x";
926                                         break;
927                                 case FT_UINT24:
928                                 case FT_INT24:
929                                         format = "%s: 0x%06x";
930                                         break;
931                                 case FT_UINT32:
932                                 case FT_INT32:
933                                         format = "%s: 0x%08x";
934                                         break;
935                                 default:
936                                         g_assert_not_reached();
937                                         ;
938                         }
939                         break;
940                 default:
941                         g_assert_not_reached();
942                         ;
943         }
944         return format;
945 }
946
947
948
949 int
950 proto_registrar_n(void)
951 {
952         return gpa_hfinfo->len;
953 }
954
955 char*
956 proto_registrar_get_abbrev(int n)
957 {
958         struct header_field_info *hfinfo;
959
960         hfinfo = find_hfinfo_record(n);
961         if (hfinfo)
962                 return hfinfo->abbrev;
963         else
964                 return NULL;
965 }
966
967 int
968 proto_registrar_get_ftype(int n)
969 {
970         struct header_field_info *hfinfo;
971
972         hfinfo = find_hfinfo_record(n);
973         if (hfinfo)
974                 return hfinfo->type;
975         else
976                 return -1;
977 }
978
979 int
980 proto_registrar_get_parent(int n)
981 {
982         struct header_field_info *hfinfo;
983
984         hfinfo = find_hfinfo_record(n);
985         if (hfinfo)
986                 return hfinfo->parent;
987         else
988                 return -2;
989 }
990
991 gboolean
992 proto_registrar_is_protocol(int n)
993 {
994         struct header_field_info *hfinfo;
995
996         hfinfo = find_hfinfo_record(n);
997         if (hfinfo)
998                 return (hfinfo->parent == -1 ? TRUE : FALSE);
999         else
1000                 return FALSE;
1001 }
1002
1003 /* Returns length of field.
1004  * 0 means undeterminable at time of registration
1005  * -1 means the field is not registered. */
1006 gint
1007 proto_registrar_get_length(int n)
1008 {
1009         struct header_field_info *hfinfo;
1010
1011         hfinfo = find_hfinfo_record(n);
1012         if (!hfinfo)
1013                 return -1;
1014
1015         switch (hfinfo->type) {
1016                 case FT_TEXT_ONLY: /* not filterable */
1017                 case NUM_FIELD_TYPES: /* satisfy picky compilers */
1018                         return -1;
1019
1020                 case FT_NONE:
1021                 case FT_BYTES:
1022                 case FT_BOOLEAN:
1023                 case FT_STRING:
1024                 case FT_DOUBLE:
1025                 case FT_ABSOLUTE_TIME:
1026                 case FT_RELATIVE_TIME:
1027                         return 0;
1028
1029                 case FT_UINT8:
1030                 case FT_INT8:
1031                         return 1;
1032
1033                 case FT_UINT16:
1034                 case FT_INT16:
1035                         return 2;
1036
1037                 case FT_UINT24:
1038                 case FT_INT24:
1039                         return 3;
1040
1041                 case FT_UINT32:
1042                 case FT_INT32:
1043                 case FT_IPXNET:
1044                 case FT_IPv4:
1045                         return 4;
1046
1047                 case FT_ETHER:
1048                         return 6;
1049
1050                 case FT_IPv6:
1051                         return 16;
1052         }
1053         g_assert_not_reached();
1054         return -1;
1055 }
1056
1057 /* Looks for a protocol or a field in a proto_tree. Returns TRUE if
1058  * it exists anywhere, or FALSE if it exists nowhere. */
1059 gboolean
1060 proto_check_for_protocol_or_field(proto_tree* tree, int id)
1061 {
1062         proto_tree_search_info  sinfo;
1063
1064         sinfo.target = id;
1065         sinfo.result.node = NULL;
1066         sinfo.parent = -1;
1067         sinfo.traverse_func = NULL;
1068
1069         /* do a quicker check if target is a protocol */
1070         if (proto_registrar_is_protocol(id) == TRUE) {
1071                 proto_find_protocol_multi(tree, id, &check_for_protocol_or_field_id, &sinfo);
1072         }
1073         else {
1074                 /* find the field's parent protocol */
1075                 sinfo.parent = proto_registrar_get_parent(id);
1076
1077                 /* Go through each protocol subtree, checking if the protocols
1078                  * is the parent protocol of the field that we're looking for.
1079                  * We may have protocols that occur more than once (e.g., IP in IP),
1080                  * so we do indeed have to check all protocol subtrees, looking
1081                  * for the parent protocol. That's why proto_find_protocol()
1082                  * is not used --- it assumes a protocol occurs only once. */
1083                 g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2,
1084                                                 check_for_field_within_protocol, &sinfo);
1085         }
1086
1087         if (sinfo.result.node)
1088                 return TRUE;
1089         else
1090                 return FALSE;
1091 }
1092
1093 static gboolean
1094 check_for_protocol_or_field_id(GNode *node, gpointer data)
1095 {
1096         field_info              *fi = (field_info*) (node->data);
1097         proto_tree_search_info  *sinfo = (proto_tree_search_info*) data;
1098
1099         if (fi) { /* !fi == the top most container node which holds nothing */
1100                 if (fi->hfinfo->id == sinfo->target) {
1101                         sinfo->result.node = node;
1102                         return TRUE; /* halt traversal */
1103                 }
1104         }
1105         return FALSE; /* keep traversing */
1106 }
1107
1108 static gboolean
1109 check_for_field_within_protocol(GNode *node, gpointer data)
1110 {
1111         field_info              *fi = (field_info*) (node->data);
1112         proto_tree_search_info  *sinfo = (proto_tree_search_info*) data;
1113
1114         if (fi) { /* !fi == the top most container node which holds nothing */
1115                 if (fi->hfinfo->id == sinfo->parent) {
1116                         g_node_traverse(node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
1117                                         check_for_protocol_or_field_id, sinfo);
1118                         if (sinfo->result.node)
1119                                 return TRUE; /* halt traversal */
1120                 }
1121         }
1122         return FALSE; /* keep traversing */
1123 }
1124
1125 /* Looks for a protocol at the top layer of the tree. The protocol can occur
1126  * more than once, for those encapsulated protocols. For each protocol subtree
1127  * that is found, the callback function is called.
1128  */
1129 void
1130 proto_find_protocol_multi(proto_tree* tree, int target, GNodeTraverseFunc callback,
1131                         proto_tree_search_info *sinfo)
1132 {
1133         g_assert(callback != NULL);
1134         g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, callback, (gpointer*)sinfo);
1135 }
1136
1137 /* Simple wrappter to traverse all nodes, calling the sinfo traverse function with sinfo as an arg */
1138 gboolean
1139 proto_get_field_values(proto_tree* subtree, proto_tree_search_info *sinfo)
1140 {
1141         /* Don't try to check value of top-level NULL GNode */
1142         if (!((GNode*)subtree)->data) {
1143                 return FALSE; /* don't halt */
1144         }
1145         g_node_traverse((GNode*)subtree, G_IN_ORDER, G_TRAVERSE_ALL, -1, sinfo->traverse_func, (gpointer*)sinfo);
1146         return FALSE; /* don't halt */
1147 }
1148
1149 /* Dumps the contents of the registration database to stdout. An indepedent program can take
1150  * this output and format it into nice tables or HTML or whatever.
1151  *
1152  * There is one record per line. Each record is either a protocol or a header
1153  * field, differentiated by the first field. The fields are tab-delimited.
1154  *
1155  * Protocols
1156  * ---------
1157  * Field 1 = 'P'
1158  * Field 2 = protocol name
1159  * Field 3 = protocol abbreviation
1160  *
1161  * Header Fields
1162  * -------------
1163  * Field 1 = 'F'
1164  * Field 2 = field name
1165  * Field 3 = field abbreviation
1166  * Field 4 = type ( textual representation of the the ftenum type )
1167  * Field 5 = parent protocol abbreviation
1168  */
1169 void
1170 proto_registrar_dump(void)
1171 {
1172         header_field_info       *hfinfo, *parent_hfinfo;
1173         int                     i, len;
1174         const char              *enum_name;
1175
1176         len = gpa_hfinfo->len;
1177         for (i = 0; i < len ; i++) {
1178                 hfinfo = find_hfinfo_record(i);
1179
1180                 /* format for protocols */
1181                 if (proto_registrar_is_protocol(i)) {
1182                         printf("P\t%s\t%s\n", hfinfo->name, hfinfo->abbrev);
1183                 }
1184                 /* format for header fields */
1185                 else {
1186                         parent_hfinfo = find_hfinfo_record(hfinfo->parent);
1187                         g_assert(parent_hfinfo);
1188
1189                         switch(hfinfo->type) {
1190                         case FT_NONE:
1191                                 enum_name = "FT_NONE";
1192                                 break;
1193                         case FT_BOOLEAN:
1194                                 enum_name = "FT_BOOLEAN";
1195                                 break;
1196                         case FT_UINT8:
1197                                 enum_name = "FT_UINT8";
1198                                 break;
1199                         case FT_UINT16:
1200                                 enum_name = "FT_UINT16";
1201                                 break;
1202                         case FT_UINT32:
1203                                 enum_name = "FT_UINT32";
1204                                 break;
1205                         case FT_INT8:
1206                                 enum_name = "FT_INT8";
1207                                 break;
1208                         case FT_INT16:
1209                                 enum_name = "FT_INT16";
1210                                 break;
1211                         case FT_INT24:
1212                                 enum_name = "FT_INT24";
1213                                 break;
1214                         case FT_INT32:
1215                                 enum_name = "FT_INT32";
1216                                 break;
1217                         case FT_DOUBLE:
1218                                 enum_name = "FT_DOUBLE";
1219                                 break;
1220                         case FT_ABSOLUTE_TIME:
1221                                 enum_name = "FT_ABSOLUTE_TIME";
1222                                 break;
1223                         case FT_RELATIVE_TIME:
1224                                 enum_name = "FT_RELATIVE_TIME";
1225                                 break;
1226                         case FT_STRING:
1227                                 enum_name = "FT_STRING";
1228                                 break;
1229                         case FT_ETHER:
1230                                 enum_name = "FT_ETHER";
1231                                 break;
1232                         case FT_BYTES:
1233                                 enum_name = "FT_BYTES";
1234                                 break;
1235                         case FT_IPv4:
1236                                 enum_name = "FT_IPv4";
1237                                 break;
1238                         case FT_IPv6:
1239                                 enum_name = "FT_IPv6";
1240                                 break;
1241                         case FT_IPXNET:
1242                                 enum_name = "FT_IPXNET";
1243                                 break;
1244                         case FT_TEXT_ONLY:
1245                                 enum_name = "FT_TEXT_ONLY";
1246                                 break;
1247                         default:
1248                                 enum_name = "UNKNOWN";
1249                                 break;
1250                         }
1251                         printf("F\t%s\t%s\t%s\t%s\n", hfinfo->name, hfinfo->abbrev,
1252                                 enum_name,parent_hfinfo->abbrev);
1253                 }
1254         }
1255 }