d185bf3943186365025ffd087083308eec4f6259
[obnox/wireshark/wip.git] / proto.c
1 /* proto.c
2  * Routines for protocol tree
3  *
4  * $Id: proto.c,v 1.16 1999/08/20 06:55:06 guy 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 #define cVALS(x) (const value_string*)(x)
65
66 #if defined(HAVE_UCD_SNMP_SNMP_H)
67   #define WITH_SNMP_UCD 1
68 #elif defined(HAVE_SNMP_SNMP_H)
69   #define WITH_SNMP_CMU 1
70 #endif
71
72 static gboolean
73 proto_tree_free_node(GNode *node, gpointer data);
74
75 static struct header_field_info*
76 find_hfinfo_record(int hfindex);
77
78 static proto_item *
79 proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
80         gint length, int include_format, int visible, va_list ap);
81
82 static gboolean proto_check_id(GNode *node, gpointer data);
83
84 static int proto_register_field_init(header_field_info *hfinfo, int parent);
85
86 void dfilter_yacc_init(void);
87
88 /* centralization of registration functions */
89 void proto_register_aarp(void);
90 void proto_register_arp(void);
91 void proto_register_atalk(void);
92 void proto_register_atm(void);
93 void proto_register_bootp(void);
94 void proto_register_cdp(void);
95 void proto_register_data(void);
96 void proto_register_dns(void);
97 void proto_register_eth(void);
98 void proto_register_fddi(void);
99 void proto_register_frame(void);
100 void proto_register_ftp(void);
101 void proto_register_giop(void);
102 void proto_register_gre(void);
103 void proto_register_http(void);
104 void proto_register_icmp(void);
105 void proto_register_icmpv6(void);
106 void proto_register_igmp(void);
107 void proto_register_ip(void);
108 void proto_register_ipsec(void);
109 void proto_register_ipv6(void);
110 void proto_register_ipx(void);
111 void proto_register_isakmp(void);
112 void proto_register_lapb(void);
113 void proto_register_llc(void);
114 void proto_register_nbipx(void);
115 void proto_register_nbt(void);
116 void proto_register_ncp(void);
117 void proto_register_netbios(void);
118 void proto_register_nntp(void);
119 void proto_register_null(void);
120 void proto_register_osi(void);
121 void proto_register_ospf(void);
122 void proto_register_pop(void);
123 void proto_register_ppp(void);
124 void proto_register_radius(void);
125 void proto_register_rip(void);
126 void proto_register_rsvp(void);
127 void proto_register_rtsp(void);
128 void proto_register_sdp(void);
129 void proto_register_smb(void);
130 #if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
131 void proto_register_snmp(void);
132 #endif
133 void proto_register_telnet(void);
134 void proto_register_tftp(void);
135 void proto_register_tcp(void);
136 void proto_register_tr(void);
137 void proto_register_trmac(void);
138 void proto_register_udp(void);
139 void proto_register_x25(void);
140
141 /* special-case header field used within proto.c */
142 int hf_text_only = 1;
143
144 /* Contains information about protocols and header fields. Used when
145  * dissectors register their data */
146 GMemChunk *gmc_hfinfo = NULL;
147
148 /* Contains information about a field when a dissector calls
149  * proto_tree_add_item.  */
150 GMemChunk *gmc_field_info = NULL;
151
152 /* String space for protocol and field items for the GUI */
153 GMemChunk *gmc_item_labels = NULL;
154
155 /* List which stores protocols and fields that have been registered */
156 GPtrArray *gpa_hfinfo = NULL;
157
158
159 /* initialize data structures and register protocols and fields */
160 void
161 proto_init(void)
162 {
163         if (gmc_hfinfo)
164                 g_mem_chunk_destroy(gmc_hfinfo);
165         if (gmc_field_info)
166                 g_mem_chunk_destroy(gmc_field_info);
167         if (gmc_item_labels)
168                 g_mem_chunk_destroy(gmc_item_labels);
169         if (gpa_hfinfo)
170                 g_ptr_array_free(gpa_hfinfo, FALSE); /* ever needs to be TRUE?  */
171
172         gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
173                 sizeof(struct header_field_info), 50 * sizeof(struct 
174                 header_field_info), G_ALLOC_ONLY);
175         gmc_field_info = g_mem_chunk_new("gmc_field_info",
176                 sizeof(struct field_info), 200 * sizeof(struct field_info),
177                 G_ALLOC_AND_FREE);
178         gmc_item_labels = g_mem_chunk_new("gmc_item_labels",
179                 ITEM_LABEL_LENGTH, 20 * ITEM_LABEL_LENGTH,
180                 G_ALLOC_AND_FREE);
181         gpa_hfinfo = g_ptr_array_new();
182
183         /* Have each dissector register its protocols and fields. The
184          * order doesn't matter. Put the calls in alphabetical order
185          * just to make it easy. */
186         proto_register_aarp();
187         proto_register_arp();
188         proto_register_atalk();
189         proto_register_atm();
190         proto_register_bootp();
191         proto_register_cdp();
192         proto_register_data();
193         proto_register_dns();
194         proto_register_eth();
195         proto_register_fddi();
196         proto_register_frame();
197         proto_register_ftp();
198         proto_register_giop();
199         proto_register_gre();
200         proto_register_http();
201         proto_register_icmp();
202         proto_register_icmpv6();
203         proto_register_igmp();
204         proto_register_ip();
205         proto_register_ipsec();
206         proto_register_ipv6();
207         proto_register_ipx();
208         proto_register_isakmp();
209         proto_register_lapb();
210         proto_register_llc();
211         proto_register_nbipx();
212         proto_register_nbt();
213         proto_register_ncp();
214         proto_register_netbios();
215         proto_register_nntp();
216         proto_register_null();
217         proto_register_osi();
218         proto_register_ospf();
219         proto_register_pop();
220         proto_register_ppp();
221         proto_register_radius();
222         proto_register_rip();
223         proto_register_rsvp();
224         proto_register_rtsp();
225         proto_register_sdp();
226         proto_register_smb();
227 #if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
228         proto_register_snmp();
229 #endif
230         proto_register_telnet();
231         proto_register_tftp();
232         proto_register_tcp();
233         proto_register_tr();
234         proto_register_trmac();
235         proto_register_udp();
236         proto_register_x25();
237
238         /* Register one special-case FT_TEXT_ONLY field for use when
239                 converting ethereal to new-style proto_tree. These fields
240                 are merely strings on the GUI tree; they are not filterable */
241         hf_text_only = proto_register_field (
242                 /* name */      "Text",
243                 /* abbrev */    "text",
244                 /* ftype */     FT_TEXT_ONLY,
245                 /* parent */    -1,
246                 /* vals[] */    NULL );
247 }
248
249 /* frees the resources that the dissection a proto_tree uses */
250 void
251 proto_tree_free(proto_tree *tree)
252 {
253         g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, -1,
254                 proto_tree_free_node, NULL);
255         g_node_destroy((GNode*)tree);
256 }
257
258 static gboolean
259 proto_tree_free_node(GNode *node, gpointer data)
260 {
261         field_info *fi = (field_info*) (node->data);
262
263         if (fi != NULL) {
264                 if (fi->representation)
265                         g_mem_chunk_free(gmc_item_labels, fi->representation);
266                 if (fi->hfinfo->type == FT_STRING)
267                         g_free(fi->value.string);
268                 g_mem_chunk_free(gmc_field_info, fi);
269         }
270         return FALSE; /* FALSE = do not end traversal of GNode tree */
271 }       
272
273 /* Finds a record in the hf_info_records array. */
274 static struct header_field_info*
275 find_hfinfo_record(int hfindex)
276 {
277         g_assert(hfindex >= 0 && hfindex < gpa_hfinfo->len);
278         return g_ptr_array_index(gpa_hfinfo, hfindex);
279 }
280
281 proto_item *
282 proto_tree_add_item(proto_tree *tree, int hfindex, gint start, gint length, ...)
283 {
284         proto_item      *pi;
285         va_list         ap;
286
287         va_start(ap, length);
288         pi = proto_tree_add_item_value(tree, hfindex, start, length, 0, 1, ap);
289         va_end(ap);
290
291         return pi;
292 }
293
294 proto_item *
295 proto_tree_add_item_hidden(proto_tree *tree, int hfindex, gint start, gint length, ...)
296 {
297         proto_item      *pi;
298         va_list         ap;
299
300         va_start(ap, length);
301         pi = proto_tree_add_item_value(tree, hfindex, start, length, 0, 0, ap);
302         va_end(ap);
303
304         return pi;
305 }
306
307 proto_item *
308 proto_tree_add_item_format(proto_tree *tree, int hfindex, gint start, gint length, ...)
309 {
310         proto_item      *pi;
311         va_list         ap;
312
313         va_start(ap, length);
314         pi = proto_tree_add_item_value(tree, hfindex, start, length, 1, 1, ap);
315         va_end(ap);
316
317         return pi;
318 }
319
320 proto_item *
321 proto_tree_add_text(proto_tree *tree, gint start, gint length, ...)
322 {
323         proto_item      *pi;
324         va_list         ap;
325
326         va_start(ap, length);
327         pi = proto_tree_add_item_value(tree, hf_text_only, start, length, 1, 1, ap);
328         va_end(ap);
329
330         return pi;
331 }
332
333 static proto_item *
334 proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
335         gint length, int include_format, int visible, va_list ap)
336 {
337         proto_item      *pi;
338         field_info      *fi;
339         char            *junk, *format;
340
341         if (!tree)
342                 return(NULL);
343   
344         fi = g_mem_chunk_alloc(gmc_field_info);
345
346         fi->hfinfo = find_hfinfo_record(hfindex);
347         g_assert(fi->hfinfo != NULL);
348         fi->start = start;
349         fi->length = length;
350         fi->tree_type = ETT_NONE;
351         fi->visible = visible;
352
353 /* from the stdarg man page on Solaris 2.6:
354 NOTES
355      It is up to the calling routine to specify  in  some  manner
356      how  many arguments there are, since it is not always possi-
357      ble to determine the number  of  arguments  from  the  stack
358      frame.   For example, execl is passed a zero pointer to sig-
359      nal the end of the list.  printf can tell how many arguments
360      there  are  by  the format.  It is non-portable to specify a
361      second argument of char, short, or float to va_arg,  because
362      arguments  seen  by the called function are not char, short,
363      or float.  C converts char and short arguments  to  int  and
364      converts  float arguments to double before passing them to a
365      function.
366 */
367         switch(fi->hfinfo->type) {
368                 case FT_NONE:
369                         junk = va_arg(ap, guint8*);
370                         break;
371
372                 case FT_BOOLEAN:
373                         fi->value.boolean = va_arg(ap, unsigned int) ? TRUE : FALSE;
374                         break;
375
376                 case FT_UINT8:
377                 case FT_VALS_UINT8:
378                         fi->value.numeric = va_arg(ap, unsigned int);
379                         break;
380
381                 case FT_UINT16:
382                 case FT_VALS_UINT16:
383                         fi->value.numeric = va_arg(ap, unsigned int);
384                         break;
385
386                 case FT_UINT32:
387                 case FT_VALS_UINT24:
388                 case FT_VALS_UINT32:
389                 case FT_RELATIVE_TIME:
390                 case FT_IPv4:
391                 case FT_IPXNET:
392                         fi->value.numeric = va_arg(ap, unsigned int);
393                         break;
394
395                 case FT_ETHER:
396                         memcpy(fi->value.ether, va_arg(ap, guint8*), 6);
397                         break;
398
399                 case FT_ABSOLUTE_TIME:
400                         memcpy(&fi->value.abs_time, va_arg(ap, struct timeval*),
401                                 sizeof(struct timeval));
402                         break;
403
404                 case FT_STRING:
405                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
406                         fi->value.string = g_strdup(va_arg(ap, char*));
407                         break;
408
409                 case FT_TEXT_ONLY:
410                         ; /* nothing */
411                         break;
412
413                 default:
414                         g_error("hfinfo->type %d not handled\n", fi->hfinfo->type);
415                         break;
416         }
417
418         pi = (proto_item*) g_node_new(fi);
419         g_node_append((GNode*)tree, (GNode*)pi);
420
421         /* are there any formatting arguments? */
422         if (visible && include_format) {
423                 fi->representation = g_mem_chunk_alloc(gmc_item_labels);
424                 format = va_arg(ap, char*);
425                 vsnprintf(fi->representation, ITEM_LABEL_LENGTH,
426                                 format, ap);
427         }
428         else {
429                 fi->representation = NULL;
430         }
431
432         return pi;
433 }
434
435 void
436 proto_item_set_len(proto_item *pi, gint length)
437 {
438         field_info *fi = (field_info*) (((GNode*)pi)->data);
439         fi->length = length;
440 }
441
442 proto_tree*
443 proto_tree_create_root(void)
444 {
445         return (proto_tree*) g_node_new(NULL);
446 }
447
448 proto_tree*
449 proto_item_add_subtree(proto_item *pi,  gint idx) {
450         field_info *fi = (field_info*) (((GNode*)pi)->data);
451         fi->tree_type = idx;
452         return (proto_tree*) pi;
453 }
454
455
456 int
457 proto_register_protocol(char *name, char *abbrev)
458 {
459         return proto_register_field(name, abbrev, FT_NONE, -1, NULL);
460 }
461
462 /* for use with static arrays only, since we don't allocate our own copies
463 of the header_field_info struct contained withing the hf_register_info struct */
464 void
465 proto_register_field_array(int parent, hf_register_info *hf, int num_records)
466 {
467         int                     field_id, i;
468         hf_register_info        *ptr = hf;
469
470         for (i = 0; i < num_records; i++, ptr++) {
471                 field_id = proto_register_field_init(&ptr->hfinfo, parent);
472                 *ptr->p_id = field_id;
473         }
474 }
475
476
477 /* Here we do allocate a new header_field_info struct */
478 int
479 proto_register_field(char *name, char *abbrev, enum ftenum type, int parent,
480         struct value_string* vals)
481 {
482         struct header_field_info *hfinfo;
483
484         hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
485         hfinfo->name = name; /* should I g_strdup? */
486         hfinfo->abbrev = abbrev; /* should I g_strdup? */
487         hfinfo->type = type;
488         hfinfo->vals = vals;
489         hfinfo->parent = parent; /* this field differentiates protos and fields */
490
491         return proto_register_field_init(hfinfo, parent);
492 }
493
494 static int
495 proto_register_field_init(header_field_info *hfinfo, int parent)
496 {
497         g_assert((hfinfo->vals == NULL) || (hfinfo->type == FT_VALS_UINT8 || hfinfo->type == FT_VALS_UINT16 ||
498                 hfinfo->type == FT_VALS_UINT24 || hfinfo->type == FT_VALS_UINT32));
499
500         hfinfo->parent = parent;
501
502         /* if we always add and never delete, then id == len - 1 is correct */
503         g_ptr_array_add(gpa_hfinfo, hfinfo);
504         hfinfo->id = gpa_hfinfo->len - 1;
505         return hfinfo->id;
506 }
507
508 void
509 proto_item_fill_label(field_info *fi, gchar *label_str)
510 {
511         char *s;
512
513         switch(fi->hfinfo->type) {
514                 case FT_NONE:
515                         snprintf(label_str, ITEM_LABEL_LENGTH,
516                                 "%s", fi->hfinfo->name);
517                         break;
518
519                 case FT_BOOLEAN:
520                         snprintf(label_str, ITEM_LABEL_LENGTH,
521                                 "%s: %s", fi->hfinfo->name,
522                                 fi->value.boolean == TRUE ? "True" : "False");
523                         break;
524
525                 case FT_UINT8:
526                 case FT_UINT16:
527                 case FT_UINT32:
528                         snprintf(label_str, ITEM_LABEL_LENGTH,
529                                 "%s: %u", fi->hfinfo->name,
530                                 fi->value.numeric);
531                         break;
532
533                 case FT_ABSOLUTE_TIME:
534                         snprintf(label_str, ITEM_LABEL_LENGTH,
535                                 "%s: %s", fi->hfinfo->name,
536                                 abs_time_to_str(&fi->value.abs_time));
537                         break;
538
539                 case FT_VALS_UINT8:
540                         s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
541                         snprintf(label_str, ITEM_LABEL_LENGTH,
542                                 "%s: %s (0x%02x)", fi->hfinfo->name,
543                                 (s ? s : "Unknown"), fi->value.numeric);
544                         break;
545
546                 case FT_VALS_UINT16:
547                         s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
548                         snprintf(label_str, ITEM_LABEL_LENGTH,
549                                 "%s: %s (0x%04x)", fi->hfinfo->name,
550                                 (s ? s : "Unknown"), fi->value.numeric);
551                         break;
552
553                 case FT_VALS_UINT24:
554                         s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
555                         snprintf(label_str, ITEM_LABEL_LENGTH,
556                                 "%s: %s (0x%06x)", fi->hfinfo->name,
557                                 (s ? s : "Unknown"), fi->value.numeric);
558                         break;
559
560
561                 case FT_VALS_UINT32:
562                         s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
563                         snprintf(label_str, ITEM_LABEL_LENGTH,
564                                 "%s: %s (0x%08x)", fi->hfinfo->name,
565                                 (s ? s : "Unknown"), fi->value.numeric);
566                         break;
567
568                 case FT_IPXNET:
569                         snprintf(label_str, ITEM_LABEL_LENGTH,
570                                 "%s: 0x%08X", fi->hfinfo->name, fi->value.numeric);
571                         break;
572
573                 case FT_ETHER:
574                         snprintf(label_str, ITEM_LABEL_LENGTH,
575                                 "%s: %s (%s)", fi->hfinfo->name,
576                                 ether_to_str(fi->value.ether),
577                                 get_ether_name(fi->value.ether));
578                         break;
579
580                 case FT_IPv4:
581                         snprintf(label_str, ITEM_LABEL_LENGTH,
582                                 "%s: %s (%s)", fi->hfinfo->name,
583                                 get_hostname(fi->value.numeric),
584                                 ip_to_str((guint8*)&fi->value.numeric));
585                         break;
586         
587                 case FT_STRING:
588                         snprintf(label_str, ITEM_LABEL_LENGTH,
589                                 "%s: %s", fi->hfinfo->name, fi->value.string);
590                         break;
591
592                 default:
593                         g_error("hfinfo->type %d not handled\n", fi->hfinfo->type);
594                         break;
595         }
596 }
597
598 int
599 proto_registrar_n(void)
600 {
601         return gpa_hfinfo->len;
602 }
603
604 char*
605 proto_registrar_get_abbrev(int n)
606 {
607         struct header_field_info *hfinfo;
608
609         hfinfo = find_hfinfo_record(n);
610         if (hfinfo)
611                 return hfinfo->abbrev;
612         else
613                 return NULL;
614 }
615
616 int
617 proto_registrar_get_ftype(int n)
618 {
619         struct header_field_info *hfinfo;
620
621         hfinfo = find_hfinfo_record(n);
622         if (hfinfo)
623                 return hfinfo->type;
624         else
625                 return -1;
626 }
627
628 int
629 proto_registrar_get_parent(int n)
630 {
631         struct header_field_info *hfinfo;
632
633         hfinfo = find_hfinfo_record(n);
634         if (hfinfo)
635                 return hfinfo->parent;
636         else
637                 return -2;
638 }
639
640 gboolean
641 proto_registrar_is_protocol(int n)
642 {
643         struct header_field_info *hfinfo;
644
645         hfinfo = find_hfinfo_record(n);
646         if (hfinfo)
647                 return (hfinfo->parent == -1 ? TRUE : FALSE);
648         else
649                 return FALSE;
650 }
651
652 typedef struct find_id_info {
653         int     target;
654         GNode   *result;
655 } find_id_info;
656
657 /* looks for a protocol or a header field in a proto_tree. Assumes that protocols
658  * are at the top level, and header fields only occur underneath their parent's
659  * subtree. Returns NULL if field not found 
660  */
661 proto_item*
662 proto_find_field(proto_tree* tree, int id)
663 {
664         find_id_info    fiinfo;
665         int             parent_protocol;
666         proto_tree      *subtree;
667
668         fiinfo.target = id;
669         fiinfo.result = NULL;
670
671         /* do a quicker check if field is a protocol */
672         if (proto_registrar_is_protocol(id) == TRUE) {
673                 return proto_find_protocol(tree, id);
674         }
675
676         /* find the field's parent protocol */
677         parent_protocol = proto_registrar_get_parent(id);
678         subtree = proto_find_protocol(tree, parent_protocol);
679
680         /* if there is a tree with that protocol, search it for the field */
681         if (subtree)
682                 g_node_traverse((GNode*)subtree, G_IN_ORDER, G_TRAVERSE_ALL, -1, proto_check_id, &fiinfo);
683
684         return (proto_item*) fiinfo.result;
685 }
686
687
688 /* Looks for a protocol at the top layer of the tree.
689  *  Assumption: a protocol can occur only once in a proto_tree.
690  */
691 proto_item*
692 proto_find_protocol(proto_tree* tree, int protocol_id)
693 {
694         find_id_info    fiinfo;
695
696         fiinfo.target = protocol_id;
697         fiinfo.result = NULL;
698
699         g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, proto_check_id, &fiinfo);
700         return (proto_item*) fiinfo.result;
701 }
702
703
704 static gboolean
705 proto_check_id(GNode *node, gpointer data)
706 {
707         field_info      *fi = (field_info*) (node->data);
708         find_id_info    *fiinfo = (find_id_info*) data;
709
710         if (fi) { /* !fi == the top most container node which holds nothing */
711                 if (fi->hfinfo->id == fiinfo->target) {
712                         fiinfo->result = node;
713                         return TRUE; /* halt traversal */
714                 }
715         }
716         return FALSE; /* keep traversing */
717 }
718
719 void
720 proto_get_field_values(proto_tree* subtree, GNodeTraverseFunc fill_array_func, proto_tree_search_info *sinfo)
721 {
722         g_node_traverse((GNode*)subtree, G_IN_ORDER, G_TRAVERSE_ALL, -1, fill_array_func, sinfo);
723 }
724
725 /* Dumps the contents of the registration database to stdout. An indepedent program can take
726  * this output and format it into nice tables or HTML or whatever.
727  *
728  * There is one record per line. Each record is either a protocol or a header
729  * field, differentiated by the first field. The fields are tab-delimited.
730  *
731  * Protocols
732  * ---------
733  * Field 1 = 'P'
734  * Field 2 = protocol name
735  * Field 3 = protocol abbreviation
736  *
737  * Header Fields
738  * -------------
739  * Field 1 = 'F'
740  * Field 2 = field name
741  * Field 3 = field abbreviation
742  * Field 4 = type ( textual representation of the the ftenum type )
743  * Field 5 = parent protocol abbreviation
744  */
745 void
746 proto_registrar_dump(void)
747 {
748         header_field_info       *hfinfo, *parent_hfinfo;
749         int                     i, len;
750         const char              *enum_name;
751
752         len = gpa_hfinfo->len;
753         for (i = 0; i < len ; i++) {
754                 hfinfo = find_hfinfo_record(i);
755
756                 /* format for protocols */
757                 if (proto_registrar_is_protocol(i)) {
758                         printf("P\t%s\t%s\n", hfinfo->name, hfinfo->abbrev);
759                 }
760                 /* format for header fields */
761                 else {
762                         parent_hfinfo = find_hfinfo_record(hfinfo->parent);
763                         g_assert(parent_hfinfo);
764
765                         switch(hfinfo->type) {
766                         case FT_NONE:
767                                 enum_name = "FT_NONE";
768                                 break;
769                         case FT_BOOLEAN:
770                                 enum_name = "FT_BOOLEAN";
771                                 break;
772                         case FT_UINT8:
773                                 enum_name = "FT_UINT8";
774                                 break;
775                         case FT_UINT16:
776                                 enum_name = "FT_UINT16";
777                                 break;
778                         case FT_UINT32:
779                                 enum_name = "FT_UINT32";
780                                 break;
781                         case FT_ABSOLUTE_TIME:
782                                 enum_name = "FT_ABSOLUTE_TIME";
783                                 break;
784                         case FT_RELATIVE_TIME:
785                                 enum_name = "FT_RELATIVE_TIME";
786                                 break;
787                         case FT_STRING:
788                                 enum_name = "FT_STRING";
789                                 break;
790                         case FT_ETHER:
791                                 enum_name = "FT_ETHER";
792                                 break;
793                         case FT_BYTES:
794                                 enum_name = "FT_BYTES";
795                                 break;
796                         case FT_IPv4:
797                                 enum_name = "FT_IPv4";
798                                 break;
799                         case FT_IPv6:
800                                 enum_name = "FT_IPv6";
801                                 break;
802                         case FT_IPXNET:
803                                 enum_name = "FT_IPXNET";
804                                 break;
805                         case FT_VALS_UINT8:
806                                 enum_name = "FT_VALS_UINT8";
807                                 break;
808                         case FT_VALS_UINT16:
809                                 enum_name = "FT_VALS_UINT16";
810                                 break;
811                         case FT_VALS_UINT24:
812                                 enum_name = "FT_VALS_UINT24";
813                                 break;
814                         case FT_VALS_UINT32:
815                                 enum_name = "FT_VALS_UINT32";
816                                 break;
817                         case FT_TEXT_ONLY:
818                                 enum_name = "FT_TEXT_ONLY";
819                                 break;
820                         default:
821                                 enum_name = "UNKNOWN";
822                                 break;
823                         }
824                         printf("F\t%s\t%s\t%s\t%s\n", hfinfo->name, hfinfo->abbrev,
825                                 enum_name,parent_hfinfo->abbrev);
826                 }
827         }
828 }