/* proto.c
* Routines for protocol tree
*
- * $Id: proto.c,v 1.6 1999/07/31 02:15:12 guy Exp $
+ * $Id: proto.c,v 1.52 2000/01/22 04:59:55 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
#include "resolv.h"
#endif
+#ifndef __REGISTER_H__
+#include "register.h"
+#endif
+
+#include "packet-ipv6.h"
+
#define cVALS(x) (const value_string*)(x)
-static void
+static gboolean
proto_tree_free_node(GNode *node, gpointer data);
static struct header_field_info*
proto_tree_add_item_value(proto_tree *tree, int hfindex, gint start,
gint length, int include_format, int visible, va_list ap);
-static gboolean proto_check_id(GNode *node, gpointer data);
+static void fill_label_boolean(field_info *fi, gchar *label_str);
+static void fill_label_uint(field_info *fi, gchar *label_str);
+static void fill_label_enumerated_uint(field_info *fi, gchar *label_str);
+static void fill_label_enumerated_bitfield(field_info *fi, gchar *label_str);
+static void fill_label_numeric_bitfield(field_info *fi, gchar *label_str);
+static void fill_label_int(field_info *fi, gchar *label_str);
+static void fill_label_enumerated_int(field_info *fi, gchar *label_str);
-static int proto_register_field_init(header_field_info *hfinfo, int parent);
+static int hfinfo_bitwidth(header_field_info *hfinfo);
+static char* hfinfo_uint_vals_format(header_field_info *hfinfo);
+static char* hfinfo_uint_format(header_field_info *hfinfo);
+static char* hfinfo_int_vals_format(header_field_info *hfinfo);
+static char* hfinfo_int_format(header_field_info *hfinfo);
-void dfilter_yacc_init(void);
-
-/* centralization of registration functions */
-void proto_register_aarp(void);
-void proto_register_arp(void);
-void proto_register_atalk(void);
-void proto_register_bootp(void);
-void proto_register_cdp(void);
-void proto_register_data(void);
-void proto_register_dns(void);
-void proto_register_eth(void);
-void proto_register_fddi(void);
-void proto_register_frame(void);
-void proto_register_ftp(void);
-void proto_register_giop(void);
-void proto_register_gre(void);
-void proto_register_http(void);
-void proto_register_icmp(void);
-void proto_register_icmpv6(void);
-void proto_register_igmp(void);
-void proto_register_ip(void);
-void proto_register_ipsec(void);
-void proto_register_ipv6(void);
-void proto_register_ipx(void);
-void proto_register_isakmp(void);
-void proto_register_llc(void);
-void proto_register_nbipx(void);
-void proto_register_nbt(void);
-void proto_register_ncp(void);
-void proto_register_nntp(void);
-void proto_register_null(void);
-void proto_register_osi(void);
-void proto_register_ospf(void);
-void proto_register_pop(void);
-void proto_register_ppp(void);
-void proto_register_rip(void);
-void proto_register_rsvp(void);
-void proto_register_rtsp(void);
-void proto_register_sdp(void);
-void proto_register_smb(void);
-#if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
-void proto_register_snmp(void);
-#endif
-void proto_register_telnet(void);
-void proto_register_tftp(void);
-void proto_register_tcp(void);
-void proto_register_tr(void);
-void proto_register_trmac(void);
-void proto_register_udp(void);
+static gboolean check_for_protocol_or_field_id(GNode *node, gpointer data);
+static gboolean check_for_field_within_protocol(GNode *node, gpointer data);
+
+static int proto_register_field_init(header_field_info *hfinfo, int parent);
/* special-case header field used within proto.c */
int hf_text_only = 1;
/* List which stores protocols and fields that have been registered */
GPtrArray *gpa_hfinfo = NULL;
+/* Points to the first element of an array of Booleans, indexed by
+ a subtree item type; that array element is TRUE if subtrees of
+ an item of that type are to be expanded. */
+gboolean *tree_is_expanded;
+
+/* Number of elements in that array. */
+int num_tree_types;
+
+/* Is the parsing being done for a visible proto_tree or an invisible one?
+ * By setting this correctly, the proto_tree creation is sped up by not
+ * having to call vsnprintf and copy strings around.
+ */
+gboolean proto_tree_is_visible = TRUE;
/* initialize data structures and register protocols and fields */
void
proto_init(void)
{
+ static hf_register_info hf[] = {
+ { &hf_text_only,
+ { "Text", "text", FT_TEXT_ONLY, BASE_NONE, NULL, 0x0,
+ "" }},
+ };
+
if (gmc_hfinfo)
g_mem_chunk_destroy(gmc_hfinfo);
if (gmc_field_info)
if (gmc_item_labels)
g_mem_chunk_destroy(gmc_item_labels);
if (gpa_hfinfo)
- g_ptr_array_free(gpa_hfinfo, FALSE); /* ever needs to be TRUE? */
+ g_ptr_array_free(gpa_hfinfo, FALSE);
+ if (tree_is_expanded != NULL)
+ g_free(tree_is_expanded);
gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
sizeof(struct header_field_info), 50 * sizeof(struct
G_ALLOC_AND_FREE);
gpa_hfinfo = g_ptr_array_new();
- /* Have each dissector register its protocols and fields. The
- * order doesn't matter. Put the calls in alphabetical order
- * just to make it easy. */
- proto_register_aarp();
- proto_register_arp();
- proto_register_atalk();
- proto_register_bootp();
- proto_register_cdp();
- proto_register_data();
- proto_register_dns();
- proto_register_eth();
- proto_register_fddi();
- proto_register_frame();
- proto_register_ftp();
- proto_register_giop();
- proto_register_gre();
- proto_register_http();
- proto_register_icmp();
- proto_register_icmpv6();
- proto_register_igmp();
- proto_register_ip();
- proto_register_ipsec();
- proto_register_ipv6();
- proto_register_ipx();
- proto_register_isakmp();
- proto_register_llc();
- proto_register_nbipx();
- proto_register_nbt();
- proto_register_ncp();
- proto_register_nntp();
- proto_register_null();
- proto_register_osi();
- proto_register_ospf();
- proto_register_pop();
- proto_register_ppp();
- proto_register_rip();
- proto_register_rsvp();
- proto_register_rtsp();
- proto_register_sdp();
- proto_register_smb();
-#if defined(WITH_SNMP_CMU) || defined(WITH_SNMP_UCD)
- proto_register_snmp();
-#endif
- proto_register_telnet();
- proto_register_tftp();
- proto_register_tcp();
- proto_register_tr();
- proto_register_trmac();
- proto_register_udp();
+ /* Allocate "tree_is_expanded", with one element for ETT_NONE,
+ and initialize that element to FALSE. */
+ tree_is_expanded = g_malloc(sizeof (gint));
+ tree_is_expanded[0] = FALSE;
+ num_tree_types = 1;
+
+ /* Have each dissector register its protocols and fields. */
+ register_all_protocols();
/* Register one special-case FT_TEXT_ONLY field for use when
converting ethereal to new-style proto_tree. These fields
are merely strings on the GUI tree; they are not filterable */
- hf_text_only = proto_register_field (
- /* name */ "Text",
- /* abbrev */ "text",
- /* ftype */ FT_TEXT_ONLY,
- /* parent */ -1,
- /* vals[] */ NULL );
+ proto_register_field_array(-1, hf, array_length(hf));
- dfilter_yacc_init();
+ /* We've assigned all the subtree type values; allocate the array
+ for them, and zero it out. */
+ tree_is_expanded = g_malloc(num_tree_types*sizeof (gint *));
+ memset(tree_is_expanded, '\0', num_tree_types*sizeof (gint *));
+}
+
+void
+proto_cleanup(void)
+{
+ if (gmc_hfinfo)
+ g_mem_chunk_destroy(gmc_hfinfo);
+ if (gmc_field_info)
+ g_mem_chunk_destroy(gmc_field_info);
+ if (gmc_item_labels)
+ g_mem_chunk_destroy(gmc_item_labels);
+ if (gpa_hfinfo)
+ g_ptr_array_free(gpa_hfinfo, FALSE);
}
/* frees the resources that the dissection a proto_tree uses */
proto_tree_free(proto_tree *tree)
{
g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, -1,
- (GNodeTraverseFunc)proto_tree_free_node, NULL);
+ proto_tree_free_node, NULL);
+ g_node_destroy((GNode*)tree);
}
-static void
+static gboolean
proto_tree_free_node(GNode *node, gpointer data)
{
field_info *fi = (field_info*) (node->data);
- if (fi->representation)
- g_mem_chunk_free(gmc_item_labels, fi->representation);
- if (fi->hfinfo->type == FT_STRING)
- g_free(fi->value.string);
- g_mem_chunk_free(gmc_field_info, fi);
+
+ if (fi != NULL) {
+ if (fi->representation)
+ g_mem_chunk_free(gmc_item_labels, fi->representation);
+ if (fi->hfinfo->type == FT_STRING)
+ g_free(fi->value.string);
+ else if (fi->hfinfo->type == FT_BYTES)
+ g_free(fi->value.bytes);
+ g_mem_chunk_free(gmc_field_info, fi);
+ }
+ return FALSE; /* FALSE = do not end traversal of GNode tree */
}
/* Finds a record in the hf_info_records array. */
return pi;
}
+proto_item *
+proto_tree_add_notext(proto_tree *tree, gint start, gint length, ...)
+{
+ proto_item *pi;
+ va_list ap;
+
+ va_start(ap, length);
+ pi = proto_tree_add_item_value(tree, hf_text_only, start, length, 0, 1, ap);
+ va_end(ap);
+
+ return pi;
+}
+
proto_item *
proto_tree_add_text(proto_tree *tree, gint start, gint length, ...)
{
proto_item *pi;
field_info *fi;
char *junk, *format;
+ header_field_info *hfinfo;
if (!tree)
return(NULL);
-
+
+ /* either visibility flag can nullify the other */
+ visible = proto_tree_is_visible && visible;
+
fi = g_mem_chunk_alloc(gmc_field_info);
fi->hfinfo = find_hfinfo_record(hfindex);
fi->tree_type = ETT_NONE;
fi->visible = visible;
+ /* for convenience */
+
+ hfinfo = fi->hfinfo;
/* from the stdarg man page on Solaris 2.6:
NOTES
It is up to the calling routine to specify in some manner
converts float arguments to double before passing them to a
function.
*/
- switch(fi->hfinfo->type) {
+ switch(hfinfo->type) {
case FT_NONE:
junk = va_arg(ap, guint8*);
break;
- case FT_BOOLEAN:
- fi->value.boolean = va_arg(ap, unsigned int) ? TRUE : FALSE;
+ case FT_BYTES:
+ /* This g_malloc'ed memory is freed in
+ proto_tree_free_node() */
+ fi->value.bytes = (guint8 *)g_malloc(length);
+ memcpy(fi->value.bytes, va_arg(ap, guint8*), length);
break;
+ case FT_BOOLEAN:
case FT_UINT8:
- case FT_VALS_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
fi->value.numeric = va_arg(ap, unsigned int);
+ if (hfinfo->bitmask) {
+ /* Mask out irrelevant portions */
+ fi->value.numeric &= hfinfo->bitmask;
+
+ /* Shift bits */
+ if (hfinfo->bitshift > 0) {
+ fi->value.numeric >>= hfinfo->bitshift;
+ }
+ }
break;
- case FT_UINT16:
- case FT_VALS_UINT16:
+ case FT_IPv4:
+ ipv4_addr_set_net_order_addr(&(fi->value.ipv4), va_arg(ap, unsigned int));
+ ipv4_addr_set_netmask_bits(&(fi->value.ipv4), 32);
+ break;
+
+ case FT_IPXNET:
fi->value.numeric = va_arg(ap, unsigned int);
break;
- case FT_UINT32:
- case FT_VALS_UINT24:
- case FT_VALS_UINT32:
- case FT_RELATIVE_TIME:
- case FT_IPv4:
- case FT_IPXSERVER:
- fi->value.numeric = va_arg(ap, guint32);
+ case FT_IPv6:
+ memcpy(fi->value.ipv6, va_arg(ap, guint8*), 16);
+ break;
+
+ case FT_DOUBLE:
+ fi->value.floating = va_arg(ap, double);
break;
case FT_ETHER:
- case FT_ETHER_VENDOR:
-/* fi->value.ether = va_arg(ap, guint8*);*/
memcpy(fi->value.ether, va_arg(ap, guint8*), 6);
break;
case FT_ABSOLUTE_TIME:
- memcpy(&fi->value.abs_time, va_arg(ap, struct timeval*),
+ case FT_RELATIVE_TIME:
+ memcpy(&fi->value.time, va_arg(ap, struct timeval*),
sizeof(struct timeval));
break;
case FT_STRING:
- fi->value.string = g_strdup(va_arg(ap, char*)); /* XXX */
+ /* This g_strdup'ed memory is freed in proto_tree_free_node() */
+ fi->value.string = g_strdup(va_arg(ap, char*));
break;
case FT_TEXT_ONLY:
break;
default:
- g_error("hfinfo->type %d not handled\n", fi->hfinfo->type);
+ g_error("hfinfo->type %d not handled\n", hfinfo->type);
break;
}
/* are there any formatting arguments? */
if (visible && include_format) {
- fi->representation = g_mem_chunk_alloc(gmc_item_labels);
format = va_arg(ap, char*);
+ fi->representation = g_mem_chunk_alloc(gmc_item_labels);
vsnprintf(fi->representation, ITEM_LABEL_LENGTH,
format, ap);
}
return pi;
}
+void
+proto_item_set_text(proto_item *pi, ...)
+{
+ field_info *fi = (field_info*) (((GNode*)pi)->data);
+ va_list ap;
+ char *format;
+
+ if (fi->representation)
+ g_mem_chunk_free(gmc_item_labels, fi->representation);
+
+ fi->representation = g_mem_chunk_alloc(gmc_item_labels);
+ va_start(ap, pi);
+ format = va_arg(ap, char*);
+ vsnprintf(fi->representation, ITEM_LABEL_LENGTH,
+ format, ap);
+ va_end(ap);
+}
+
void
proto_item_set_len(proto_item *pi, gint length)
{
proto_tree*
proto_item_add_subtree(proto_item *pi, gint idx) {
field_info *fi = (field_info*) (((GNode*)pi)->data);
+ g_assert(idx >= 0 && idx < num_tree_types);
fi->tree_type = idx;
return (proto_tree*) pi;
}
int
proto_register_protocol(char *name, char *abbrev)
{
- return proto_register_field(name, abbrev, FT_NONE, -1, NULL);
+ struct header_field_info *hfinfo;
+
+ /* Here we do allocate a new header_field_info struct */
+ hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
+ hfinfo->name = name;
+ hfinfo->abbrev = abbrev;
+ hfinfo->type = FT_NONE;
+ hfinfo->strings = NULL;
+ hfinfo->bitmask = 0;
+ hfinfo->bitshift = 0;
+ hfinfo->blurb = "";
+ hfinfo->parent = -1; /* this field differentiates protos and fields */
+
+ return proto_register_field_init(hfinfo, hfinfo->parent);
}
/* for use with static arrays only, since we don't allocate our own copies
}
}
-
-/* Here we do allocate a new header_field_info struct */
-int
-proto_register_field(char *name, char *abbrev, enum ftenum type, int parent,
- struct value_string* vals)
-{
- struct header_field_info *hfinfo;
-
- hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
- hfinfo->name = name; /* should I g_strdup? */
- hfinfo->abbrev = abbrev; /* should I g_strdup? */
- hfinfo->type = type;
- hfinfo->vals = vals;
- hfinfo->parent = parent; /* this field differentiates protos and fields */
-
- return proto_register_field_init(hfinfo, parent);
-}
-
static int
proto_register_field_init(header_field_info *hfinfo, int parent)
{
- g_assert((hfinfo->vals == NULL) || (hfinfo->type == FT_VALS_UINT8 || hfinfo->type == FT_VALS_UINT16 ||
- hfinfo->type == FT_VALS_UINT24 || hfinfo->type == FT_VALS_UINT32));
+ /* These types of fields are allowed to have value_strings or true_false_strings */
+ g_assert((hfinfo->strings == NULL) || (
+ (hfinfo->type == FT_UINT8) ||
+ (hfinfo->type == FT_UINT16) ||
+ (hfinfo->type == FT_UINT24) ||
+ (hfinfo->type == FT_UINT32) ||
+ (hfinfo->type == FT_INT8) ||
+ (hfinfo->type == FT_INT16) ||
+ (hfinfo->type == FT_INT24) ||
+ (hfinfo->type == FT_INT32) ||
+ (hfinfo->type == FT_BOOLEAN) ));
+
+ /* if this is a bitfield, compure bitshift */
+ if (hfinfo->bitmask) {
+ while ((hfinfo->bitmask & (1 << hfinfo->bitshift)) == 0)
+ hfinfo->bitshift++;
+ }
hfinfo->parent = parent;
- hfinfo->color = 0;
/* if we always add and never delete, then id == len - 1 is correct */
g_ptr_array_add(gpa_hfinfo, hfinfo);
return hfinfo->id;
}
+void
+proto_register_subtree_array(gint **indices, int num_indices)
+{
+ int i;
+ gint **ptr = indices;
+
+ /*
+ * Add "num_indices" elements to "tree_is_expanded".
+ */
+ tree_is_expanded = g_realloc(tree_is_expanded,
+ (num_tree_types + num_indices)*sizeof (gint));
+
+ /*
+ * Assign "num_indices" subtree numbers starting at "num_tree_types",
+ * returning the indices through the pointers in the array whose
+ * first element is pointed to by "indices", set to FALSE the
+ * elements to which those subtree numbers refer, and update
+ * "num_tree_types" appropriately.
+ */
+ for (i = 0; i < num_indices; i++, ptr++, num_tree_types++) {
+ tree_is_expanded[num_tree_types] = FALSE;
+ **ptr = num_tree_types;
+ }
+}
+
void
proto_item_fill_label(field_info *fi, gchar *label_str)
{
- char *s;
+ struct header_field_info *hfinfo = fi->hfinfo;
+ guint32 n_addr; /* network-order IPv4 address */
- switch(fi->hfinfo->type) {
+ switch(hfinfo->type) {
case FT_NONE:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s", fi->hfinfo->name);
+ "%s", hfinfo->name);
break;
case FT_BOOLEAN:
+ fill_label_boolean(fi, label_str);
+ break;
+
+ case FT_BYTES:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s", fi->hfinfo->name,
- fi->value.boolean == TRUE ? "True" : "False");
+ "%s: %s", hfinfo->name,
+ bytes_to_str(fi->value.bytes, fi->length));
break;
+ /* Four types of integers to take care of:
+ * Bitfield, with val_string
+ * Bitfield, w/o val_string
+ * Non-bitfield, with val_string
+ * Non-bitfield, w/o val_string
+ */
case FT_UINT8:
case FT_UINT16:
+ case FT_UINT24:
case FT_UINT32:
- snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %u", fi->hfinfo->name,
- fi->value.numeric);
+ if (hfinfo->bitmask) {
+ if (hfinfo->strings) {
+ fill_label_enumerated_bitfield(fi, label_str);
+ }
+ else {
+ fill_label_numeric_bitfield(fi, label_str);
+ }
+ }
+ else {
+ if (hfinfo->strings) {
+ fill_label_enumerated_uint(fi, label_str);
+ }
+ else {
+ fill_label_uint(fi, label_str);
+ }
+ }
break;
- case FT_ABSOLUTE_TIME:
- snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s", fi->hfinfo->name,
- abs_time_to_str(&fi->value.abs_time));
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ g_assert(!hfinfo->bitmask);
+ if (hfinfo->strings) {
+ fill_label_enumerated_int(fi, label_str);
+ }
+ else {
+ fill_label_int(fi, label_str);
+ }
break;
- case FT_VALS_UINT8:
- s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
+ case FT_DOUBLE:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s (0x%02x)", fi->hfinfo->name,
- (s ? s : "Unknown"), fi->value.numeric);
+ "%s: %g", fi->hfinfo->name,
+ fi->value.floating);
break;
- case FT_VALS_UINT16:
- s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
+ case FT_ABSOLUTE_TIME:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s (0x%04x)", fi->hfinfo->name,
- (s ? s : "Unknown"), fi->value.numeric);
+ "%s: %s", fi->hfinfo->name,
+ abs_time_to_str(&fi->value.time));
break;
- case FT_VALS_UINT24:
- s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
+ case FT_RELATIVE_TIME:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s (0x%06x)", fi->hfinfo->name,
- (s ? s : "Unknown"), fi->value.numeric);
+ "%s: %s seconds", fi->hfinfo->name,
+ rel_time_to_str(&fi->value.time));
break;
-
- case FT_VALS_UINT32:
- s = match_strval(fi->value.numeric, cVALS(fi->hfinfo->vals));
+ case FT_IPXNET:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s (0x%08x)", fi->hfinfo->name,
- (s ? s : "Unknown"), fi->value.numeric);
+ "%s: 0x%08X (%s)", fi->hfinfo->name,
+ fi->value.numeric, get_ipxnet_name(fi->value.numeric));
break;
case FT_ETHER:
get_ether_name(fi->value.ether));
break;
- case FT_ETHER_VENDOR:
+ case FT_IPv4:
+ n_addr = ipv4_get_net_order_addr(&fi->value.ipv4);
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %02x:%02x:%02x (%s)", fi->hfinfo->name,
- fi->value.ether[0],
- fi->value.ether[1],
- fi->value.ether[2],
- get_manuf_name(fi->value.ether));
+ "%s: %s (%s)", fi->hfinfo->name,
+ get_hostname(n_addr),
+ ip_to_str((guint8*)&n_addr));
break;
- case FT_IPv4:
+ case FT_IPv6:
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s (%s)", fi->hfinfo->name,
- get_hostname(fi->value.numeric),
- ip_to_str((guint8*)&fi->value.numeric));
+ get_hostname6((struct e_in6_addr *)fi->value.ipv6),
+ ip6_to_str((struct e_in6_addr*)fi->value.ipv6));
break;
case FT_STRING:
}
}
+static void
+fill_label_boolean(field_info *fi, gchar *label_str)
+{
+ char *p = label_str;
+ int bitfield_byte_length = 0, bitwidth;
+ guint32 unshifted_value;
+
+ struct header_field_info *hfinfo = fi->hfinfo;
+ struct true_false_string default_tf = { "True", "False" };
+ struct true_false_string *tfstring = &default_tf;
+
+ if (hfinfo->strings) {
+ tfstring = (struct true_false_string*) hfinfo->strings;
+ }
+
+ if (hfinfo->bitmask) {
+ /* Figure out the bit width */
+ bitwidth = hfinfo_bitwidth(hfinfo);
+
+ /* Un-shift bits */
+ unshifted_value = fi->value.numeric;
+ if (hfinfo->bitshift > 0) {
+ unshifted_value <<= hfinfo->bitshift;
+ }
+
+ /* Create the bitfield first */
+ p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
+ bitfield_byte_length = p - label_str;
+ }
+
+ /* Fill in the textual info */
+ snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+ "%s: %s", hfinfo->name,
+ fi->value.numeric ? tfstring->true_string : tfstring->false_string);
+}
+
+
+/* Fills data for bitfield ints with val_strings */
+static void
+fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
+{
+ char *format = NULL, *p;
+ int bitfield_byte_length, bitwidth;
+ guint32 unshifted_value;
+
+ struct header_field_info *hfinfo = fi->hfinfo;
+
+ /* Figure out the bit width */
+ bitwidth = hfinfo_bitwidth(hfinfo);
+
+ /* Pick the proper format string */
+ format = hfinfo_uint_vals_format(hfinfo);
+
+ /* Un-shift bits */
+ unshifted_value = fi->value.numeric;
+ if (hfinfo->bitshift > 0) {
+ unshifted_value <<= hfinfo->bitshift;
+ }
+
+ /* Create the bitfield first */
+ p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
+ bitfield_byte_length = p - label_str;
+
+ /* Fill in the textual info using stored (shifted) value */
+ snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+ format, hfinfo->name,
+ val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
+ fi->value.numeric);
+}
+
+static void
+fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
+{
+ char *format = NULL, *p;
+ int bitfield_byte_length, bitwidth;
+ guint32 unshifted_value;
+
+ struct header_field_info *hfinfo = fi->hfinfo;
+
+ /* Figure out the bit width */
+ bitwidth = hfinfo_bitwidth(hfinfo);
+
+ /* Pick the proper format string */
+ format = hfinfo_uint_format(hfinfo);
+
+ /* Un-shift bits */
+ unshifted_value = fi->value.numeric;
+ if (hfinfo->bitshift > 0) {
+ unshifted_value <<= hfinfo->bitshift;
+ }
+
+ /* Create the bitfield using */
+ p = decode_bitfield_value(label_str, unshifted_value, hfinfo->bitmask, bitwidth);
+ bitfield_byte_length = p - label_str;
+
+ /* Fill in the textual info using stored (shifted) value */
+ snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
+ format, hfinfo->name, fi->value.numeric);
+}
+
+static void
+fill_label_enumerated_uint(field_info *fi, gchar *label_str)
+{
+ char *format = NULL;
+ struct header_field_info *hfinfo = fi->hfinfo;
+
+ /* Pick the proper format string */
+ format = hfinfo_uint_vals_format(hfinfo);
+
+ /* Fill in the textual info */
+ snprintf(label_str, ITEM_LABEL_LENGTH,
+ format, hfinfo->name,
+ val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
+ fi->value.numeric);
+}
+
+static void
+fill_label_uint(field_info *fi, gchar *label_str)
+{
+ char *format = NULL;
+ struct header_field_info *hfinfo = fi->hfinfo;
+
+ /* Pick the proper format string */
+ format = hfinfo_uint_format(hfinfo);
+
+ /* Fill in the textual info */
+ snprintf(label_str, ITEM_LABEL_LENGTH,
+ format, hfinfo->name, fi->value.numeric);
+}
+
+static void
+fill_label_enumerated_int(field_info *fi, gchar *label_str)
+{
+ char *format = NULL;
+ struct header_field_info *hfinfo = fi->hfinfo;
+
+ /* Pick the proper format string */
+ format = hfinfo_int_vals_format(hfinfo);
+
+ /* Fill in the textual info */
+ snprintf(label_str, ITEM_LABEL_LENGTH,
+ format, hfinfo->name,
+ val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
+ fi->value.numeric);
+}
+
+static void
+fill_label_int(field_info *fi, gchar *label_str)
+{
+ char *format = NULL;
+ struct header_field_info *hfinfo = fi->hfinfo;
+
+ /* Pick the proper format string */
+ format = hfinfo_int_format(hfinfo);
+
+ /* Fill in the textual info */
+ snprintf(label_str, ITEM_LABEL_LENGTH,
+ format, hfinfo->name, fi->value.numeric);
+}
+
+static int
+hfinfo_bitwidth(header_field_info *hfinfo)
+{
+ int bitwidth = 0;
+
+ if (!hfinfo->bitmask) {
+ return 0;
+ }
+
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ case FT_INT8:
+ bitwidth = 8;
+ break;
+ case FT_UINT16:
+ case FT_INT16:
+ bitwidth = 16;
+ break;
+ case FT_UINT24:
+ case FT_INT24:
+ bitwidth = 24;
+ break;
+ case FT_UINT32:
+ case FT_INT32:
+ bitwidth = 32;
+ break;
+ case FT_BOOLEAN:
+ bitwidth = hfinfo->display; /* hacky? :) */
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ return bitwidth;
+}
+
+static char*
+hfinfo_uint_vals_format(header_field_info *hfinfo)
+{
+ char *format = NULL;
+
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ case BASE_NONE:
+ case BASE_OCT: /* I'm lazy */
+ case BASE_BIN: /* I'm lazy */
+ format = "%s: %s (%u)";
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ format = "%s: %s (0x%02x)";
+ break;
+ case FT_UINT16:
+ format = "%s: %s (0x%04x)";
+ break;
+ case FT_UINT24:
+ format = "%s: %s (0x%06x)";
+ break;
+ case FT_UINT32:
+ format = "%s: %s (0x%08x)";
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ return format;
+}
+
+static char*
+hfinfo_uint_format(header_field_info *hfinfo)
+{
+ char *format = NULL;
+
+ /* Pick the proper format string */
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ case BASE_NONE:
+ case BASE_OCT: /* I'm lazy */
+ case BASE_BIN: /* I'm lazy */
+ format = "%s: %u";
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ format = "%s: 0x%02x";
+ break;
+ case FT_UINT16:
+ format = "%s: 0x%04x";
+ break;
+ case FT_UINT24:
+ format = "%s: 0x%06x";
+ break;
+ case FT_UINT32:
+ format = "%s: 0x%08x";
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ return format;
+}
+
+static char*
+hfinfo_int_vals_format(header_field_info *hfinfo)
+{
+ char *format = NULL;
+
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ case BASE_NONE:
+ case BASE_OCT: /* I'm lazy */
+ case BASE_BIN: /* I'm lazy */
+ format = "%s: %s (%d)";
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_INT8:
+ format = "%s: %s (0x%02x)";
+ break;
+ case FT_INT16:
+ format = "%s: %s (0x%04x)";
+ break;
+ case FT_INT24:
+ format = "%s: %s (0x%06x)";
+ break;
+ case FT_INT32:
+ format = "%s: %s (0x%08x)";
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ return format;
+}
+
+static char*
+hfinfo_int_format(header_field_info *hfinfo)
+{
+ char *format = NULL;
+
+ /* Pick the proper format string */
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ case BASE_NONE:
+ case BASE_OCT: /* I'm lazy */
+ case BASE_BIN: /* I'm lazy */
+ format = "%s: %d";
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_INT8:
+ format = "%s: 0x%02x";
+ break;
+ case FT_INT16:
+ format = "%s: 0x%04x";
+ break;
+ case FT_INT24:
+ format = "%s: 0x%06x";
+ break;
+ case FT_INT32:
+ format = "%s: 0x%08x";
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ return format;
+}
+
+
+
int
proto_registrar_n(void)
{
return gpa_hfinfo->len;
}
+char*
+proto_registrar_get_name(int n)
+{
+ struct header_field_info *hfinfo;
+ hfinfo = find_hfinfo_record(n);
+ if (hfinfo)
+ return hfinfo->name;
+ else return NULL;
+}
+
char*
proto_registrar_get_abbrev(int n)
{
return FALSE;
}
-typedef struct find_id_info {
- int target;
- GNode *result;
-} find_id_info;
-
-/* looks for a protocol or a header field in a proto_tree. Assumes that protocols
- * are at the top level, and header fields only occur underneath their parent's
- * subtree. Returns NULL if field not found
- */
-proto_item*
-proto_find_field(proto_tree* tree, int id)
+/* Returns length of field in packet (not necessarily the length
+ * in our internal representation, as in the case of IPv4).
+ * 0 means undeterminable at time of registration
+ * -1 means the field is not registered. */
+gint
+proto_registrar_get_length(int n)
{
- find_id_info fiinfo;
- int parent_protocol;
- proto_tree *subtree;
+ struct header_field_info *hfinfo;
- fiinfo.target = id;
- fiinfo.result = NULL;
+ hfinfo = find_hfinfo_record(n);
+ if (!hfinfo)
+ return -1;
- /* do a quicker check if field is a protocol */
- if (proto_registrar_is_protocol(id) == TRUE) {
- return proto_find_protocol(tree, id);
- }
+ switch (hfinfo->type) {
+ case FT_TEXT_ONLY: /* not filterable */
+ case NUM_FIELD_TYPES: /* satisfy picky compilers */
+ return -1;
- /* find the field's parent protocol */
- parent_protocol = proto_registrar_get_parent(id);
- subtree = proto_find_protocol(tree, parent_protocol);
+ case FT_NONE:
+ case FT_BYTES:
+ case FT_BOOLEAN:
+ case FT_STRING:
+ case FT_DOUBLE:
+ case FT_ABSOLUTE_TIME:
+ case FT_RELATIVE_TIME:
+ return 0;
- /* if there is a tree with that protocol, search it for the field */
- if (subtree)
- g_node_traverse((GNode*)subtree, G_IN_ORDER, G_TRAVERSE_ALL, -1, proto_check_id, &fiinfo);
+ case FT_UINT8:
+ case FT_INT8:
+ return 1;
- return (proto_item*) fiinfo.result;
-}
+ case FT_UINT16:
+ case FT_INT16:
+ return 2;
+ case FT_UINT24:
+ case FT_INT24:
+ return 3;
-/* Looks for a protocol at the top layer of the tree.
- * Assumption: a protocol can occur only once in a proto_tree.
- */
-proto_item*
-proto_find_protocol(proto_tree* tree, int protocol_id)
-{
- find_id_info fiinfo;
+ case FT_UINT32:
+ case FT_INT32:
+ case FT_IPXNET:
+ case FT_IPv4:
+ return 4;
- fiinfo.target = protocol_id;
- fiinfo.result = NULL;
+ case FT_ETHER:
+ return 6;
- g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, proto_check_id, &fiinfo);
- return (proto_item*) fiinfo.result;
+ case FT_IPv6:
+ return 16;
+ }
+ g_assert_not_reached();
+ return -1;
}
+/* Looks for a protocol or a field in a proto_tree. Returns TRUE if
+ * it exists anywhere, or FALSE if it exists nowhere. */
+gboolean
+proto_check_for_protocol_or_field(proto_tree* tree, int id)
+{
+ proto_tree_search_info sinfo;
+
+ sinfo.target = id;
+ sinfo.result.node = NULL;
+ sinfo.parent = -1;
+ sinfo.traverse_func = NULL;
+
+ /* do a quicker check if target is a protocol */
+ if (proto_registrar_is_protocol(id) == TRUE) {
+ proto_find_protocol_multi(tree, id, &check_for_protocol_or_field_id, &sinfo);
+ }
+ else {
+ /* find the field's parent protocol */
+ sinfo.parent = proto_registrar_get_parent(id);
+
+ /* Go through each protocol subtree, checking if the protocols
+ * is the parent protocol of the field that we're looking for.
+ * We may have protocols that occur more than once (e.g., IP in IP),
+ * so we do indeed have to check all protocol subtrees, looking
+ * for the parent protocol. That's why proto_find_protocol()
+ * is not used --- it assumes a protocol occurs only once. */
+ g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2,
+ check_for_field_within_protocol, &sinfo);
+ }
+
+ if (sinfo.result.node)
+ return TRUE;
+ else
+ return FALSE;
+}
static gboolean
-proto_check_id(GNode *node, gpointer data)
+check_for_protocol_or_field_id(GNode *node, gpointer data)
{
- field_info *fi = (field_info*) (node->data);
- find_id_info *fiinfo = (find_id_info*) data;
+ field_info *fi = (field_info*) (node->data);
+ proto_tree_search_info *sinfo = (proto_tree_search_info*) data;
if (fi) { /* !fi == the top most container node which holds nothing */
- if (fi->hfinfo->id == fiinfo->target) {
- fiinfo->result = node;
+ if (fi->hfinfo->id == sinfo->target) {
+ sinfo->result.node = node;
return TRUE; /* halt traversal */
}
}
return FALSE; /* keep traversing */
}
+static gboolean
+check_for_field_within_protocol(GNode *node, gpointer data)
+{
+ field_info *fi = (field_info*) (node->data);
+ proto_tree_search_info *sinfo = (proto_tree_search_info*) data;
+
+ if (fi) { /* !fi == the top most container node which holds nothing */
+ if (fi->hfinfo->id == sinfo->parent) {
+ g_node_traverse(node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
+ check_for_protocol_or_field_id, sinfo);
+ if (sinfo->result.node)
+ return TRUE; /* halt traversal */
+ }
+ }
+ return FALSE; /* keep traversing */
+}
+
+/* Looks for a protocol at the top layer of the tree. The protocol can occur
+ * more than once, for those encapsulated protocols. For each protocol subtree
+ * that is found, the callback function is called.
+ */
void
-proto_get_field_values(proto_tree* subtree, GNodeTraverseFunc fill_array_func, proto_tree_search_info *sinfo)
+proto_find_protocol_multi(proto_tree* tree, int target, GNodeTraverseFunc callback,
+ proto_tree_search_info *sinfo)
{
- g_node_traverse((GNode*)subtree, G_IN_ORDER, G_TRAVERSE_ALL, -1, fill_array_func, sinfo);
+ g_assert(callback != NULL);
+ g_node_traverse((GNode*)tree, G_IN_ORDER, G_TRAVERSE_ALL, 2, callback, (gpointer*)sinfo);
+}
+
+/* Simple wrappter to traverse all nodes, calling the sinfo traverse function with sinfo as an arg */
+gboolean
+proto_get_field_values(proto_tree* subtree, proto_tree_search_info *sinfo)
+{
+ /* Don't try to check value of top-level NULL GNode */
+ if (!((GNode*)subtree)->data) {
+ return FALSE; /* don't halt */
+ }
+ g_node_traverse((GNode*)subtree, G_IN_ORDER, G_TRAVERSE_ALL, -1, sinfo->traverse_func, (gpointer*)sinfo);
+ return FALSE; /* don't halt */
}
/* Dumps the contents of the registration database to stdout. An indepedent program can take
case FT_UINT16:
enum_name = "FT_UINT16";
break;
+ case FT_UINT24:
+ enum_name = "FT_UINT24";
+ break;
case FT_UINT32:
enum_name = "FT_UINT32";
break;
+ case FT_INT8:
+ enum_name = "FT_INT8";
+ break;
+ case FT_INT16:
+ enum_name = "FT_INT16";
+ break;
+ case FT_INT24:
+ enum_name = "FT_INT24";
+ break;
+ case FT_INT32:
+ enum_name = "FT_INT32";
+ break;
+ case FT_DOUBLE:
+ enum_name = "FT_DOUBLE";
+ break;
case FT_ABSOLUTE_TIME:
enum_name = "FT_ABSOLUTE_TIME";
break;
case FT_ETHER:
enum_name = "FT_ETHER";
break;
- case FT_ETHER_VENDOR:
- enum_name = "FT_ETHER_VENDOR";
- break;
case FT_BYTES:
enum_name = "FT_BYTES";
break;
case FT_IPv6:
enum_name = "FT_IPv6";
break;
- case FT_IPXSERVER:
- enum_name = "FT_IPXSERVER";
- break;
- case FT_VALS_UINT8:
- enum_name = "FT_VALS_UINT8";
- break;
- case FT_VALS_UINT16:
- enum_name = "FT_VALS_UINT16";
- break;
- case FT_VALS_UINT24:
- enum_name = "FT_VALS_UINT24";
- break;
- case FT_VALS_UINT32:
- enum_name = "FT_VALS_UINT32";
+ case FT_IPXNET:
+ enum_name = "FT_IPXNET";
break;
case FT_TEXT_ONLY:
enum_name = "FT_TEXT_ONLY";