aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilbert Ramirez <gram@alumni.rice.edu>1999-10-12 04:21:13 +0000
committerGilbert Ramirez <gram@alumni.rice.edu>1999-10-12 04:21:13 +0000
commit1efcb7b2cfc60043e672d5cc4c78aabbe50f5416 (patch)
tree8cd2fc805be40ddf06f39ad6ccdfb858df0be348
parent0faf7339147a90ae176d10932e14b4170241734a (diff)
Re-implemented fix to keep display filter from reading data from outside
the packet boundary. Now the field boundary is honored. The frame boundary is ignored, but of course we put proper field lengths in the proto_tree, right? :) Implemented negative offsets in byte-strings: frame[-4:4] will read the last 4 bytes of a frame. Implemented "offset-only" byte-string comparisons, since the dfilter compiler knows the length of the byte-string you supplied. These are now legal: frame[-4] == 0.0.0.1 tr.dst[0] == 00:06:29 Implemented the use of integers if you're comparing one byte. These are legal: llc[0] == 0xaa llc[0:1] == 0xaa All these forms check against the length of the field, so these will be reported as bad to the user: eth.src[5] == 00:06:29 (goes beyond field boundary) eth.dst == 1.2.3.4.5.6.7 (too long, goes beyond field boundary) Thes is also reported as bad: eth.dst[0:3] == 1.2 (incorrect number of bytes specified) eth.dst[0:1] == eth.src[0:2] (disparate lengths) I had to add a new function, proto_registrar_get_length() in proto.c, which reports the length of a field as can be determined at registration time. There are some shift/reduce errors in the grammar that I need to get rid of. svn path=/trunk/; revision=811
-rw-r--r--dfilter-grammar.y166
-rw-r--r--dfilter-scanner.l21
-rw-r--r--dfilter.c69
-rw-r--r--dfilter.h4
-rw-r--r--file.c8
-rw-r--r--proto.c55
-rw-r--r--proto.h7
7 files changed, 294 insertions, 36 deletions
diff --git a/dfilter-grammar.y b/dfilter-grammar.y
index b49ac0b9ff..9a966985d0 100644
--- a/dfilter-grammar.y
+++ b/dfilter-grammar.y
@@ -3,7 +3,7 @@
/* dfilter-grammar.y
* Parser for display filters
*
- * $Id: dfilter-grammar.y,v 1.25 1999/10/11 19:39:29 guy Exp $
+ * $Id: dfilter-grammar.y,v 1.26 1999/10/12 04:21:09 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -93,6 +93,13 @@ static GNode* dfilter_mknode_bytes_variable(gint id, gint offset, guint length);
static guint32 string_to_value(char *s);
static int ether_str_to_guint8_array(const char *s, guint8 *mac);
static int ipv6_str_to_guint8_array(const char *s, guint8 *ipv6);
+static guint dfilter_get_bytes_variable_offset(GNode *gnode);
+static guint dfilter_get_bytes_value_length(GNode* gnode);
+static void dfilter_set_bytes_variable_length(GNode *gnode, guint length);
+static guint dfilter_get_bytes_variable_length(GNode *gnode);
+static gint dfilter_get_bytes_variable_field_registered_length(GNode *gnode);
+static char* dfilter_get_variable_abbrev(GNode *gnode);
+static int check_bytes_variable_sanity(GNode *gnode);
/* This is the dfilter we're currently processing. It's how
* dfilter_compile communicates with us.
@@ -223,10 +230,56 @@ relation: numeric_variable numeric_relation numeric_value
| bytes_variable bytes_relation bytes_value
{
+ int a_len, b_len;
+
+ a_len = dfilter_get_bytes_variable_length($1);
+ b_len = dfilter_get_bytes_value_length($3);
+
+ if (a_len == 0) {
+ dfilter_set_bytes_variable_length($1, b_len);
+ a_len = b_len;
+ }
+
+ if (!check_bytes_variable_sanity($1)) {
+ YYERROR;
+ }
+
+ if (a_len != b_len) {
+ dfilter_fail("Field \"%s\" has %u byte%s being compared, but %u byte%s "
+ "were supplied.",
+ dfilter_get_variable_abbrev($1),
+ a_len, plurality(a_len, "", "s"),
+ b_len, plurality(b_len, "", "s"));
+ YYERROR;
+ }
+
$$ = dfilter_mknode_join($1, relation, $2, $3);
}
| bytes_variable bytes_relation bytes_variable
{
+ int a_len, b_len;
+
+ a_len = dfilter_get_bytes_variable_length($1);
+ b_len = dfilter_get_bytes_variable_length($3);
+
+ if (!check_bytes_variable_sanity($1)) {
+ YYERROR;
+ }
+
+ if (!check_bytes_variable_sanity($3)) {
+ YYERROR;
+ }
+
+ if (a_len != b_len) {
+ dfilter_fail("Fields \"%s\" and \"%s\" are being compared with "
+ "disparate lengths of %u byte%s and %u byte%s.",
+ dfilter_get_variable_abbrev($1),
+ dfilter_get_variable_abbrev($3),
+ a_len, plurality(a_len, "", "s"),
+ b_len, plurality(b_len, "", "s"));
+ YYERROR;
+ }
+
$$ = dfilter_mknode_join($1, relation, $2, $3);
}
@@ -304,8 +357,27 @@ bytes_value: T_VAL_BYTE_STRING
$$ = dfilter_mknode_bytes_value(barray);
g_free($1);
}
- ;
+ | T_VAL_NUMBER_STRING
+ {
+ guint32 val32 = string_to_value($1);
+ guint8 val8;
+ GByteArray *barray;
+
+ if (val32 > 0xff) {
+ dfilter_fail("The value \"%s\" cannot be stored in a single-byte byte-string. "
+ "Use the multi-byte \"xx:yy\" representation.", $1);
+ YYERROR;
+ }
+ val8 = (guint8) val32;
+ barray = g_byte_array_new();
+ global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray);
+ g_byte_array_append(barray, &val8, 1);
+
+ $$ = dfilter_mknode_bytes_value(barray);
+ g_free($1);
+ }
+ ;
numeric_variable: T_FT_UINT8 { $$ = dfilter_mknode_numeric_variable($1.id); }
| T_FT_UINT16 { $$ = dfilter_mknode_numeric_variable($1.id); }
@@ -532,6 +604,62 @@ dfilter_mknode_bytes_variable(gint id, gint offset, guint length)
return gnode;
}
+/* Gets length of variable represented by node from proto_register */
+static gint
+dfilter_get_bytes_variable_field_registered_length(GNode *gnode)
+{
+ dfilter_node *node = gnode->data;
+
+ /* Is this really a bytes_variable? */
+ g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+ return proto_registrar_get_length(node->value.variable);
+}
+
+/* Sets the length of a bytes_variable node */
+static void
+dfilter_set_bytes_variable_length(GNode *gnode, guint length)
+{
+ dfilter_node *node = gnode->data;
+
+ /* Is this really a bytes_variable? */
+ g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+ node->length = length;
+}
+
+/* Gets the length of a bytes_variable node */
+static guint
+dfilter_get_bytes_variable_length(GNode *gnode)
+{
+ dfilter_node *node = gnode->data;
+
+ /* Is this really a bytes_variable? */
+ g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+ return node->length;
+}
+
+/* Gets the offset of a bytes_variable node */
+static guint
+dfilter_get_bytes_variable_offset(GNode *gnode)
+{
+ dfilter_node *node = gnode->data;
+
+ /* Is this really a bytes_variable? */
+ g_assert(node->fill_array_func = fill_array_bytes_variable);
+
+ return node->offset;
+}
+
+static char*
+dfilter_get_variable_abbrev(GNode *gnode)
+{
+ dfilter_node *node = gnode->data;
+
+ return proto_registrar_get_abbrev(node->value.variable);
+}
+
static GNode*
dfilter_mknode_numeric_value(guint32 val)
{
@@ -664,6 +792,17 @@ dfilter_mknode_bytes_value(GByteArray *barray)
return gnode;
}
+/* Given a node representing a bytes_value, returns
+ * the length of the byte array */
+static guint
+dfilter_get_bytes_value_length(GNode* gnode)
+{
+ dfilter_node *node = gnode->data;
+
+ g_assert(node->ntype == bytes);
+ return node->length;
+}
+
static guint32
string_to_value(char *s)
{
@@ -764,3 +903,26 @@ ipv6_str_to_guint8_array(const char *s, guint8 *ipv6)
return 1; /* read exactly 16 hex pairs */
}
+
+static int
+check_bytes_variable_sanity(GNode *gnode)
+{
+ int a_off, a_len, reg_len, t_off;
+
+ a_off = dfilter_get_bytes_variable_offset(gnode);
+ a_len = dfilter_get_bytes_variable_length(gnode);
+ reg_len = dfilter_get_bytes_variable_field_registered_length(gnode);
+
+ if (reg_len > 0) {
+ t_off = a_off >= 0 ? a_off : reg_len + a_off;
+ if (t_off + a_len > reg_len) {
+ dfilter_fail("The \"%s\" field is only %u byte%s wide, but "
+ "%u byte%s were supplied.",
+ dfilter_get_variable_abbrev(gnode),
+ reg_len, plurality(reg_len, "", "s"),
+ a_len, plurality(a_len, "", "s"));
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/dfilter-scanner.l b/dfilter-scanner.l
index b6bab0d9e2..1bf22ac53b 100644
--- a/dfilter-scanner.l
+++ b/dfilter-scanner.l
@@ -3,7 +3,7 @@
/* dfilter-scanner.l
* Scanner for display filters
*
- * $Id: dfilter-scanner.l,v 1.18 1999/10/11 17:04:33 deniel Exp $
+ * $Id: dfilter-scanner.l,v 1.19 1999/10/12 04:21:10 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -132,6 +132,25 @@ le|\<\= { dfilter_lval.operand = TOK_LE; return TOK_LE; }
return T_VAL_BYTE_RANGE;
}
+\[{whitespace}*-?[0-9]+{whitespace}*\] { /* range [ x ] */
+
+ char *byterange_string = g_strdup(yytext);
+ char *s = byterange_string + 1; /* I don't want the first '[' */
+ char *p;
+
+ /* Get the offset from the string */
+ if ((p = strtok(s, "]"))) {
+ dfilter_lval.byte_range.offset = strtol(p, NULL, 10);
+ }
+ else {
+ g_free(byterange_string);
+ return 0;
+ }
+
+ dfilter_lval.byte_range.length = 0;
+ g_free(byterange_string);
+ return T_VAL_BYTE_RANGE;
+}
{hex}({hexsep}{hex})+ { /* byte string, any length */
dfilter_lval.string = g_strdup(yytext);
diff --git a/dfilter.c b/dfilter.c
index 56ac93d336..4f0486239a 100644
--- a/dfilter.c
+++ b/dfilter.c
@@ -1,7 +1,7 @@
/* dfilter.c
* Routines for display filters
*
- * $Id: dfilter.c,v 1.28 1999/10/11 17:04:34 deniel Exp $
+ * $Id: dfilter.c,v 1.29 1999/10/12 04:21:10 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -87,10 +87,10 @@ YYSTYPE yylval;
gchar dfilter_error_msg_buf[1024];
gchar *dfilter_error_msg; /* NULL when no error resulted */
-static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd, guint len);
-static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd, guint len);
-static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd, guint len);
-static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd, guint len);
+static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd);
+static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
+static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
+static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd);
static GArray* get_values_from_dfilter(dfilter_node *dnode, GNode *gnode);
static gboolean check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree);
static void clear_byte_array(gpointer data, gpointer user_data);
@@ -293,17 +293,17 @@ g_strcmp(gconstpointer a, gconstpointer b)
gboolean
-dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd, guint len)
+dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd)
{
gboolean retval;
if (dfcode == NULL)
return FALSE;
- retval = dfilter_apply_node(dfcode->dftree, ptree, pd, len);
+ retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
return retval;
}
static gboolean
-dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd, guint len)
+dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
{
GNode *gnode_a, *gnode_b;
dfilter_node *dnode = (dfilter_node*) (gnode->data);
@@ -321,11 +321,11 @@ dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd, guint len)
case logical:
g_assert(gnode_a);
- return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd, len);
+ return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
case relation:
g_assert(gnode_a && gnode_b);
- return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd, len);
+ return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
case alternation:
g_assert_not_reached();
@@ -356,21 +356,21 @@ dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd, guint len)
}
static gboolean
-check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd, guint len)
+check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
{
- gboolean val_a = dfilter_apply_node(a, ptree, pd, len);
+ gboolean val_a = dfilter_apply_node(a, ptree, pd);
gboolean val_b;
switch(operand) {
case TOK_AND:
g_assert(b);
- return (val_a && dfilter_apply_node(b, ptree, pd, len));
+ return (val_a && dfilter_apply_node(b, ptree, pd));
case TOK_OR:
g_assert(b);
- return (val_a || dfilter_apply_node(b, ptree, pd, len));
+ return (val_a || dfilter_apply_node(b, ptree, pd));
case TOK_XOR:
g_assert(b);
- val_b = dfilter_apply_node(b, ptree, pd, len);
+ val_b = dfilter_apply_node(b, ptree, pd);
return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
case TOK_NOT:
return (!val_a);
@@ -388,7 +388,7 @@ check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8
* faster.
*/
static gboolean
-check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd, guint len)
+check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
{
dfilter_node *node_a = (dfilter_node*) (a->data);
dfilter_node *node_b = (dfilter_node*) (b->data);
@@ -399,12 +399,12 @@ check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8
bytes_length = MIN(node_a->length, node_b->length);
bytes_offset = MIN(node_a->offset, node_b->offset);
if (node_a->ntype == variable)
- vals_a = get_values_from_ptree(node_a, ptree, pd, len);
+ vals_a = get_values_from_ptree(node_a, ptree, pd);
else
vals_a = get_values_from_dfilter(node_a, a);
if (node_b->ntype == variable)
- vals_b = get_values_from_ptree(node_b, ptree, pd, len);
+ vals_b = get_values_from_ptree(node_b, ptree, pd);
else
vals_b = get_values_from_dfilter(node_b, b);
@@ -426,7 +426,7 @@ check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
}
static GArray*
-get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd, guint len)
+get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
{
GArray *array;
int parent_protocol;
@@ -438,7 +438,6 @@ get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd,
sinfo.target = dnode->value.variable;
sinfo.result.array = array;
sinfo.packet_data = pd;
- sinfo.packet_len = len;
sinfo.traverse_func = dnode->fill_array_func;
/* Find the proto_tree subtree where we should start searching.*/
@@ -511,16 +510,36 @@ gboolean fill_array_bytes_variable(GNode *gnode, gpointer data)
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
field_info *fi = (field_info*) (gnode->data);
GByteArray *barray;
- guint start_of_data = fi->start + bytes_offset;
+ guint read_start, pkt_end;
if (fi->hfinfo->id == sinfo->target) {
- if (sinfo->packet_len >= start_of_data + bytes_length) {
- barray = g_byte_array_new();
- g_byte_array_append(barray, sinfo->packet_data + start_of_data, bytes_length);
- g_array_append_val(sinfo->result.array, barray);
+ if (bytes_offset < 0) {
+ /* Handle negative byte offsets */
+ bytes_offset = fi->length + bytes_offset;
+ if (bytes_offset < 0) {
+ goto FAIL;
+ }
+ }
+
+ /* Check to make sure offset exists for this field */
+ if (bytes_offset >= fi->length) {
+ goto FAIL;
}
+
+ pkt_end = fi->start + fi->length;
+ read_start = fi->start + bytes_offset;
+
+ /* Check to make sure entire length requested is inside field */
+ if (pkt_end < read_start + bytes_length) {
+ goto FAIL;
+ }
+
+ barray = g_byte_array_new();
+ g_byte_array_append(barray, sinfo->packet_data + read_start, bytes_length);
+ g_array_append_val(sinfo->result.array, barray);
}
+ FAIL:
return FALSE; /* FALSE = do not end traversal of GNode tree */
}
diff --git a/dfilter.h b/dfilter.h
index c5ad3c4055..bb4d5d868e 100644
--- a/dfilter.h
+++ b/dfilter.h
@@ -1,7 +1,7 @@
/* dfilter.h
* Definitions for display filters
*
- * $Id: dfilter.h,v 1.12 1999/10/11 14:58:01 gram Exp $
+ * $Id: dfilter.h,v 1.13 1999/10/12 04:21:11 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -61,6 +61,6 @@ void dfilter_destroy(dfilter *df);
dfilter* dfilter_compile(gchar* dfilter_text);
/* Apply compiled dfilter to a proto_tree */
-gboolean dfilter_apply(dfilter *df, proto_tree *ptree, const guint8* pd, guint len);
+gboolean dfilter_apply(dfilter *df, proto_tree *ptree, const guint8* pd);
#endif /* ! __DFILTER_H__ */
diff --git a/file.c b/file.c
index 0d87394374..1b7abe7e2a 100644
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.106 1999/10/11 14:58:02 gram Exp $
+ * $Id: file.c,v 1.107 1999/10/12 04:21:11 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -627,7 +627,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
protocol_tree = proto_tree_create_root();
dissect_packet(buf, fdata, protocol_tree);
if( DFILTER_CONTAINS_FILTER(cf->dfcode) )
- fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd, fdata->cap_len);
+ fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
else
fdata->passed_dfilter = TRUE;
/* Apply color filters. */
@@ -639,7 +639,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
continue;
}
if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
- cf->pd, fdata->cap_len)){
+ cf->pd)){
color = crow;
break;
}
@@ -752,7 +752,7 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
if (DFILTER_CONTAINS_FILTER(cf->rfcode)) {
protocol_tree = proto_tree_create_root();
dissect_packet(buf, fdata, protocol_tree);
- passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd, fdata->cap_len);
+ passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
proto_tree_free(protocol_tree);
}
}
diff --git a/proto.c b/proto.c
index cefed2863f..4550814078 100644
--- a/proto.c
+++ b/proto.c
@@ -1,7 +1,7 @@
/* proto.c
* Routines for protocol tree
*
- * $Id: proto.c,v 1.33 1999/10/11 17:02:06 deniel Exp $
+ * $Id: proto.c,v 1.34 1999/10/12 04:21:12 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -725,6 +725,59 @@ proto_registrar_is_protocol(int n)
return FALSE;
}
+/* Returns length of field.
+ * 0 means undeterminable at time of registration
+ * -1 means the field is not registered. */
+gint
+proto_registrar_get_length(int n)
+{
+ struct header_field_info *hfinfo;
+
+ hfinfo = find_hfinfo_record(n);
+ if (!hfinfo)
+ return -1;
+
+ switch (hfinfo->type) {
+ case FT_TEXT_ONLY: /* not filterable */
+ case NUM_FIELD_TYPES: /* satisfy picky compilers */
+ return -1;
+
+ 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;
+
+ case FT_UINT8:
+ case FT_VALS_UINT8:
+ return 1;
+
+ case FT_UINT16:
+ case FT_VALS_UINT16:
+ return 2;
+
+ case FT_VALS_UINT24:
+ return 3;
+
+ case FT_UINT32:
+ case FT_VALS_UINT32:
+ case FT_IPXNET:
+ case FT_IPv4:
+ return 4;
+
+ case FT_ETHER:
+ return 6;
+
+ case FT_IPv6:
+ return 128;
+ }
+ 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
diff --git a/proto.h b/proto.h
index f60466a9e4..13d627a8b9 100644
--- a/proto.h
+++ b/proto.h
@@ -1,7 +1,7 @@
/* proto.h
* Definitions for protocol display
*
- * $Id: proto.h,v 1.15 1999/10/11 17:02:08 deniel Exp $
+ * $Id: proto.h,v 1.16 1999/10/12 04:21:13 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -183,6 +183,11 @@ int proto_registrar_get_parent(int n);
/* Is item #n a protocol? */
gboolean proto_registrar_is_protocol(int n);
+/* Get length of registered field according to field type.
+ * 0 means undeterminable at registration time.
+ * -1 means unknown field */
+gint proto_registrar_get_length(int n);
+
/* Checks for existence any protocol or field within a tree.
* TRUE = found, FALSE = not found */
gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id);