diff options
Diffstat (limited to 'epan')
51 files changed, 5484 insertions, 3138 deletions
diff --git a/epan/Makefile.am b/epan/Makefile.am index b7b716ac91..e3448e772d 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -2,7 +2,7 @@ # Automake file for the EPAN library # (Ethereal Protocol ANalyzer Library) # -# $Id: Makefile.am,v 1.15 2001/01/17 06:13:39 guy Exp $ +# $Id: Makefile.am,v 1.16 2001/02/01 20:21:15 gram Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs <gerald@zing.org> @@ -23,9 +23,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# Any POSIX-compatible YACC should honor the -p flag -YFLAGS=-d -p dfilter_ +SUBDIRS = ftypes dfilter # EPAN will eventually be a shared library. While I move source code around, # however, it is an archive library. @@ -41,11 +39,6 @@ libethereal_a_SOURCES = \ bitswap.h \ conversation.c \ conversation.h \ - dfilter-int.h \ - dfilter-grammar.y \ - dfilter-scanner.l \ - dfilter.c \ - dfilter.h \ epan.c \ epan.h \ except.c \ @@ -53,6 +46,7 @@ libethereal_a_SOURCES = \ exceptions.h \ filesystem.c \ filesystem.h \ + gdebug.h \ ipv4.c \ ipv4.h \ packet.c \ @@ -78,9 +72,6 @@ EXTRA_libethereal_a_SOURCES = \ EXTRA_DIST = \ config.h.win32 \ - dfilter-grammar.c \ - dfilter-grammar.h \ - dfilter-scanner.c \ Makefile.nmake \ tvbtest.c @@ -94,8 +85,6 @@ CLEANFILES = \ libethereal_a_LIBADD = @INET_ATON_O@ @INET_PTON_O@ @INET_NTOP_O@ libethereal_a_DEPENDENCIES = @INET_ATON_O@ @INET_PTON_O@ @INET_NTOP_O@ -dfilter-scanner.c : dfilter-scanner.l - $(LEX) -Pdfilter_ -odfilter-scanner.c $(srcdir)/dfilter-scanner.l tvbtest: tvbtest.o tvbuff.o except.o strutil.o $(LINK) -o tvbtest tvbtest.o tvbuff.o except.o strutil.o `glib-config --libs` diff --git a/epan/configure.in b/epan/configure.in index b16734acce..51f84b489b 100644 --- a/epan/configure.in +++ b/epan/configure.in @@ -1,4 +1,4 @@ -# $Id: configure.in,v 1.3 2001/01/12 04:18:49 gram Exp $ +# $Id: configure.in,v 1.4 2001/02/01 20:21:15 gram Exp $ dnl dnl Process this file with autoconf 2.13 or later to produce a dnl configure script; 2.12 doesn't generate a "configure" script that @@ -143,4 +143,8 @@ fi AC_SUBST(INET_NTOP_C) AC_SUBST(INET_NTOP_O) -AC_OUTPUT(Makefile) +AC_OUTPUT( + Makefile + dfilter/Makefile + ftypes/Makefile +) diff --git a/epan/dfilter-grammar.y b/epan/dfilter-grammar.y deleted file mode 100644 index 757798c8ec..0000000000 --- a/epan/dfilter-grammar.y +++ /dev/null @@ -1,1191 +0,0 @@ -%{ -/* dfilter-grammar.y - * Parser for display filters - * - * $Id: dfilter-grammar.y,v 1.2 2000/12/22 12:05:36 gram Exp $ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -#ifdef HAVE_NETINET_IN_H -# include <netinet/in.h> -#endif - -#ifdef NEED_SNPRINTF_H -# ifdef HAVE_STDARG_H -# include <stdarg.h> -# else -# include <varargs.h> -# endif -# include "snprintf.h" -#endif - -#ifndef __GLIB_H__ -#include <glib.h> -#endif - -#include <string.h> -#include <errno.h> -#include <math.h> - -#ifndef _STDLIB_H -#include <stdlib.h> -#endif - -#ifndef __PROTO_H__ -#include "proto.h" -#endif - -#ifndef __PACKET_H__ -#include "packet.h" -#endif - -#ifndef __DFILTER_H__ -#include "dfilter.h" -#endif - -#include "dfilter-int.h" - -#ifndef __RESOLV_H__ -#include "resolv.h" -#endif - -static GNode* dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2); -static GNode* dfilter_mknode_unary(int operand, GNode *n2); -static GNode* dfilter_mknode_numeric_variable(gint id); -static GNode* dfilter_mknode_numeric_value(guint32 val); -static GNode* dfilter_mknode_floating_variable(gint id); -static GNode* dfilter_mknode_floating_value(double val); -static GNode* dfilter_mknode_ether_value(gchar*); -static GNode* dfilter_mknode_ether_variable(gint id); -static GNode* dfilter_mknode_ipxnet_value(guint32); -static GNode* dfilter_mknode_ipxnet_variable(gint id); -static GNode* dfilter_mknode_ipv4_value(char *host, int nmask_bits); -static GNode* dfilter_mknode_ipv4_variable(gint id); -static GNode* dfilter_mknode_ipv6_value(char *host); -static GNode* dfilter_mknode_ipv6_variable(gint id); -static GNode* dfilter_mknode_existence(gint id); -static GNode* dfilter_mknode_bytes_value(GByteArray *barray); -static GNode* dfilter_mknode_bytes_variable(gint id, gint offset, guint length, gboolean to_the_end); -static GNode* dfilter_mknode_string_value(char *s); -static GNode* dfilter_mknode_string_variable(gint id); - -static guint32 string_to_guint32(char *s, gboolean *success); -static double string_to_double(char *s, gboolean *success); -static int ether_str_to_guint8_array(const char *s, guint8 *mac); -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. - */ -dfilter *global_df = NULL; - -%} - -%union { - gint operand; /* logical, relation, alternation */ - struct { - gint id; - gint type; /* using macros defined below, in this yacc grammar */ - } variable; - GNode* node; - gchar* string; - struct { - gint offset; - guint length; - } byte_range; -} - -%type <node> statement expression relation -%type <node> numeric_value numeric_variable -%type <node> floating_value floating_variable -%type <node> ether_value ether_variable -%type <node> ipxnet_value ipxnet_variable -%type <node> ipv4_value ipv4_variable -%type <node> ipv6_value ipv6_variable -%type <node> string_value string_variable -%type <node> variable_name -%type <node> bytes_value bytes_variable - -%type <operand> numeric_relation -%type <operand> equality_relation -%type <operand> bytes_relation - -%type <variable> any_variable_type - -%token <variable> T_FT_UINT8 -%token <variable> T_FT_UINT16 -%token <variable> T_FT_UINT24 -%token <variable> T_FT_UINT32 -%token <variable> T_FT_INT8 -%token <variable> T_FT_INT16 -%token <variable> T_FT_INT24 -%token <variable> T_FT_INT32 -%token <variable> T_FT_ETHER -%token <variable> T_FT_IPv4 -%token <variable> T_FT_IPv6 -%token <variable> T_FT_NONE -%token <variable> T_FT_BYTES -%token <variable> T_FT_BOOLEAN -%token <variable> T_FT_STRING -%token <variable> T_FT_IPXNET -%token <variable> T_FT_DOUBLE - -%token <string> T_VAL_UNQUOTED_STRING -%token <string> T_VAL_QUOTED_STRING -%token <string> T_VAL_BYTE_STRING -%token <byte_range> T_VAL_BYTE_RANGE - -%token <operand> TOK_AND TOK_OR TOK_NOT TOK_XOR -%token <operand> TOK_EQ TOK_NE TOK_GT TOK_GE TOK_LT TOK_LE - -%expect 4 -%left TOK_AND -%left TOK_OR TOK_XOR -%nonassoc TOK_NOT - -%% - -statement: expression - { - global_df->dftree = $1; - } - | /* NULL */ { if (global_df != NULL) global_df->dftree = NULL; } - ; - -expression: '(' expression ')' { $$ = $2; } - | expression TOK_AND expression { $$ = dfilter_mknode_join($1, logical, $2, $3); } - | expression TOK_OR expression { $$ = dfilter_mknode_join($1, logical, $2, $3); } - | expression TOK_XOR expression { $$ = dfilter_mknode_join($1, logical, $2, $3); } - | TOK_NOT expression { $$ = dfilter_mknode_unary(TOK_NOT, $2); } - | relation { $$ = $1; } - | variable_name { $$ = $1; } - | expression error { YYABORT; } - ; - -relation: numeric_variable numeric_relation numeric_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | numeric_variable numeric_relation numeric_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - | floating_variable numeric_relation floating_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | floating_variable numeric_relation floating_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - | ether_variable equality_relation ether_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | ether_variable equality_relation ether_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - | ipxnet_variable equality_relation ipxnet_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | ipxnet_variable equality_relation ipxnet_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - | string_variable equality_relation string_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | string_variable equality_relation string_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - - | ipv4_variable numeric_relation ipv4_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | ipv4_variable numeric_relation ipv4_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - | ipv6_variable equality_relation ipv6_value - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - | ipv6_variable equality_relation ipv6_variable - { - $$ = dfilter_mknode_join($1, relation, $2, $3); - } - - | 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 " - "%s supplied.", - dfilter_get_variable_abbrev($1), - a_len, plurality(a_len, "", "s"), - b_len, plurality(b_len, "", "s"), - plurality(b_len, "was", "were")); - 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); - } - - ; - - -numeric_value: T_VAL_UNQUOTED_STRING - { - gboolean success; - $$ = dfilter_mknode_numeric_value(string_to_guint32($1, &success)); - g_free($1); - if (!success) { - YYERROR; - } - } - ; - -ether_value: T_VAL_BYTE_STRING - { - $$ = dfilter_mknode_ether_value($1); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - ; - -string_value: T_VAL_UNQUOTED_STRING - { - $$ = dfilter_mknode_string_value($1); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - | T_VAL_QUOTED_STRING - { - $$ = dfilter_mknode_string_value($1); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - ; - -ipxnet_value: T_VAL_UNQUOTED_STRING - { - gboolean success; - $$ = dfilter_mknode_ipxnet_value(string_to_guint32($1, &success)); - g_free($1); - if (!success) { - YYERROR; - } - } - ; - -floating_value: T_VAL_UNQUOTED_STRING - { - gboolean success; - $$ = dfilter_mknode_floating_value(string_to_double($1, &success)); - g_free($1); - if (!success) { - YYERROR; - } - } - - | T_VAL_BYTE_STRING - { - /* e.g., 0.0, 0.1, 0.01 ... */ - gboolean success; - $$ = dfilter_mknode_floating_value(string_to_double($1, &success)); - g_free($1); - if (!success) { - YYERROR; - } - } - ; - -ipv4_value: T_VAL_UNQUOTED_STRING - { - $$ = dfilter_mknode_ipv4_value($1, 32); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - - | T_VAL_BYTE_STRING - { - $$ = dfilter_mknode_ipv4_value($1, 32); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - - | T_VAL_UNQUOTED_STRING '/' T_VAL_UNQUOTED_STRING - { - gboolean success; - guint32 nmask_bits; - - nmask_bits = string_to_guint32($3, &success); - if (!success) { - g_free($1); - g_free($3); - YYERROR; - } - - if (nmask_bits > 32) { - dfilter_fail("The number of netmask bits in \"%s/%s\" should " - "be between 0 and 32.", $1, $3); - g_free($1); - g_free($3); - YYERROR; - } - - $$ = dfilter_mknode_ipv4_value($1, nmask_bits); - g_free($1); - g_free($3); - if ($$ == NULL) { - YYERROR; - } - } - - | T_VAL_BYTE_STRING '/' T_VAL_UNQUOTED_STRING - { - gboolean success; - guint32 nmask_bits; - - nmask_bits = string_to_guint32($3, &success); - if (!success) { - g_free($1); - g_free($3); - YYERROR; - } - - if (nmask_bits > 32) { - dfilter_fail("The number of netmask bits in \"%s/%s\" should " - "be between 0 and 32.", $1, $3); - g_free($1); - g_free($3); - YYERROR; - } - $$ = dfilter_mknode_ipv4_value($1, nmask_bits); - g_free($1); - g_free($3); - if ($$ == NULL) { - YYERROR; - } - } - ; - -ipv6_value: T_VAL_UNQUOTED_STRING - { - $$ = dfilter_mknode_ipv6_value($1); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - - | T_VAL_BYTE_STRING - { - $$ = dfilter_mknode_ipv6_value($1); - g_free($1); - if ($$ == NULL) { - YYERROR; - } - } - ; - -bytes_value: T_VAL_BYTE_STRING - { - GByteArray *barray; - - /* the next function appends to list_of_byte_arrays for me */ - barray = byte_str_to_guint8_array($1); - $$ = dfilter_mknode_bytes_value(barray); - g_free($1); - } - - | T_VAL_UNQUOTED_STRING - { - gboolean success; - guint32 val32; - guint8 val8; - GByteArray *barray; - - val32 = string_to_guint32($1, &success); - if (!success) { - g_free($1); - YYERROR; - } - 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); - g_free($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); } - | T_FT_UINT24 { $$ = dfilter_mknode_numeric_variable($1.id); } - | T_FT_UINT32 { $$ = dfilter_mknode_numeric_variable($1.id); } - | T_FT_INT8 { $$ = dfilter_mknode_numeric_variable($1.id); } - | T_FT_INT16 { $$ = dfilter_mknode_numeric_variable($1.id); } - | T_FT_INT24 { $$ = dfilter_mknode_numeric_variable($1.id); } - | T_FT_INT32 { $$ = dfilter_mknode_numeric_variable($1.id); } - ; - -ether_variable: T_FT_ETHER { $$ = dfilter_mknode_ether_variable($1.id); } - ; - -floating_variable: T_FT_DOUBLE { $$ = dfilter_mknode_floating_variable($1.id); } - ; - -ipxnet_variable: T_FT_IPXNET { $$ = dfilter_mknode_ipxnet_variable($1.id); } - ; - -ipv4_variable: T_FT_IPv4 { $$ = dfilter_mknode_ipv4_variable($1.id); } - ; - -ipv6_variable: T_FT_IPv6 { $$ = dfilter_mknode_ipv6_variable($1.id); } - ; - -string_variable: T_FT_STRING { $$ = dfilter_mknode_string_variable($1.id); } - ; - -bytes_variable: T_FT_BYTES T_VAL_BYTE_RANGE - { - $$ = dfilter_mknode_bytes_variable($1.id, $2.offset, $2.length, FALSE); - } - - | T_FT_BYTES - { - $$ = dfilter_mknode_bytes_variable($1.id, 0, 0, TRUE); - } - - ; - -variable_name: any_variable_type - { - GNode *variable; - GNode *value; - if ($1.type == T_FT_BOOLEAN) { - /* Make "variable == TRUE" for BOOLEAN variable */ - variable = dfilter_mknode_numeric_variable($1.id); - value = dfilter_mknode_numeric_value(TRUE); - $$ = dfilter_mknode_join(variable, relation, TOK_EQ, value); - } - else { - $$ = dfilter_mknode_existence($1.id); - } - } - ; - -any_variable_type: T_FT_UINT8 { $$ = $1; } - | T_FT_UINT16 { $$ = $1; } - | T_FT_UINT24 { $$ = $1; } - | T_FT_UINT32 { $$ = $1; } - | T_FT_INT8 { $$ = $1; } - | T_FT_INT16 { $$ = $1; } - | T_FT_INT24 { $$ = $1; } - | T_FT_INT32 { $$ = $1; } - | T_FT_DOUBLE { $$ = $1; } - | T_FT_ETHER { $$ = $1; } - | T_FT_IPv4 { $$ = $1; } - | T_FT_IPv6 { $$ = $1; } - | T_FT_IPXNET { $$ = $1; } - | T_FT_NONE { $$ = $1; } - | T_FT_BYTES { $$ = $1; } - | T_FT_BOOLEAN { $$ = $1; } - | T_FT_STRING { $$ = $1; } - ; - -numeric_relation: TOK_EQ { $$ = TOK_EQ; } - | TOK_NE { $$ = TOK_NE; } - | TOK_GT { $$ = TOK_GT; } - | TOK_GE { $$ = TOK_GE; } - | TOK_LT { $$ = TOK_LT; } - | TOK_LE { $$ = TOK_LE; } - ; - -equality_relation: TOK_EQ { $$ = TOK_EQ; } - | TOK_NE { $$ = TOK_NE; } - ; - -bytes_relation: TOK_EQ { $$ = TOK_EQ; } - | TOK_NE { $$ = TOK_NE; } - | TOK_GT { $$ = TOK_GT; } - | TOK_LT { $$ = TOK_LT; } - ; - -%% - -static GNode* -dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2) -{ - dfilter_node *node_root; - GNode *gnode_root; - - node_root = g_mem_chunk_alloc(global_df->node_memchunk); - node_root->ntype = ntype; - node_root->elem_size = 0; - node_root->fill_array_variable_func = NULL; - node_root->fill_array_value_func = NULL; - node_root->check_relation_func = NULL; - if (ntype == relation) { - node_root->value.relation = operand; - } - else if (ntype == logical) { - node_root->value.logical = operand; - } - else { - g_assert_not_reached(); - } - - gnode_root = g_node_new(node_root); - g_node_append(gnode_root, n1); - g_node_append(gnode_root, n2); - - return gnode_root; -} - -static GNode* -dfilter_mknode_unary(int operand, GNode *n2) -{ - dfilter_node *node_root; - GNode *gnode_root; - - node_root = g_mem_chunk_alloc(global_df->node_memchunk); - node_root->ntype = logical; - node_root->value.logical = operand; - node_root->elem_size = 0; - node_root->fill_array_variable_func = NULL; - node_root->fill_array_value_func = NULL; - node_root->check_relation_func = NULL; - - gnode_root = g_node_new(node_root); - g_node_append(gnode_root, n2); - - return gnode_root; -} - - -static GNode* -dfilter_mknode_numeric_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(guint32); - node->fill_array_variable_func = fill_array_numeric_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_numeric; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_ether_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(guint8) * 6; - node->fill_array_variable_func = fill_array_ether_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_ether; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_floating_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(double); - node->fill_array_variable_func = fill_array_floating_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_floating; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_ipxnet_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(guint8) * 4; - node->fill_array_variable_func = fill_array_numeric_variable; /* cheating ! */ - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_numeric; /* cheating ! */ - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_ipv4_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(ipv4_addr); - node->fill_array_variable_func = fill_array_ipv4_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_ipv4; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_ipv6_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = 16; - node->fill_array_variable_func = fill_array_ipv6_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_ipv6; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_string_variable(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(char*); - node->fill_array_variable_func = fill_array_string_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_string; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_bytes_variable(gint id, gint offset, guint length, gboolean to_the_end) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = variable; - node->elem_size = sizeof(GByteArray*); - node->fill_array_variable_func = fill_array_bytes_variable; - node->fill_array_value_func = NULL; - node->check_relation_func = check_relation_bytes; - node->value.variable = id; - node->offset = offset; - node->length = length; - node->to_the_end = to_the_end; - gnode = g_node_new(node); - - 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_variable_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_variable_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_variable_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_variable_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) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = numeric; - node->elem_size = sizeof(guint32); - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_numeric_value; - node->check_relation_func = check_relation_numeric; - node->value.numeric = val; - gnode = g_node_new(node); - - return gnode; -} - -static GNode* -dfilter_mknode_floating_value(double val) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = floating; - node->elem_size = sizeof(double); - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_floating_value; - node->check_relation_func = check_relation_floating; - node->value.floating = val; - gnode = g_node_new(node); - - return gnode; -} - -/* Returns NULL on bad parse of ETHER value */ -static GNode* -dfilter_mknode_ether_value(gchar *byte_string) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = ether; - node->elem_size = sizeof(guint8) * 6; - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_ether_value; - node->check_relation_func = check_relation_ether; - - if (!ether_str_to_guint8_array(byte_string, &node->value.ether[0])) { - /* Rather than free the mem_chunk allocation, let it - * stay. It will be cleaned up when "dfilter_compile()" - * calls "dfilter_destroy()". */ - dfilter_fail("\"%s\" is not a valid hardware address.", - byte_string); - return NULL; - } - - gnode = g_node_new(node); - return gnode; -} - -static GNode* -dfilter_mknode_ipxnet_value(guint32 ipx_net_val) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = ipxnet; - node->elem_size = sizeof(guint8) * 4; - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_numeric_value; /* cheating ! */ - node->check_relation_func = check_relation_numeric; /* cheating ! */ - node->value.numeric = ipx_net_val; - gnode = g_node_new(node); - - return gnode; -} - -/* Returns NULL on bad parse of IP value */ -static GNode* -dfilter_mknode_ipv4_value(char *host, int nmask_bits) -{ - dfilter_node *node; - GNode *gnode; - guint32 addr; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = numeric; - node->elem_size = sizeof(ipv4_addr); - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_ipv4_value; - node->check_relation_func = check_relation_ipv4; - if (!get_host_ipaddr(host, &addr)) { - /* Rather than free the mem_chunk allocation, let it - * stay. It will be cleaned up when "dfilter_compile()" - * calls "dfilter_destroy()". */ - dfilter_fail("\"%s\" isn't a valid host name or IP address.", - host); - return NULL; - } - ipv4_addr_set_host_order_addr(&node->value.ipv4, addr); - ipv4_addr_set_netmask_bits(&node->value.ipv4, nmask_bits); - - gnode = g_node_new(node); - return gnode; -} - -/* Returns NULL on bad parse of IPv6 value */ -static GNode* -dfilter_mknode_ipv6_value(char *host) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = ipv6; - node->elem_size = 16; - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_ipv6_value; - node->check_relation_func = check_relation_ipv6; - - if (!get_host_ipaddr6(host, (struct e_in6_addr*)&node->value.ipv6[0])) { - /* Rather than free the mem_chunk allocation, let it - * stay. It will be cleaned up when "dfilter_compile()" - * calls "dfilter_destroy()". */ - dfilter_fail("\"%s\" isn't a valid IPv6 address.", - host); - return NULL; - } - - gnode = g_node_new(node); - return gnode; -} - - -static GNode* -dfilter_mknode_string_value(char *s) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = string; - node->elem_size = sizeof(char*); - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_string_value; - node->check_relation_func = check_relation_string; - node->value.string = g_strdup(s); - global_df->list_of_strings = g_slist_append(global_df->list_of_strings, - node->value.string); - gnode = g_node_new(node); - - return gnode; -} - - -static GNode* -dfilter_mknode_bytes_value(GByteArray *barray) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = bytes; - node->elem_size = sizeof(GByteArray*); - node->fill_array_variable_func = NULL; - node->fill_array_value_func = fill_array_bytes_value; - node->check_relation_func = check_relation_bytes; - node->value.bytes = barray; - node->offset = G_MAXINT; - node->length = barray->len; - gnode = g_node_new(node); - - 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_guint32(char *s, gboolean *success) -{ - char *endptr; - guint32 val; - - val = strtoul(s, &endptr, 0); - *success = TRUE; - if (endptr == s || *endptr != '\0') { - /* This isn't a valid number. */ - dfilter_fail("\"%s\" is not a valid number.", s); - *success = FALSE; - } - if (errno == ERANGE) { - *success = FALSE; - if (val == ULONG_MAX) { - dfilter_fail("\"%s\" causes an integer overflow.", s); - } - else { - dfilter_fail("\"%s\" is not an integer.", s); - } - } - - return (guint32)val; -} - -static double -string_to_double(char *s, gboolean *success) -{ - char *endptr = NULL; - double retval; - - retval = strtod(s, &endptr); - *success = TRUE; - - if (endptr == s) { - dfilter_fail("\"%s\" is not a valid floating-point number.", s); - *success = FALSE; - } - - if (errno == ERANGE) { - *success = FALSE; - if (retval == 0) { - dfilter_fail("\"%s\" causes a floating-point underflow.", s); - } - else if (retval == HUGE_VAL) { - dfilter_fail("\"%s\" causes a floating-point overflow.", s); - } - else { - dfilter_fail("\"%s\" is not a valid floating-point.", s); - } - } - return retval; -} - -static GNode* -dfilter_mknode_existence(gint id) -{ - dfilter_node *node; - GNode *gnode; - - node = g_mem_chunk_alloc(global_df->node_memchunk); - node->ntype = existence; - node->elem_size = sizeof(guint32); - node->fill_array_variable_func = NULL; - node->fill_array_value_func = NULL; - node->check_relation_func = NULL; - node->value.variable = id; - gnode = g_node_new(node); - - return gnode; -} - - -/* converts a string representing an ether HW address - * to a guint8 array. - * - * Returns 0 on failure, 1 on success. - */ -static int -ether_str_to_guint8_array(const char *s, guint8 *mac) -{ - char ether_str[18]; /* 2+1+2+1+2+1+2+1+2+1+2 + 1 */ - char *p, *str; - int i = 0; - - if (strlen(s) > 17) { - return 0; - } - strcpy(ether_str, s); /* local copy of string */ - str = ether_str; - while ((p = strtok(str, "-:."))) { - /* catch short strings with too many hex bytes: 0.0.0.0.0.0.0 */ - if (i > 5) { - return 0; - } - mac[i] = (guint8) strtoul(p, NULL, 16); - i++; - /* subsequent calls to strtok() require NULL as arg 1 */ - str = NULL; - } - if (i != 6) - return 0; /* failed to read 6 hex pairs */ - else - return 1; /* read exactly 6 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 %s supplied.", - dfilter_get_variable_abbrev(gnode), - reg_len, plurality(reg_len, "", "s"), - a_len, plurality(a_len, "", "s"), - plurality(a_len, "was", "were")); - return 0; - } - } - return 1; -} diff --git a/epan/dfilter-int.h b/epan/dfilter-int.h deleted file mode 100644 index c50462440d..0000000000 --- a/epan/dfilter-int.h +++ /dev/null @@ -1,148 +0,0 @@ -/* dfilter-int.h - * Definitions for routines common to multiple modules in the display - * filter code, but not used outside that code. - * - * $Id: dfilter-int.h,v 1.2 2000/12/22 12:05:36 gram Exp $ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DFILTER_INT_H__ -#define __DFILTER_INT_H__ - -#ifndef __IPV4_H__ -#include "ipv4.h" -#endif - -/* in dfilter-scanner.l */ -GByteArray *byte_str_to_guint8_array(const char *s); -void dfilter_scanner_text(char*); -void dfilter_scanner_cleanup(void); - -/* in dfilter-grammar.y */ -extern dfilter *global_df; - -/* Here we provide interfaces to make our scanner act and look like lex */ -int dfilter_lex(void); -void dfilter_error(char *s); - -/* Report an error during compilation of a filter; this is called by code - * other than parser code, so all it does is record that an error occurred, - * so that even if the filter is nominally syntactically valid, we still - * fail. - */ -#if __GNUC__ == 2 -void dfilter_fail(char *fmt, ...) - __attribute__((format (printf, 1, 2))); -#else -void dfilter_fail(char *fmt, ...); -#endif - -/* functions that dfilter-grammar.y needs during parsing*/ -gboolean check_relation_numeric(gint operand, GArray *a, GArray *b); -gboolean check_relation_floating(gint operand, GArray *a, GArray *b); -gboolean check_relation_ether(gint operand, GArray *a, GArray *b); -gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b); -gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b); -gboolean check_relation_bytes(gint operand, GArray *a, GArray *b); -gboolean check_relation_string(gint operand, GArray *a, GArray *b); - -void fill_array_numeric_variable(field_info*, GArray*, const guint8*); -void fill_array_floating_variable(field_info*, GArray*, const guint8*); -void fill_array_ether_variable(field_info*, GArray*, const guint8*); -void fill_array_ipv4_variable(field_info*, GArray*, const guint8*); -void fill_array_ipv6_variable(field_info*, GArray*, const guint8*); -void fill_array_bytes_variable(field_info*, GArray*, const guint8*); -void fill_array_string_variable(field_info*, GArray*, const guint8*); - -gboolean fill_array_numeric_value(GNode *gnode, gpointer data); -gboolean fill_array_floating_value(GNode *gnode, gpointer data); -gboolean fill_array_ether_value(GNode *gnode, gpointer data); -gboolean fill_array_ipv4_value(GNode *gnode, gpointer data); -gboolean fill_array_ipv6_value(GNode *gnode, gpointer data); -gboolean fill_array_bytes_value(GNode *gnode, gpointer data); -gboolean fill_array_string_value(GNode *gnode, gpointer data); - -#ifdef WIN32 -#define boolean truth_value -#endif - -enum node_type { - relation, /* eq, ne, gt, ge, lt, le */ - logical, /* and, or, not, xor */ - variable, /* protocol or header field id */ - existence, /* existence of a variable (protocol or hf) */ - alternation, /* &, | */ - boolean, /* true, false */ - numeric, /* uint8, uint16, or uint32 value */ - floating, /* double */ - abs_time, - string, - ether, - bytes, - ipv4, - ipv6, - ipxnet -}; - -typedef gboolean(*CheckRelationFunc) (gint operand, GArray *a, GArray *b); -typedef void(*FillArrayFunc) (field_info*, GArray*, const guint8*); - -/* This struct is the parse tree node created by this grammary and used - * directly in the display filter routines to filter packets. - */ -typedef struct dfilter_node { - enum node_type ntype; /* from dfilter-grammar.h */ - int elem_size; /* computed at dfilter parse time rather than - when finding elements for each packet. Saves time - in get_values_from_ptree() */ - CheckRelationFunc check_relation_func; - FillArrayFunc fill_array_variable_func; - GNodeTraverseFunc fill_array_value_func; - - /* copied from proto.h */ - union { - gint relation; /* if type == relation (eq, ne, gt, ge, lt, le) */ - gint logical; /* if type == logical (and, or, not, xor) */ - gint variable; /* if type == variable (protocol or header field abbrev) */ - gint alternation; /* if type == alternation (& or |) */ - - guint32 numeric; - double floating; - struct timeval abs_time; /* the whole struct, not a pointer */ - gchar *string; - guint8 ether[6]; - ipv4_addr ipv4; /* the whole struct, not a pointer */ - guint8 ipv6[16]; - GByteArray *bytes; - } value; - - /* used for byte-ranges */ - gint offset; - guint length; - - /* used to indicate range should go to end of sequence */ - gboolean to_the_end; -} dfilter_node; - -/* lookup an abbreviation in our token hash, returing the ID # */ -int dfilter_lookup_token(char *abbrev); - -#endif /* ! __DFILTER_INT_H__ */ diff --git a/epan/dfilter-scanner.l b/epan/dfilter-scanner.l deleted file mode 100644 index b78ddcb2c4..0000000000 --- a/epan/dfilter-scanner.l +++ /dev/null @@ -1,366 +0,0 @@ -%{ - -/* dfilter-scanner.l - * Scanner for display filters - * - * $Id: dfilter-scanner.l,v 1.1 2000/09/27 04:54:48 gram Exp $ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_IO_H -#include <io.h> /* for isatty() on win32 */ -#endif - -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -#ifndef _STDIO_H -#include <stdio.h> -#endif - -#ifndef _STRING_H -#include <string.h> -#endif - -#ifndef __G_LIB_H__ -#include <glib.h> -#endif - -#ifndef __PROTO_H__ -#include "proto.h" -#endif - -#ifndef __DFILTER_H__ -#include "dfilter.h" -#endif - -#include "dfilter-int.h" - -#include "dfilter-grammar.h" - -/* Flex has a few routines which help us get the scanner to read - * from a string rather than from a file. POSIX lex only provides - * for reading from a file; any method of reading from a string - * is inherently non-portable. Besides reading from a string, - * we have to worry about resetting the scanner after a bad - * parse; this too is non-portable. Combine the reset with - * a string input, and you have major non-portability. I'll provide - * the routines for flex here. If you really want to modify the - * scanner and use a non-flex lex implementation, you may - * add more ifdef's below. - */ -#ifdef FLEX_SCANNER - -/* Flex has built-in support for using a string as an input source - * instead of using a file. Nice! - */ -YY_BUFFER_STATE string_input_buffer; - -/* We don't need yyunput, so use this macro to get it out of the - * generated C file, avoiding a compiler warning about its lack of use */ -#define YY_NO_UNPUT 1 - -#else - -static char *in_buffer; -#undef getc -#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++) - -#endif - - -%} - -whitespace [\t ] -hex [A-Fa-f0-9]{1,2} -hexsep [-:\.] -minus [-] -plus [+] - -%% - -[\t\n ]+ /* ignore whitespace */ - - -and|\&\& { dfilter_lval.operand = TOK_AND; return TOK_AND; } -or|\|\| { dfilter_lval.operand = TOK_OR; return TOK_OR; } -not|\! { dfilter_lval.operand = TOK_NOT; return TOK_NOT; } -xor|\^\^ { dfilter_lval.operand = TOK_XOR; return TOK_XOR; } -eq|\=\= { dfilter_lval.operand = TOK_EQ; return TOK_EQ; } -ne|\!\= { dfilter_lval.operand = TOK_NE; return TOK_NE; } -gt|\> { dfilter_lval.operand = TOK_GT; return TOK_GT; } -ge|\>\= { dfilter_lval.operand = TOK_GE; return TOK_GE; } -lt|\< { dfilter_lval.operand = TOK_LT; return TOK_LT; } -le|\<\= { dfilter_lval.operand = TOK_LE; return TOK_LE; } - -\[{whitespace}*-?[0-9]+{whitespace}*:{whitespace}*[0-9]+{whitespace}*\] { /* range [ x : y ] */ - - 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; - } - - /* Get the Length from the string */ - if ((p = strtok(NULL, "]"))) { - dfilter_lval.byte_range.length = strtoul(p, NULL, 10); - } - else { - g_free(byterange_string); - return 0; - } - g_free(byterange_string); - 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); - return T_VAL_BYTE_STRING; -} - - -0[xX][A-Fa-f0-9]+ { /* hex values */ - dfilter_lval.string = g_strdup(yytext); - return T_VAL_UNQUOTED_STRING; -} - -[A-Za-z0-9\:][A-Za-z0-9\.\_\-\:]+ { - /* looks like a protocol, field name, or hostname */ - - int retval = 0; - enum ftenum ftype; - dfilter_lval.variable.id = dfilter_lookup_token(yytext); - if (dfilter_lval.variable.id < 0) { - dfilter_lval.string = g_strdup(yytext); - return T_VAL_UNQUOTED_STRING; - } - - ftype = proto_registrar_get_ftype(dfilter_lval.variable.id); - switch (ftype) { - case FT_NONE: - retval = T_FT_NONE; - break; - case FT_BOOLEAN: - retval = T_FT_BOOLEAN; - break; - case FT_UINT8: - retval = T_FT_UINT8; - break; - case FT_UINT16: - retval = T_FT_UINT16; - break; - case FT_UINT24: - retval = T_FT_UINT24; - break; - case FT_UINT32: - retval = T_FT_UINT32; - break; - case FT_INT8: - retval = T_FT_INT8; - break; - case FT_INT16: - retval = T_FT_INT16; - break; - case FT_INT24: - retval = T_FT_INT24; - break; - case FT_INT32: - retval = T_FT_INT32; - break; - case FT_DOUBLE: - retval = T_FT_DOUBLE; - break; - case FT_ABSOLUTE_TIME: - dfilter_fail("Sorry, you can't filter on field \"%s\", as we don't yet support filtering on time-of-day values.", - yytext); - retval = 0; - break; - case FT_RELATIVE_TIME: - dfilter_fail("Sorry, you can't filter on field \"%s\", as we don't yet support filtering on time-delta values.", - yytext); - retval = 0; - break; - case FT_STRING: - case FT_STRINGZ: - case FT_UINT_STRING: - retval = T_FT_STRING; - break; - case FT_ETHER: - retval = T_FT_ETHER; - break; - case FT_BYTES: - retval = T_FT_BYTES; - break; - case FT_IPv4: - retval = T_FT_IPv4; - break; - case FT_IPv6: - retval = T_FT_IPv6; - break; - case FT_IPXNET: - retval = T_FT_IPXNET; - break; - default: - printf("ftype for %s is %d\n", yytext, ftype); - g_assert_not_reached(); - retval = 0; - break; - } - dfilter_lval.variable.type = retval; - return retval; -} - -({plus}|{minus})?[0-9]+ { /* decimal and octal integers */ - dfilter_lval.string = g_strdup(yytext); - return T_VAL_UNQUOTED_STRING; -} - -({plus}|{minus})?([0-9]+|[0-9]+\.[0-9]+|\.[0-9]+)([eE]({plus}|{minus})?[0-9]+)? { - /* I'm trying to capture all floating points here, and - * am using the strtod manpage as the description of - * valid formats */ - dfilter_lval.string = g_strdup(yytext); - return T_VAL_UNQUOTED_STRING; -} - -[0-9\:\.]+ { - dfilter_lval.string = g_strdup(yytext); - return T_VAL_UNQUOTED_STRING; -} - -\"[^"]+\" { - int length; - - /* Don't copy the first quote. */ - dfilter_lval.string = g_strdup(&yytext[1]); - - /* Chop of the final quote mark. */ - length = strlen(dfilter_lval.string); - g_assert(length > 0); - dfilter_lval.string[length - 1] = 0; - - return T_VAL_QUOTED_STRING; -} - -. return yytext[0]; -%% - -/* Resets scanner and assigns the char* argument - * as the text to scan - */ -void -dfilter_scanner_text(char *text) -{ -#ifdef FLEX_SCANNER - string_input_buffer = yy_scan_string(text); -#else - in_buffer = text; -#endif -} - -void -dfilter_scanner_cleanup(void) -{ -#ifdef FLEX_SCANNER - yy_delete_buffer(string_input_buffer); -#else - /* There is no standard way to reset a lex scanner. - * This is necessary after a failed parse on a syntactically - * incorrect display filter. You have to reset the scanner - * so that yy_lex() doesn't start scanning from the middle - * of the previous input string. - */ -#endif -} - -/* Flex has an option '%option noyywrap' so that I don't have to - * provide this yywrap function, but in order to maintain portability, - * I'll just use this yywrap() function. - */ -int -yywrap() -{ - return 1; /* stop at EOF, instead of looking for next file */ -} - -/* converts a string representing a byte array - * to a guint8 array. - * - * Returns a non-null GByteArray pointer on success, NULL on failure. - */ -GByteArray* -byte_str_to_guint8_array(const char *s) -{ - GByteArray *barray; - guint8 val; - char *byte_str; - char *p, *str; - - barray = g_byte_array_new(); - /* XXX - don't use global_df, but pass in pointer to GSList* */ - global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray); - - /* Local copy of string, since strtok will munge it */ - byte_str = g_strdup(s); - str = byte_str; - while ((p = strtok(str, "-:."))) { - val = (guint8) strtoul(p, NULL, 16); - g_byte_array_append(barray, &val, 1); - - /* subsequent calls to strtok() require NULL as arg 1 */ - str = NULL; - } - - g_free(byte_str); - return barray; -} diff --git a/epan/dfilter.c b/epan/dfilter.c deleted file mode 100644 index 378c109d9b..0000000000 --- a/epan/dfilter.c +++ /dev/null @@ -1,1086 +0,0 @@ -/* dfilter.c - * Routines for display filters - * - * $Id: dfilter.c,v 1.3 2000/12/22 12:05:36 gram Exp $ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -#include <stdio.h> -#include <string.h> -#include <glib.h> - -#ifdef NEED_SNPRINTF_H -# include "snprintf.h" -#endif - -#include "proto.h" -#include "dfilter.h" -#include "dfilter-int.h" -#include "dfilter-grammar.h" - -int dfilter_parse(void); /* yacc entry-point */ - -#define DFILTER_LEX_ABBREV_OFFSET 2000 - -/* Balanced tree of abbreviations and IDs */ -GTree *dfilter_tokens = NULL; - -/* Comparision function for tree insertion. A wrapper around strcmp() */ -static int g_strcmp(gconstpointer a, gconstpointer b); - -/* Silly global variables used to pass parameter to check_relation_bytes() */ -int bytes_offset = 0; -int bytes_length = 0; -gboolean bytes_to_the_end = FALSE; - -YYSTYPE yylval; - -/* Global error message space for dfilter_compile errors */ -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); -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); - -/* this is not so pretty. I need my own g_array "function" (macro) to - * retreive the pointer to the data stored in an array cell. I need this - * for type ether.. GArray makes it easy for me to store 6 bytes inside an array - * cell, but hard to retrieve it. - */ -#define g_array_index_ptr(a,s,i) (((guint8*) (a)->data) + (i*s)) - -extern int hf_text_only; /* in proto.c */ - -void -dfilter_init(void) -{ - int i, num_symbols, symbol; - char *s; - - dfilter_tokens = g_tree_new(g_strcmp); - - /* Add the header field and protocol abbrevs to the symbol table */ - num_symbols = proto_registrar_n(); - - for (i=0; i < num_symbols; i++) { - if (i == hf_text_only) { - continue; - } - s = proto_registrar_get_abbrev(i); - g_assert(s); /* Not Null */ - g_assert(s[0] != 0); /* Not empty string */ - /* Make sure we don't have duplicate abbreviation */ - if (g_tree_lookup(dfilter_tokens, s)) { - g_message("Already have abbreviation \"%s\"", s); - g_assert(0); - } - symbol = DFILTER_LEX_ABBREV_OFFSET + i; - g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol)); - } -} - -void -dfilter_cleanup(void) -{ - if (dfilter_tokens) - g_tree_destroy(dfilter_tokens); -} - -/* Compiles the textual representation of the display filter into a tree - * of operations to perform. Can be called multiple times, compiling a new - * display filter each time, without having to clear any memory used, since - * dfilter_compile will take care of that automatically. - * - * Returns 0 on success, non-zero on failure. - * - * On success, sets the "dfilter *" pointed to by its second argument - * either to a null pointer (if the filter is a null filter, as - * generated by an all-blank string) or to a pointer to a newly-allocated - * dfilter structure (if the filter isn't null). - * - * On failure, "dfilter_error_msg" points to an appropriate error message. - * This error message is a global string, so another invocation of - * dfilter_compile will clear it. If the caller needs is stored, he - * needs to g_strdup it himself. - */ -int -dfilter_compile(gchar *dfilter_text, dfilter **dfp) -{ - dfilter *df; - int retval; - - g_assert(dfilter_text != NULL); - - df = dfilter_new(); - - /* tell the scanner to use the filter string as input */ - dfilter_scanner_text(dfilter_text); - - /* Assign global variable so dfilter_parse knows which dfilter we're - * talking about. Reset the global error message. - */ - global_df = df; - dfilter_error_msg = NULL; - - /* The magic happens right here. */ - retval = dfilter_parse(); - - /* clean up lex */ - dfilter_scanner_cleanup(); - - /* Errors not found by the parser may not cause the parse to - * fail; if "dfilter_error_msg" is set, it means somebody - * else called "dfilter_fail()", e.g. the lexical analyzer, - * so treat that as a parse error. */ - if (dfilter_error_msg != NULL) - retval = 1; - - if (retval != 0) { - if (dfilter_error_msg == NULL) { - snprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf), - "Unable to parse filter string \"%s\".", - dfilter_text); - dfilter_error_msg = &dfilter_error_msg_buf[0]; - } - } - - /* Set global_df to NULL just to be tidy. */ - global_df = NULL; - - if (retval == 0) { - /* Success. Check if the filter is empty; if so, discard - * it and set "*dfp" to NULL, otherwise set "*dfp" to - * point to the filter. */ - if (df->dftree == NULL) { - /* The filter is empty. */ - dfilter_destroy(df); - df = NULL; - } - *dfp = df; - } else { - /* Failure. Destroy the filter. */ - dfilter_destroy(df); - df = NULL; - } - return retval; -} - -/* Allocates new dfilter, initializes values, and returns pointer to dfilter */ -dfilter* -dfilter_new(void) -{ - dfilter *df; - - df = g_malloc(sizeof(dfilter)); - - df->dftree = NULL; - df->node_memchunk = g_mem_chunk_new("df->node_memchunk", - sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY); - df->list_of_byte_arrays = NULL; - df->list_of_strings = NULL; - - return df; -} - -static void -free_string(gpointer data, gpointer user_data) -{ - char *string = data; - if (string) - g_free(string); -} - -/* Frees all memory used by dfilter, and frees dfilter itself */ -void -dfilter_destroy(dfilter *df) -{ - if (!df) - return; - - if (df->dftree != NULL) - g_node_destroy(df->dftree); - - /* clear the memory that the tree was using for nodes */ - if (df->node_memchunk) - g_mem_chunk_reset(df->node_memchunk); - - /* clear the memory that the tree was using for byte arrays */ - if (df->list_of_byte_arrays) { - g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL); - g_slist_free(df->list_of_byte_arrays); - } - - /* clear the allocated strings */ - if (df->list_of_strings) { - g_slist_foreach(df->list_of_strings, free_string, NULL); - g_slist_free(df->list_of_strings); - } - - df->dftree = NULL; - df->list_of_byte_arrays = NULL; - df->list_of_strings = NULL; - - /* Git rid of memchunk */ - if (df->node_memchunk) - g_mem_chunk_destroy(df->node_memchunk); - - g_free(df); -} - - -static void -clear_byte_array(gpointer data, gpointer user_data) -{ - GByteArray *barray = data; - if (barray) - g_byte_array_free(barray, TRUE); -} - -/* Called when the yacc grammar finds a parsing error */ -void -dfilter_error(char *s) -{ -} - -/* Called when an error other than a parsing error occurs. */ -void -dfilter_fail(char *format, ...) -{ - va_list ap; - - /* If we've already reported one error, don't overwrite it with this - * one. */ - if (dfilter_error_msg != NULL) - return; - - va_start(ap, format); - vsnprintf(dfilter_error_msg_buf, sizeof dfilter_error_msg_buf, format, ap); - dfilter_error_msg = dfilter_error_msg_buf; - va_end(ap); -} - -/* lookup an abbreviation in our token tree, returing the ID # - * If the abbreviation doesn't exit, returns -1 */ -int dfilter_lookup_token(char *abbrev) -{ - int value; - - g_assert(abbrev != NULL); - value = GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev)); - - if (value < DFILTER_LEX_ABBREV_OFFSET) { - return -1; - } - return value - DFILTER_LEX_ABBREV_OFFSET; -} - -static int -g_strcmp(gconstpointer a, gconstpointer b) -{ - return strcmp((const char*)a, (const char*)b); -} - - -gboolean -dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd, guint pd_len) -{ - gboolean retval; - if (dfcode == NULL) - return FALSE; - retval = dfilter_apply_node(dfcode->dftree, ptree, pd); - return retval; -} - -static gboolean -dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd) -{ - GNode *gnode_a, *gnode_b; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - /* We'll get 2 NULLs if we don't have children */ - gnode_a = g_node_nth_child(gnode, 0); - gnode_b = g_node_nth_child(gnode, 1); - - switch(dnode->ntype) { - case variable: - /* We'll never see this case because if the parser finds the name of - * a variable, it will cause it to be an 'existence' operation. - */ - g_assert_not_reached(); - - case logical: - g_assert(gnode_a); - 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); - - case alternation: - g_assert_not_reached(); - /* not coded yet */ - - case numeric: - case floating: - case ipv4: - case ipv6: - case boolean: - case ether: - case string: - case abs_time: - case bytes: - case ipxnet: - /* the only time we'll see these at this point is if the display filter - * is really wacky. (like simply "192.168.1.1"). The parser as it stands - * now let these by. Just return TRUE */ - g_assert(!gnode_a && !gnode_b); - return TRUE; - - case existence: /* checking the existence of a protocol or hf*/ - g_assert(!gnode_a && !gnode_b); - return check_existence_in_ptree(dnode, ptree); - } - - g_assert_not_reached(); - return FALSE; -} - -static gboolean -check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd) -{ - 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)); - case TOK_OR: - g_assert(b); - return (val_a || dfilter_apply_node(b, ptree, pd)); - case TOK_XOR: - g_assert(b); - val_b = dfilter_apply_node(b, ptree, pd); - return ( ( val_a || val_b ) && ! ( val_a && val_b ) ); - case TOK_NOT: - return (!val_a); - default: - g_assert_not_reached(); - } - g_assert_not_reached(); - return FALSE; -} - - -static void -free_array_of_byte_arrays(GArray *array) -{ - int i, len; - GByteArray *ba_ptr; - - len = array->len; - - for (i = 0; i < len ; i++) { - ba_ptr = g_array_index(array, GByteArray*, i); - g_byte_array_free(ba_ptr, TRUE); - } -} - -/* this is inefficient. I get arrays for both a and b that represent all the values present. That is, - * if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol - * tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare - * them all. It makes my coding easier in the beginning, but I should change this to make it run - * faster. - */ -static gboolean -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); - GArray *vals_a, *vals_b; - gboolean retval; - - - if (node_a->ntype == variable) - 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); - else - vals_b = get_values_from_dfilter(node_b, b); - - retval = node_a->check_relation_func(operand, vals_a, vals_b); - - /* Free GByteArrays alloated by fill_array_bytes_variable() */ - if (node_a->fill_array_variable_func == fill_array_bytes_variable) { - free_array_of_byte_arrays(vals_a); - } - - if (node_b->fill_array_variable_func == fill_array_bytes_variable) { - free_array_of_byte_arrays(vals_b); - } - - g_array_free(vals_a, FALSE); - g_array_free(vals_b, FALSE); - - return retval; -} - - -static gboolean -check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree) -{ - int target; - - target = dnode->value.variable; - return proto_check_for_protocol_or_field(ptree, target); -} - -static GArray* -get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd) -{ - GArray *result_array; - GPtrArray *finfo_array; - int i, len; - field_info *finfo; - - /* Prepare the array for results */ - g_assert(dnode->elem_size > 0); - result_array = g_array_new(FALSE, FALSE, dnode->elem_size); - - /* Set bytes_offset, bytes_length, and bytes_to_the_end - * for this dnode - */ - - bytes_offset = dnode->offset; - bytes_length = dnode->length; - bytes_to_the_end = dnode->to_the_end; - - /* Cull the finfos from the proto_tree */ - finfo_array = proto_get_finfo_ptr_array(ptree, dnode->value.variable); - if (!finfo_array) { - return result_array; - } - - len = g_ptr_array_len(finfo_array); - - for (i = 0; i < len; i++) { - finfo = g_ptr_array_index(finfo_array, i); - dnode->fill_array_variable_func(finfo, result_array, pd); - } - - g_ptr_array_free(finfo_array, FALSE); - - return result_array; -} - - -void -fill_array_numeric_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - g_array_append_val(array, finfo->value.numeric); -} - -void -fill_array_floating_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - g_array_append_val(array, finfo->value.floating); -} - -void -fill_array_ether_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - /* hmmm, yes, I *can* copy a pointer instead of memcpy() */ - g_array_append_val(array, finfo->value.ether); -} - -void -fill_array_ipv4_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - /* hmmm, yes, I *can* copy a pointer instead of memcpy() */ - g_array_append_val(array, finfo->value.ipv4); -} - -void -fill_array_ipv6_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - /* hmmm, yes, I *can* copy a pointer instead of memcpy() */ - g_array_append_val(array, finfo->value.ipv6); -} - -void -fill_array_string_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - g_array_append_val(array, finfo->value.string); -} - -void -fill_array_bytes_variable(field_info *finfo, GArray *array, const guint8 *pd) -{ - GByteArray *barray; - guint read_start, pkt_end, read_len; - - if (bytes_offset < 0) { - /* Handle negative byte offsets */ - bytes_offset = finfo->length + bytes_offset; - if (bytes_offset < 0) { - return; - } - } - - /* Check to make sure offset exists for this field */ - if (bytes_offset >= finfo->length) { - return; - } - - pkt_end = finfo->start + finfo->length; - read_start = finfo->start + bytes_offset; - if(bytes_to_the_end){ - read_len = pkt_end - read_start;; - } - else { - read_len = bytes_length; - } - /* Check to make sure entire length requested is inside field */ - if (pkt_end < read_start + read_len) { - return; - } - - barray = g_byte_array_new(); - g_byte_array_append(barray, pd + read_start, read_len); - g_array_append_val(array, barray); -} - -static GArray* -get_values_from_dfilter(dfilter_node *dnode, GNode *gnode) -{ - GArray *array; - - g_assert(dnode->elem_size > 0); - array = g_array_new(FALSE, FALSE, dnode->elem_size); - - g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, - dnode->fill_array_value_func, array); - return array; -} - -gboolean fill_array_numeric_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - g_array_append_val(array, dnode->value.numeric); - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean fill_array_floating_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - g_array_append_val(array, dnode->value.floating); - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean fill_array_ether_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - g_array_append_val(array, dnode->value.ether); - - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean fill_array_ipv4_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - g_array_append_val(array, dnode->value.ipv4); - - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean fill_array_ipv6_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - g_array_append_val(array, dnode->value.ipv6); - - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean fill_array_bytes_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - GByteArray *barray = dnode->value.bytes; - - g_array_append_val(array, barray); - - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean fill_array_string_value(GNode *gnode, gpointer data) -{ - GArray *array = (GArray*)data; - dfilter_node *dnode = (dfilter_node*) (gnode->data); - - g_array_append_val(array, dnode->value.string); - - return FALSE; /* FALSE = do not end traversal of GNode tree */ -} - -gboolean check_relation_numeric(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - guint32 val_a; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, guint32, i); - for (j = 0; j < len_b; j++) { - if (val_a == g_array_index(b, guint32, j)) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, guint32, i); - for (j = 0; j < len_b; j++) { - if (val_a != g_array_index(b, guint32, j)) - return TRUE; - } - } - return FALSE; - - case TOK_GT: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, guint32, i); - for (j = 0; j < len_b; j++) { - if (val_a > g_array_index(b, guint32, j)) - return TRUE; - } - } - return FALSE; - - case TOK_GE: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, guint32, i); - for (j = 0; j < len_b; j++) { - if (val_a >= g_array_index(b, guint32, j)) - return TRUE; - } - } - return FALSE; - - case TOK_LT: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, guint32, i); - for (j = 0; j < len_b; j++) { - if (val_a < g_array_index(b, guint32, j)) - return TRUE; - } - } - return FALSE; - - case TOK_LE: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, guint32, i); - for (j = 0; j < len_b; j++) { - if (val_a <= g_array_index(b, guint32, j)) - return TRUE; - } - } - return FALSE; - - default: - g_assert_not_reached(); - } - - g_assert_not_reached(); - return FALSE; -} - -gboolean check_relation_floating(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - double val_a; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, double, i); - for (j = 0; j < len_b; j++) { - if (val_a == g_array_index(b, double, j)) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, double, i); - for (j = 0; j < len_b; j++) { - if (val_a != g_array_index(b, double, j)) - return TRUE; - } - } - return FALSE; - - case TOK_GT: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, double, i); - for (j = 0; j < len_b; j++) { - if (val_a > g_array_index(b, double, j)) - return TRUE; - } - } - return FALSE; - - case TOK_GE: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, double, i); - for (j = 0; j < len_b; j++) { - if (val_a >= g_array_index(b, double, j)) - return TRUE; - } - } - return FALSE; - - case TOK_LT: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, double, i); - for (j = 0; j < len_b; j++) { - if (val_a < g_array_index(b, double, j)) - return TRUE; - } - } - return FALSE; - - case TOK_LE: - for(i = 0; i < len_a; i++) { - val_a = g_array_index(a, double, i); - for (j = 0; j < len_b; j++) { - if (val_a <= g_array_index(b, double, j)) - return TRUE; - } - } - return FALSE; - - default: - g_assert_not_reached(); - } - - g_assert_not_reached(); - return FALSE; -} - -gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - ipv4_addr *ptr_a, *ptr_b; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i); - for (j = 0; j < len_b; j++) { - ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j); - if (ipv4_addr_eq(ptr_a, ptr_b)) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i); - for (j = 0; j < len_b; j++) { - ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j); - if (ipv4_addr_ne(ptr_a, ptr_b)) - return TRUE; - } - } - return FALSE; - - case TOK_GT: - for(i = 0; i < len_a; i++) { - ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i); - for (j = 0; j < len_b; j++) { - ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j); - if (ipv4_addr_gt(ptr_a, ptr_b)) - return TRUE; - } - } - return FALSE; - - case TOK_GE: - for(i = 0; i < len_a; i++) { - ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i); - for (j = 0; j < len_b; j++) { - ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j); - if (ipv4_addr_ge(ptr_a, ptr_b)) - return TRUE; - } - } - return FALSE; - - case TOK_LT: - for(i = 0; i < len_a; i++) { - ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i); - for (j = 0; j < len_b; j++) { - ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j); - if (ipv4_addr_lt(ptr_a, ptr_b)) - return TRUE; - } - } - return FALSE; - - case TOK_LE: - for(i = 0; i < len_a; i++) { - ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i); - for (j = 0; j < len_b; j++) { - ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j); - if (ipv4_addr_le(ptr_a, ptr_b)) - return TRUE; - } - } - return FALSE; - } - - g_assert_not_reached(); - return FALSE; -} - -gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - guint8 *ptr_a, *ptr_b; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index_ptr(a, 16, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index_ptr(b, 16, j); - if (memcmp(ptr_a, ptr_b, 16) == 0) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index_ptr(a, 16, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index_ptr(b, 16, j); - if (memcmp(ptr_a, ptr_b, 16) != 0) - return TRUE; - } - } - return FALSE; - } - - g_assert_not_reached(); - return FALSE; -} - -gboolean check_relation_ether(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - guint8 *ptr_a, *ptr_b; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index_ptr(a, 6, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index_ptr(b, 6, j); - if (memcmp(ptr_a, ptr_b, 6) == 0) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index_ptr(a, 6, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index_ptr(b, 6, j); - if (memcmp(ptr_a, ptr_b, 6) != 0) - return TRUE; - } - } - return FALSE; - } - - g_assert_not_reached(); - return FALSE; -} - -gboolean check_relation_bytes(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - GByteArray *ptr_a,*ptr_b; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index(a, GByteArray*, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index(b, GByteArray*, j); - if(ptr_a->len != ptr_b->len) - return FALSE; if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) == 0) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index(a, GByteArray*, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index(b, GByteArray*, j); - if(ptr_a->len != ptr_b->len) - return TRUE; - if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) != 0) - return TRUE; - } - } - return FALSE; - - case TOK_GT: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index(a, GByteArray*, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index(b, GByteArray*, j); - if(ptr_a->len > ptr_b->len) - return TRUE; - if(ptr_a->len < ptr_b->len) - return FALSE; - if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) > 0) - return TRUE; - } - } - return FALSE; - - case TOK_LT: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index(a, GByteArray*, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index(b, GByteArray*, j); - if(ptr_a->len < ptr_b->len) - return TRUE; - if(ptr_a->len > ptr_b->len) - return FALSE; - if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) < 0) - return TRUE; - } - } - return FALSE; - } - - g_assert_not_reached(); - return FALSE; -} - -gboolean check_relation_string(gint operand, GArray *a, GArray *b) -{ - int i, j, len_a, len_b; - char *ptr_a, *ptr_b; - - len_a = a->len; - len_b = b->len; - - - switch(operand) { - case TOK_EQ: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index(a, char*, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index(b, char*, j); - if (strcmp(ptr_a, ptr_b) == 0) - return TRUE; - } - } - return FALSE; - - case TOK_NE: - for(i = 0; i < len_a; i++) { - ptr_a = g_array_index(a, char*, i); - for (j = 0; j < len_b; j++) { - ptr_b = g_array_index(b, char*, j); - if (strcmp(ptr_a, ptr_b) != 0) - return TRUE; - } - } - return FALSE; - } - - g_assert_not_reached(); - return FALSE; -} - diff --git a/epan/dfilter.h b/epan/dfilter.h deleted file mode 100644 index 200430001e..0000000000 --- a/epan/dfilter.h +++ /dev/null @@ -1,70 +0,0 @@ -/* dfilter.h - * Definitions for display filters - * - * $Id: dfilter.h,v 1.1 2000/09/27 04:54:49 gram Exp $ - * - * Ethereal - Network traffic analyzer - * By Gerald Combs <gerald@zing.org> - * Copyright 1998 Gerald Combs - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __DFILTER_H__ -#define __DFILTER_H__ - -#include "proto.h" - -/* dfilter_error_msg is NULL if there was no error during dfilter_compile, - * otherwise it points to a displayable error message. */ -extern gchar *dfilter_error_msg; -extern gchar dfilter_error_msg_buf[1024]; - -typedef struct { - - GNode *dftree; - - /* space for dfilter_nodes */ - GMemChunk *node_memchunk; - - /* list of byte arrays we allocate during parse. We can traverse this list - * faster than the tree when we go back and free the byte arrays */ - GSList *list_of_byte_arrays; - - /* List of strings allocated during parse. */ - GSList *list_of_strings; - -} dfilter; - -/* Initialization of the symbol table. Called once during program startup */ -void dfilter_init(void); - -/* Free the memory used by the symbol table. Called at program shutdown */ -void dfilter_cleanup(void); - -/* Allocate and initialize new dfilter struct. Returns pointer to new dfilter */ -dfilter* dfilter_new(void); - -/* Frees all memory used by dfilter, and frees dfilter itself */ -void dfilter_destroy(dfilter *df); - -/* Compile display filter text */ -int dfilter_compile(gchar* dfilter_text, dfilter** dfp); - -/* Apply compiled dfilter to a proto_tree */ -gboolean dfilter_apply(dfilter *df, proto_tree *ptree, const guint8* pd, guint pd_len); - -#endif /* ! __DFILTER_H__ */ diff --git a/epan/dfilter/.cvsignore b/epan/dfilter/.cvsignore new file mode 100644 index 0000000000..8881f6cef9 --- /dev/null +++ b/epan/dfilter/.cvsignore @@ -0,0 +1,8 @@ +.cvsignore +.deps +scanner.c +Makefile +grammar.h +grammar.out +Makefile.in +grammar.c diff --git a/epan/dfilter/Makefile.am b/epan/dfilter/Makefile.am new file mode 100644 index 0000000000..3de048250d --- /dev/null +++ b/epan/dfilter/Makefile.am @@ -0,0 +1,81 @@ +# Makefile.am +# Automake file for the GTK interface routines for Ethereal +# +# $Id: Makefile.am,v 1.1 2001/02/01 20:21:18 gram Exp $ +# +# Ethereal - Network traffic analyzer +# By Gerald Combs <gerald@zing.org> +# Copyright 2001 Gerald Combs +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# We produce an archive library. In the future, when libethereal is a +# shared library, this will be linked into libethereal. While libethereal +# is an archive library, any executable linking against libethereal will +# also need to link against libftypes. +noinst_LIBRARIES = libdfilter.a + +CLEANFILES = \ + libdfilter.a \ + *~ + +INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/$(LEMON) + +libdfilter_a_SOURCES = \ + cppmagic.h \ + dfilter.c \ + dfilter.h \ + dfilter-int.h \ + dfvm.c \ + dfvm.h \ + gencode.c \ + gencode.h \ + glib-util.c \ + glib-util.h \ + grammar.c \ + grammar.h \ + scanner.c \ + semcheck.c \ + semcheck.h \ + sttype-pointer.c \ + sttype-range.c \ + sttype-range.h \ + sttype-string.c \ + sttype-test.c \ + sttype-test.h \ + syntax-tree.c \ + syntax-tree.h + +# Makefile.nmake +EXTRA_DIST = \ + grammar.lemon \ + lemonflex-head.inc \ + lemonflex-tail.inc \ + lemon.c \ + lempar.c \ + scanner.l + +scanner.c : scanner.l + $(LEX) -Pdf_ -oscanner.c $(srcdir)/scanner.l + +scanner.o : scanner.c grammar.h + +LEMON=../../tools/lemon + +grammar.c grammar.h : grammar.lemon + $(LEMON)/lemon t=$(srcdir)/$(LEMON)/lempar.c $(srcdir)/grammar.lemon || \ + (rm -f grammar.c grammar.h ; false) + diff --git a/epan/dfilter/cppmagic.h b/epan/dfilter/cppmagic.h new file mode 100644 index 0000000000..92bef11eb1 --- /dev/null +++ b/epan/dfilter/cppmagic.h @@ -0,0 +1,14 @@ +/* $Id: cppmagic.h,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +/**************************************** CPP definitions ***************/ + +/* CPP magic: Concatenate two strings or macros that resolve to strings. + * Use CONCAT(), not _CONCAT() */ +#define _CONCAT(a,b) a ## b +#define CONCAT(a,b) _CONCAT(a,b) + +/* CPP magic: Surround a string or a macro that resolves to a string with + * double quotes. */ +#define _STRINGIFY(a) # a +#define STRINGIFY(a) _STRINGIFY(a) + diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h new file mode 100644 index 0000000000..e3bd84325e --- /dev/null +++ b/epan/dfilter/dfilter-int.h @@ -0,0 +1,52 @@ +/* dfilter-int.h + * Header information for use by multiple files in the dfilter submodule. + * + * $Id: dfilter-int.h,v 1.1 2001/02/01 20:21:18 gram Exp $ + * + */ + +#ifndef DFILTER_INT_H +#define DFILTER_INT_H + +#include "dfilter.h" +#include "syntax-tree.h" + +#include "proto.h" + +/* Passed back to user */ +struct _dfilter_t { + GPtrArray *insns; + int num_registers; + GList **registers; + gboolean *attempted_load; +}; + +typedef struct { + /* Syntax Tree stuff */ + stnode_t *st_root; + gboolean syntax_error; + GPtrArray *insns; + GHashTable *loaded_fields; + int next_insn_id; + int next_register; +} dfwork_t; + +/* Constructor/Destructor prototypes for Lemon Parser */ +void *DfilterAlloc(void* (*)()); +void DfilterFree(void*, void (*)()); +void Dfilter(void*, int, stnode_t*, dfwork_t*); + +/* Scanner's lval */ +extern stnode_t *df_lval; + +/* Given a field abbreviation, returns the proto ID, or -1 if + * it doesn't exist. */ +header_field_info* +dfilter_lookup_token(char *abbrev); + +/* Set dfilter_error_msg_buf and dfilter_error_msg */ +void +dfilter_fail(char *format, ...); + + +#endif diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c new file mode 100644 index 0000000000..a8d249cbf4 --- /dev/null +++ b/epan/dfilter/dfilter.c @@ -0,0 +1,352 @@ +/* dfilter.c + * Main entry point for dfilter routines + * + * $Id: dfilter.c,v 1.1 2001/02/01 20:21:18 gram Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#ifdef NEED_SNPRINTF_H +#include "snprintf.h" +#endif + +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "gencode.h" +#include "semcheck.h" +#include "dfvm.h" + + +/* Balanced tree of abbreviations and IDs */ +GTree *dfilter_tokens = NULL; + +#define DFILTER_TOKEN_ID_OFFSET 1 + +/* Comparision function for tree insertion. A wrapper around strcmp() */ +static int g_strcmp(gconstpointer a, gconstpointer b); + +/* Global error message space for dfilter_compile errors */ +gchar dfilter_error_msg_buf[1024]; +gchar *dfilter_error_msg; /* NULL when no error resulted */ + +/* In proto.c */ +extern int hf_text_only; + +/* From scanner.c */ +void df_scanner_text(const char *text); +void df_scanner_file(FILE *fh); +void df_scanner_cleanup(void); +int df_lex(void); + +/* Holds the singular instance of our Lemon parser object */ +void* ParserObj = NULL; + +void +dfilter_fail(char *format, ...) +{ + va_list args; + + /* If we've already reported one error, don't overwite it */ + if (dfilter_error_msg != NULL) + return; + + va_start(args, format); + + vsnprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf), + format, args); + dfilter_error_msg = dfilter_error_msg_buf; + va_end(args); +} + + +/* Initialize the dfilter module */ +void +dfilter_init(void) +{ + int id, num_symbols; + char *abbrev; + header_field_info *hfinfo, *same_name_hfinfo; + + num_symbols = proto_registrar_n(); + + if (dfilter_tokens) { + /* XXX - needed? */ + g_message("I expected hf_ids to be NULL\n"); + g_tree_destroy(dfilter_tokens); + + /* Make sure the hfinfo->same_name links are broken */ + for (id = 0; id < num_symbols; id++) { + hfinfo = proto_registrar_get_nth(id); + hfinfo->same_name = NULL; + } + } + dfilter_tokens = g_tree_new(g_strcmp); + + /* Populate the abbrev/ID GTree (header-field symbol table) */ + + + for (id = 0; id < num_symbols; id++) { + if (id == hf_text_only) { + continue; + } + abbrev = proto_registrar_get_abbrev(id); + hfinfo = proto_registrar_get_nth(id); + + g_assert(abbrev); /* Not Null */ + g_assert(abbrev[0] != 0); /* Not empty string */ + + /* We allow multiple hfinfo's to be registered under the same + * abbreviation. This was done for X.25 */ + same_name_hfinfo = g_tree_lookup(dfilter_tokens, abbrev); + if (same_name_hfinfo) { + /* Set the "same_name" pointer in the hfinfo, then + * allow the code after this if{} block to replace the + * old hfinfo with the new hfinfo in the GTree. Thus, + * we end up with a linked-list of same-named hfinfo's, + * with the root of the list being the hfinfo in the GTree */ + hfinfo->same_name = same_name_hfinfo; + + } + g_tree_insert(dfilter_tokens, abbrev, hfinfo); + } + + if (ParserObj) { + g_message("I expected ParserObj to be NULL\n"); + /* Free the Lemon Parser object */ + DfilterFree(ParserObj, g_free); + } + /* Allocate an instance of our Lemon-based parser */ + ParserObj = DfilterAlloc(g_malloc); + + /* Initialize the syntax-tree sub-sub-system */ + sttype_init(); +} + +/* Clean-up the dfilter module */ +void +dfilter_cleanup(void) +{ + /* Free the abbrev/ID GTree */ + if (dfilter_tokens) { + g_tree_destroy(dfilter_tokens); + dfilter_tokens = NULL; + } + + /* Free the Lemon Parser object */ + if (ParserObj) { + DfilterFree(ParserObj, g_free); + } + + /* Clean up the syntax-tree sub-sub-system */ + sttype_cleanup(); +} + + + +/* Lookup an abbreviation in our token tree, returing the ID # + * If the abbreviation doesn't exit, returns -1 */ +header_field_info* +dfilter_lookup_token(char *abbrev) +{ + g_assert(abbrev != NULL); + return g_tree_lookup(dfilter_tokens, abbrev); +} + +/* String comparison func for dfilter_token GTree */ +static int +g_strcmp(gconstpointer a, gconstpointer b) +{ + return strcmp((const char*)a, (const char*)b); +} + +static dfilter_t* +dfilter_new(void) +{ + dfilter_t *df; + + df = g_new(dfilter_t, 1); + df->insns = NULL; + + return df; +} + +/* Given a GPtrArray of instructions (dfvm_insn_t), + * free them. */ +static void +free_insns(GPtrArray *insns) +{ + int i; + dfvm_insn_t *insn; + + for (i = 0; i < insns->len; i++) { + insn = g_ptr_array_index(insns, i); + dfvm_insn_free(insn); + } +} + +void +dfilter_free(dfilter_t *df) +{ + if (df->insns) { + free_insns(df->insns); + } + + g_free(df->registers); + g_free(df->attempted_load); + g_free(df); +} + + +static dfwork_t* +dfwork_new(void) +{ + dfwork_t *dfw; + + dfw = g_new(dfwork_t, 1); + + dfw->st_root = NULL; + dfw->syntax_error = FALSE; + dfw->insns = NULL; + dfw->loaded_fields = NULL; + dfw->next_insn_id = 0; + dfw->next_register = 0; + + return dfw; +} + +static void +dfwork_free(dfwork_t *dfw) +{ + if (dfw->st_root) { + stnode_free(dfw->st_root); + } + + if (dfw->loaded_fields) { + g_hash_table_destroy(dfw->loaded_fields); + } + + if (dfw->insns) { + free_insns(dfw->insns); + } + + g_free(dfw); +} + + +gboolean +dfilter_compile(gchar *text, dfilter_t **dfp) +{ + int token; + dfilter_t *dfilter; + dfwork_t *dfw; + + dfilter_error_msg = NULL; + + dfw = dfwork_new(); + + df_scanner_text(text); + + while (1) { + df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL); + token = df_lex(); + + /* Check for end-of-input */ + if (token == 0) { + /* Tell the parser that we have reached the end of input */ + Dfilter(ParserObj, 0, NULL, dfw); + + /* Free the stnode_t that we just generated, since + * the parser doesn't know about it and won't free it + * for us. */ + stnode_free(df_lval); + df_lval = NULL; + break; + } + + /* Give the token to the parser */ + Dfilter(ParserObj, token, df_lval, dfw); + + if (dfw->syntax_error) { + break; + } + } + + /* One last check for syntax error (after EOF) */ + if (dfw->syntax_error) { + goto FAILURE; + } + + + /* Success, but was it an empty filter? If so, discard + * it and set *dfp to NULL */ + if (dfw->st_root == NULL) { + *dfp = NULL; + } + else { + + /* Check semantics and do necessary type conversion*/ + if (!dfw_semcheck(dfw)) { + goto FAILURE; + } + + /* Create bytecode */ + dfw_gencode(dfw); + + /* Tuck away the bytecode in the dfilter_t */ + dfilter = dfilter_new(); + dfilter->insns = dfw->insns; + dfw->insns = NULL; + + /* Initialize run-time space */ + dfilter->num_registers = dfw->next_register; + dfilter->registers = g_new0(GList*, dfilter->num_registers); + dfilter->attempted_load = g_new0(gboolean, dfilter->num_registers); + + /* And give it to the user. */ + *dfp = dfilter; + } + /* SUCCESS */ + dfwork_free(dfw); + + /* Reset flex */ + df_scanner_cleanup(); + + return TRUE; + +FAILURE: + if (dfw) { + dfwork_free(dfw); + } + dfilter_fail("Unable to parse filter string \"%s\".", text); + *dfp = NULL; + + /* Reset flex */ + df_scanner_cleanup(); + return FALSE; + +} + + +gboolean +dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree) +{ + return dfvm_apply(df, tvb, tree); +} + +gboolean +dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt) +{ + return dfvm_apply(df, edt->tvb, edt->tree); +} + + +void +dfilter_dump(dfilter_t *df) +{ + dfvm_dump(stdout, df->insns); +} diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h new file mode 100644 index 0000000000..b9442f42c8 --- /dev/null +++ b/epan/dfilter/dfilter.h @@ -0,0 +1,65 @@ +/* dfilter.h + * + * $Id: dfilter.h,v 1.1 2001/02/01 20:21:18 gram Exp $ + */ + +#ifndef DFILTER_H +#define DFILTER_H + +#include <glib.h> +#include "epan.h" +#include "proto.h" + +/* Passed back to user */ +typedef struct _dfilter_t dfilter_t; + +/* Module-level initialization */ +void +dfilter_init(void); + +/* Module-level cleanup */ +void +dfilter_cleanup(void); + +/* Compiles a string to a dfilter_t. + * On success, sets the dfilter* pointed to by dfp + * to either a NULL pointer (if the filter is a null + * filter, as generated by an all-blank string) or to + * a pointer to the newly-allocated dfilter_t + * structure. + * + * On failure, dfilter_error_msg points to an + * appropriate error message. This error message is + * a global string, so another invocation of + * dfilter_compile() will clear it. The dfilter* + * will be set to NULL after a failure. + * + * Returns TRUE on success, FALSE on failure. + */ +gboolean +dfilter_compile(gchar *text, dfilter_t **dfp); + +/* Frees all memory used by dfilter, and frees + * the dfilter itself. */ +void +dfilter_free(dfilter_t *df); + + +/* dfilter_error_msg is NULL if there was no error during dfilter_compile, + * otherwise it points to a displayable error message. */ +extern gchar *dfilter_error_msg; + +/* Apply compiled dfilter */ +gboolean +dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt); + +/* Apply compiled dfilter */ +gboolean +dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree); + + +/* Print bytecode of dfilter to stdout */ +void +dfilter_dump(dfilter_t *df); + +#endif diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c new file mode 100644 index 0000000000..bf8bfe8e17 --- /dev/null +++ b/epan/dfilter/dfvm.c @@ -0,0 +1,395 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dfvm.h" + +dfvm_insn_t* +dfvm_insn_new(dfvm_opcode_t op) +{ + dfvm_insn_t *insn; + + insn = g_new(dfvm_insn_t, 1); + insn->op = op; + insn->arg1 = NULL; + insn->arg2 = NULL; + insn->arg3 = NULL; + insn->arg4 = NULL; + return insn; +} + +void +dfvm_insn_free(dfvm_insn_t *insn) +{ + if (insn->arg1) { + dfvm_value_free(insn->arg1); + } + if (insn->arg2) { + dfvm_value_free(insn->arg2); + } + if (insn->arg3) { + dfvm_value_free(insn->arg3); + } + if (insn->arg4) { + dfvm_value_free(insn->arg4); + } + g_free(insn); +} + + + +dfvm_value_t* +dfvm_value_new(dfvm_value_type_t type) +{ + dfvm_value_t *v; + + v = g_new(dfvm_value_t, 1); + v->type = type; + return v; +} + +void +dfvm_value_free(dfvm_value_t *v) +{ + switch (v->type) { + case FVALUE: + fvalue_free(v->value.fvalue); + break; + default: + /* nothing */ + ; + } + g_free(v); +} + + +void +dfvm_dump(FILE *f, GPtrArray *insns) +{ + int id, length; + dfvm_insn_t *insn; + dfvm_value_t *arg1; + dfvm_value_t *arg2; + dfvm_value_t *arg3; + dfvm_value_t *arg4; + + length = insns->len; + + for (id = 0; id < length; id++) { + + insn = g_ptr_array_index(insns, id); + arg1 = insn->arg1; + arg2 = insn->arg2; + arg3 = insn->arg3; + arg4 = insn->arg4; + + switch (insn->op) { + case CHECK_EXISTS: + fprintf(f, "%05d CHECK_EXISTS\t%s\n", + id, proto_registrar_get_abbrev(arg1->value.numeric)); + break; + + case READ_TREE: + fprintf(f, "%05d READ_TREE\t\t%s -> reg#%d\n", + id, proto_registrar_get_abbrev(arg1->value.numeric), + arg2->value.numeric); + break; + + case PUT_FVALUE: + fprintf(f, "%05d PUT_FVALUE\t<%s> -> reg#%d\n", + id, fvalue_type_name(arg1->value.fvalue), + arg2->value.numeric); + break; + + case MK_RANGE: + fprintf(f, "%05d MK_RANGE\t\treg#%d[%d:%d] -> reg#%d\n", + id, + arg1->value.numeric, + arg3->value.numeric, + arg4->value.numeric, + arg2->value.numeric); + break; + + case ANY_EQ: + fprintf(f, "%05d ANY_EQ\t\treg#%d == reg#%d\n", + id, arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_NE: + fprintf(f, "%05d ANY_NE\t\treg#%d == reg#%d\n", + id, arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_GT: + fprintf(f, "%05d ANY_GT\t\treg#%d == reg#%d\n", + id, arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_GE: + fprintf(f, "%05d ANY_GE\t\treg#%d == reg#%d\n", + id, arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_LT: + fprintf(f, "%05d ANY_LT\t\treg#%d == reg#%d\n", + id, arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_LE: + fprintf(f, "%05d ANY_LE\t\treg#%d == reg#%d\n", + id, arg1->value.numeric, arg2->value.numeric); + break; + + case NOT: + fprintf(f, "%05d NOT\n", id); + break; + + case RETURN: + fprintf(f, "%05d RETURN\n", id); + break; + + case IF_TRUE_GOTO: + fprintf(f, "%05d IF-TRUE-GOTO\t%d\n", + id, arg1->value.numeric); + break; + + case IF_FALSE_GOTO: + fprintf(f, "%05d IF-FALSE-GOTO\t%d\n", + id, arg1->value.numeric); + break; + + default: + g_assert_not_reached(); + break; + } + } +} + +/* Reads a field from the proto_tree and loads the fvalues into a register, + * if that field has not already been read. */ +static gboolean +read_tree(dfilter_t *df, proto_tree *tree, int field_id, int reg) +{ + GPtrArray *finfos; + field_info *finfo; + int i, len; + GList *fvalues = NULL; + + /* Already loaded in this run of the dfilter? */ + if (df->attempted_load[reg]) { + if (df->registers[reg]) { + return TRUE; + } + else { + return FALSE; + } + } + + df->attempted_load[reg] = TRUE; + + finfos = proto_get_finfo_ptr_array(tree, field_id); + if (!finfos) { + return FALSE; + } + + len = finfos->len; + for (i = 0; i < len; i++) { + finfo = g_ptr_array_index(finfos, i); + fvalues = g_list_prepend(fvalues, finfo->value); + } + fvalues = g_list_reverse(fvalues); + + df->registers[reg] = fvalues; + return TRUE; +} + + +static gboolean +put_fvalue(dfilter_t *df, fvalue_t *fv, int reg) +{ + df->registers[reg] = g_list_append(NULL, fv); + return TRUE; +} + +typedef gboolean (*FvalueCmpFunc)(fvalue_t*, fvalue_t*); + +static gboolean +any_test(dfilter_t *df, FvalueCmpFunc cmp, int reg1, int reg2) +{ + GList *list_a, *list_b; + + list_a = df->registers[reg1]; + + while (list_a) { + list_b = df->registers[reg2]; + while (list_b) { + if (cmp(list_a->data, list_b->data)) { + return TRUE; + } + list_b = g_list_next(list_b); + } + list_a = g_list_next(list_a); + } + return FALSE; +} + + +/* Free the list nodes w/o freeing the memory that each + * list node points to. */ +static void +free_register_overhead(dfilter_t* df) +{ + int i; + + for (i = 0; i < df->num_registers; i++) { + if (df->registers[i]) { + g_list_free(df->registers[i]); + } + } +} + +/* Takes the list of fvalue_t's in a register, uses fvalue_slice() + * to make a new list of fvalue_t's (which are ranges, or byte-slices), + * and puts the new list into a new register. */ +static void +mk_range(dfilter_t *df, int from_reg, int to_reg, int start, int end) +{ + GList *from_list, *to_list; + fvalue_t *old_fv, *new_fv; + + to_list = NULL; + from_list = df->registers[from_reg]; + + while (from_list) { + old_fv = from_list->data; + new_fv = fvalue_slice(old_fv, start, end); + /* Assert there because semcheck.c should have + * already caught the cases in which a slice + * cannot be made. */ + g_assert(new_fv); + to_list = g_list_append(to_list, new_fv); + + from_list = g_list_next(from_list); + } + + df->registers[to_reg] = to_list; +} + + + +gboolean +dfvm_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree) +{ + int i, id, length; + gboolean accum = TRUE; + dfvm_insn_t *insn; + dfvm_value_t *arg1; + dfvm_value_t *arg2; + dfvm_value_t *arg3; + dfvm_value_t *arg4; + + g_assert(tvb); + g_assert(tree); + + + /* Clear registers */ + for (i = 0; i < df->num_registers; i++) { + df->registers[i] = NULL; + df->attempted_load[i] = FALSE; + } + + length = df->insns->len; + + for (id = 0; id < length; id++) { + + AGAIN: + insn = g_ptr_array_index(df->insns, id); + arg1 = insn->arg1; + arg2 = insn->arg2; + + switch (insn->op) { + case CHECK_EXISTS: + accum = proto_check_for_protocol_or_field(tree, + arg1->value.numeric); + break; + + case READ_TREE: + accum = read_tree(df, tree, + arg1->value.numeric, arg2->value.numeric); + break; + + case PUT_FVALUE: + accum = put_fvalue(df, + arg1->value.fvalue, arg2->value.numeric); + break; + + case MK_RANGE: + arg3 = insn->arg3; + arg4 = insn->arg4; + mk_range(df, + arg1->value.numeric, arg2->value.numeric, + arg3->value.numeric, arg4->value.numeric); + break; + + case ANY_EQ: + accum = any_test(df, fvalue_eq, + arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_NE: + accum = any_test(df, fvalue_ne, + arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_GT: + accum = any_test(df, fvalue_gt, + arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_GE: + accum = any_test(df, fvalue_ge, + arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_LT: + accum = any_test(df, fvalue_lt, + arg1->value.numeric, arg2->value.numeric); + break; + + case ANY_LE: + accum = any_test(df, fvalue_le, + arg1->value.numeric, arg2->value.numeric); + break; + + case NOT: + accum = !accum; + break; + + case RETURN: + free_register_overhead(df); + return accum; + + case IF_TRUE_GOTO: + if (accum) { + id = arg1->value.numeric; + goto AGAIN; + } + break; + + case IF_FALSE_GOTO: + if (!accum) { + id = arg1->value.numeric; + goto AGAIN; + } + break; + + + default: + g_assert_not_reached(); + break; + } + } + + g_assert_not_reached(); + return FALSE; /* to appease the compiler */ +} diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h new file mode 100644 index 0000000000..d7803635da --- /dev/null +++ b/epan/dfilter/dfvm.h @@ -0,0 +1,77 @@ +#ifndef DFVM_H +#define DFVM_H + +#include <stdio.h> +#include "proto.h" +#include "dfilter-int.h" +#include "syntax-tree.h" + +typedef enum { + EMPTY, + FVALUE, + FIELD_ID, + INSN_NUMBER, + REGISTER, + INTEGER +} dfvm_value_type_t; + +typedef struct { + dfvm_value_type_t type; + + union { + fvalue_t *fvalue; + guint32 numeric; + } value; + +} dfvm_value_t; + + +typedef enum { + + IF_TRUE_GOTO, + IF_FALSE_GOTO, + CHECK_EXISTS, + NOT, + RETURN, + READ_TREE, + PUT_FVALUE, + ANY_EQ, + ANY_NE, + ANY_GT, + ANY_GE, + ANY_LT, + ANY_LE, + MK_RANGE + +} dfvm_opcode_t; + +typedef struct { + int id; + int LHS; + dfvm_opcode_t op; + dfvm_value_t *arg1; + dfvm_value_t *arg2; + dfvm_value_t *arg3; + dfvm_value_t *arg4; +} dfvm_insn_t; + +dfvm_insn_t* +dfvm_insn_new(dfvm_opcode_t op); + +void +dfvm_insn_free(dfvm_insn_t *insn); + +dfvm_value_t* +dfvm_value_new(dfvm_value_type_t type); + +void +dfvm_value_free(dfvm_value_t *v); + +void +dfvm_dump(FILE *f, GPtrArray *insns); + +gboolean +dfvm_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree); + + +#endif diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c new file mode 100644 index 0000000000..61c5546cb6 --- /dev/null +++ b/epan/dfilter/gencode.c @@ -0,0 +1,299 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dfilter-int.h" +#include "dfvm.h" +#include "syntax-tree.h" +#include "sttype-range.h" +#include "sttype-test.h" +#include "ftypes/ftypes.h" +#include "gdebug.h" + +static void +gencode(dfwork_t *dfw, stnode_t *st_node); + +static void +dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn) +{ + insn->id = dfw->next_insn_id; + dfw->next_insn_id++; + g_ptr_array_add(dfw->insns, insn); +} + +/* returns register number */ +static int +dfw_append_read_tree(dfwork_t *dfw, int field_id) +{ + dfvm_insn_t *insn; + dfvm_value_t *val1, *val2; + int reg = -1; + + /* Keep track of which registers + * were used for which field_id's so that we + * can re-use registers. */ + reg = GPOINTER_TO_UINT( + g_hash_table_lookup(dfw->loaded_fields, + GUINT_TO_POINTER(field_id))); + if (reg) { + /* Reg's are stored in has as reg+1, so + * that the non-existence of a field_id in + * the hash, or 0, can be differentiated from + * a field_id being loaded into register #0. */ + reg--; + } + else { + reg = dfw->next_register++; + g_hash_table_insert(dfw->loaded_fields, + GUINT_TO_POINTER(field_id), + GUINT_TO_POINTER(reg + 1)); + } + + insn = dfvm_insn_new(READ_TREE); + val1 = dfvm_value_new(FIELD_ID); + val1->value.numeric = field_id; + val2 = dfvm_value_new(REGISTER); + val2->value.numeric = reg; + + insn->arg1 = val1; + insn->arg2 = val2; + dfw_append_insn(dfw, insn); + + return reg; +} + +/* returns register number */ +static int +dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv) +{ + dfvm_insn_t *insn; + dfvm_value_t *val1, *val2; + int reg; + + insn = dfvm_insn_new(PUT_FVALUE); + val1 = dfvm_value_new(FVALUE); + val1->value.fvalue = fv; + val2 = dfvm_value_new(REGISTER); + reg = dfw->next_register++; + val2->value.numeric = reg; + insn->arg1 = val1; + insn->arg2 = val2; + dfw_append_insn(dfw, insn); + + return reg; +} + +/* returns register number */ +static int +dfw_append_mk_range(dfwork_t *dfw, stnode_t *node) +{ + int hf_reg, reg; + header_field_info *hfinfo; + dfvm_insn_t *insn; + dfvm_value_t *val; + + hfinfo = sttype_range_hfinfo(node); + hf_reg = dfw_append_read_tree(dfw, hfinfo->id); + + insn = dfvm_insn_new(MK_RANGE); + + val = dfvm_value_new(REGISTER); + val->value.numeric = hf_reg; + insn->arg1 = val; + + val = dfvm_value_new(REGISTER); + reg =dfw->next_register++; + val->value.numeric = reg; + insn->arg2 = val; + + val = dfvm_value_new(INTEGER); + val->value.numeric = sttype_range_start(node); + insn->arg3 = val; + + val = dfvm_value_new(INTEGER); + val->value.numeric = sttype_range_end(node); + insn->arg4 = val; + + dfw_append_insn(dfw, insn); + + return reg; +} + + +static void +gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_arg2) +{ + sttype_id_t type1, type2; + dfvm_insn_t *insn; + dfvm_value_t *val1, *val2; + dfvm_value_t *jmp1 = NULL, *jmp2 = NULL; + int reg1 = -1, reg2 = -1; + header_field_info *hfinfo; + + fvalue_t *junk = NULL; + + type1 = stnode_type_id(st_arg1); + type2 = stnode_type_id(st_arg2); + + if (type1 == STTYPE_FIELD) { + hfinfo = stnode_data(st_arg1); + reg1 = dfw_append_read_tree(dfw, hfinfo->id); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + jmp1 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = jmp1; + dfw_append_insn(dfw, insn); + } + else if (type1 == STTYPE_FVALUE) { + reg1 = dfw_append_put_fvalue(dfw, stnode_data(st_arg1)); + } + else if (type1 == STTYPE_RANGE) { + reg1 = dfw_append_mk_range(dfw, st_arg1); + } + else { + g_assert_not_reached(); + } + + if (type2 == STTYPE_FIELD) { + hfinfo = stnode_data(st_arg2); + reg2 = dfw_append_read_tree(dfw, hfinfo->id); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + jmp2 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = jmp2; + dfw_append_insn(dfw, insn); + } + else if (type2 == STTYPE_FVALUE) { + reg2 = dfw_append_put_fvalue(dfw, stnode_data(st_arg2)); + } + else { + g_assert_not_reached(); + } + + insn = dfvm_insn_new(op); + val1 = dfvm_value_new(REGISTER); + val1->value.numeric = reg1; + val2 = dfvm_value_new(REGISTER); + val2->value.numeric = reg2; + insn->arg1 = val1; + insn->arg2 = val2; + dfw_append_insn(dfw, insn); + + if (jmp1) { + jmp1->value.numeric = dfw->next_insn_id; + } + + if (jmp2) { + jmp2->value.numeric = dfw->next_insn_id; + } +} + + +static void +gen_test(dfwork_t *dfw, stnode_t *st_node) +{ + test_op_t st_op; + stnode_t *st_arg1, *st_arg2; + dfvm_value_t *val1; + dfvm_insn_t *insn; + + header_field_info *hfinfo; + + sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2); + + switch (st_op) { + case TEST_OP_UNINITIALIZED: + g_assert_not_reached(); + break; + + case TEST_OP_EXISTS: + val1 = dfvm_value_new(FIELD_ID); + hfinfo = stnode_data(st_arg1); + val1->value.numeric = hfinfo->id; + insn = dfvm_insn_new(CHECK_EXISTS); + insn->arg1 = val1; + dfw_append_insn(dfw, insn); + break; + + case TEST_OP_NOT: + gencode(dfw, st_arg1); + insn = dfvm_insn_new(NOT); + dfw_append_insn(dfw, insn); + break; + + case TEST_OP_AND: + gencode(dfw, st_arg1); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + val1 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = val1; + dfw_append_insn(dfw, insn); + + gencode(dfw, st_arg2); + val1->value.numeric = dfw->next_insn_id; + break; + + case TEST_OP_OR: + gencode(dfw, st_arg1); + + insn = dfvm_insn_new(IF_TRUE_GOTO); + val1 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = val1; + dfw_append_insn(dfw, insn); + + gencode(dfw, st_arg2); + val1->value.numeric = dfw->next_insn_id; + break; + + case TEST_OP_EQ: + gen_relation(dfw, ANY_EQ, st_arg1, st_arg2); + break; + + case TEST_OP_NE: + gen_relation(dfw, ANY_NE, st_arg1, st_arg2); + break; + + case TEST_OP_GT: + gen_relation(dfw, ANY_GT, st_arg1, st_arg2); + break; + + case TEST_OP_GE: + gen_relation(dfw, ANY_GE, st_arg1, st_arg2); + break; + + case TEST_OP_LT: + gen_relation(dfw, ANY_LT, st_arg1, st_arg2); + break; + + case TEST_OP_LE: + gen_relation(dfw, ANY_LE, st_arg1, st_arg2); + break; + } +} + +static void +gencode(dfwork_t *dfw, stnode_t *st_node) +{ + const char *name; + + name = stnode_type_name(st_node); + + switch (stnode_type_id(st_node)) { + case STTYPE_TEST: + gen_test(dfw, st_node); + break; + default: + g_assert_not_reached(); + } +} + + +void +dfw_gencode(dfwork_t *dfw) +{ + dfw->insns = g_ptr_array_new(); + dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal); + gencode(dfw, dfw->st_root); + dfw_append_insn(dfw, dfvm_insn_new(RETURN)); +} + diff --git a/epan/dfilter/gencode.h b/epan/dfilter/gencode.h new file mode 100644 index 0000000000..db56b9082c --- /dev/null +++ b/epan/dfilter/gencode.h @@ -0,0 +1,7 @@ +#ifndef GENCODE_H +#define GENCODE_H + +void +dfw_gencode(dfwork_t *dfw); + +#endif diff --git a/epan/dfilter/glib-util.c b/epan/dfilter/glib-util.c new file mode 100644 index 0000000000..9e63fab4f3 --- /dev/null +++ b/epan/dfilter/glib-util.c @@ -0,0 +1,47 @@ +/* $Id: glib-util.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +#include <string.h> +#include <glib.h> + + +#include <glib-util.h> + +char* +g_substrdup(const char *s, int start, int len) +{ + int s_len, abs_start, abs_len; + char *newstring; + + + s_len = strlen(s); + + if (start < 0) { + abs_start = s_len + start; + if (abs_start < 0) { + return NULL; + } + } + else { + abs_start = start; + } + + if (len < 0) { + abs_len = s_len + len + 1 - abs_start; + if (abs_len < 0) { + return NULL; + } + } + else { + abs_len = len; + } + + + if (abs_start + abs_len > s_len) { + return NULL; + } + + newstring = g_strndup(s + abs_start, abs_len + 1); + newstring[abs_len] = 0; + + return newstring; +} diff --git a/epan/dfilter/glib-util.h b/epan/dfilter/glib-util.h new file mode 100644 index 0000000000..90a81f7eed --- /dev/null +++ b/epan/dfilter/glib-util.h @@ -0,0 +1,4 @@ +/* $Id: glib-util.h,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +char* +g_substrdup(const char *s, int start, int len); diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon new file mode 100644 index 0000000000..8072458ab7 --- /dev/null +++ b/epan/dfilter/grammar.lemon @@ -0,0 +1,185 @@ +/* $Id: grammar.lemon,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +%include { +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "sttype-range.h" +#include "sttype-test.h" + +/*extern char *df_text;*/ + +/* End of C code */ +} + +/* Parser Information */ +%name Dfilter +%token_prefix TOKEN_ +%extra_argument {dfwork_t *dfw} + +/* Terminal and Non-Terminal types and destructors */ +%token_type {stnode_t*} +%token_destructor {stnode_free($$);} + +%type sentence {stnode_t*} +%destructor sentence {stnode_free($$);} + +%type expr {stnode_t*} +%destructor expr {stnode_free($$);} + +%type entity {stnode_t*} +%destructor entity {stnode_free($$);} + +%type relation_test {stnode_t*} +%destructor relation_test {stnode_free($$);} + +%type logical_test {stnode_t*} +%destructor logical_test {stnode_free($$);} + +%type rel_op2 {test_op_t} + +%type range {stnode_t*} +%destructor range {stnode_free($$);} + +/* This is called as soon as a syntax error happens. After that, +any "error" symbols are shifted, if possible. */ +%syntax_error { + + header_field_info *hfinfo; + + if (!TOKEN) { + dfilter_fail("Unexpected end of filter string."); + return; + } + + switch(stnode_type_id(TOKEN)) { + case STTYPE_UNINITIALIZED: + dfilter_fail("Syntax error."); + break; + case STTYPE_TEST: + dfilter_fail("Syntax error, TEST."); + break; + case STTYPE_STRING: + dfilter_fail("The string \"%s\" was unexpected in this context.", + stnode_data(TOKEN)); + break; + case STTYPE_FIELD: + hfinfo = stnode_data(TOKEN); + dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev); + break; + + /* These aren't handed to use as terminal tokens from + the scanner, so was can assert that we'll never + see them here. */ + case STTYPE_NUM_TYPES: + case STTYPE_RANGE: + case STTYPE_FVALUE: + g_assert_not_reached(); + break; + } +} + +/* When a parse fails, mark an error. This occurs after +the above syntax_error code and after the parser fails to +use error recovery, shifting an "error" symbol and successfully +shifting 3 more symbols. */ +%parse_failure { + dfw->syntax_error = TRUE; +} + +/* ----------------- The grammar -------------- */ + +/* Associativity */ +%left TEST_AND. +%left TEST_OR. +%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE. +%right TEST_NOT. + +/* Top-level targets */ +sentence ::= expr(X). { dfw->st_root = X; } +sentence ::= . { dfw->st_root = NULL; } + +expr(X) ::= relation_test(R). { X = R; } +expr(X) ::= logical_test(L). { X = L; } + +expr(X) ::= LPAREN expr(Y) RPAREN. +{ + X = Y; +} + + +/* Logical tests */ +logical_test(T) ::= expr(E) TEST_AND expr(F). +{ + T = stnode_new(STTYPE_TEST, NULL); + sttype_test_set2(T, TEST_OP_AND, E, F); +} + +logical_test(T) ::= expr(E) TEST_OR expr(F). +{ + T = stnode_new(STTYPE_TEST, NULL); + sttype_test_set2(T, TEST_OP_OR, E, F); +} + +logical_test(T) ::= TEST_NOT expr(E). +{ + T = stnode_new(STTYPE_TEST, NULL); + sttype_test_set1(T, TEST_OP_NOT, E); +} + +logical_test(T) ::= FIELD(F). +{ + T = stnode_new(STTYPE_TEST, NULL); + sttype_test_set1(T, TEST_OP_EXISTS, F); +} + + + +/* Entities, or things that can be compared/tested/checked */ +entity(E) ::= FIELD(F). { E = F; } +entity(E) ::= STRING(S). { E = S; } +entity(E) ::= range(R). { E = R; } + +range(R) ::= FIELD(F) LBRACKET STRING(X) COLON STRING(Y) RBRACKET. +{ + R = stnode_new(STTYPE_RANGE, NULL); + sttype_range_set(R, F, X, Y); +} + +range(R) ::= FIELD(F) LBRACKET STRING(X) COLON RBRACKET. +{ + R = stnode_new(STTYPE_RANGE, NULL); + sttype_range_set(R, F, X, NULL); +} + +range(R) ::= FIELD(F) LBRACKET COLON STRING(Y) RBRACKET. +{ + R = stnode_new(STTYPE_RANGE, NULL); + sttype_range_set(R, F, NULL, Y); +} + +range(R) ::= FIELD(F) LBRACKET STRING(Y) RBRACKET. +{ + R = stnode_new(STTYPE_RANGE, NULL); + sttype_range_set1(R, F, Y); +} + +/* Relational tests */ +relation_test(T) ::= entity(E) rel_op2(O) entity(F). +{ + T = stnode_new(STTYPE_TEST, NULL); + sttype_test_set2(T, O, E, F); +} + +rel_op2(O) ::= TEST_EQ. { O = TEST_OP_EQ; } +rel_op2(O) ::= TEST_NE. { O = TEST_OP_NE; } +rel_op2(O) ::= TEST_GT. { O = TEST_OP_GT; } +rel_op2(O) ::= TEST_GE. { O = TEST_OP_GE; } +rel_op2(O) ::= TEST_LT. { O = TEST_OP_LT; } +rel_op2(O) ::= TEST_LE. { O = TEST_OP_LE; } + + + diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l new file mode 100644 index 0000000000..a10c9fd77f --- /dev/null +++ b/epan/dfilter/scanner.l @@ -0,0 +1,157 @@ +%{ +/* scanner.l + * Scanner for Ethereal's dfilter language + * + * $Id: scanner.l,v 1.1 2001/02/01 20:21:18 gram Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "glib-util.h" +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "grammar.h" + +#define LVAL df_lval +#define LVAL_TYPE stnode_t* +#define LVAL_INIT_VAL NULL +#define MODNAME df + +#include <lemonflex-head.inc> + +/*#undef YY_NO_UNPUT*/ + +int set_lval(int token, gpointer data); +int simple(int token); + +%} + +%x RANGE + +BWCHARS [[:alnum:]\[\]\-_.+!@#%^&*=/:] +INITVAR [_A-Za-z] +VARCHARS [[:alnum:]_] + + +%% + +[[:blank:]\n]+ /* ignore whitespace */ + + + +"(" return simple(TOKEN_LPAREN); +")" return simple(TOKEN_RPAREN); + +"==" return simple(TOKEN_TEST_EQ); +"eq" return simple(TOKEN_TEST_EQ); +"!=" return simple(TOKEN_TEST_NE); +"ne" return simple(TOKEN_TEST_NE); +">" return simple(TOKEN_TEST_GT); +"gt" return simple(TOKEN_TEST_GT); +">=" return simple(TOKEN_TEST_GE); +"ge" return simple(TOKEN_TEST_GE); +"<" return simple(TOKEN_TEST_LT); +"lt" return simple(TOKEN_TEST_LT); +"<=" return simple(TOKEN_TEST_LE); +"le" return simple(TOKEN_TEST_LE); + +"!" return simple(TOKEN_TEST_NOT); +"not" return simple(TOKEN_TEST_NOT); +"&&" return simple(TOKEN_TEST_AND); +"and" return simple(TOKEN_TEST_AND); +"||" return simple(TOKEN_TEST_OR); +"or" return simple(TOKEN_TEST_OR); + + +"[" { + BEGIN(RANGE); + return simple(TOKEN_LBRACKET); +} + +<RANGE>[+-]?[[:digit:]]+ { + return set_lval(TOKEN_STRING, g_strdup(yytext)); +} +<RANGE>[+-]?0x[[:xdigit:]]+ { + return set_lval(TOKEN_STRING, g_strdup(yytext)); +} +<RANGE>":" return simple(TOKEN_COLON); + +<RANGE>"]" { + BEGIN(INITIAL); + return simple(TOKEN_RBRACKET); +} + + +\"[^"]*\" { + return set_lval(TOKEN_STRING, g_substrdup(yytext, 1, -2)); +} + + + +[[:alnum:]_.:]+ { + /* Is it a field name? */ + header_field_info *hfinfo; + + hfinfo = dfilter_lookup_token(yytext); + if (hfinfo) { + /* Yes, it's a field name */ + return set_lval(TOKEN_FIELD, hfinfo); + } + else { + /* No, so treat it as a string */ + return set_lval(TOKEN_STRING, g_strdup(yytext)); + } +} + + + +%% + +int +simple(int token) +{ + switch (token) { + case TOKEN_LPAREN: + case TOKEN_RPAREN: + case TOKEN_LBRACKET: + case TOKEN_RBRACKET: + case TOKEN_COLON: + case TOKEN_TEST_EQ: + case TOKEN_TEST_NE: + case TOKEN_TEST_GT: + case TOKEN_TEST_GE: + case TOKEN_TEST_LT: + case TOKEN_TEST_LE: + case TOKEN_TEST_NOT: + case TOKEN_TEST_AND: + case TOKEN_TEST_OR: + break; + default: + g_assert_not_reached(); + } + return token; +} + +int +set_lval(int token, gpointer data) +{ + sttype_id_t type_id = STTYPE_UNINITIALIZED; + + switch (token) { + case TOKEN_STRING: + type_id = STTYPE_STRING; + break; + case TOKEN_FIELD: + type_id = STTYPE_FIELD; + break; + default: + g_assert_not_reached(); + } + + stnode_init(df_lval, type_id, data); + return token; +} + +#include <lemonflex-tail.inc> diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c new file mode 100644 index 0000000000..24b1b93f80 --- /dev/null +++ b/epan/dfilter/semcheck.c @@ -0,0 +1,472 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "sttype-range.h" +#include "sttype-test.h" + +#include "exceptions.h" + +static void +semcheck(dfwork_t *dfw, stnode_t *st_node); + +typedef gboolean (*FtypeCanFunc)(enum ftenum); + +/* Compares to ftenum_t's and decides if they're + * compatible or not (if they're the same basic type) */ +static gboolean +compatible_ftypes(ftenum_t a, ftenum_t b) +{ + switch (a) { + case FT_NONE: + case FT_PROTOCOL: + case FT_DOUBLE: + case FT_ABSOLUTE_TIME: + case FT_RELATIVE_TIME: + case FT_IPv4: + case FT_IPv6: + case FT_IPXNET: + return a == b; + + case FT_ETHER: + case FT_BYTES: + return (b == FT_ETHER || b == FT_BYTES); + + case FT_BOOLEAN: + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + switch (b) { + case FT_BOOLEAN: + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + return TRUE; + default: + return FALSE; + } + + case FT_STRING: + case FT_STRINGZ: + case FT_UINT_STRING: + switch (b) { + case FT_STRING: + case FT_STRINGZ: + case FT_UINT_STRING: + return TRUE; + default: + return FALSE; + } + + case FT_NUM_TYPES: + g_assert_not_reached(); + } + + g_assert_not_reached(); + return FALSE; +} + +/* Creates a FT_UINT32 fvalue with a given value. */ +static fvalue_t* +mk_uint32_fvalue(guint32 val) +{ + fvalue_t *fv; + + fv = fvalue_new(FT_UINT32); + fvalue_set_integer(fv, val); + + return fv; +} + + +/* Try to make an fvalue from a string using a value_string or true_false_string. + * This works only for ftypes that are integers. Returns the created fvalue_t* + * or NULL if impossible. */ +static fvalue_t* +mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) +{ + static true_false_string default_tf = { "True", "False" }; + true_false_string *tf = &default_tf; + value_string *vals; + + /* Early return? */ + switch(hfinfo->type) { + case FT_NONE: + case FT_PROTOCOL: + case FT_DOUBLE: + case FT_ABSOLUTE_TIME: + case FT_RELATIVE_TIME: + case FT_IPv4: + case FT_IPv6: + case FT_IPXNET: + case FT_ETHER: + case FT_BYTES: + case FT_STRING: + case FT_STRINGZ: + case FT_UINT_STRING: + return FALSE; + + case FT_BOOLEAN: + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + break; + + case FT_NUM_TYPES: + g_assert_not_reached(); + } + + /* Reset the dfilter error message, since *something* interesting + * will happen, and the error message will be more interesting than + * any error message I happen to have now. */ + dfilter_error_msg = NULL; + + /* TRUE/FALSE *always* exist for FT_BOOLEAN. */ + if (hfinfo->type == FT_BOOLEAN) { + if (hfinfo->strings) { + tf = hfinfo->strings; + } + + if (strcasecmp(s, tf->true_string) == 0) { + return mk_uint32_fvalue(TRUE); + } + else if (strcasecmp(s, tf->false_string) == 0) { + return mk_uint32_fvalue(FALSE); + } + else { + dfilter_fail("\"%s\" cannot be found among the possible values for %s.", + s, hfinfo->abbrev); + return NULL; + } + } + + /* Do val_strings exist? */ + if (!hfinfo->strings) { + dfilter_fail("%s cannot accept strings as values.", + hfinfo->abbrev); + return FALSE; + } + + vals = hfinfo->strings; + while (vals->strptr != NULL) { + if (strcasecmp(s, vals->strptr) == 0) { + return mk_uint32_fvalue(vals->value); + } + vals++; + } + dfilter_fail("\"%s\" cannot be found among the possible values for %s.", + s, hfinfo->abbrev); + return FALSE; +} + + +static gboolean +is_bytes_type(enum ftenum type) +{ + switch(type) { + case FT_ETHER: + case FT_BYTES: + case FT_IPv6: + return TRUE; + + case FT_NONE: + case FT_PROTOCOL: + case FT_DOUBLE: + case FT_ABSOLUTE_TIME: + case FT_RELATIVE_TIME: + case FT_IPv4: + case FT_IPXNET: + case FT_STRING: + case FT_STRINGZ: + case FT_UINT_STRING: + case FT_BOOLEAN: + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + return FALSE; + + case FT_NUM_TYPES: + g_assert_not_reached(); + } + + g_assert_not_reached(); + return FALSE; +} + +/* This could really be split up... it's too big. */ +static void +check_relation(dfwork_t *dfw, FtypeCanFunc can_func, stnode_t *st_node, + stnode_t *st_arg1, stnode_t *st_arg2) +{ + stnode_t *new_st; + sttype_id_t type1, type2; + header_field_info *hfinfo1, *hfinfo2; + ftenum_t ftype1, ftype2; + fvalue_t *fvalue; + char *s; + + type1 = stnode_type_id(st_arg1); + type2 = stnode_type_id(st_arg2); + if (type1 == STTYPE_FIELD) { + hfinfo1 = stnode_data(st_arg1); + ftype1 = hfinfo1->type; + + if (!can_func(ftype1)) { + dfilter_fail("%s (type=%s) cannot participate in specified comparison.", + hfinfo1->abbrev, ftype_pretty_name(ftype1)); + THROW(TypeError); + } + + + if (type2 == STTYPE_FIELD) { + hfinfo2 = stnode_data(st_arg2); + ftype2 = hfinfo2->type; + + if (!compatible_ftypes(ftype1, ftype2)) { + dfilter_fail("%s and %s are not of compatible types.", + hfinfo1->abbrev, hfinfo2->abbrev); + THROW(TypeError); + } + /* Do this check even though you'd think that if + * they're compatible, then can_func() would pass. */ + if (!can_func(ftype2)) { + dfilter_fail("%s (type=%s) cannot participate in specified comparison.", + hfinfo2->abbrev, ftype_pretty_name(ftype2)); + THROW(TypeError); + } + } + else if (type2 == STTYPE_STRING) { + s = stnode_data(st_arg2); + fvalue = fvalue_from_string(ftype1, s, dfilter_fail); + if (!fvalue) { + /* check value_string */ + fvalue = mk_fvalue_from_val_string(hfinfo1, s); + if (!fvalue) { + THROW(TypeError); + } + } + + new_st = stnode_new(STTYPE_FVALUE, fvalue); + sttype_test_set2_args(st_node, st_arg1, new_st); + stnode_free(st_arg2); + } + else if (type2 == STTYPE_RANGE) { + if (!is_bytes_type(ftype1)) { + if (!ftype_can_slice(ftype1)) { + dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", + hfinfo1->abbrev, + ftype_pretty_name(ftype1)); + THROW(TypeError); + } + + /* Convert entire field to bytes */ + new_st = stnode_new(STTYPE_RANGE, NULL); + + /* st_arg1 is freed in this step */ + sttype_range_set(new_st, st_arg1, NULL, NULL); + + sttype_test_set2_args(st_node, new_st, st_arg2); + } + } + else { + g_assert_not_reached(); + } + } + else if (type1 == STTYPE_STRING) { + + if (type2 == STTYPE_FIELD) { + hfinfo2 = stnode_data(st_arg2); + ftype2 = hfinfo2->type; + + s = stnode_data(st_arg1); + fvalue = fvalue_from_string(ftype2, s, dfilter_fail); + if (!fvalue) { + /* check value_string */ + fvalue = mk_fvalue_from_val_string(hfinfo2, s); + if (!fvalue) { + THROW(TypeError); + } + } + + new_st = stnode_new(STTYPE_FVALUE, fvalue); + sttype_test_set2_args(st_node, new_st, st_arg2); + stnode_free(st_arg1); + } + else if (type2 == STTYPE_STRING) { + /* Well now that's silly... */ + dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.", + stnode_data(st_arg1), + stnode_data(st_arg2)); + THROW(TypeError); + } + else if (type2 == STTYPE_RANGE) { + s = stnode_data(st_arg1); + fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail); + if (!fvalue) { + THROW(TypeError); + } + new_st = stnode_new(STTYPE_FVALUE, fvalue); + sttype_test_set2_args(st_node, new_st, st_arg2); + stnode_free(st_arg1); + } + else { + g_assert_not_reached(); + } + } + else if (type1 == STTYPE_RANGE) { + hfinfo1 = sttype_range_hfinfo(st_arg1); + ftype1 = hfinfo1->type; + + if (!ftype_can_slice(ftype1)) { + dfilter_fail("\"%s\" is a %s and cannot be sliced into a sequence of bytes.", + hfinfo1->abbrev, ftype_pretty_name(ftype1)); + THROW(TypeError); + } + + + if (type2 == STTYPE_FIELD) { + hfinfo2 = sttype_range_hfinfo(st_arg2); + ftype2 = hfinfo2->type; + + if (!is_bytes_type(ftype2)) { + if (!ftype_can_slice(ftype2)) { + dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", + hfinfo2->abbrev, + ftype_pretty_name(ftype2)); + THROW(TypeError); + } + + /* Convert entire field to bytes */ + new_st = stnode_new(STTYPE_RANGE, NULL); + + /* st_arg2 is freed in this step */ + sttype_range_set(new_st, st_arg2, NULL, NULL); + + sttype_test_set2_args(st_node, st_arg1, new_st); + } + } + else if (type2 == STTYPE_STRING) { + s = stnode_data(st_arg2); + fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail); + if (!fvalue) { + THROW(TypeError); + } + new_st = stnode_new(STTYPE_FVALUE, fvalue); + sttype_test_set2_args(st_node, st_arg1, new_st); + stnode_free(st_arg2); + } + else if (type2 == STTYPE_RANGE) { + /* XXX - check lengths of both ranges */ + } + else { + g_assert_not_reached(); + } + } + else { + g_assert_not_reached(); + } +} + +static void +check_test(dfwork_t *dfw, stnode_t *st_node) +{ + test_op_t st_op; + stnode_t *st_arg1, *st_arg2; + + sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2); + + switch (st_op) { + case TEST_OP_UNINITIALIZED: + g_assert_not_reached(); + break; + + case TEST_OP_EXISTS: + /* nothing */ + break; + + case TEST_OP_NOT: + semcheck(dfw, st_arg1); + break; + + case TEST_OP_AND: + case TEST_OP_OR: + semcheck(dfw, st_arg1); + semcheck(dfw, st_arg2); + break; + + case TEST_OP_EQ: + check_relation(dfw, ftype_can_eq, st_node, st_arg1, st_arg2); + break; + case TEST_OP_NE: + check_relation(dfw, ftype_can_ne, st_node, st_arg1, st_arg2); + break; + case TEST_OP_GT: + check_relation(dfw, ftype_can_gt, st_node, st_arg1, st_arg2); + break; + case TEST_OP_GE: + check_relation(dfw, ftype_can_ge, st_node, st_arg1, st_arg2); + break; + case TEST_OP_LT: + check_relation(dfw, ftype_can_lt, st_node, st_arg1, st_arg2); + break; + case TEST_OP_LE: + check_relation(dfw, ftype_can_le, st_node, st_arg1, st_arg2); + break; + } +} + + +static void +semcheck(dfwork_t *dfw, stnode_t *st_node) +{ + const char *name; + + name = stnode_type_name(st_node); + + switch (stnode_type_id(st_node)) { + case STTYPE_TEST: + check_test(dfw, st_node); + break; + default: + g_assert_not_reached(); + } +} + + +gboolean +dfw_semcheck(dfwork_t *dfw) +{ + TRY { + semcheck(dfw, dfw->st_root); + } + CATCH(TypeError) { + return FALSE; + } + ENDTRY; + + return TRUE; +} diff --git a/epan/dfilter/semcheck.h b/epan/dfilter/semcheck.h new file mode 100644 index 0000000000..54f795dfe4 --- /dev/null +++ b/epan/dfilter/semcheck.h @@ -0,0 +1,10 @@ +#ifndef SEMCHECK_H +#define SEMCHECK_H + + + +gboolean +dfw_semcheck(dfwork_t *dfw); + + +#endif diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c new file mode 100644 index 0000000000..64a49658f2 --- /dev/null +++ b/epan/dfilter/sttype-pointer.c @@ -0,0 +1,28 @@ +/* $Id: sttype-pointer.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ftypes/ftypes.h" +#include "syntax-tree.h" + +void +sttype_register_pointer(void) +{ + static sttype_t field_type = { + STTYPE_FIELD, + "FIELD", + NULL, + NULL, + }; + static sttype_t fvalue_type = { + STTYPE_FVALUE, + "FVALUE", + NULL, + NULL, + }; + + sttype_register(&field_type); + sttype_register(&fvalue_type); +} diff --git a/epan/dfilter/sttype-range.c b/epan/dfilter/sttype-range.c new file mode 100644 index 0000000000..12bada4cc4 --- /dev/null +++ b/epan/dfilter/sttype-range.c @@ -0,0 +1,174 @@ +/* $Id: sttype-range.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +/* The ideas in this code came from Ed Warnicke's original implementation + * of dranges for the old display filter code (Ethereal 0.8.15 and before). + * The code is different, but definitely inspired by his code. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <errno.h> +#include "proto.h" +#include "sttype-range.h" + +typedef struct { + guint32 magic; + header_field_info *hfinfo; + gint start; + gint end; + char *start_error; + char *end_error; +} range_t; + +#define RANGE_MAGIC 0xec0990ce + +static gpointer +range_new(gpointer junk) +{ + range_t *range; + + g_assert(junk == NULL); + + range = g_new(range_t, 1); + + range->magic = RANGE_MAGIC; + range->hfinfo = NULL; + range->start = 0; + range->end = -1; + range->start_error = NULL; + range->end_error = NULL; + + return (gpointer) range; +} + +static void +range_free(gpointer value) +{ + range_t *range = value; + assert_magic(range, RANGE_MAGIC); + + if (range->start_error) + g_free(range->start_error); + if (range->end_error) + g_free(range->end_error); + + g_free(range); +} + +static gint +string_to_gint(char *s, gboolean *success) +{ + char *endptr; + gint val; + + *success = TRUE; + val = strtol(s, &endptr, 0); + + if (endptr == s || *endptr != '\0') { + *success = FALSE; + } + else if (errno == ERANGE) { + *success = FALSE; + } + + return val; +} + +static void +range_set(stnode_t *node, stnode_t *field, char *start, char *end) +{ + range_t *range; + gboolean success; + + range = stnode_data(node); + assert_magic(range, RANGE_MAGIC); + + range->hfinfo = stnode_data(field); + stnode_free(field); + + if (start) { + range->start = string_to_gint(start, &success); + if (!success) { + /* Save the error-causing string for later reporting */ + range->start_error = g_strdup(start); + } + } + else { + range->start = 0; + } + + if (end) { + range->end = string_to_gint(end, &success); + + if (!success) { + /* Save the error-causing string for later reporting */ + range->end_error = g_strdup(end); + } + } + else { + range->end = G_MAXINT; + } +} + +void +sttype_range_set(stnode_t *node, stnode_t *field, stnode_t *start, stnode_t *end) +{ + char *start_str, *end_str; + + if (start) { + start_str = stnode_data(start); + } + else { + start_str = NULL; + } + + if (end) { + end_str = stnode_data(end); + } + else { + end_str = NULL; + } + + range_set(node, field, start_str, end_str); + + if (start) + stnode_free(start); + if (end) + stnode_free(end); +} + +void +sttype_range_set1(stnode_t *node, stnode_t *field, stnode_t *offset) +{ + char *offset_str; + + g_assert(offset); + + offset_str = stnode_data(offset); + range_set(node, field, offset_str, "1"); + stnode_free(offset); +} + + +STTYPE_ACCESSOR(header_field_info*, range, hfinfo, RANGE_MAGIC) +STTYPE_ACCESSOR(gint, range, start, RANGE_MAGIC) +STTYPE_ACCESSOR(gint, range, end, RANGE_MAGIC) +STTYPE_ACCESSOR(char*, range, start_error, RANGE_MAGIC) +STTYPE_ACCESSOR(char*, range, end_error, RANGE_MAGIC) + + +void +sttype_register_range(void) +{ + static sttype_t range_type = { + STTYPE_RANGE, + "RANGE", + range_new, + range_free, + }; + + sttype_register(&range_type); +} diff --git a/epan/dfilter/sttype-range.h b/epan/dfilter/sttype-range.h new file mode 100644 index 0000000000..aff39c84b5 --- /dev/null +++ b/epan/dfilter/sttype-range.h @@ -0,0 +1,20 @@ +#ifndef STTYPE_RANGE_H +#define STTYPE_RANGE_H + +#include "syntax-tree.h" + +STTYPE_ACCESSOR_PROTOTYPE(header_field_info*, range, hfinfo) +STTYPE_ACCESSOR_PROTOTYPE(gint, range, start) +STTYPE_ACCESSOR_PROTOTYPE(gint, range, end) +STTYPE_ACCESSOR_PROTOTYPE(char*, range, start_error) +STTYPE_ACCESSOR_PROTOTYPE(char*, range, end_error) + +/* Set a range, [x:y], [:y], [x:] */ +void +sttype_range_set(stnode_t *node, stnode_t *field, stnode_t *start, stnode_t *end); + +/* Set a single-byte lookup, [x] */ +void +sttype_range_set1(stnode_t *node, stnode_t *field, stnode_t *offset); + +#endif diff --git a/epan/dfilter/sttype-string.c b/epan/dfilter/sttype-string.c new file mode 100644 index 0000000000..c19797844d --- /dev/null +++ b/epan/dfilter/sttype-string.c @@ -0,0 +1,29 @@ +/* $Id: sttype-string.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +#include "syntax-tree.h" + +static gpointer +string_new(gpointer string) +{ + return (gpointer) g_strdup((char*) string); +} + +static void +string_free(gpointer value) +{ + g_free(value); +} + + +void +sttype_register_string(void) +{ + static sttype_t string_type = { + STTYPE_STRING, + "STRING", + string_new, + string_free, + }; + + sttype_register(&string_type); +} diff --git a/epan/dfilter/sttype-test.c b/epan/dfilter/sttype-test.c new file mode 100644 index 0000000000..90b07048e0 --- /dev/null +++ b/epan/dfilter/sttype-test.c @@ -0,0 +1,144 @@ +/* $Id: sttype-test.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */ + +#include "syntax-tree.h" +#include "sttype-test.h" + +typedef struct { + guint32 magic; + test_op_t op; + stnode_t *val1; + stnode_t *val2; +} test_t; + +#define TEST_MAGIC 0xab9009ba + +static gpointer +test_new(gpointer junk) +{ + test_t *test; + + g_assert(junk == NULL); + + test = g_new(test_t, 1); + + test->magic = TEST_MAGIC; + test->op = TEST_OP_UNINITIALIZED; + test->val1 = NULL; + test->val2 = NULL; + + return (gpointer) test; +} + +static void +test_free(gpointer value) +{ + test_t *test = value; + assert_magic(test, TEST_MAGIC); + + if (test->val1) + stnode_free(test->val1); + if (test->val2) + stnode_free(test->val2); + + g_free(test); +} + +static int +num_operands(test_op_t op) +{ + switch(op) { + case TEST_OP_UNINITIALIZED: + g_assert_not_reached(); + case TEST_OP_EXISTS: + return 1; + case TEST_OP_NOT: + return 1; + case TEST_OP_AND: + return 2; + case TEST_OP_OR: + return 2; + case TEST_OP_EQ: + return 2; + case TEST_OP_NE: + return 2; + case TEST_OP_GT: + return 2; + case TEST_OP_GE: + return 2; + case TEST_OP_LT: + return 2; + case TEST_OP_LE: + return 2; + } + g_assert_not_reached(); + return -1; +} + + +void +sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1) +{ + test_t *test; + + test = stnode_data(node); + assert_magic(test, TEST_MAGIC); + + g_assert(num_operands(op) == 1); + test->op = op; + test->val1 = val1; +} + +void +sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2) +{ + test_t *test; + + test = stnode_data(node); + assert_magic(test, TEST_MAGIC); + + g_assert(num_operands(op) == 2); + test->op = op; + test->val1 = val1; + test->val2 = val2; +} + +void +sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2) +{ + test_t *test; + + test = stnode_data(node); + assert_magic(test, TEST_MAGIC); + + if (num_operands(test->op) == 1) { + g_assert(val2 == NULL); + } + test->val1 = val1; + test->val2 = val2; +} + +void +sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2) +{ + test_t *test; + + test = stnode_data(node); + assert_magic(test, TEST_MAGIC); + + *p_op = test->op; + *p_val1 = test->val1; + *p_val2 = test->val2; +} + +void +sttype_register_test(void) +{ + static sttype_t test_type = { + STTYPE_TEST, + "TEST", + test_new, + test_free, + }; + + sttype_register(&test_type); +} diff --git a/epan/dfilter/sttype-test.h b/epan/dfilter/sttype-test.h new file mode 100644 index 0000000000..69765df9e3 --- /dev/null +++ b/epan/dfilter/sttype-test.h @@ -0,0 +1,30 @@ +#ifndef STTYPE_TEST_H +#define STTYPE_TEST_H + +typedef enum { + TEST_OP_UNINITIALIZED, + TEST_OP_EXISTS, + TEST_OP_NOT, + TEST_OP_AND, + TEST_OP_OR, + TEST_OP_EQ, + TEST_OP_NE, + TEST_OP_GT, + TEST_OP_GE, + TEST_OP_LT, + TEST_OP_LE +} test_op_t; + +void +sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1); + +void +sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2); + +void +sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2); + +void +sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2); + +#endif diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c new file mode 100644 index 0000000000..238f685d84 --- /dev/null +++ b/epan/dfilter/syntax-tree.c @@ -0,0 +1,169 @@ +/* syntax-tree.c + * + * $Id: syntax-tree.c,v 1.1 2001/02/01 20:21:18 gram Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "syntax-tree.h" + +/* Keep track of sttype_t's via their sttype_id_t number */ +static sttype_t* type_list[STTYPE_NUM_TYPES]; + +/* These are the sttype_t registration function prototypes. */ +void sttype_register_pointer(void); +void sttype_register_range(void); +void sttype_register_string(void); +void sttype_register_test(void); + + +#define STNODE_MAGIC 0xe9b00b9e + + +void +sttype_init(void) +{ + sttype_register_pointer(); + sttype_register_range(); + sttype_register_string(); + sttype_register_test(); +} + +void +sttype_cleanup(void) +{ + /* nothing to do */ +} + + +void +sttype_register(sttype_t *type) +{ + sttype_id_t type_id; + + type_id = type->id; + + /* Check input */ + g_assert(type_id >= 0); + g_assert(type_id < STTYPE_NUM_TYPES); + + /* Don't re-register. */ + g_assert(type_list[type_id] == NULL); + + type_list[type_id] = type; +} + +static sttype_t* +sttype_lookup(sttype_id_t type_id) +{ + sttype_t *result; + + /* Check input */ + g_assert(type_id >= 0); + g_assert(type_id < STTYPE_NUM_TYPES); + + result = type_list[type_id]; + + /* Check output. */ + g_assert(result != NULL); + + return result; +} + + +stnode_t* +stnode_new(sttype_id_t type_id, gpointer data) +{ + sttype_t *type; + stnode_t *node; + + node = g_new(stnode_t, 1); + node->magic = STNODE_MAGIC; + + if (type_id == STTYPE_UNINITIALIZED) { + node->type = NULL; + node->data = NULL; + } + else { + type = sttype_lookup(type_id); + g_assert(type); + node->type = type; + if (type->func_new) { + node->data = type->func_new(data); + } + else { + node->data = data; + } + + } + + return node; +} + +void +stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data) +{ + sttype_t *type; + + assert_magic(node, STNODE_MAGIC); + g_assert(!node->type); + g_assert(!node->data); + + type = sttype_lookup(type_id); + g_assert(type); + node->type = type; + if (type->func_new) { + node->data = type->func_new(data); + } + else { + node->data = data; + } +} + +void +stnode_free(stnode_t *node) +{ + assert_magic(node, STNODE_MAGIC); + if (node->type) { + if (node->type->func_free) { + node->type->func_free(node->data); + } + } + else { + g_assert(!node->data); + } + g_free(node); +} + +const char* +stnode_type_name(stnode_t *node) +{ + assert_magic(node, STNODE_MAGIC); + if (node->type) + return node->type->name; + else + return "UNINITIALIZED"; +} + +sttype_id_t +stnode_type_id(stnode_t *node) +{ + assert_magic(node, STNODE_MAGIC); + if (node->type) + return node->type->id; + else + return STTYPE_UNINITIALIZED; +} + +gpointer +stnode_data(stnode_t *node) +{ + assert_magic(node, STNODE_MAGIC); + if (node) + return node->data; + else + return NULL; +} diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h new file mode 100644 index 0000000000..3f60c09f1a --- /dev/null +++ b/epan/dfilter/syntax-tree.h @@ -0,0 +1,95 @@ +/* syntax-tree.h + * + * $Id: syntax-tree.h,v 1.1 2001/02/01 20:21:18 gram Exp $ + * + */ +#ifndef SYNTAX_TREE_H +#define SYNTAX_TREE_H + +#include <glib.h> +#include "cppmagic.h" + +typedef enum { + STTYPE_UNINITIALIZED, + STTYPE_TEST, + STTYPE_STRING, + STTYPE_FIELD, + STTYPE_FVALUE, + STTYPE_RANGE, + STTYPE_NUM_TYPES +} sttype_id_t; + +typedef gpointer (*STTypeNewFunc)(gpointer); +typedef void (*STTypeFreeFunc)(gpointer); + + +/* Type information */ +typedef struct { + sttype_id_t id; + const char *name; + STTypeNewFunc func_new; + STTypeFreeFunc func_free; +} sttype_t; + +/* Node (type instance) information */ +typedef struct { + guint32 magic; + sttype_t *type; + gpointer data; + +} stnode_t; + +void +sttype_init(void); + +void +sttype_cleanup(void); + +void +sttype_register(sttype_t *type); + +stnode_t* +stnode_new(sttype_id_t type_id, gpointer data); + +void +stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data); + +void +stnode_free(stnode_t *node); + +const char* +stnode_type_name(stnode_t *node); + +sttype_id_t +stnode_type_id(stnode_t *node); + +gpointer +stnode_data(stnode_t *node); + +#define assert_magic(obj, mnum) \ + g_assert((obj)); \ + if ((obj)->magic != (mnum)) { \ + g_print("\nMagic num is 0x%08x, but should be 0x%08x", \ + (obj)->magic, (mnum)); \ + g_assert((obj)->magic == (mnum)); \ + } + + + + +#define STTYPE_ACCESSOR(ret,type,attr,magicnum) \ + ret \ + CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node) \ +{\ + CONCAT(type,_t) *value; \ + value = stnode_data(node);\ + assert_magic(value, magicnum); \ + return value->attr; \ +} + +#define STTYPE_ACCESSOR_PROTOTYPE(ret,type,attr) \ + ret \ + CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node); + + +#endif diff --git a/epan/epan.c b/epan/epan.c index 74f89d9b15..7ebf350f12 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -1,6 +1,6 @@ /* epan.h * - * $Id: epan.c,v 1.5 2001/01/26 06:14:50 guy Exp $ + * $Id: epan.c,v 1.6 2001/02/01 20:21:16 gram Exp $ * * Ethereal Protocol Analyzer Library * @@ -14,7 +14,7 @@ #include <epan.h> #include "conversation.h" -#include "dfilter.h" +#include "dfilter/dfilter.h" #include "except.h" #include "packet.h" #include "proto.h" @@ -69,11 +69,6 @@ epan_conversation_init(void) } -struct epan_dissect { - - tvbuff_t *tvb; - proto_tree *tree; -}; epan_dissect_t* epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, proto_tree *tree) @@ -83,6 +78,8 @@ epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, proto_ edt = g_new(epan_dissect_t, 1); /* XXX - init tree */ + edt->tree = tree; + dissect_packet(&edt->tvb, pseudo_header, data, fd, tree); return edt; diff --git a/epan/epan.h b/epan/epan.h index 3c6a921206..9f94865f2e 100644 --- a/epan/epan.h +++ b/epan/epan.h @@ -1,6 +1,6 @@ /* epan.h * - * $Id: epan.h,v 1.4 2000/10/16 23:17:39 guy Exp $ + * $Id: epan.h,v 1.5 2001/02/01 20:21:16 gram Exp $ * * Ethereal Protocol Analyzer Library * @@ -44,7 +44,10 @@ epan_free(epan_t*); * as the structures that the epan_dissect_t contains might have pointers * to addresses in your byte array. */ -typedef struct epan_dissect epan_dissect_t; +typedef struct { + tvbuff_t *tvb; + proto_tree *tree; +} epan_dissect_t; epan_dissect_t* epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, proto_tree *tree); diff --git a/epan/exceptions.h b/epan/exceptions.h index 19eda9fe2b..54932dd2f5 100644 --- a/epan/exceptions.h +++ b/epan/exceptions.h @@ -11,6 +11,7 @@ /* Ethereal's exceptions */ #define BoundsError 1 /* Index is out of range */ #define ReportedBoundsError 2 /* Index is beyond reported length (not cap_len) */ +#define TypeError 3 /* During dfilter parsing */ /* Usage: * diff --git a/epan/ftypes/.cvsignore b/epan/ftypes/.cvsignore new file mode 100644 index 0000000000..601c4fbff4 --- /dev/null +++ b/epan/ftypes/.cvsignore @@ -0,0 +1,4 @@ +.cvsignore +.deps +Makefile +Makefile.in diff --git a/epan/ftypes/Makefile.am b/epan/ftypes/Makefile.am new file mode 100644 index 0000000000..3af23be17c --- /dev/null +++ b/epan/ftypes/Makefile.am @@ -0,0 +1,52 @@ +# Makefile.am +# Automake file for the GTK interface routines for Ethereal +# +# $Id: Makefile.am,v 1.1 2001/02/01 20:21:19 gram Exp $ +# +# Ethereal - Network traffic analyzer +# By Gerald Combs <gerald@zing.org> +# Copyright 1998 Gerald Combs +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# We produce an archive library. In the future, when libethereal is a +# shared library, this will be linked into libethereal. While libethereal +# is an archive library, any executable linking against libethereal will +# also need to link against libftypes. +noinst_LIBRARIES = libftypes.a + +CLEANFILES = \ + libftypes.a \ + *~ + +INCLUDES = -I$(srcdir)/../.. + +libftypes_a_SOURCES = \ + ftypes.c \ + ftypes.h \ + ftypes-int.h \ + ftype-bytes.c \ + ftype-double.c \ + ftype-integer.c \ + ftype-ipv4.c \ + ftype-none.c \ + ftype-string.c \ + ftype-time.c \ + ftype-tvbuff.c + +#EXTRA_DIST = \ +# Makefile.nmake + diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c new file mode 100644 index 0000000000..726bbbd707 --- /dev/null +++ b/epan/ftypes/ftype-bytes.c @@ -0,0 +1,386 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> +#include <string.h> +#include <ctype.h> +#include "resolv.h" + +#define ETHER_LEN 6 +#define IPv6_LEN 16 + +static void +ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length, + gboolean little_endian) +{ + /* XXX */ + g_assert_not_reached(); +} + + +static void +bytes_fvalue_new(fvalue_t *fv) +{ + fv->value.bytes = NULL; +} + +void +bytes_fvalue_free(fvalue_t *fv) +{ + if (fv->value.bytes) { + g_byte_array_free(fv->value.bytes, TRUE); + } +} + + +static void +bytes_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + g_assert(already_copied); + fv->value.bytes = value; +} + +static void +common_fvalue_set(fvalue_t *fv, guint8* data, guint len) +{ + fv->value.bytes = g_byte_array_new(); + g_byte_array_append(fv->value.bytes, data, len); +} + +static void +ether_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + g_assert(!already_copied); + common_fvalue_set(fv, value, ETHER_LEN); +} + +static void +ipv6_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + g_assert(!already_copied); + common_fvalue_set(fv, value, IPv6_LEN); +} + +static gpointer +value_get(fvalue_t *fv) +{ + return fv->value.bytes->data; +} + +static gboolean +is_byte_sep(guint8 c) +{ + return (c == '-' || c == ':' || c == '.'); +} + +static gboolean +val_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + GByteArray *bytes; + guint8 val; + char *p, *q, *punct; + char two_digits[3]; + char one_digit[2]; + gboolean fail = FALSE; + + bytes = g_byte_array_new(); + + p = s; + while (*p) { + q = p+1; + if (*q && isxdigit(*p) && isxdigit(*q)) { + two_digits[0] = *p; + two_digits[1] = *q; + two_digits[2] = '\0'; + + val = (guint8) strtoul(two_digits, NULL, 16); + g_byte_array_append(bytes, &val, 1); + punct = q + 1; + if (*punct) { + if (is_byte_sep(*punct)) { + p = punct + 1; + continue; + } + else { + fail = TRUE; + break; + } + } + else { + p = punct; + continue; + } + } + else if (*q && isxdigit(*p) && is_byte_sep(*q)) { + one_digit[0] = *p; + one_digit[1] = '\0'; + + val = (guint8) strtoul(one_digit, NULL, 16); + g_byte_array_append(bytes, &val, 1); + p = q + 1; + continue; + } + else if (!*q && isxdigit(*p)) { + one_digit[0] = *p; + one_digit[1] = '\0'; + + val = (guint8) strtoul(one_digit, NULL, 16); + g_byte_array_append(bytes, &val, 1); + p = q; + continue; + } + else { + fail = TRUE; + break; + } + } + + if (fail) { + g_byte_array_free(bytes, TRUE); + return FALSE; + } + + fv->value.bytes = bytes; + + + return TRUE; +} + +static gboolean +ether_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + guint8 *mac; + + if (val_from_string(fv, s, log)) { + return TRUE; + } + + mac = get_ether_addr(s); + if (!mac) { + return FALSE; + } + + ether_fvalue_set(fv, mac, FALSE); + return TRUE; +} + +static gboolean +ipv6_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + guint8 buffer[16]; + + if (!get_host_ipaddr6(s, (struct e_in6_addr*)buffer)) { + return FALSE; + } + + ipv6_fvalue_set(fv, buffer, FALSE); + return TRUE; +} + +static guint +len(fvalue_t *fv) +{ + return fv->value.bytes->len; +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length) +{ + guint8* data; + + data = fv->value.bytes->data + offset; + + g_byte_array_append(bytes, data, length); +} + + +static gboolean +cmp_eq(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (a->len != b->len) { + return FALSE; + } + + return (memcmp(a->data, b->data, a->len) == 0); +} + + +static gboolean +cmp_ne(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (a->len != b->len) { + return FALSE; + } + + return (memcmp(a->data, b->data, a->len) != 0); +} + + +static gboolean +cmp_gt(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (a->len > b->len) { + return TRUE; + } + + if (a->len < b->len) { + return FALSE; + } + + return (memcmp(a->data, b->data, a->len) > 0); +} + +static gboolean +cmp_ge(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (a->len > b->len) { + return TRUE; + } + + if (a->len < b->len) { + return FALSE; + } + + return (memcmp(a->data, b->data, a->len) >= 0); +} + +static gboolean +cmp_lt(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (a->len < b->len) { + return TRUE; + } + + if (a->len > b->len) { + return FALSE; + } + + return (memcmp(a->data, b->data, a->len) < 0); +} + +static gboolean +cmp_le(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (a->len < b->len) { + return TRUE; + } + + if (a->len > b->len) { + return FALSE; + } + + return (memcmp(a->data, b->data, a->len) <= 0); +} + +void +ftype_register_bytes(void) +{ + + static ftype_t bytes_type = { + "FT_BYTES", + "sequence of bytes", + 0, + bytes_fvalue_new, + bytes_fvalue_free, + ftype_from_tvbuff, + val_from_string, + + bytes_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + + len, + slice, + }; + + static ftype_t ether_type = { + "FT_ETHER", + "Ethernet or other MAC address", + ETHER_LEN, + bytes_fvalue_new, + bytes_fvalue_free, + ftype_from_tvbuff, + ether_from_string, + + ether_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + + len, + slice, + }; + + static ftype_t ipv6_type = { + "FT_IPv6", + "IPv6 address", + IPv6_LEN, + bytes_fvalue_new, + bytes_fvalue_free, + ftype_from_tvbuff, + ipv6_from_string, + + ipv6_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + + len, + slice, + }; + + ftype_register(FT_BYTES, &bytes_type); + ftype_register(FT_ETHER, ðer_type); + ftype_register(FT_IPv6, &ipv6_type); +} diff --git a/epan/ftypes/ftype-double.c b/epan/ftypes/ftype-double.c new file mode 100644 index 0000000000..146794a597 --- /dev/null +++ b/epan/ftypes/ftype-double.c @@ -0,0 +1,133 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> +#include <stdlib.h> +#include <math.h> +#include <errno.h> + +static void +ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length, + gboolean little_endian) +{ + /* XXX */ + g_assert_not_reached(); +} + + +static void +double_fvalue_new(fvalue_t *fv) +{ + fv->value.floating = 0.0; +} + +static void +double_fvalue_set_floating(fvalue_t *fv, gdouble value) +{ + fv->value.floating = value; +} + +static double +value_get_floating(fvalue_t *fv) +{ + return fv->value.floating; +} + +static gboolean +val_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + char *endptr = NULL; + + fv->value.floating = strtod(s, &endptr); + + if (endptr == s || *endptr != '\0') { + /* This isn't a valid number. */ + log("\"%s\" is not a valid number.", s); + return FALSE; + } + if (errno == ERANGE) { + if (fv->value.floating == 0) { + log("\"%s\" causes floating-point underflow.", s); + } + else if (fv->value.floating == HUGE_VAL) { + log("\"%s\" causes floating-point overflow.", s); + } + else { + log("\"%s\" is not a valid floating-point number.", s); + } + return FALSE; + } + + return TRUE; +} + + +static gboolean +cmp_eq(fvalue_t *a, fvalue_t *b) +{ + return a->value.floating == b->value.floating; +} + +static gboolean +cmp_ne(fvalue_t *a, fvalue_t *b) +{ + return a->value.floating != b->value.floating; +} + +static gboolean +cmp_gt(fvalue_t *a, fvalue_t *b) +{ + return a->value.floating > b->value.floating; +} + +static gboolean +cmp_ge(fvalue_t *a, fvalue_t *b) +{ + return a->value.floating >= b->value.floating; +} + +static gboolean +cmp_lt(fvalue_t *a, fvalue_t *b) +{ + return a->value.floating < b->value.floating; +} + +static gboolean +cmp_le(fvalue_t *a, fvalue_t *b) +{ + return a->value.floating <= b->value.floating; +} + +void +ftype_register_double(void) +{ + + static ftype_t double_type = { + "FT_DOUBLE", + "floating point", + 0, + double_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + NULL, + double_fvalue_set_floating, + + NULL, + NULL, + value_get_floating, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + }; + + ftype_register(FT_DOUBLE, &double_type); +} diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c new file mode 100644 index 0000000000..cef237c7ed --- /dev/null +++ b/epan/ftypes/ftype-integer.c @@ -0,0 +1,417 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#ifdef NEED_SNPRINTF_H +#include "snprintf.h" +#endif + +#include <stdlib.h> +#include <errno.h> +#include "ftypes-int.h" +#include "resolv.h" + + +static void +ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length, + gboolean little_endian) +{ + /* XXX */ + g_assert_not_reached(); +} + + +static void +int_fvalue_new(fvalue_t *fv) +{ + fv->value.integer = 0; +} + +static void +set_integer(fvalue_t *fv, guint32 value) +{ + fv->value.integer = value; +} + +static guint32 +get_integer(fvalue_t *fv) +{ + return fv->value.integer; +} + +static gboolean +val_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + char *endptr; + + fv->value.integer = strtoul(s, &endptr, 0); + + if (endptr == s || *endptr != '\0') { + /* This isn't a valid number. */ + log("\"%s\" is not a valid number.", s); + return FALSE; + } + if (errno == ERANGE) { + if (fv->value.integer == ULONG_MAX) { + log("\"%s\" causes an integer overflow.", s); + } + else { + log("\"%s\" is not an integer.", s); + } + return FALSE; + } + + return TRUE; +} + +static gboolean +ipxnet_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + guint32 val; + gboolean known; + + if (val_from_string(fv, s, log)) { + return TRUE; + } + + val = get_ipxnet_addr(s, &known); + if (known) { + fv->value.integer = val; + return TRUE; + } + + return FALSE; +} + +static gboolean +cmp_eq(fvalue_t *a, fvalue_t *b) +{ + return a->value.integer == b->value.integer; +} + +static gboolean +cmp_ne(fvalue_t *a, fvalue_t *b) +{ + return a->value.integer != b->value.integer; +} + +static gboolean +u_cmp_gt(fvalue_t *a, fvalue_t *b) +{ + return (int)a->value.integer > (int)b->value.integer; +} + +static gboolean +u_cmp_ge(fvalue_t *a, fvalue_t *b) +{ + return (int)a->value.integer >= (int)b->value.integer; +} + +static gboolean +u_cmp_lt(fvalue_t *a, fvalue_t *b) +{ + return (int)a->value.integer < (int)b->value.integer; +} + +static gboolean +u_cmp_le(fvalue_t *a, fvalue_t *b) +{ + return (int)a->value.integer <= (int)b->value.integer; +} + +static gboolean +s_cmp_gt(fvalue_t *a, fvalue_t *b) +{ + return a->value.integer > b->value.integer; +} + +static gboolean +s_cmp_ge(fvalue_t *a, fvalue_t *b) +{ + return a->value.integer >= b->value.integer; +} + +static gboolean +s_cmp_lt(fvalue_t *a, fvalue_t *b) +{ + return a->value.integer < b->value.integer; +} + +static gboolean +s_cmp_le(fvalue_t *a, fvalue_t *b) +{ + return a->value.integer <= b->value.integer; +} + +/* BOOLEAN-specific */ + +static void +boolean_fvalue_new(fvalue_t *fv) +{ + fv->value.integer = TRUE; +} + + + + + +void +ftype_register_integers(void) +{ + + static ftype_t uint8_type = { + "FT_UINT8", + "unsigned, 1 byte", + 1, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + u_cmp_gt, + u_cmp_ge, + u_cmp_lt, + u_cmp_le, + }; + static ftype_t uint16_type = { + "FT_UINT16", + "unsigned, 2 bytes", + 2, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + u_cmp_gt, + u_cmp_ge, + u_cmp_lt, + u_cmp_le, + }; + static ftype_t uint24_type = { + "FT_UINT24", + "unsigned, 3 bytes", + 3, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + u_cmp_gt, + u_cmp_ge, + u_cmp_lt, + u_cmp_le, + }; + static ftype_t uint32_type = { + "FT_UINT32", + "unsigned, 4 bytes", + 4, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + u_cmp_gt, + u_cmp_ge, + u_cmp_lt, + u_cmp_le, + }; + static ftype_t int8_type = { + "FT_INT8", + "signed, 1 byte", + 1, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + s_cmp_gt, + s_cmp_ge, + s_cmp_lt, + s_cmp_le, + }; + static ftype_t int16_type = { + "FT_INT16", + "signed, 2 bytes", + 2, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + s_cmp_gt, + s_cmp_ge, + s_cmp_lt, + s_cmp_le, + }; + static ftype_t int24_type = { + "FT_INT24", + "signed, 3 bytes", + 3, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + s_cmp_gt, + s_cmp_ge, + s_cmp_lt, + s_cmp_le, + }; + static ftype_t int32_type = { + "FT_INT32", + "signed, 4 bytes", + 4, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + s_cmp_gt, + s_cmp_ge, + s_cmp_lt, + s_cmp_le, + }; + static ftype_t boolean_type = { + "FT_BOOLEAN", + "Boolean", + 0, + boolean_fvalue_new, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + u_cmp_gt, + u_cmp_ge, + u_cmp_lt, + u_cmp_le, + }; + + static ftype_t ipxnet_type = { + "FT_IPXNET", + "IPX network number", + 4, + int_fvalue_new, + NULL, + ftype_from_tvbuff, + ipxnet_from_string, + + NULL, + set_integer, + NULL, + + NULL, + get_integer, + NULL, + + cmp_eq, + cmp_ne, + u_cmp_gt, + u_cmp_ge, + u_cmp_lt, + u_cmp_le, + }; + + + ftype_register(FT_UINT8, &uint8_type); + ftype_register(FT_UINT16, &uint16_type); + ftype_register(FT_UINT24, &uint24_type); + ftype_register(FT_UINT32, &uint32_type); + ftype_register(FT_INT8, &int8_type); + ftype_register(FT_INT16, &int16_type); + ftype_register(FT_INT24, &int24_type); + ftype_register(FT_INT32, &int32_type); + ftype_register(FT_BOOLEAN, &boolean_type); + ftype_register(FT_IPXNET, &ipxnet_type); +} diff --git a/epan/ftypes/ftype-ipv4.c b/epan/ftypes/ftype-ipv4.c new file mode 100644 index 0000000000..eae5677a25 --- /dev/null +++ b/epan/ftypes/ftype-ipv4.c @@ -0,0 +1,114 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> +#include "ipv4.h" +#include "resolv.h" + +static void +ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length, + gboolean little_endian) +{ + /* XXX */ + g_assert_not_reached(); +} + + + +static void +set_integer(fvalue_t *fv, guint32 value) +{ + ipv4_addr_set_net_order_addr(&(fv->value.ipv4), value); + ipv4_addr_set_netmask_bits(&(fv->value.ipv4), 32); +} + +static gpointer +value_get(fvalue_t *fv) +{ + return &(fv->value.ipv4); +} + +static gboolean +val_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + guint32 addr; + + if (!get_host_ipaddr(s, &addr)) { + log("\"%s\" is not a valid hostname or IPv4 address.", s); + return FALSE; + } + ipv4_addr_set_host_order_addr(&(fv->value.ipv4), addr); + /*ipv4_addr_set_netmask_bits(&node->value.ipv4, nmask_bits);*/ + ipv4_addr_set_netmask_bits(&(fv->value.ipv4), 32); + return TRUE; +} + +static gboolean +cmp_eq(fvalue_t *a, fvalue_t *b) +{ + return ipv4_addr_eq(&a->value.ipv4, &b->value.ipv4); +} + +static gboolean +cmp_ne(fvalue_t *a, fvalue_t *b) +{ + return ipv4_addr_ne(&a->value.ipv4, &b->value.ipv4); +} + +static gboolean +cmp_gt(fvalue_t *a, fvalue_t *b) +{ + return ipv4_addr_gt(&a->value.ipv4, &b->value.ipv4); +} + +static gboolean +cmp_ge(fvalue_t *a, fvalue_t *b) +{ + return ipv4_addr_ge(&a->value.ipv4, &b->value.ipv4); +} + +static gboolean +cmp_lt(fvalue_t *a, fvalue_t *b) +{ + return ipv4_addr_lt(&a->value.ipv4, &b->value.ipv4); +} + +static gboolean +cmp_le(fvalue_t *a, fvalue_t *b) +{ + return ipv4_addr_le(&a->value.ipv4, &b->value.ipv4); +} + +void +ftype_register_ipv4(void) +{ + + static ftype_t ipv4_type = { + "FT_IPv4", + "IPv4 address", + 4, + NULL, + NULL, + ftype_from_tvbuff, + val_from_string, + + NULL, + set_integer, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + }; + + ftype_register(FT_IPv4, &ipv4_type); +} diff --git a/epan/ftypes/ftype-none.c b/epan/ftypes/ftype-none.c new file mode 100644 index 0000000000..1bb64a3759 --- /dev/null +++ b/epan/ftypes/ftype-none.c @@ -0,0 +1,20 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> + + +void +ftype_register_none(void) +{ + + static ftype_t none_type = { + "FT_NONE", + "label", + 0, + }; + + ftype_register(FT_NONE, &none_type); +} diff --git a/epan/ftypes/ftype-string.c b/epan/ftypes/ftype-string.c new file mode 100644 index 0000000000..38ce87faa0 --- /dev/null +++ b/epan/ftypes/ftype-string.c @@ -0,0 +1,198 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> +#include <string.h> + +static void +ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length, + gboolean little_endian) +{ + /* XXX */ + g_assert_not_reached(); +} + + +static void +string_fvalue_new(fvalue_t *fv) +{ + fv->value.string = NULL; +} + +static void +string_fvalue_free(fvalue_t *fv) +{ + if (fv->value.string) { + g_free(fv->value.string); + } +} + +static void +string_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + if (already_copied) { + fv->value.string = value; + } + else { + fv->value.string = g_strdup(value); + } +} + +static gpointer +value_get(fvalue_t *fv) +{ + return fv->value.string; +} + +static gboolean +val_from_string(fvalue_t *fv, char *s, LogFunc log) +{ + fv->value.string = g_strdup(s); + return TRUE; +} + +static guint +len(fvalue_t *fv) +{ + return strlen(fv->value.string); +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length) +{ + guint8* data; + + data = fv->value.string + offset; + + g_byte_array_append(bytes, data, length); +} + + +static gboolean +cmp_eq(fvalue_t *a, fvalue_t *b) +{ + return (strcmp(a->value.string, b->value.string) == 0); +} + +static gboolean +cmp_ne(fvalue_t *a, fvalue_t *b) +{ + return (strcmp(a->value.string, b->value.string) != 0); +} + +static gboolean +cmp_gt(fvalue_t *a, fvalue_t *b) +{ + return (strcmp(a->value.string, b->value.string) > 0); +} + +static gboolean +cmp_ge(fvalue_t *a, fvalue_t *b) +{ + return (strcmp(a->value.string, b->value.string) >= 0); +} + +static gboolean +cmp_lt(fvalue_t *a, fvalue_t *b) +{ + return (strcmp(a->value.string, b->value.string) < 0); +} + +static gboolean +cmp_le(fvalue_t *a, fvalue_t *b) +{ + return (strcmp(a->value.string, b->value.string) <= 0); +} + +void +ftype_register_string(void) +{ + + static ftype_t string_type = { + "FT_STRING", + "character string", + 0, + string_fvalue_new, + string_fvalue_free, + ftype_from_tvbuff, + val_from_string, + + string_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + + len, + slice, + }; + static ftype_t stringz_type = { + "FT_STRINGZ", + "character string", + 0, + string_fvalue_new, + string_fvalue_free, + ftype_from_tvbuff, + val_from_string, + + string_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + + len, + slice, + }; + static ftype_t uint_string_type = { + "FT_UINT_STRING", + "character string", + 0, + string_fvalue_new, + string_fvalue_free, + ftype_from_tvbuff, + val_from_string, + + string_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + cmp_eq, + cmp_ne, + cmp_gt, + cmp_ge, + cmp_lt, + cmp_le, + + len, + slice, + }; + + ftype_register(FT_STRING, &string_type); + ftype_register(FT_STRINGZ, &stringz_type); + ftype_register(FT_UINT_STRING, &uint_string_type); +} diff --git a/epan/ftypes/ftype-time.c b/epan/ftypes/ftype-time.c new file mode 100644 index 0000000000..6eb2a3d4cb --- /dev/null +++ b/epan/ftypes/ftype-time.c @@ -0,0 +1,78 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> + +static void +ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length, + gboolean little_endian) +{ + /* XXX */ + g_assert_not_reached(); +} + + +static void +time_fvalue_new(fvalue_t *fv) +{ + fv->value.time.tv_sec = 0; + fv->value.time.tv_usec = 0; +} + +static void +time_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + g_assert(!already_copied); + memcpy(&(fv->value.time), value, sizeof(struct timeval)); +} + +static gpointer +value_get(fvalue_t *fv) +{ + return &(fv->value.time); +} + +void +ftype_register_time(void) +{ + + static ftype_t abstime_type = { + "FT_ABSOLUTE_TIME", + "date/time", + 0, + time_fvalue_new, + NULL, + ftype_from_tvbuff, + NULL, + + time_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL + }; + static ftype_t reltime_type = { + "FT_RELATIVE_TIME", + "time offset", + 0, + time_fvalue_new, + NULL, + ftype_from_tvbuff, + NULL, + + time_fvalue_set, + NULL, + NULL, + + value_get, + NULL, + NULL + }; + + ftype_register(FT_ABSOLUTE_TIME, &abstime_type); + ftype_register(FT_RELATIVE_TIME, &reltime_type); +} diff --git a/epan/ftypes/ftype-tvbuff.c b/epan/ftypes/ftype-tvbuff.c new file mode 100644 index 0000000000..e9617ca607 --- /dev/null +++ b/epan/ftypes/ftype-tvbuff.c @@ -0,0 +1,84 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> +#include "gdebug.h" + +static void +value_new(fvalue_t *fv) +{ + fv->value.tvb = NULL; +} + + +static void +value_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + g_assert(already_copied); + fv->value.tvb = value; +} + +static gpointer +value_get(fvalue_t *fv) +{ + return fv->value.tvb; +} + +static guint +len(fvalue_t *fv) +{ + if (fv->value.tvb) + return tvb_length(fv->value.tvb); + else + return 0; +} + +static void +slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length) +{ + guint8* data; + + if (fv->value.tvb) { + data = tvb_get_ptr(fv->value.tvb, offset, length); + g_byte_array_append(bytes, data, length); + } +} + +void +ftype_register_tvbuff(void) +{ + + static ftype_t protocol_type = { + "FT_PROTOCOL", + "protocol", + 0, + value_new, + NULL, + NULL, + NULL, + + value_set, + NULL, + NULL, + + value_get, + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + len, + slice, + + }; + + + ftype_register(FT_PROTOCOL, &protocol_type); +} diff --git a/epan/ftypes/ftypes-int.h b/epan/ftypes/ftypes-int.h new file mode 100644 index 0000000000..4e6ce75bee --- /dev/null +++ b/epan/ftypes/ftypes-int.h @@ -0,0 +1,60 @@ +#ifndef FTYPES_INT_H +#define FTYPES_INT_H + +#include "packet.h" +#include "ftypes.h" + +typedef void (*FtypeFromTvbuffFunc)(field_info*, tvbuff_t*, int, int, gboolean); +typedef void (*FvalueNewFunc)(fvalue_t*); +typedef void (*FvalueFreeFunc)(fvalue_t*); + +typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc); + +typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean); +typedef void (*FvalueSetIntegerFunc)(fvalue_t*, guint32); +typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble); + +typedef gpointer (*FvalueGetFunc)(fvalue_t*); +typedef guint32 (*FvalueGetIntegerFunc)(fvalue_t*); +typedef double (*FvalueGetFloatingFunc)(fvalue_t*); + +typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*); + +typedef guint (*FvalueLen)(fvalue_t*); +typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint, guint); + +struct _ftype_t { + const char *name; + const char *pretty_name; + int wire_size; + FvalueNewFunc new_value; + FvalueFreeFunc free_value; + FtypeFromTvbuffFunc from_tvbuff; + FvalueFromString val_from_string; + + /* could be union */ + FvalueSetFunc set_value; + FvalueSetIntegerFunc set_value_integer; + FvalueSetFloatingFunc set_value_floating; + + /* could be union */ + FvalueGetFunc get_value; + FvalueGetIntegerFunc get_value_integer; + FvalueGetFloatingFunc get_value_floating; + + FvalueCmp cmp_eq; + FvalueCmp cmp_ne; + FvalueCmp cmp_gt; + FvalueCmp cmp_ge; + FvalueCmp cmp_lt; + FvalueCmp cmp_le; + + FvalueLen len; + FvalueSlice slice; +}; + + +void +ftype_register(enum ftenum ftype, ftype_t *ft); + +#endif diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c new file mode 100644 index 0000000000..7234008d53 --- /dev/null +++ b/epan/ftypes/ftypes.c @@ -0,0 +1,410 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ftypes-int.h> + +/* Keep track of ftype_t's via their ftenum number */ +static ftype_t* type_list[FT_NUM_TYPES]; + +/* Space for quickly allocating/de-allocating fvalue_t's */ +static GMemChunk *gmc_fvalue = NULL; + +/* These are the ftype registration functions that need to be called. + * This list and the initialization function could be produced + * via a script, like the dissector registration, but there's so few + * that I don't mind doing it by hand for now. */ +void ftype_register_bytes(void); +void ftype_register_double(void); +void ftype_register_integers(void); +void ftype_register_ipv4(void); +void ftype_register_none(void); +void ftype_register_string(void); +void ftype_register_time(void); +void ftype_register_tvbuff(void); + +/* Initialize the ftype module. */ +void +ftypes_initialize(void) +{ + ftype_register_bytes(); + ftype_register_double(); + ftype_register_integers(); + ftype_register_ipv4(); + ftype_register_none(); + ftype_register_string(); + ftype_register_time(); + ftype_register_tvbuff(); + + if (gmc_fvalue) + g_mem_chunk_destroy(gmc_fvalue); + + gmc_fvalue = g_mem_chunk_new("gmc_fvalue", sizeof(fvalue_t), + 200 * sizeof(fvalue_t), G_ALLOC_AND_FREE); +} + +void +ftypes_cleanup(void) +{ + if (gmc_fvalue) + g_mem_chunk_destroy(gmc_fvalue); +} + + + +/* Each ftype_t is registered via this function */ +void +ftype_register(enum ftenum ftype, ftype_t *ft) +{ + /* Check input */ + g_assert(ftype >= 0); + g_assert(ftype < FT_NUM_TYPES); + + /* Don't re-register. */ + g_assert(type_list[ftype] == NULL); + + type_list[ftype] = ft; +} + +/* Given an ftenum number, return an ftype_t* */ +static ftype_t* +ftype_lookup(enum ftenum ftype) +{ + ftype_t* result; + + /* Check input */ + g_assert(ftype >= 0); + g_assert(ftype < FT_NUM_TYPES); + + result = type_list[ftype]; + + /* Check output. */ + g_assert(result != NULL); + + return result; +} + + +/* Returns a string representing the name of the type. Useful + * for glossary production. */ +const char* +ftype_name(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->name; +} + +const char* +ftype_pretty_name(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->pretty_name; +} + +int +ftype_length(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->wire_size; +} + +gboolean +ftype_can_slice(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->slice ? TRUE : FALSE; +} + +gboolean +ftype_can_eq(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_eq ? TRUE : FALSE; +} + +gboolean +ftype_can_ne(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_ne ? TRUE : FALSE; +} + +gboolean +ftype_can_gt(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_gt ? TRUE : FALSE; +} + +gboolean +ftype_can_ge(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_ge ? TRUE : FALSE; +} + +gboolean +ftype_can_lt(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_lt ? TRUE : FALSE; +} + +gboolean +ftype_can_le(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_le ? TRUE : FALSE; +} + +/* ---------------------------------------------------------- */ + +/* Allocate and initialize an fvalue_t, given an ftype */ +fvalue_t* +fvalue_new(ftenum_t ftype) +{ + fvalue_t *fv; + ftype_t *ft; + FvalueNewFunc new_value; + + fv = g_mem_chunk_alloc(gmc_fvalue); + + ft = ftype_lookup(ftype); + fv->ftype = ft; + + new_value = ft->new_value; + if (new_value) { + new_value(fv); + } + + return fv; +} + +/* Free all memory used by an fvalue_t */ +void +fvalue_free(fvalue_t *fv) +{ + FvalueFreeFunc free_value; + + free_value = fv->ftype->free_value; + if (free_value) { + free_value(fv); + } + + g_mem_chunk_free(gmc_fvalue, fv); +} + + + +fvalue_t* +fvalue_from_string(ftenum_t ftype, char *s, LogFunc log) +{ + fvalue_t *fv; + + fv = fvalue_new(ftype); + if (fv->ftype->val_from_string) { + if (fv->ftype->val_from_string(fv, s, log)) { + return fv; + } + } + else { + log("\"%s\" cannot be converted to %s.", + s, ftype_pretty_name(ftype)); + } + fvalue_free(fv); + return NULL; +} + +const char* +fvalue_type_name(fvalue_t *fv) +{ + return fv->ftype->name; +} + + +guint +fvalue_length(fvalue_t *fv) +{ + if (fv->ftype->len) + return fv->ftype->len(fv); + else + return fv->ftype->wire_size; +} + +/* Returns a new FT_BYTES fvalue_t* if possible, otherwise NULL */ +fvalue_t* +fvalue_slice(fvalue_t *fv, gint start, gint end) +{ + GByteArray *bytes; + guint data_length, abs_end; + guint offset=0, length=0; + fvalue_t *new_fv; + + if (!fv->ftype->slice) { + return NULL; + } + + data_length = fvalue_length(fv); + bytes = g_byte_array_new(); + + /* Find absolute start position (offset) */ + if (start < 0) { + start = data_length + start; + if (start < 0) { + offset = 0; + } + else { + offset = start; + } + } + else { + offset = start; + } + + /* Limit the offset value */ + if (offset > data_length) { + offset = data_length; + } + + /* Find absolute end position (abs_end) */ + if (end < 0) { + end = data_length + end; + if (end < 0) { + abs_end = 0; + } + else { + abs_end = end; + } + } + else { + abs_end = end; + } + + /* Limit the abs_end value */ + if (abs_end > data_length) { + abs_end = data_length; + } + + /* Does end position occur *after* start position? */ + if (abs_end > offset) { + length = abs_end - offset; + fv->ftype->slice(fv, bytes, offset, length); + } + + new_fv = fvalue_new(FT_BYTES); + fvalue_set(new_fv, bytes, TRUE); + return new_fv; +} + + +void +fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied) +{ + g_assert(fv->ftype->set_value); + fv->ftype->set_value(fv, value, already_copied); +} + +void +fvalue_set_integer(fvalue_t *fv, guint32 value) +{ + g_assert(fv->ftype->set_value_integer); + fv->ftype->set_value_integer(fv, value); +} + +void +fvalue_set_floating(fvalue_t *fv, gdouble value) +{ + g_assert(fv->ftype->set_value_floating); + fv->ftype->set_value_floating(fv, value); +} + + +gpointer +fvalue_get(fvalue_t *fv) +{ + g_assert(fv->ftype->get_value); + return fv->ftype->get_value(fv); +} + +guint32 +fvalue_get_integer(fvalue_t *fv) +{ + g_assert(fv->ftype->get_value_integer); + return fv->ftype->get_value_integer(fv); +} + +double +fvalue_get_floating(fvalue_t *fv) +{ + g_assert(fv->ftype->get_value_floating); + return fv->ftype->get_value_floating(fv); +} + +gboolean +fvalue_eq(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_eq); + return a->ftype->cmp_eq(a, b); +} + +gboolean +fvalue_ne(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_ne); + return a->ftype->cmp_ne(a, b); +} + +gboolean +fvalue_gt(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_gt); + return a->ftype->cmp_gt(a, b); +} + +gboolean +fvalue_ge(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_ge); + return a->ftype->cmp_ge(a, b); +} + +gboolean +fvalue_lt(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_lt); + return a->ftype->cmp_lt(a, b); +} + +gboolean +fvalue_le(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_le); + return a->ftype->cmp_le(a, b); +} diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h new file mode 100644 index 0000000000..1431f35427 --- /dev/null +++ b/epan/ftypes/ftypes.h @@ -0,0 +1,197 @@ +/* ftypes.h + * Definitions for field types + * + * $Id: ftypes.h,v 1.1 2001/02/01 20:21:19 gram Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@zing.org> + * Copyright 2001 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef FTYPES_H +#define FTYPES_H + +#include <glib.h> + + +/* field types */ +enum ftenum { + FT_NONE, /* used for text labels with no value */ + FT_PROTOCOL, + FT_BOOLEAN, /* TRUE and FALSE come from <glib.h> */ + FT_UINT8, + FT_UINT16, + FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/ + FT_UINT32, + FT_INT8, + FT_INT16, + FT_INT24, + FT_INT32, + FT_DOUBLE, + FT_ABSOLUTE_TIME, + FT_RELATIVE_TIME, + FT_STRING, + FT_STRINGZ, /* for use with proto_tree_add_item() */ + FT_UINT_STRING, /* for use with proto_tree_add_item() */ + FT_ETHER, + FT_BYTES, + FT_IPv4, + FT_IPv6, + FT_IPXNET, +/* FT_TEXT_ONLY,*/ /* non-filterable, used when converting ethereal + from old-style proto_tree to new-style proto_tree */ + FT_NUM_TYPES /* last item number plus one */ +}; + +typedef enum ftenum ftenum_t; +typedef struct _ftype_t ftype_t; + +/* Initialize the ftypes subsytem. Called once. */ +void +ftypes_initialize(void); + +/* Cleanup the ftypes subsystem. Called once. */ +void +ftypes_cleanup(void); + + +/* ---------------- FTYPE ----------------- */ + +/* Return a string representing the name of the type */ +const char* +ftype_name(ftenum_t ftype); + +/* Return a string presenting a "pretty" representation of the + * name of the type. The pretty name means more to the user than + * that "FT_*" name. */ +const char* +ftype_pretty_name(ftenum_t ftype); + +/* Returns length of field in packet, or 0 if not determinable/defined. */ +int +ftype_length(ftenum_t ftype); + +gboolean +ftype_can_slice(enum ftenum ftype); + +gboolean +ftype_can_eq(enum ftenum ftype); + +gboolean +ftype_can_ne(enum ftenum ftype); + +gboolean +ftype_can_gt(enum ftenum ftype); + +gboolean +ftype_can_ge(enum ftenum ftype); + +gboolean +ftype_can_lt(enum ftenum ftype); + +gboolean +ftype_can_le(enum ftenum ftype); + +/* ---------------- FVALUE ----------------- */ + +#include "ipv4.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#include "tvbuff.h" + +typedef struct { + ftype_t *ftype; + union { + /* Put a few basic types in here */ + gpointer pointer; + guint32 integer; + gdouble floating; + gchar *string; + GByteArray *bytes; + ipv4_addr ipv4; + guint8 ipv6[16]; + struct timeval time; + tvbuff_t *tvb; + } value; +} fvalue_t; + +fvalue_t* +fvalue_new(ftenum_t ftype); + +void +fvalue_free(fvalue_t *fv); + +typedef void (*LogFunc)(char*,...); + +fvalue_t* +fvalue_from_string(ftenum_t ftype, char *s, LogFunc log); + +const char* +fvalue_type_name(fvalue_t *fv); + +void +fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied); + +void +fvalue_set_integer(fvalue_t *fv, guint32 value); + +void +fvalue_set_floating(fvalue_t *fv, gdouble value); + +gpointer +fvalue_get(fvalue_t *fv); + +guint32 +fvalue_get_integer(fvalue_t *fv); + +double +fvalue_get_floating(fvalue_t *fv); + +gboolean +fvalue_eq(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_ne(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_gt(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_ge(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_lt(fvalue_t *a, fvalue_t *b); + +gboolean +fvalue_le(fvalue_t *a, fvalue_t *b); + +guint +fvalue_length(fvalue_t *fv); + +fvalue_t* +fvalue_slice(fvalue_t *fv, gint start, gint end); + +#endif /* ftypes.h */ diff --git a/epan/gdebug.h b/epan/gdebug.h new file mode 100644 index 0000000000..230931fbf8 --- /dev/null +++ b/epan/gdebug.h @@ -0,0 +1,38 @@ +/* $Id: gdebug.h,v 1.1 2001/02/01 20:21:16 gram Exp $ */ + +#ifndef GDEBUG_H +#define GDEBUG_H + +#ifdef __GNUC__ + +/* The last "%s" in g_log() is for the empty-string arg that + * g_debug() always passes. */ +#define _g_debug(format, args...) \ + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ + "%s():%s +%d: " format "%s", \ + G_GNUC_PRETTY_FUNCTION, __FILE__, __LINE__, ##args) ; + +/* Always pass a empty-string argument to _g_debug() so that g_debug will always + * have at least 2 arguments. If user passes 1 arg to g_debug() (i.e., only + * a format string), _g_debug() will still work. */ +#define g_debug(args...) \ + _g_debug(args, "") + + +#else + +#include <stdio.h> +#include <stdarg.h> + +static void +g_debug(const char* format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + +#endif /* __GNUC__ */ + +#endif /* GDEBUG_H */ diff --git a/epan/ipv4.h b/epan/ipv4.h index 8154465cfb..20728bd56d 100644 --- a/epan/ipv4.h +++ b/epan/ipv4.h @@ -5,7 +5,7 @@ * * Gilbert Ramirez <gram@xiexie.org> * - * $Id: ipv4.h,v 1.1 2000/09/28 03:52:12 gram Exp $ + * $Id: ipv4.h,v 1.2 2001/02/01 20:21:16 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -30,6 +30,8 @@ #ifndef __IPV4_H__ #define __IPV4_H__ +#include <glib.h> + typedef struct { guint32 addr; /* stored in host order */ guint32 nmask; /* stored in host order */ diff --git a/epan/proto.c b/epan/proto.c index fd45be0eae..29df3f68bc 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -1,7 +1,7 @@ /* proto.c * Routines for protocol tree * - * $Id: proto.c,v 1.6 2001/02/01 07:34:30 guy Exp $ + * $Id: proto.c,v 1.7 2001/02/01 20:21:16 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -60,7 +60,7 @@ 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 hfinfo_bitwidth(header_field_info *hfinfo); +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); @@ -166,7 +166,7 @@ proto_init(const char *plugin_dir) { static hf_register_info hf[] = { { &hf_text_only, - { "Text", "text", FT_TEXT_ONLY, BASE_NONE, NULL, 0x0, + { "Text", "text", FT_NONE, BASE_NONE, NULL, 0x0, "" }}, }; @@ -182,8 +182,7 @@ proto_init(const char *plugin_dir) g_free(tree_is_expanded); gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo", - sizeof(struct header_field_info), 50 * sizeof(struct - header_field_info), G_ALLOC_ONLY); + sizeof(header_field_info), 50 * sizeof(header_field_info), G_ALLOC_ONLY); gmc_field_info = g_mem_chunk_new("gmc_field_info", sizeof(struct field_info), 200 * sizeof(struct field_info), G_ALLOC_AND_FREE); @@ -198,6 +197,9 @@ proto_init(const char *plugin_dir) tree_is_expanded[0] = FALSE; num_tree_types = 1; + /* Initialize the ftype subsystem */ + ftypes_initialize(); + /* Have each built-in dissector register its protocols, fields, dissector tables, and dissectors to be called through a handle, and do whatever one-time initialization it needs to @@ -241,6 +243,9 @@ proto_cleanup(void) g_mem_chunk_destroy(gmc_item_labels); if (gpa_hfinfo) g_ptr_array_free(gpa_hfinfo, FALSE); + + /* Cleanup the ftype subsystem */ + ftypes_cleanup(); } /* frees the resources that the dissection a proto_tree uses */ @@ -265,23 +270,17 @@ proto_tree_free_node(GNode *node, gpointer data) field_info *fi = (field_info*) (node->data); if (fi != NULL) { - if (fi->representation) + 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_STRINGZ) - g_free(fi->value.string); - else if (fi->hfinfo->type == FT_UINT_STRING) - g_free(fi->value.string); - else if (fi->hfinfo->type == FT_BYTES) - g_free(fi->value.bytes); + } + fvalue_free(fi->value); free_field_info(fi); } return FALSE; /* FALSE = do not end traversal of GNode tree */ } /* Finds a record in the hf_info_records array by id. */ -struct header_field_info* +header_field_info* proto_registrar_get_nth(int hfindex) { g_assert(hfindex >= 0 && hfindex < gpa_hfinfo->len); @@ -458,6 +457,10 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, /* no value to set for FT_NONE */ break; + case FT_PROTOCOL: + proto_tree_set_protocol_tvb(new_fi, tvb); + break; + case FT_BYTES: proto_tree_set_bytes_tvb(new_fi, tvb, start, length); break; @@ -542,7 +545,7 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, default: g_error("new_fi->hfinfo->type %d (%s) not handled\n", new_fi->hfinfo->type, - proto_registrar_ftype_name(new_fi->hfinfo->type)); + ftype_name(new_fi->hfinfo->type)); g_assert_not_reached(); break; @@ -576,7 +579,7 @@ proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, /* Add a FT_NONE to a proto_tree */ proto_item * -proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, +proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, const char *format, ...) { proto_item *pi; @@ -596,10 +599,48 @@ proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gin va_end(ap); /* no value to set for FT_NONE */ + return pi; +} + + +static void +proto_tree_set_protocol_tvb(field_info *fi, tvbuff_t *tvb) +{ + fvalue_set(fi->value, tvb, TRUE); +} + +/* Add a FT_PROTOCOL to a proto_tree */ +proto_item * +proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...) +{ + proto_item *pi; + va_list ap; + header_field_info *hfinfo; + field_info *new_fi; + + if (!tree) + return (NULL); + hfinfo = proto_registrar_get_nth(hfindex); + g_assert(hfinfo->type == FT_PROTOCOL); + + pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi); + + va_start(ap, format); + proto_tree_set_representation(pi, format, ap); + va_end(ap); + + if (start == 0) { + proto_tree_set_protocol_tvb(new_fi, tvb); + } + else { + proto_tree_set_protocol_tvb(new_fi, NULL); + } return pi; } + /* Add a FT_BYTES to a proto_tree */ proto_item * proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, @@ -656,34 +697,23 @@ proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s return pi; } -/* Set the FT_BYTES value */ static void proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length) { - g_assert(start_ptr != NULL); + GByteArray *bytes; + bytes = g_byte_array_new(); if (length > 0) { - /* This g_malloc'ed memory is freed in - proto_tree_free_node() */ - fi->value.bytes = g_malloc(length); - memcpy(fi->value.bytes, start_ptr, length); - } - else { - fi->value.bytes = NULL; + g_byte_array_append(bytes, start_ptr, length); } + fvalue_set(fi->value, bytes, TRUE); } + static void proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length) { - if (length > 0) { - /* This g_malloc'ed memory is freed in - proto_tree_free_node() */ - fi->value.bytes = tvb_memdup(tvb, offset, length); - } - else { - fi->value.bytes = NULL; - } + proto_tree_set_bytes(fi, tvb_get_ptr(tvb, offset, length), length); } /* Add a FT_*TIME to a proto_tree */ @@ -747,7 +777,7 @@ proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st static void proto_tree_set_time(field_info *fi, struct timeval *value_ptr) { - memcpy(&fi->value.time, value_ptr, sizeof(struct timeval)); + fvalue_set(fi->value, value_ptr, FALSE); } /* Add a FT_IPXNET to a proto_tree */ @@ -810,7 +840,7 @@ proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint static void proto_tree_set_ipxnet(field_info *fi, guint32 value) { - fi->value.numeric = value; + fvalue_set_integer(fi->value, value); } /* Add a FT_IPv4 to a proto_tree */ @@ -873,8 +903,7 @@ proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st static void proto_tree_set_ipv4(field_info *fi, guint32 value) { - ipv4_addr_set_net_order_addr(&(fi->value.ipv4), value); - ipv4_addr_set_netmask_bits(&(fi->value.ipv4), 32); + fvalue_set_integer(fi->value, value); } /* Add a FT_IPv6 to a proto_tree */ @@ -937,13 +966,13 @@ proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st static void proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr) { - memcpy(fi->value.ipv6, value_ptr, 16); + fvalue_set(fi->value, (gpointer) value_ptr, FALSE); } static void proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start) { - tvb_memcpy(tvb, fi->value.ipv6, start, 16); + proto_tree_set_ipv6(fi, tvb_get_ptr(tvb, start, 16)); } /* Add a FT_STRING to a proto_tree */ @@ -1006,17 +1035,19 @@ proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint static void proto_tree_set_string(field_info *fi, const char* value) { - /* This g_strdup'ed memory is freed in proto_tree_free_node() */ - fi->value.string = g_strdup(value); + fvalue_set(fi->value, (gpointer) value, FALSE); } static void proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length) { + gchar *string; + /* This memory is freed in proto_tree_free_node() */ - fi->value.string = g_malloc(length + 1); - tvb_memcpy(tvb, fi->value.string, start, length); - fi->value.string[length] = '\0'; + string = g_malloc(length + 1); + tvb_memcpy(tvb, string, start, length); + string[length] = '\0'; + fvalue_set(fi->value, string, TRUE); } /* Add a FT_ETHER to a proto_tree */ @@ -1079,13 +1110,13 @@ proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s static void proto_tree_set_ether(field_info *fi, const guint8* value) { - memcpy(fi->value.ether, value, 6); + fvalue_set(fi->value, (gpointer) value, FALSE); } static void proto_tree_set_ether_tvb(field_info *fi, tvbuff_t *tvb, gint start) { - tvb_memcpy(tvb, fi->value.ether, start, 6); + proto_tree_set_ether(fi, tvb_get_ptr(tvb, start, 6)); } /* Add a FT_BOOLEAN to a proto_tree */ @@ -1146,7 +1177,7 @@ proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint /* Set the FT_BOOLEAN value */ static void -proto_tree_set_boolean(field_info *fi, guint32 value) +proto_tree_set_boolean(field_info *fi, guint32 value) { proto_tree_set_uint(fi, value); } @@ -1211,7 +1242,7 @@ proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint static void proto_tree_set_double(field_info *fi, double value) { - fi->value.floating = value; + fvalue_set_floating(fi->value, value); } /* Add any FT_UINT* to a proto_tree */ @@ -1283,19 +1314,22 @@ proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st static void proto_tree_set_uint(field_info *fi, guint32 value) { - header_field_info *hfinfo; + header_field_info *hfinfo; + guint32 integer; hfinfo = fi->hfinfo; - fi->value.numeric = value; + integer = value; + if (hfinfo->bitmask) { /* Mask out irrelevant portions */ - fi->value.numeric &= hfinfo->bitmask; + integer &= hfinfo->bitmask; /* Shift bits */ if (hfinfo->bitshift > 0) { - fi->value.numeric >>= hfinfo->bitshift; + integer >>= hfinfo->bitshift; } } + fvalue_set_integer(fi->value, integer); } /* Add any FT_INT* to a proto_tree */ @@ -1367,19 +1401,22 @@ proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint sta static void proto_tree_set_int(field_info *fi, gint32 value) { - header_field_info *hfinfo; + header_field_info *hfinfo; + guint32 integer; hfinfo = fi->hfinfo; - fi->value.numeric = (guint32) value; + integer = (guint32) value; + if (hfinfo->bitmask) { /* Mask out irrelevant portions */ - fi->value.numeric &= hfinfo->bitmask; + integer &= hfinfo->bitmask; /* Shift bits */ if (hfinfo->bitshift > 0) { - fi->value.numeric >>= hfinfo->bitshift; + integer >>= hfinfo->bitshift; } } + fvalue_set_integer(fi->value, integer); } @@ -1437,6 +1474,8 @@ alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length) fi->visible = proto_tree_is_visible; fi->representation = NULL; + fi->value = fvalue_new(fi->hfinfo->type); + return fi; } @@ -1508,7 +1547,7 @@ int proto_register_protocol(char *name, char *short_name, char *filter_name) { protocol_t *protocol; - struct header_field_info *hfinfo; + header_field_info *hfinfo; int proto_id; /* Add this protocol to the list of known protocols; the list @@ -1528,7 +1567,7 @@ proto_register_protocol(char *name, char *short_name, char *filter_name) hfinfo = g_mem_chunk_alloc(gmc_hfinfo); hfinfo->name = name; hfinfo->abbrev = filter_name; - hfinfo->type = FT_NONE; + hfinfo->type = FT_PROTOCOL; hfinfo->strings = NULL; hfinfo->bitmask = 0; hfinfo->bitshift = 0; @@ -1735,6 +1774,7 @@ proto_register_field_init(header_field_info *hfinfo, int parent) } hfinfo->parent = parent; + hfinfo->same_name = NULL; /* if we always add and never delete, then id == len - 1 is correct */ g_ptr_array_add(gpa_hfinfo, hfinfo); @@ -1770,11 +1810,16 @@ proto_register_subtree_array(gint **indices, int num_indices) void proto_item_fill_label(field_info *fi, gchar *label_str) { - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; + + guint8 *bytes; + guint32 integer; + ipv4_addr *ipv4; guint32 n_addr; /* network-order IPv4 address */ switch(hfinfo->type) { case FT_NONE: + case FT_PROTOCOL: snprintf(label_str, ITEM_LABEL_LENGTH, "%s", hfinfo->name); break; @@ -1784,10 +1829,11 @@ proto_item_fill_label(field_info *fi, gchar *label_str) break; case FT_BYTES: - if (fi->value.bytes) { + bytes = fvalue_get(fi->value); + if (bytes) { snprintf(label_str, ITEM_LABEL_LENGTH, "%s: %s", hfinfo->name, - bytes_to_str(fi->value.bytes, fi->length)); + bytes_to_str(bytes, fi->length)); } else { snprintf(label_str, ITEM_LABEL_LENGTH, @@ -1838,37 +1884,39 @@ proto_item_fill_label(field_info *fi, gchar *label_str) case FT_DOUBLE: snprintf(label_str, ITEM_LABEL_LENGTH, - "%s: %g", hfinfo->name, - fi->value.floating); + "%s: %g", hfinfo->name, fvalue_get_floating(fi->value)); break; case FT_ABSOLUTE_TIME: snprintf(label_str, ITEM_LABEL_LENGTH, "%s: %s", hfinfo->name, - abs_time_to_str(&fi->value.time)); + abs_time_to_str(fvalue_get(fi->value))); break; case FT_RELATIVE_TIME: snprintf(label_str, ITEM_LABEL_LENGTH, "%s: %s seconds", hfinfo->name, - rel_time_to_str(&fi->value.time)); + rel_time_to_str(fvalue_get(fi->value))); break; case FT_IPXNET: + integer = fvalue_get_integer(fi->value); snprintf(label_str, ITEM_LABEL_LENGTH, "%s: 0x%08X (%s)", hfinfo->name, - fi->value.numeric, get_ipxnet_name(fi->value.numeric)); + integer, get_ipxnet_name(integer)); break; case FT_ETHER: + bytes = fvalue_get(fi->value); snprintf(label_str, ITEM_LABEL_LENGTH, "%s: %s (%s)", hfinfo->name, - ether_to_str(fi->value.ether), - get_ether_name(fi->value.ether)); + ether_to_str(bytes), + get_ether_name(bytes)); break; case FT_IPv4: - n_addr = ipv4_get_net_order_addr(&fi->value.ipv4); + ipv4 = fvalue_get(fi->value); + n_addr = ipv4_get_net_order_addr(ipv4); snprintf(label_str, ITEM_LABEL_LENGTH, "%s: %s (%s)", hfinfo->name, get_hostname(n_addr), @@ -1876,23 +1924,24 @@ proto_item_fill_label(field_info *fi, gchar *label_str) break; case FT_IPv6: + bytes = fvalue_get(fi->value); snprintf(label_str, ITEM_LABEL_LENGTH, "%s: %s (%s)", hfinfo->name, - get_hostname6((struct e_in6_addr *)fi->value.ipv6), - ip6_to_str((struct e_in6_addr*)fi->value.ipv6)); + get_hostname6((struct e_in6_addr *)bytes), + ip6_to_str((struct e_in6_addr*)bytes)); break; case FT_STRING: case FT_STRINGZ: case FT_UINT_STRING: snprintf(label_str, ITEM_LABEL_LENGTH, - "%s: %s", hfinfo->name, fi->value.string); + "%s: %s", hfinfo->name, (char*) fvalue_get(fi->value)); break; default: g_error("hfinfo->type %d (%s) not handled\n", hfinfo->type, - proto_registrar_ftype_name(hfinfo->type)); + ftype_name(hfinfo->type)); g_assert_not_reached(); break; } @@ -1901,24 +1950,26 @@ proto_item_fill_label(field_info *fi, gchar *label_str) static void fill_label_boolean(field_info *fi, gchar *label_str) { - char *p = label_str; - int bitfield_byte_length = 0, bitwidth; - guint32 unshifted_value; + char *p = label_str; + int bitfield_byte_length = 0, bitwidth; + guint32 unshifted_value; + guint32 value; - struct header_field_info *hfinfo = fi->hfinfo; - struct true_false_string default_tf = { "True", "False" }; - struct true_false_string *tfstring = &default_tf; + header_field_info *hfinfo = fi->hfinfo; + static true_false_string default_tf = { "True", "False" }; + true_false_string *tfstring = &default_tf; if (hfinfo->strings) { tfstring = (struct true_false_string*) hfinfo->strings; } + value = fvalue_get_integer(fi->value); if (hfinfo->bitmask) { /* Figure out the bit width */ bitwidth = hfinfo_bitwidth(hfinfo); /* Un-shift bits */ - unshifted_value = fi->value.numeric; + unshifted_value = value; if (hfinfo->bitshift > 0) { unshifted_value <<= hfinfo->bitshift; } @@ -1931,7 +1982,7 @@ fill_label_boolean(field_info *fi, gchar *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); + value ? tfstring->true_string : tfstring->false_string); } @@ -1942,8 +1993,9 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str) char *format = NULL, *p; int bitfield_byte_length, bitwidth; guint32 unshifted_value; + guint32 value; - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; /* Figure out the bit width */ bitwidth = hfinfo_bitwidth(hfinfo); @@ -1952,7 +2004,8 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str) format = hfinfo_uint_vals_format(hfinfo); /* Un-shift bits */ - unshifted_value = fi->value.numeric; + unshifted_value = fvalue_get_integer(fi->value); + value = unshifted_value; if (hfinfo->bitshift > 0) { unshifted_value <<= hfinfo->bitshift; } @@ -1964,8 +2017,7 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *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); + val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value); } static void @@ -1974,8 +2026,9 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str) char *format = NULL, *p; int bitfield_byte_length, bitwidth; guint32 unshifted_value; + guint32 value; - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; /* Figure out the bit width */ bitwidth = hfinfo_bitwidth(hfinfo); @@ -1984,7 +2037,8 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str) format = hfinfo_uint_format(hfinfo); /* Un-shift bits */ - unshifted_value = fi->value.numeric; + unshifted_value = fvalue_get_integer(fi->value); + value = unshifted_value; if (hfinfo->bitshift > 0) { unshifted_value <<= hfinfo->bitshift; } @@ -1995,70 +2049,77 @@ fill_label_numeric_bitfield(field_info *fi, gchar *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); + format, hfinfo->name, value); } static void fill_label_enumerated_uint(field_info *fi, gchar *label_str) { char *format = NULL; - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; + guint32 value; /* Pick the proper format string */ format = hfinfo_uint_vals_format(hfinfo); + value = fvalue_get_integer(fi->value); + /* 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); + val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value); } static void fill_label_uint(field_info *fi, gchar *label_str) { char *format = NULL; - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; + guint32 value; /* Pick the proper format string */ format = hfinfo_uint_format(hfinfo); + value = fvalue_get_integer(fi->value); /* Fill in the textual info */ snprintf(label_str, ITEM_LABEL_LENGTH, - format, hfinfo->name, fi->value.numeric); + format, hfinfo->name, value); } static void fill_label_enumerated_int(field_info *fi, gchar *label_str) { char *format = NULL; - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; + guint32 value; /* Pick the proper format string */ format = hfinfo_int_vals_format(hfinfo); + value = fvalue_get_integer(fi->value); /* 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); + val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value); } static void fill_label_int(field_info *fi, gchar *label_str) { char *format = NULL; - struct header_field_info *hfinfo = fi->hfinfo; + header_field_info *hfinfo = fi->hfinfo; + guint32 value; /* Pick the proper format string */ format = hfinfo_int_format(hfinfo); + value = fvalue_get_integer(fi->value); /* Fill in the textual info */ snprintf(label_str, ITEM_LABEL_LENGTH, - format, hfinfo->name, fi->value.numeric); + format, hfinfo->name, value); } -static int +int hfinfo_bitwidth(header_field_info *hfinfo) { int bitwidth = 0; @@ -2267,7 +2328,7 @@ proto_registrar_n(void) char* proto_registrar_get_name(int n) { - struct header_field_info *hfinfo; + header_field_info *hfinfo; hfinfo = proto_registrar_get_nth(n); if (hfinfo) return hfinfo->name; @@ -2277,7 +2338,7 @@ proto_registrar_get_name(int n) char* proto_registrar_get_abbrev(int n) { - struct header_field_info *hfinfo; + header_field_info *hfinfo; hfinfo = proto_registrar_get_nth(n); if (hfinfo) @@ -2289,7 +2350,7 @@ proto_registrar_get_abbrev(int n) int proto_registrar_get_ftype(int n) { - struct header_field_info *hfinfo; + header_field_info *hfinfo; hfinfo = proto_registrar_get_nth(n); if (hfinfo) @@ -2301,7 +2362,7 @@ proto_registrar_get_ftype(int n) int proto_registrar_get_parent(int n) { - struct header_field_info *hfinfo; + header_field_info *hfinfo; hfinfo = proto_registrar_get_nth(n); if (hfinfo) @@ -2313,7 +2374,7 @@ proto_registrar_get_parent(int n) gboolean proto_registrar_is_protocol(int n) { - struct header_field_info *hfinfo; + header_field_info *hfinfo; hfinfo = proto_registrar_get_nth(n); if (hfinfo) @@ -2329,54 +2390,13 @@ proto_registrar_is_protocol(int n) gint proto_registrar_get_length(int n) { - struct header_field_info *hfinfo; + header_field_info *hfinfo; hfinfo = proto_registrar_get_nth(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_STRINGZ: - case FT_UINT_STRING: - case FT_DOUBLE: - case FT_ABSOLUTE_TIME: - case FT_RELATIVE_TIME: - return 0; - - case FT_UINT8: - case FT_INT8: - return 1; - - case FT_UINT16: - case FT_INT16: - return 2; - - case FT_UINT24: - case FT_INT24: - return 3; - - case FT_UINT32: - case FT_INT32: - case FT_IPXNET: - case FT_IPv4: - return 4; - - case FT_ETHER: - return 6; - - case FT_IPv6: - return 16; - } - g_assert_not_reached(); - return -1; + return ftype_length(hfinfo->type); } @@ -2577,91 +2597,193 @@ proto_registrar_dump(void) parent_hfinfo = proto_registrar_get_nth(hfinfo->parent); g_assert(parent_hfinfo); - enum_name = proto_registrar_ftype_name(hfinfo->type); + enum_name = ftype_name(hfinfo->type); printf("F\t%s\t%s\t%s\t%s\n", hfinfo->name, hfinfo->abbrev, enum_name,parent_hfinfo->abbrev); } } } - -/* Returns a string representing the field type */ -const char* -proto_registrar_ftype_name(enum ftenum ftype) +static char* +hfinfo_numeric_format(header_field_info *hfinfo) { - const char *enum_name = NULL; + char *format = NULL; - switch(ftype) { - case FT_NONE: - enum_name = "FT_NONE"; + /* 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 */ + switch(hfinfo->type) { + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + format = "%s == %u"; + break; + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + format = "%s == %d"; + break; + default: + g_assert_not_reached(); + ; + } + 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; +} + +char* +proto_alloc_dfilter_string(field_info *finfo, guint8 *pd) +{ + header_field_info *hfinfo; + int abbrev_len; + char *buf, *stringified, *format, *ptr; + int dfilter_len, i; + guint8 *c; + + hfinfo = finfo->hfinfo; + g_assert(hfinfo); + abbrev_len = strlen(hfinfo->abbrev); + + switch(hfinfo->type) { + case FT_BOOLEAN: - enum_name = "FT_BOOLEAN"; + dfilter_len = abbrev_len + 2; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s%s", fvalue_get_integer(finfo->value) ? "" : "!", + hfinfo->abbrev); break; + case FT_UINT8: - enum_name = "FT_UINT8"; - break; 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"; + dfilter_len = abbrev_len + 20; + buf = g_malloc0(dfilter_len); + format = hfinfo_numeric_format(hfinfo); + snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer(finfo->value)); break; - case FT_ABSOLUTE_TIME: - enum_name = "FT_ABSOLUTE_TIME"; - break; - case FT_RELATIVE_TIME: - enum_name = "FT_RELATIVE_TIME"; + + case FT_IPv4: + dfilter_len = abbrev_len + 4 + 15 + 1; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev, + ipv4_addr_str(fvalue_get(finfo->value))); break; - case FT_UINT_STRING: - enum_name = "FT_UINT_STRING"; + + case FT_IPXNET: + dfilter_len = abbrev_len + 15; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev, + fvalue_get_integer(finfo->value)); break; - case FT_STRING: - enum_name = "FT_STRING"; + + case FT_IPv6: + stringified = ip6_to_str((struct e_in6_addr*) fvalue_get(finfo->value)); + dfilter_len = abbrev_len + 4 + strlen(stringified) + 1; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev, + stringified); break; - case FT_STRINGZ: - enum_name = "FT_STRINGZ"; + + case FT_DOUBLE: + dfilter_len = abbrev_len + 30; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev, + fvalue_get_floating(finfo->value)); break; + case FT_ETHER: - enum_name = "FT_ETHER"; - break; - case FT_BYTES: - enum_name = "FT_BYTES"; - break; - case FT_IPv4: - enum_name = "FT_IPv4"; - break; - case FT_IPv6: - enum_name = "FT_IPv6"; + dfilter_len = abbrev_len + 22; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == %s", + hfinfo->abbrev, + ether_to_str(fvalue_get(finfo->value))); break; - case FT_IPXNET: - enum_name = "FT_IPXNET"; +#if 0 + + case FT_ABSOLUTE_TIME: + case FT_RELATIVE_TIME: + memcpy(&fi->value.time, va_arg(ap, struct timeval*), + sizeof(struct timeval)); break; + case FT_TEXT_ONLY: - enum_name = "FT_TEXT_ONLY"; - break; - case NUM_FIELD_TYPES: - g_assert_not_reached(); + ; /* nothing */ break; +#endif + + case FT_STRING: + dfilter_len = abbrev_len + + strlen(fvalue_get(finfo->value)) + 7; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == \"%s\"", + hfinfo->abbrev, (char*)fvalue_get(finfo->value)); + break; + + case FT_BYTES: + dfilter_len = finfo->length*3 - 1; + dfilter_len += abbrev_len + 7; + buf = g_malloc0(dfilter_len); + snprintf(buf, dfilter_len, "%s == %s", + hfinfo->abbrev, + bytes_to_str_punct(fvalue_get(finfo->value), finfo->length,':')); + break; + default: + c = pd + finfo->start; + buf = g_malloc0(32 + finfo->length * 3); + ptr = buf; + + sprintf(ptr, "frame[%d] == ", finfo->start); + ptr = buf+strlen(buf); + + if (finfo->length == 1) { + sprintf(ptr, "0x%02x", *c++); + } + else { + for (i=0;i<finfo->length; i++) { + if (i == 0 ) { + sprintf(ptr, "%02x", *c++); + } + else { + sprintf(ptr, ":%02x", *c++); + } + ptr = buf+strlen(buf); + } + } + break; } - g_assert(enum_name); - return enum_name; + + return buf; } diff --git a/epan/proto.h b/epan/proto.h index e5abb3fd13..ce6afbf284 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1,7 +1,7 @@ /* proto.h * Definitions for protocol display * - * $Id: proto.h,v 1.5 2001/02/01 07:34:30 guy Exp $ + * $Id: proto.h,v 1.6 2001/02/01 20:21:16 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -43,6 +43,7 @@ #include "ipv4.h" #include "tvbuff.h" +#include "ftypes/ftypes.h" /* needs glib.h */ typedef GNode proto_tree; @@ -73,34 +74,6 @@ struct value_string; } \ } -/* field types */ -enum ftenum { - FT_NONE, /* used for protocol labels (thus no field type) */ - FT_BOOLEAN, /* TRUE and FALSE come from <glib.h> */ - FT_UINT8, - FT_UINT16, - FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/ - FT_UINT32, - FT_INT8, - FT_INT16, - FT_INT24, - FT_INT32, - FT_DOUBLE, - FT_ABSOLUTE_TIME, - FT_RELATIVE_TIME, - FT_STRING, - FT_STRINGZ, /* for use with proto_tree_add_item() */ - FT_UINT_STRING, /* for use with proto_tree_add_item() */ - FT_ETHER, - FT_BYTES, - FT_IPv4, - FT_IPv6, - FT_IPXNET, - FT_TEXT_ONLY, /* non-filterable, used when converting ethereal - from old-style proto_tree to new-style proto_tree */ - NUM_FIELD_TYPES /* last item number plus one */ -}; - enum { BASE_NONE, BASE_DEC, @@ -109,8 +82,11 @@ enum { BASE_BIN }; +typedef struct _header_field_info header_field_info; + /* information describing a header field */ -typedef struct header_field_info { +struct _header_field_info { + /* ---------- set by dissector --------- */ char *name; char *abbrev; enum ftenum type; @@ -119,10 +95,12 @@ typedef struct header_field_info { guint32 bitmask; char *blurb; /* Brief description of field. */ - int id; /* assigned by registration function, not programmer */ + /* ---------- set by proto routines --------- */ + int id; /* Field ID */ int parent; /* parent protocol */ int bitshift; /* bits to shift */ -} header_field_info; + header_field_info *same_name; /* Link to next hfinfo with same abbrev*/ +}; @@ -135,22 +113,13 @@ typedef struct hf_register_info { /* Info stored in each proto_item GNode */ typedef struct field_info { - struct header_field_info *hfinfo; + header_field_info *hfinfo; gint start; gint length; gint tree_type; /* ETT_* */ char *representation; /* for GUI tree */ int visible; - union { - guint32 numeric; - struct timeval time; /* the whole struct, not a pointer */ - gdouble floating; - gchar *string; - guint8 *bytes; - guint8 ether[6]; - ipv4_addr ipv4; - guint8 ipv6[16]; - } value; + fvalue_t *value; } field_info; @@ -213,6 +182,18 @@ proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb, /* Add a FT_NONE to a proto_tree */ #if __GNUC__ == 2 proto_item * +proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...) + __attribute__((format (printf, 6, 7))); +#else +proto_item * +proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, + gint length, const char *format, ...); +#endif + +/* Add a FT_PROTOCOL to a proto_tree */ +#if __GNUC__ == 2 +proto_item * proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, const char *format, ...) __attribute__((format (printf, 6, 7))); @@ -487,7 +468,7 @@ char* proto_registrar_get_name(int n); char* proto_registrar_get_abbrev(int n); /* get the header field information based upon a field or protocol id */ -struct header_field_info* proto_registrar_get_nth(int hfindex); +header_field_info* proto_registrar_get_nth(int hfindex); /* Returns enum ftenum for item # n */ int proto_registrar_get_ftype(int n); @@ -569,7 +550,10 @@ extern int num_tree_types; #define g_ptr_array_len(a) ((a)->len) #endif -/* Returns a string representing the field type */ -const char* proto_registrar_ftype_name(enum ftenum ftype); +int +hfinfo_bitwidth(header_field_info *hfinfo); + +char* +proto_alloc_dfilter_string(field_info *finfo, guint8 *pd); #endif /* proto.h */ |