aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHadriel Kaplan <hadrielk@yahoo.com>2015-07-08 15:20:50 -0400
committerHadriel Kaplan <hadrielk@yahoo.com>2015-07-09 01:49:11 +0000
commit281055af9ccdd701ba18accb39f3d25ab77168df (patch)
tree1471e64a629d3b02ac76077c256eb6cebb2f23fa
parent7b85f62ba3fe95e20004c31165c989a4fd29beb3 (diff)
Lua: add functions for more field information
Add Lua functions so a plugin can introspect field information, such as the type of field, flags, tvb, etc. Also add a couple of Tvb and ByteArray methods. And cleanup the TreeItem code a little. Change-Id: I7b58ce589ace91cce14b8abccd01ceabb63e2653 Reviewed-on: https://code.wireshark.org/review/6500 Petri-Dish: Hadriel Kaplan <hadrielk@yahoo.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Hadriel Kaplan <hadrielk@yahoo.com> Tested-by: Hadriel Kaplan <hadrielk@yahoo.com>
-rw-r--r--epan/wslua/init_wslua.c12
-rw-r--r--epan/wslua/lrexlib.h6
-rw-r--r--epan/wslua/lrexlib_glib.c3
-rw-r--r--epan/wslua/wslua.h9
-rw-r--r--epan/wslua/wslua_field.c197
-rw-r--r--epan/wslua/wslua_proto.c35
-rw-r--r--epan/wslua/wslua_tree.c203
-rw-r--r--epan/wslua/wslua_tvb.c108
-rw-r--r--test/lua/field.lua34
9 files changed, 532 insertions, 75 deletions
diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c
index 90b9e43d6a..fd42080ada 100644
--- a/epan/wslua/init_wslua.c
+++ b/epan/wslua/init_wslua.c
@@ -163,9 +163,6 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data
lua_pinfo = pinfo;
lua_tvb = tvb;
- lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
- PROTO_ITEM_SET_HIDDEN(lua_tree->item);
-
/*
* almost equivalent to Lua:
* dissectors[current_proto](tvb,pinfo,tree)
@@ -185,7 +182,8 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data
push_Tvb(L,tvb);
push_Pinfo(L,pinfo);
- push_TreeItem(L,lua_tree);
+ lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
+ PROTO_ITEM_SET_HIDDEN(lua_tree->item);
if ( lua_pcall(L,3,1,0) ) {
proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0, "Lua Error: %s", lua_tostring(L,-1));
@@ -278,12 +276,10 @@ gboolean heur_dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, v
return FALSE;
}
- lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
- PROTO_ITEM_SET_HIDDEN(lua_tree->item);
-
push_Tvb(L,tvb);
push_Pinfo(L,pinfo);
- push_TreeItem(L,lua_tree);
+ lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
+ PROTO_ITEM_SET_HIDDEN(lua_tree->item);
if ( lua_pcall(L,3,1,0) ) {
proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,
diff --git a/epan/wslua/lrexlib.h b/epan/wslua/lrexlib.h
index eff305cecb..34e2ce9189 100644
--- a/epan/wslua/lrexlib.h
+++ b/epan/wslua/lrexlib.h
@@ -53,9 +53,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* public function declarations */
REX_API int REX_OPENLIB (lua_State *L);
-int Gregex_get_compile_flags (lua_State *L);
-int Gregex_get_match_flags (lua_State *L);
-int Gregex_get_flags (lua_State *L);
+extern int Gregex_get_compile_flags (lua_State *L);
+extern int Gregex_get_match_flags (lua_State *L);
+extern int Gregex_get_flags (lua_State *L);
/* Special values for maxmatch in gsub. They all must be negative. */
#define GSUB_UNLIMITED -1
diff --git a/epan/wslua/lrexlib_glib.c b/epan/wslua/lrexlib_glib.c
index fd24c28a5c..8a4c11a47c 100644
--- a/epan/wslua/lrexlib_glib.c
+++ b/epan/wslua/lrexlib_glib.c
@@ -54,9 +54,6 @@ THE SOFTWARE.
#include "lauxlib.h"
#include "lrexlib.h"
-extern int Gregex_get_flags (lua_State *L);
-extern int Gregex_get_compile_flags (lua_State *L);
-extern int Gregex_get_match_flags (lua_State *L);
extern flag_pair gregex_error_flags[];
/* These 2 settings may be redefined from the command-line or the makefile.
diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h
index 8d41607ee3..18ea9d3019 100644
--- a/epan/wslua/wslua.h
+++ b/epan/wslua/wslua.h
@@ -118,7 +118,7 @@ typedef struct _wslua_field_t {
int hfid;
int ett;
char* name;
- char* abbr;
+ char* abbrev;
char* blob;
enum ftenum type;
unsigned base;
@@ -128,7 +128,7 @@ typedef struct _wslua_field_t {
typedef struct _wslua_expert_field_t {
expert_field ids;
- const gchar *abbr;
+ const gchar *abbrev;
const gchar *text;
int group;
int severity;
@@ -707,9 +707,10 @@ extern void clear_outstanding_Columns(void);
extern void clear_outstanding_PrivateTable(void);
extern int get_hf_wslua_text(void);
-extern TreeItem* push_TreeItem(lua_State* L, TreeItem ti);
+extern TreeItem push_TreeItem(lua_State *L, proto_tree *tree, proto_item *item);
extern void clear_outstanding_TreeItem(void);
+extern FieldInfo* push_FieldInfo(lua_State *L, field_info* f);
extern void clear_outstanding_FieldInfo(void);
extern void wslua_print_stack(char* s, lua_State* L);
@@ -720,7 +721,7 @@ extern int wslua_cleanup(void);
extern tap_extractor_t wslua_get_tap_extractor(const gchar* name);
extern int wslua_set_tap_enums(lua_State* L);
-extern int wslua_is_field_available(lua_State* L, const char* field_abbr);
+extern ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr);
extern char* wslua_get_actual_filename(const char* fname);
diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c
index 3bbdde3a1e..39a66f0e93 100644
--- a/epan/wslua/wslua_field.c
+++ b/epan/wslua/wslua_field.c
@@ -45,7 +45,13 @@ WSLUA_CLASS_DEFINE(FieldInfo,FAIL_ON_NULL_OR_EXPIRED("FieldInfo"),NOP);
static GPtrArray* outstanding_FieldInfo = NULL;
-#define PUSH_FIELDINFO(L,fi) {g_ptr_array_add(outstanding_FieldInfo,fi);pushFieldInfo(L,fi);}
+FieldInfo* push_FieldInfo(lua_State* L, field_info* f) {
+ FieldInfo fi = (FieldInfo) g_malloc(sizeof(struct _wslua_field_info));
+ fi->ws_fi = f;
+ fi->expired = FALSE;
+ g_ptr_array_add(outstanding_FieldInfo,fi);
+ return pushFieldInfo(L,fi);
+}
CLEAR_OUTSTANDING(FieldInfo,expired,TRUE)
@@ -210,7 +216,7 @@ WSLUA_METAMETHOD FieldInfo__call(lua_State* L) {
}
}
-/* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field */
+/* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field. */
WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) {
/* The string representation of the field. */
FieldInfo fi = checkFieldInfo(L,1);
@@ -244,7 +250,7 @@ WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) {
return 1;
}
-/* WSLUA_ATTRIBUTE FieldInfo_display RO The string display of this field as seen in GUI */
+/* WSLUA_ATTRIBUTE FieldInfo_display RO The string display of this field as seen in GUI. */
static int FieldInfo_get_display(lua_State* L) {
/* The display string of this field as seen in GUI. */
FieldInfo fi = checkFieldInfo(L,1);
@@ -272,7 +278,43 @@ static int FieldInfo_get_display(lua_State* L) {
return 1;
}
-/* WSLUA_ATTRIBUTE FieldInfo_range RO The `TvbRange` covering this field */
+/* WSLUA_ATTRIBUTE FieldInfo_type RO The internal field type, a number which
+ matches one of the `ftype` values in `init.lua`.
+
+ @since 1.99.9
+ */
+static int FieldInfo_get_type(lua_State* L) {
+ FieldInfo fi = checkFieldInfo(L,1);
+
+ if (fi->ws_fi->hfinfo) {
+ lua_pushnumber(L, fi->ws_fi->hfinfo->type);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE FieldInfo_source RO The source `Tvb` object the `FieldInfo` is derived
+ from, or nil if there is none.
+
+ @since 1.99.9
+ */
+static int FieldInfo_get_source(lua_State* L) {
+ FieldInfo fi = checkFieldInfo(L,1);
+
+ if (fi->ws_fi->ds_tvb) {
+ push_Tvb(L, fi->ws_fi->ds_tvb);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE FieldInfo_range RO The `TvbRange` covering this field. */
static int FieldInfo_get_range(lua_State* L) {
/* The `TvbRange` covering this field. */
FieldInfo fi = checkFieldInfo(L,1);
@@ -284,7 +326,7 @@ static int FieldInfo_get_range(lua_State* L) {
return 0;
}
-/* WSLUA_ATTRIBUTE FieldInfo_generated RO Whether this field was marked as generated (boolean) */
+/* WSLUA_ATTRIBUTE FieldInfo_generated RO Whether this field was marked as generated (boolean). */
static int FieldInfo_get_generated(lua_State* L) {
/* Whether this field was marked as generated. */
FieldInfo fi = checkFieldInfo(L,1);
@@ -293,7 +335,54 @@ static int FieldInfo_get_generated(lua_State* L) {
return 1;
}
-/* WSLUA_ATTRIBUTE FieldInfo_name RO The name of this field */
+/* WSLUA_ATTRIBUTE FieldInfo_hidden RO Whether this field was marked as hidden (boolean).
+
+ @since 1.99.9
+ */
+static int FieldInfo_get_hidden(lua_State* L) {
+ FieldInfo fi = checkFieldInfo(L,1);
+
+ lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_HIDDEN));
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE FieldInfo_is_url RO Whether this field was marked as being a URL (boolean).
+
+ @since 1.99.9
+ */
+static int FieldInfo_get_is_url(lua_State* L) {
+ FieldInfo fi = checkFieldInfo(L,1);
+
+ lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_URL));
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE FieldInfo_little_endian RO Whether this field is little-endian encoded (boolean).
+
+ @since 1.99.9
+ */
+static int FieldInfo_get_little_endian(lua_State* L) {
+ FieldInfo fi = checkFieldInfo(L,1);
+
+ lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_LITTLE_ENDIAN));
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE FieldInfo_big_endian RO Whether this field is big-endian encoded (boolean).
+
+ @since 1.99.9
+ */
+static int FieldInfo_get_big_endian(lua_State* L) {
+ FieldInfo fi = checkFieldInfo(L,1);
+
+ lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_BIG_ENDIAN));
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE FieldInfo_name RO The filter name of this field.
+
+ @since 1.99.9
+ */
static int FieldInfo_get_name(lua_State* L) {
/* The filter name of this field. */
FieldInfo fi = checkFieldInfo(L,1);
@@ -374,8 +463,14 @@ static int FieldInfo__gc(lua_State* L _U_) {
WSLUA_ATTRIBUTES FieldInfo_attributes[] = {
WSLUA_ATTRIBUTE_ROREG(FieldInfo,range),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,generated),
+ WSLUA_ATTRIBUTE_ROREG(FieldInfo,hidden),
+ WSLUA_ATTRIBUTE_ROREG(FieldInfo,is_url),
+ WSLUA_ATTRIBUTE_ROREG(FieldInfo,little_endian),
+ WSLUA_ATTRIBUTE_ROREG(FieldInfo,big_endian),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,name),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,display),
+ WSLUA_ATTRIBUTE_ROREG(FieldInfo,type),
+ WSLUA_ATTRIBUTE_ROREG(FieldInfo,source),
{ "label", FieldInfo__tostring, NULL },
{ "value", FieldInfo__call, NULL },
{ "tvb", FieldInfo_get_range, NULL },
@@ -422,11 +517,7 @@ WSLUA_FUNCTION wslua_all_field_infos(lua_State* L) {
if (found) {
for (i=0; i<found->len; i++) {
- FieldInfo fi = (FieldInfo)g_malloc(sizeof(struct _wslua_field_info));
- fi->ws_fi = (field_info *)g_ptr_array_index(found,i);
- fi->expired = FALSE;
-
- PUSH_FIELDINFO(L,fi);
+ push_FieldInfo(L, (field_info *)g_ptr_array_index(found,i));
items_found++;
}
@@ -583,6 +674,74 @@ WSLUA_CONSTRUCTOR Field_list(lua_State *L) {
WSLUA_RETURN(1); /* The array table of field filter names */
}
+/* the following is used in Field_get_xxx functions later */
+#define GET_HFINFO_MEMBER(luafunc, member) \
+ if (wanted_fields) { \
+ /* before registration, so it's a gchar** of the abbrev */ \
+ const gchar* name = (const gchar*) *fi; \
+ if (name) { \
+ hfinfo = proto_registrar_get_byname(name); \
+ if (!hfinfo) { \
+ /* could be a Lua-created field */ \
+ ProtoField pf = wslua_is_field_available(L, name); \
+ if (pf) { \
+ luafunc(L, pf->member); \
+ return 1; \
+ } \
+ } \
+ } else { \
+ luaL_error(L, "Field." #member ": unknown field"); \
+ return 0; \
+ } \
+ } else { \
+ hfinfo = *fi; \
+ } \
+ \
+ if (hfinfo) { \
+ luafunc(L,hfinfo->member); \
+ } else \
+ lua_pushnil(L)
+
+
+/* WSLUA_ATTRIBUTE Field_name RO The filter name of this field, or nil.
+
+ @since 1.99.9
+ */
+static int Field_get_name(lua_State* L) {
+ Field fi = checkField(L,1);
+ header_field_info* hfinfo = NULL;
+
+ GET_HFINFO_MEMBER(lua_pushstring, abbrev);
+
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE Field_display RO The full display name of this field, or nil.
+
+ @since 1.99.9
+ */
+static int Field_get_display(lua_State* L) {
+ Field fi = checkField(L,1);
+ header_field_info* hfinfo = NULL;
+
+ GET_HFINFO_MEMBER(lua_pushstring, name);
+
+ return 1;
+}
+
+/* WSLUA_ATTRIBUTE Field_type RO The `ftype` of this field, or nil.
+
+ @since 1.99.9
+ */
+static int Field_get_type(lua_State* L) {
+ Field fi = checkField(L,1);
+ header_field_info* hfinfo = NULL;
+
+ GET_HFINFO_MEMBER(lua_pushnumber, type);
+
+ return 1;
+}
+
WSLUA_METAMETHOD Field__call (lua_State* L) {
/* Obtain all values (see `FieldInfo`) for this field. */
Field f = checkField(L,1);
@@ -604,11 +763,7 @@ WSLUA_METAMETHOD Field__call (lua_State* L) {
guint i;
if (found) {
for (i=0; i<found->len; i++) {
- FieldInfo fi = (FieldInfo)g_malloc(sizeof(struct _wslua_field_info));
- fi->ws_fi = (field_info *)g_ptr_array_index(found,i);
- fi->expired = FALSE;
-
- PUSH_FIELDINFO(L,fi);
+ push_FieldInfo(L, (field_info *) g_ptr_array_index(found,i));
items_found++;
}
}
@@ -619,7 +774,7 @@ WSLUA_METAMETHOD Field__call (lua_State* L) {
}
WSLUA_METAMETHOD Field__tostring(lua_State* L) {
- /* Obtain a string with the field name. */
+ /* Obtain a string with the field filter name. */
Field f = checkField(L,1);
if (wanted_fields) {
@@ -636,6 +791,13 @@ static int Field__gc(lua_State* L _U_) {
return 0;
}
+WSLUA_ATTRIBUTES Field_attributes[] = {
+ WSLUA_ATTRIBUTE_ROREG(Field,name),
+ WSLUA_ATTRIBUTE_ROREG(Field,display),
+ WSLUA_ATTRIBUTE_ROREG(Field,type),
+ { NULL, NULL, NULL }
+};
+
WSLUA_METHODS Field_methods[] = {
WSLUA_CLASS_FNREG(Field,new),
WSLUA_CLASS_FNREG(Field,list),
@@ -653,6 +815,7 @@ int Field_register(lua_State* L) {
wanted_fields = g_ptr_array_new();
WSLUA_REGISTER_CLASS(Field);
+ WSLUA_REGISTER_ATTRIBUTES(Field);
outstanding_FieldInfo = g_ptr_array_new();
return 0;
diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c
index 2a4197a7ba..8cd3907ad5 100644
--- a/epan/wslua/wslua_proto.c
+++ b/epan/wslua/wslua_proto.c
@@ -876,7 +876,7 @@ WSLUA_CONSTRUCTOR ProtoField_new(lua_State* L) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
- f->abbr = g_strdup(abbr);
+ f->abbrev = g_strdup(abbr);
f->type = type;
f->base = base;
if (tfs) {
@@ -940,7 +940,7 @@ static int ProtoField_integer(lua_State* L, enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
- f->abbr = g_strdup(abbr);
+ f->abbrev = g_strdup(abbr);
f->type = type;
f->base = base;
if (vs64) {
@@ -1104,7 +1104,7 @@ static int ProtoField_boolean(lua_State* L, enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
- f->abbr = g_strdup(abbr);
+ f->abbrev = g_strdup(abbr);
f->type = type;
f->vs = TFS(tfs);
f->base = base;
@@ -1157,7 +1157,7 @@ static int ProtoField_time(lua_State* L,enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
- f->abbr = g_strdup(abbr);
+ f->abbrev = g_strdup(abbr);
f->type = type;
f->vs = NULL;
f->base = base;
@@ -1201,7 +1201,7 @@ static int ProtoField_other(lua_State* L,enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
- f->abbr = g_strdup(abbr);
+ f->abbrev = g_strdup(abbr);
f->type = type;
f->vs = NULL;
f->base = BASE_NONE;
@@ -1330,7 +1330,7 @@ WSLUA_METAMETHOD ProtoField__tostring(lua_State* L) {
/* Returns a string with info about a protofield (for debugging purposes). */
ProtoField f = checkProtoField(L,1);
gchar* s = g_strdup_printf("ProtoField(%i): %s %s %s %s %p %.8x %s",
- f->hfid,f->name,f->abbr,
+ f->hfid,f->name,f->abbrev,
ftenum_to_string(f->type),
base_to_string(f->base),
f->vs,f->mask,f->blob);
@@ -1355,7 +1355,7 @@ static int ProtoField__gc(lua_State* L) {
/* g_assert() ?? */
} else if (f->hfid == -2) {
g_free(f->name);
- g_free(f->abbr);
+ g_free(f->abbrev);
g_free(f->blob);
g_free(f);
}
@@ -1443,7 +1443,7 @@ WSLUA_CONSTRUCTOR ProtoExpert_new(lua_State* L) {
pe->ids.ei = EI_INIT_EI;
pe->ids.hf = EI_INIT_HF;
- pe->abbr = g_strdup(abbr);
+ pe->abbrev = g_strdup(abbr);
pe->text = g_strdup(text);
pe->group = group;
pe->severity = severity;
@@ -1464,7 +1464,7 @@ WSLUA_METAMETHOD ProtoExpert__tostring(lua_State* L) {
lua_pushstring(L,"ProtoExpert pointer is NULL!");
} else {
lua_pushfstring(L, "ProtoExpert: ei=%d, hf=%d, abbr=%s, text=%s, group=%d, severity=%d",
- pe->ids.ei, pe->ids.hf, pe->abbr, pe->text, pe->group, pe->severity);
+ pe->ids.ei, pe->ids.hf, pe->abbrev, pe->text, pe->group, pe->severity);
}
return 1;
}
@@ -1953,7 +1953,7 @@ int Proto_register(lua_State* L) {
* Query field abbr that is defined and bound to a Proto in lua.
* They are not registered until the end of the initialization.
*/
-int wslua_is_field_available(lua_State* L, const char* field_abbr) {
+ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr) {
lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref);
lua_pushnil(L);
while (lua_next(L, -2)) {
@@ -1965,10 +1965,10 @@ int wslua_is_field_available(lua_State* L, const char* field_abbr) {
lua_pushnil(L);
while (lua_next(L, -2)) {
ProtoField f = checkProtoField(L, -1);
- if (strcmp(field_abbr, f->abbr) == 0) {
+ if (strcmp(field_abbr, f->abbrev) == 0) {
/* found! */
lua_pop(L, 6);
- return 1;
+ return f;
}
lua_pop(L, 1); /* table value */
}
@@ -1976,7 +1976,7 @@ int wslua_is_field_available(lua_State* L, const char* field_abbr) {
}
lua_pop(L, 1); /* protocols_table_ref */
- return 0;
+ return NULL;
}
int Proto_commit(lua_State* L) {
@@ -2010,7 +2010,7 @@ int Proto_commit(lua_State* L) {
hfri.p_id = &(f->hfid);
hfri.hfinfo.name = f->name;
- hfri.hfinfo.abbrev = f->abbr;
+ hfri.hfinfo.abbrev = f->abbrev;
hfri.hfinfo.type = f->type;
hfri.hfinfo.display = f->base;
hfri.hfinfo.strings = VALS(f->vs);
@@ -2043,7 +2043,7 @@ int Proto_commit(lua_State* L) {
ei_register_info eiri = { NULL, { NULL, 0, 0, NULL, EXPFILL } };
eiri.ids = &(e->ids);
- eiri.eiinfo.name = e->abbr;
+ eiri.eiinfo.name = e->abbrev;
eiri.eiinfo.group = e->group;
eiri.eiinfo.severity = e->severity;
eiri.eiinfo.summary = e->text;
@@ -2143,12 +2143,11 @@ wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo,
lua_rawgeti(L, LUA_REGISTRYINDEX, fs->dissect_ref);
if (lua_isfunction(L,1)) {
- /* XXX: not sure if it's kosher to just use the tree as the item */
- TreeItem ti = create_TreeItem(tree, (proto_item*)tree);
push_Tvb(L,tvb);
push_Pinfo(L,pinfo);
- push_TreeItem(L,ti);
+ /* XXX: not sure if it's kosher to just use the tree as the item */
+ push_TreeItem(L, tree, (proto_item*)tree);
if ( lua_pcall(L,3,1,0) ) {
luaL_error(L, "Lua Error dissect_tcp_pdus dissect_func: %s", lua_tostring(L,-1));
diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c
index f65bed1ae1..fe251f1c83 100644
--- a/epan/wslua/wslua_tree.c
+++ b/epan/wslua/wslua_tree.c
@@ -37,13 +37,21 @@ static gint wslua_ett = -1;
static GPtrArray* outstanding_TreeItem = NULL;
-#define PUSH_TREEITEM(L,i) {g_ptr_array_add(outstanding_TreeItem,i);pushTreeItem(L,i);}
-TreeItem* push_TreeItem(lua_State*L, TreeItem t) {
- g_ptr_array_add(outstanding_TreeItem,t);
- return pushTreeItem(L,t);
+/* pushing a TreeItem with a NULL item or subtree is completely valid for this function */
+TreeItem push_TreeItem(lua_State *L, proto_tree *tree, proto_item *item) {
+ TreeItem ti = (struct _wslua_treeitem *)g_malloc(sizeof(struct _wslua_treeitem));
+
+ ti->tree = tree;
+ ti->item = item;
+ ti->expired = FALSE;
+
+ g_ptr_array_add(outstanding_TreeItem, ti);
+
+ return *(pushTreeItem(L,ti));
}
+/* creates the TreeItem but does NOT push it into Lua */
TreeItem create_TreeItem(proto_tree* tree, proto_item* item)
{
TreeItem tree_item = (TreeItem)g_malloc(sizeof(struct _wslua_treeitem));
@@ -57,8 +65,25 @@ TreeItem create_TreeItem(proto_tree* tree, proto_item* item)
CLEAR_OUTSTANDING(TreeItem, expired, TRUE)
WSLUA_CLASS_DEFINE(TreeItem,FAIL_ON_NULL_OR_EXPIRED("TreeItem"),NOP);
-/* ++TreeItem++s represent information in the packet-details pane.
- A root +TreeItem+ is passed to dissectors as the third argument. */
+/* ++TreeItem++s represent information in the packet-details pane of
+ Wireshark, and the packet details view of Tshark. A `TreeItem` represents
+ a node in the tree, which might also be a subtree and have a list of
+ children. The children of a subtree have zero or more siblings: other children
+ of the same `TreeItem` subtree.
+
+ During dissection, heuristic-dissection, and post-dissection, a root
+ +TreeItem+ is passed to dissectors as the third argument of the function
+ callback (e.g., `myproto.dissector(tvbuf,pktinfo,root)`).
+
+ In some cases the tree is not truly added to, in order to improve performance.
+ For example for packets not currently displayed/selected in Wireshark's visible
+ window pane, or if Tshark isn't invoked with the `-V` switch. However the
+ "add" type `TreeItem` functions can still be called, and still return `TreeItem`
+ objects - but the info isn't really added to the tree. Therefore you do not
+ typically need to worry about whether there's a real tree or not. If, for some
+ reason, you need to know it, you can use the `tree.visible` attribute getter
+ to retrieve the state.
+ */
/* the following is used by TreeItem_add_packet_field() - this can THROW errors */
static proto_item *
@@ -264,9 +289,7 @@ WSLUA_METHOD TreeItem_add_packet_field(lua_State *L) {
nargs--;
}
- tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
-
- PUSH_TREEITEM(L,tree_item);
+ tree_item = push_TreeItem(L, proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
/* move the tree object before the field value */
lua_insert(L, 1);
@@ -315,7 +338,11 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) {
}
if (hfid > 0 ) {
+ /* hfid is > 0 when the first arg was a ProtoField or Proto */
+
if (lua_gettop(L)) {
+ /* if we got here, the (L,1) index is the value to add, instead of decoding from the Tvb */
+
switch(type) {
case FT_PROTOCOL:
item = proto_tree_add_item(tree_item->tree,hfid,tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len,ENC_NA);
@@ -388,17 +415,20 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) {
lua_remove(L,1);
} else {
+ /* the Lua stack is empty - no value was given - so decode the value from the tvb */
if (type == FT_STRINGZ) tvbr->len = tvb_strsize (tvbr->tvb->ws_tvb, tvbr->offset);
item = proto_tree_add_item(tree_item->tree, hfid, tvbr->tvb->ws_tvb, tvbr->offset, tvbr->len, little_endian ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN);
}
if ( lua_gettop(L) ) {
+ /* if there was a value, it was removed earlier, so what's left is the display string to set */
const gchar* s = lua_tostring(L,1);
if (s) proto_item_set_text(item,"%s",s);
lua_remove(L,1);
}
} else {
+ /* no ProtoField or Proto was given */
if (lua_gettop(L)) {
const gchar* s = lua_tostring(L,1);
const int hf = get_hf_wslua_text();
@@ -416,14 +446,13 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) {
}
while(lua_gettop(L)) {
+ /* keep appending more text */
const gchar* s = lua_tostring(L,1);
if (s) proto_item_append_text(item, " %s", s);
lua_remove(L,1);
}
- tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
-
- PUSH_TREEITEM(L,tree_item);
+ tree_item = push_TreeItem(L, proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
return 1;
}
@@ -467,6 +496,38 @@ WSLUA_METHOD TreeItem_add_le(lua_State *L) {
WSLUA_RETURN(TreeItem_add_item_any(L,TRUE)); /* The new child TreeItem. */
}
+/* WSLUA_ATTRIBUTE TreeItem_text RW Set/get the `TreeItem`'s display string (string).
+
+ For the getter, if the TreeItem has no display string, then nil is returned.
+
+ @since 1.99.3
+ */
+static int TreeItem_get_text(lua_State* L) {
+ TreeItem ti = checkTreeItem(L,1);
+ gchar label_str[ITEM_LABEL_LENGTH+1];
+ gchar *label_ptr;
+ field_info *fi = PITEM_FINFO(ti->item);
+
+ if(fi) {
+ if (!fi->rep) {
+ label_ptr = label_str;
+ proto_item_fill_label(fi, label_str);
+ } else
+ label_ptr = fi->rep->representation;
+
+ if (label_ptr) {
+ lua_pushstring(L, label_ptr);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/* the following is used as both a method and attribute */
WSLUA_METHOD TreeItem_set_text(lua_State *L) {
/* Sets the text of the label.
@@ -636,14 +697,55 @@ WSLUA_METHOD TreeItem_add_tvb_expert_info(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
+
+/* WSLUA_ATTRIBUTE TreeItem_visible RO Get the `TreeItem`'s subtree visibility status (boolean).
+
+ @since 1.99.9
+ */
+static int TreeItem_get_visible(lua_State* L) {
+ TreeItem ti = checkTreeItem(L,1);
+
+ if (ti->tree) {
+ lua_pushboolean(L, PTREE_DATA(ti->tree)->visible);
+ }
+ else {
+ lua_pushboolean(L, FALSE);
+ }
+
+ return 1;
+}
+
+
+/* WSLUA_ATTRIBUTE TreeItem_generated RW Set/get the `TreeItem`'s generated state (boolean).
+
+ @since 1.99.9
+ */
+static int TreeItem_get_generated(lua_State* L) {
+ TreeItem ti = checkTreeItem(L,1);
+
+ lua_pushboolean(L, PROTO_ITEM_IS_GENERATED(ti->item));
+
+ return 1;
+}
+
+/* the following is used as both a method and attribute. As a method it defaults
+ to setting the value, because that's what it used to do before. */
WSLUA_METHOD TreeItem_set_generated(lua_State *L) {
/* Marks the `TreeItem` as a generated field (with data inferred but not contained in the packet).
This used to return nothing, but as of 1.11.3 it returns the same tree item to allow chained calls.
*/
+#define WSLUA_OPTARG_TreeItem_set_generated_BOOL 2 /* A Lua boolean, which if `true` sets the `TreeItem`
+ generated flag, else clears it (default=true) */
TreeItem ti = checkTreeItem(L,1);
+ gboolean set = wslua_optbool(L, WSLUA_OPTARG_TreeItem_set_generated_BOOL, TRUE);
- PROTO_ITEM_SET_GENERATED(ti->item);
+ if (set) {
+ PROTO_ITEM_SET_GENERATED(ti->item);
+ } else {
+ if (ti->item)
+ FI_RESET_FLAG(PITEM_FINFO(ti->item), FI_GENERATED);
+ }
/* copy the TreeItem userdata so we give it back */
lua_pushvalue(L, 1);
@@ -651,12 +753,35 @@ WSLUA_METHOD TreeItem_set_generated(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
+/* WSLUA_ATTRIBUTE TreeItem_hidden RW Set/get `TreeItem`'s hidden state (boolean).
+ @since 1.99.9
+ */
+static int TreeItem_get_hidden(lua_State* L) {
+ TreeItem ti = checkTreeItem(L,1);
+
+ lua_pushboolean(L, PROTO_ITEM_IS_HIDDEN(ti->item));
+
+ return 1;
+}
+
+/* the following is used as both a method and attribute. As a method it defaults
+ to setting the value, because that's what it used to do before. */
WSLUA_METHOD TreeItem_set_hidden(lua_State *L) {
- /* This function should not be used, and is provided for backwards-compatibility only. */
+ /* Marks the `TreeItem` as a hidden field (neither displayed nor used in filters).
+
+ This used to return nothing, but as of 1.11.3 it returns the same tree item to allow chained calls.
+ */
+#define WSLUA_OPTARG_TreeItem_set_hidden_BOOL 2 /* A Lua boolean, which if `true` sets the `TreeItem`
+ hidden flag, else clears it (default=true) */
TreeItem ti = checkTreeItem(L,1);
+ gboolean set = wslua_optbool(L, WSLUA_OPTARG_TreeItem_set_hidden_BOOL, TRUE);
- PROTO_ITEM_SET_HIDDEN(ti->item);
+ if (set) {
+ PROTO_ITEM_SET_HIDDEN(ti->item);
+ } else {
+ PROTO_ITEM_SET_VISIBLE(ti->item);
+ }
/* copy the TreeItem userdata so we give it back */
lua_pushvalue(L, 1);
@@ -664,6 +789,21 @@ WSLUA_METHOD TreeItem_set_hidden(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
+/* WSLUA_ATTRIBUTE TreeItem_len RW Set/get `TreeItem`'s length inside tvb, after it has already been created.
+
+ @since 1.99.9
+ */
+static int TreeItem_get_len(lua_State* L) {
+ TreeItem ti = checkTreeItem(L,1);
+ int len = 0;
+
+ len = proto_item_get_len(ti->item);
+
+ lua_pushinteger(L, len > 0 ? len : 0);
+
+ return 1;
+}
+
WSLUA_METHOD TreeItem_set_len(lua_State *L) {
/* Set `TreeItem`'s length inside tvb, after it has already been created.
@@ -681,6 +821,28 @@ WSLUA_METHOD TreeItem_set_len(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
+WSLUA_METAMETHOD TreeItem__tostring(lua_State* L) {
+ /* Returns string debug information about the `TreeItem`.
+
+ @since 1.99.9
+ */
+ TreeItem ti = toTreeItem(L,1);
+
+ if (ti) {
+ lua_pushfstring(L,
+ "TreeItem: expired=%s, has item=%s, has subtree=%s, they are %sthe same",
+ ti->expired ? "true" : "false",
+ ti->item ? "true" : "false",
+ ti->tree ? "true" : "false",
+ (ti->tree == ti->item) ? "" : "not ");
+ }
+ else {
+ lua_pushstring(L, "No TreeItem object!");
+ }
+
+ return 1;
+}
+
/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
static int TreeItem__gc(lua_State* L) {
TreeItem ti = toTreeItem(L,1);
@@ -692,6 +854,15 @@ static int TreeItem__gc(lua_State* L) {
return 0;
}
+WSLUA_ATTRIBUTES TreeItem_attributes[] = {
+ WSLUA_ATTRIBUTE_RWREG(TreeItem,generated),
+ WSLUA_ATTRIBUTE_RWREG(TreeItem,hidden),
+ WSLUA_ATTRIBUTE_RWREG(TreeItem,len),
+ WSLUA_ATTRIBUTE_RWREG(TreeItem,text),
+ WSLUA_ATTRIBUTE_ROREG(TreeItem,visible),
+ { NULL, NULL, NULL }
+};
+
WSLUA_METHODS TreeItem_methods[] = {
WSLUA_CLASS_FNREG(TreeItem,add_packet_field),
WSLUA_CLASS_FNREG(TreeItem,add),
@@ -709,12 +880,14 @@ WSLUA_METHODS TreeItem_methods[] = {
};
WSLUA_META TreeItem_meta[] = {
+ WSLUA_CLASS_MTREG(TreeItem,tostring),
{ NULL, NULL }
};
int TreeItem_register(lua_State *L) {
gint* etts[] = { &wslua_ett };
WSLUA_REGISTER_CLASS(TreeItem);
+ WSLUA_REGISTER_ATTRIBUTES(TreeItem);
outstanding_TreeItem = g_ptr_array_new();
proto_register_subtree_array(etts,1);
return 0;
diff --git a/epan/wslua/wslua_tvb.c b/epan/wslua/wslua_tvb.c
index 8c8ed4e118..5fad6ddbf5 100644
--- a/epan/wslua/wslua_tvb.c
+++ b/epan/wslua/wslua_tvb.c
@@ -563,6 +563,42 @@ WSLUA_METHOD Tvb_reported_length_remaining(lua_State* L) {
WSLUA_RETURN(1); /* The captured length of the `Tvb`. */
}
+WSLUA_METHOD Tvb_bytes(lua_State* L) {
+ /* Obtain a `ByteArray` from a `Tvb`.
+
+ @since 1.99.9
+ */
+#define WSLUA_OPTARG_Tvb_bytes_OFFSET 2 /* The offset (in octets) from the beginning of the `Tvb`. Defaults to 0. */
+#define WSLUA_OPTARG_Tvb_bytes_LENGTH 3 /* The length (in octets) of the range. Defaults to until the end of the `Tvb`. */
+ Tvb tvb = checkTvb(L,1);
+ GByteArray* ba;
+ int offset = luaL_optint(L, WSLUA_OPTARG_Tvb_bytes_OFFSET, 0);
+ int len = luaL_optint(L,WSLUA_OPTARG_Tvb_bytes_LENGTH,-1);
+
+ if (tvb->expired) {
+ luaL_error(L,"expired tvb");
+ return 0;
+ }
+
+ ba = g_byte_array_new();
+
+ if (len < 0) {
+ len = tvb_captured_length_remaining(tvb->ws_tvb,offset);
+ if (len < 0) {
+ luaL_error(L,"out of bounds");
+ return 0;
+ }
+ } else if ( (guint)(len + offset) > tvb_captured_length(tvb->ws_tvb)) {
+ luaL_error(L,"Range is out of bounds");
+ return 0;
+ }
+
+ g_byte_array_append(ba, tvb_get_ptr(tvb->ws_tvb, offset, len), len);
+ pushByteArray(L,ba);
+
+ WSLUA_RETURN(1); /* The `ByteArray` object or nil. */
+}
+
WSLUA_METHOD Tvb_offset(lua_State* L) {
/* Returns the raw offset (from the beginning of the source `Tvb`) of a sub `Tvb`. */
Tvb tvb = checkTvb(L,1);
@@ -674,7 +710,40 @@ WSLUA_METHOD Tvb_raw(lua_State* L) {
WSLUA_RETURN(1); /* A Lua string of the binary bytes in the `Tvb`. */
}
+WSLUA_METAMETHOD Tvb__eq(lua_State* L) {
+ /* Checks whether the two `Tvb` contents are equal.
+
+ @since 1.99.9
+ */
+ Tvb tvb_l = checkTvb(L,1);
+ Tvb tvb_r = checkTvb(L,2);
+
+ int len_l = tvb_captured_length(tvb_l->ws_tvb);
+ int len_r = tvb_captured_length(tvb_r->ws_tvb);
+
+ /* it is not an error if their ds_tvb are different... they're just not equal */
+ if (len_l == len_r)
+ {
+ const gchar* lp = tvb_get_ptr(tvb_l->ws_tvb, 0, len_l);
+ const gchar* rp = tvb_get_ptr(tvb_r->ws_tvb, 0, len_r);
+ int i = 0;
+
+ for (; i < len_l; ++i) {
+ if (lp[i] != rp[i]) {
+ lua_pushboolean(L,0);
+ return 1;
+ }
+ }
+ lua_pushboolean(L,1);
+ } else {
+ lua_pushboolean(L,0);
+ }
+
+ return 1;
+}
+
WSLUA_METHODS Tvb_methods[] = {
+ WSLUA_CLASS_FNREG(Tvb,bytes),
WSLUA_CLASS_FNREG(Tvb,range),
WSLUA_CLASS_FNREG(Tvb,len),
WSLUA_CLASS_FNREG(Tvb,offset),
@@ -685,6 +754,7 @@ WSLUA_METHODS Tvb_methods[] = {
};
WSLUA_META Tvb_meta[] = {
+ WSLUA_CLASS_MTREG(Tvb,eq),
WSLUA_CLASS_MTREG(Tvb,tostring),
{"__call", Tvb_range},
{ NULL, NULL }
@@ -722,13 +792,6 @@ WSLUA_METHOD TvbRange_uint(lua_State* L) {
case 4:
lua_pushnumber(L,tvb_get_ntohl(tvbr->tvb->ws_tvb,tvbr->offset));
WSLUA_RETURN(1); /* The unsigned integer value. */
- /*
- * XXX:
- * lua uses double so we have 52 bits to play with
- * we are missing 5 and 6 byte integers within lua's range
- * and 64 bit integers are not supported (there's a lib for
- * lua that does).
- */
default:
luaL_error(L,"TvbRange:uint() does not handle %d byte integers",tvbr->len);
return 0;
@@ -1576,6 +1639,36 @@ WSLUA_METHOD TvbRange_raw(lua_State* L) {
WSLUA_RETURN(1); /* A Lua string of the binary bytes in the `TvbRange`. */
}
+WSLUA_METAMETHOD TvbRange__eq(lua_State* L) {
+ /* Checks whether the two `TvbRange` contents are equal.
+
+ @since 1.99.9
+ */
+ TvbRange tvb_l = checkTvbRange(L,1);
+ TvbRange tvb_r = checkTvbRange(L,2);
+
+ /* it is not an error if their ds_tvb are different... they're just not equal */
+ if (tvb_l->len == tvb_r->len &&
+ tvb_l->len <= tvb_captured_length_remaining(tvb_l->tvb->ws_tvb, tvb_l->offset) &&
+ tvb_r->len <= tvb_captured_length_remaining(tvb_r->tvb->ws_tvb, tvb_r->offset))
+ {
+ const gchar* lp = tvb_get_ptr(tvb_l->tvb->ws_tvb, tvb_l->offset, tvb_l->len);
+ const gchar* rp = tvb_get_ptr(tvb_r->tvb->ws_tvb, tvb_r->offset, tvb_r->len);
+ int i = 0;
+
+ for (; i < tvb_r->len; ++i) {
+ if (lp[i] != rp[i]) {
+ lua_pushboolean(L,0);
+ return 1;
+ }
+ }
+ lua_pushboolean(L,1);
+ } else {
+ lua_pushboolean(L,0);
+ }
+
+ return 1;
+}
WSLUA_METAMETHOD TvbRange__tostring(lua_State* L) {
/* Converts the `TvbRange` into a string. Since the string gets truncated,
@@ -1635,6 +1728,7 @@ WSLUA_METHODS TvbRange_methods[] = {
WSLUA_META TvbRange_meta[] = {
WSLUA_CLASS_MTREG(TvbRange,tostring),
WSLUA_CLASS_MTREG(wslua,concat),
+ WSLUA_CLASS_MTREG(TvbRange,eq),
{"__call", TvbRange_range},
{ NULL, NULL }
};
diff --git a/test/lua/field.lua b/test/lua/field.lua
index b77528729e..2e9d1c62bb 100644
--- a/test/lua/field.lua
+++ b/test/lua/field.lua
@@ -72,6 +72,18 @@ local f_bootp_opt = Field.new("bootp.option.type")
test("Field__tostring-1", tostring(f_frame_proto) == "frame.protocols")
+test("Field.name-1", f_frame_proto.name == "frame.protocols")
+test("Field.name-2", f_eth_src.name == "eth.src")
+
+test("Field.display-1", f_frame_proto.display == "Protocols in frame")
+test("Field.display-2", f_eth_src.display == "Source")
+
+test("Field.type-1", f_frame_proto.type == ftypes.STRING)
+test("Field.type-2", f_eth_src.type == ftypes.ETHER)
+test("Field.type-3", f_ip_src.type == ftypes.IPv4)
+test("Field.type-4", f_udp_srcport.type == ftypes.UINT16)
+test("Field.type-5", f_bootp_opt.type == ftypes.UINT8)
+
-- make sure can't create a FieldInfo outside tap
test("Field__call-1",not pcall(makeFieldInfo,f_eth_src))
@@ -90,11 +102,33 @@ function tap.packet(pinfo,tvb)
test("Field__call-2",pcall(makeFieldInfo,f_eth_src))
+ test("Field.name-3", f_frame_proto.name == "frame.protocols")
+ test("Field.name-4", f_eth_src.name == "eth.src")
+
+ test("Field.display-3", f_frame_proto.display == "Protocols in frame")
+ test("Field.display-4", f_eth_src.display == "Source")
+
+ test("Field.type-6", f_frame_proto.type == ftypes.STRING)
+ test("Field.type-7", f_eth_src.type == ftypes.ETHER)
+ test("Field.type-8", f_ip_src.type == ftypes.IPv4)
+ test("Field.type-9", f_udp_srcport.type == ftypes.UINT16)
+ test("Field.type-10", f_bootp_opt.type == ftypes.UINT8)
testing("FieldInfo")
+ local finfo_udp_srcport = f_udp_srcport()
+ test("FieldInfo.name-1", finfo_udp_srcport.name == "udp.srcport")
+ test("FieldInfo.type-1", finfo_udp_srcport.type == ftypes.UINT16)
+ test("FieldInfo.little_endian-1", finfo_udp_srcport.little_endian == false)
+ -- the following should be true, but UDP doesn't set it right?
+ -- test("FieldInfo.big_endian-1", finfo_udp_srcport.big_endian == true)
+ test("FieldInfo.is_url-1", finfo_udp_srcport.is_url == false)
+ test("FieldInfo.offset-1", finfo_udp_srcport.offset == 34)
+ test("FieldInfo.source-1", finfo_udp_srcport.source == tvb)
+
-- check ether addr
local fi_eth_src = f_eth_src()
+ test("FieldInfo.type-2", fi_eth_src.type == ftypes.ETHER)
test("FieldInfo.range-0",pcall(getFieldInfo,fi_eth_src,"range"))
local eth_macs = { f_eth_mac() }
local eth_src1 = tostring(f_eth_src().range)