Handle hop-by-hop-id collisions (when matching requests and answers) better:

instead of storing the requests in an se_tree (keyed by hop-by-hop-id),
store an se_tree which is itself keyed by frame number.  When looking for
a matching request, first find the tree of pdus (by hop-by-hop-id) and then
look for the largest frame number less than or equal to the answer's frame
number.  Also verify that the end-to-end-id matches.

Move the conversation structure out of packet-diameter.h: it's only used in
packet-diameter.c

svn path=/trunk/; revision=46553
This commit is contained in:
Jeff Morriss 2012-12-16 01:12:59 +00:00
parent b369116122
commit 01fd357171
1 changed files with 218 additions and 186 deletions

View File

@ -96,52 +96,57 @@
#define DIAMETER_V16 16 #define DIAMETER_V16 16
#define DIAMETER_RFC 1 #define DIAMETER_RFC 1
/* Conversation Info */
typedef struct _diameter_conv_info_t {
emem_tree_t *pdus_tree;
} diameter_conv_info_t;
typedef struct _diam_ctx_t { typedef struct _diam_ctx_t {
proto_tree* tree; proto_tree *tree;
packet_info* pinfo; packet_info *pinfo;
emem_tree_t* avps; emem_tree_t *avps;
gboolean version_rfc; gboolean version_rfc;
} diam_ctx_t; } diam_ctx_t;
typedef struct _diam_avp_t diam_avp_t; typedef struct _diam_avp_t diam_avp_t;
typedef struct _avp_type_t avp_type_t; typedef struct _avp_type_t avp_type_t;
typedef const char* (*diam_avp_dissector_t)(diam_ctx_t*, diam_avp_t*, tvbuff_t*); typedef const char *(*diam_avp_dissector_t)(diam_ctx_t *, diam_avp_t *, tvbuff_t *);
typedef struct _diam_vnd_t { typedef struct _diam_vnd_t {
guint32 code; guint32 code;
GArray* vs_avps; GArray *vs_avps;
value_string_ext* vs_avps_ext; value_string_ext *vs_avps_ext;
GArray* vs_cmds; GArray *vs_cmds;
} diam_vnd_t; } diam_vnd_t;
struct _diam_avp_t { struct _diam_avp_t {
guint32 code; guint32 code;
const diam_vnd_t* vendor; const diam_vnd_t *vendor;
diam_avp_dissector_t dissector_v16; diam_avp_dissector_t dissector_v16;
diam_avp_dissector_t dissector_rfc; diam_avp_dissector_t dissector_rfc;
gint ett; gint ett;
int hf_value; int hf_value;
void* type_data; void *type_data;
}; };
#define VND_AVP_VS(v) ((value_string*)(void*)((v)->vs_avps->data)) #define VND_AVP_VS(v) ((value_string *)(void *)((v)->vs_avps->data))
#define VND_AVP_VS_LEN(v) ((v)->vs_avps->len) #define VND_AVP_VS_LEN(v) ((v)->vs_avps->len)
#define VND_CMD_VS(v) ((value_string*)(void*)((v)->vs_cmds->data)) #define VND_CMD_VS(v) ((value_string *)(void *)((v)->vs_cmds->data))
typedef struct _diam_dictionary_t { typedef struct _diam_dictionary_t {
emem_tree_t* avps; emem_tree_t *avps;
emem_tree_t* vnds; emem_tree_t *vnds;
value_string* applications; value_string *applications;
value_string* commands; value_string *commands;
} diam_dictionary_t; } diam_dictionary_t;
typedef diam_avp_t* (*avp_constructor_t)(const avp_type_t*, guint32, const diam_vnd_t*, const char*, const value_string*, void*); typedef diam_avp_t *(*avp_constructor_t)(const avp_type_t *, guint32, const diam_vnd_t *, const char *, const value_string *, void *);
struct _avp_type_t { struct _avp_type_t {
const char* name; const char *name;
diam_avp_dissector_t v16; diam_avp_dissector_t v16;
diam_avp_dissector_t rfc; diam_avp_dissector_t rfc;
enum ftenum ft; enum ftenum ft;
@ -150,10 +155,10 @@ struct _avp_type_t {
}; };
struct _build_dict { struct _build_dict {
GArray* hf; GArray *hf;
GPtrArray* ett; GPtrArray *ett;
GHashTable* types; GHashTable *types;
GHashTable* avps; GHashTable *avps;
}; };
@ -172,20 +177,20 @@ typedef enum {
} avp_reassemble_mode_t; } avp_reassemble_mode_t;
typedef struct _proto_avp_t { typedef struct _proto_avp_t {
char* name; char *name;
dissector_handle_t handle; dissector_handle_t handle;
avp_reassemble_mode_t reassemble_mode; avp_reassemble_mode_t reassemble_mode;
} proto_avp_t; } proto_avp_t;
static const char* simple_avp(diam_ctx_t*, diam_avp_t*, tvbuff_t*); static const char *simple_avp(diam_ctx_t *, diam_avp_t *, tvbuff_t *);
static diam_vnd_t unknown_vendor = { 0xffffffff, NULL, NULL, NULL }; static diam_vnd_t unknown_vendor = { 0xffffffff, NULL, NULL, NULL };
static diam_vnd_t no_vnd = { 0, NULL, NULL, NULL }; static diam_vnd_t no_vnd = { 0, NULL, NULL, NULL };
static diam_avp_t unknown_avp = {0, &unknown_vendor, simple_avp, simple_avp, -1, -1, NULL }; static diam_avp_t unknown_avp = {0, &unknown_vendor, simple_avp, simple_avp, -1, -1, NULL };
static GArray* all_cmds; static GArray *all_cmds;
static diam_dictionary_t dictionary = { NULL, NULL, NULL, NULL }; static diam_dictionary_t dictionary = { NULL, NULL, NULL, NULL };
static struct _build_dict build_dict; static struct _build_dict build_dict;
static const value_string* vnd_short_vs; static const value_string *vnd_short_vs;
static dissector_handle_t data_handle; static dissector_handle_t data_handle;
static dissector_handle_t eap_handle; static dissector_handle_t eap_handle;
@ -289,7 +294,7 @@ static dissector_table_t diameter_dissector_table;
static dissector_table_t diameter_3gpp_avp_dissector_table; static dissector_table_t diameter_3gpp_avp_dissector_table;
static dissector_table_t diameter_ericsson_avp_dissector_table; static dissector_table_t diameter_ericsson_avp_dissector_table;
static const char* avpflags_str[] = { static const char *avpflags_str[] = {
"---", "---",
"--P", "--P",
"-M-", "-M-",
@ -303,8 +308,8 @@ static const char* avpflags_str[] = {
static gint static gint
compare_avps (gconstpointer a, gconstpointer b) compare_avps (gconstpointer a, gconstpointer b)
{ {
value_string* vsa = (value_string*)a; value_string *vsa = (value_string *)a;
value_string* vsb = (value_string*)b; value_string *vsb = (value_string *)b;
if(vsa->value > vsb->value) if(vsa->value > vsb->value)
return 1; return 1;
@ -367,7 +372,7 @@ dissect_diameter_base_framed_ipv6_prefix(tvbuff_t *tvb, packet_info *pinfo _U_,
/* Dissect an AVP at offset */ /* Dissect an AVP at offset */
static int static int
dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset) dissect_diameter_avp(diam_ctx_t *c, tvbuff_t *tvb, int offset)
{ {
guint32 code = tvb_get_ntohl(tvb,offset); guint32 code = tvb_get_ntohl(tvb,offset);
guint32 len = tvb_get_ntohl(tvb,offset+4); guint32 len = tvb_get_ntohl(tvb,offset+4);
@ -380,20 +385,20 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
{1,&vendorid}, {1,&vendorid},
{0,NULL} {0,NULL}
}; };
diam_avp_t* a = (diam_avp_t*)emem_tree_lookup32_array(dictionary.avps,k); diam_avp_t *a = (diam_avp_t *)emem_tree_lookup32_array(dictionary.avps,k);
proto_item *pi, *avp_item; proto_item *pi, *avp_item;
proto_tree *avp_tree, *save_tree; proto_tree *avp_tree, *save_tree;
tvbuff_t* subtvb; tvbuff_t *subtvb;
diam_vnd_t* vendor; diam_vnd_t *vendor;
const char* code_str; const char *code_str;
const char* avp_str; const char *avp_str;
len &= 0x00ffffff; len &= 0x00ffffff;
if (!a) { if (!a) {
a = &unknown_avp; a = &unknown_avp;
if (vendor_flag) { if (vendor_flag) {
if (! (vendor = (diam_vnd_t*)emem_tree_lookup32(dictionary.vnds,vendorid) )) if (! (vendor = (diam_vnd_t *)emem_tree_lookup32(dictionary.vnds,vendorid) ))
vendor = &unknown_vendor; vendor = &unknown_vendor;
} else { } else {
vendor = &no_vnd; vendor = &no_vnd;
@ -408,7 +413,7 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
g_strdup_printf("diameter_vendor_%s",val_to_str_ext_const(vendorid, &sminmpec_values_ext, "Unknown"))); g_strdup_printf("diameter_vendor_%s",val_to_str_ext_const(vendorid, &sminmpec_values_ext, "Unknown")));
#if 0 #if 0
{ /* Debug code */ { /* Debug code */
value_string* vendor_avp_vs=VALUE_STRING_EXT_VS_P(vendor->vs_avps_ext); value_string *vendor_avp_vs=VALUE_STRING_EXT_VS_P(vendor->vs_avps_ext);
gint i = 0; gint i = 0;
while(vendor_avp_vs[i].strptr!=NULL) { while(vendor_avp_vs[i].strptr!=NULL) {
g_warning("%u %s",vendor_avp_vs[i].value,vendor_avp_vs[i].strptr); g_warning("%u %s",vendor_avp_vs[i].value,vendor_avp_vs[i].strptr);
@ -428,8 +433,8 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
/* Code */ /* Code */
if (a == &unknown_avp) { if (a == &unknown_avp) {
proto_tree* tu = proto_item_add_subtree(pi,ett_unknown); proto_tree *tu = proto_item_add_subtree(pi,ett_unknown);
proto_item* iu = proto_tree_add_text(tu,tvb,offset,4,"Unknown AVP, " proto_item *iu = proto_tree_add_text(tu,tvb,offset,4,"Unknown AVP, "
"if you know what this is you can add it to dictionary.xml"); "if you know what this is you can add it to dictionary.xml");
expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN,
"Unknown AVP %u (vendor=%s)", code, "Unknown AVP %u (vendor=%s)", code,
@ -444,7 +449,7 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
/* Flags */ /* Flags */
pi = proto_tree_add_item(avp_tree,hf_diameter_avp_flags,tvb,offset,1,ENC_BIG_ENDIAN); pi = proto_tree_add_item(avp_tree,hf_diameter_avp_flags,tvb,offset,1,ENC_BIG_ENDIAN);
{ {
proto_tree* flags_tree = proto_item_add_subtree(pi,ett_diameter_avp_flags); proto_tree *flags_tree = proto_item_add_subtree(pi,ett_diameter_avp_flags);
proto_tree_add_item(flags_tree,hf_diameter_avp_flags_vendor_specific,tvb,offset,1,ENC_BIG_ENDIAN); proto_tree_add_item(flags_tree,hf_diameter_avp_flags_vendor_specific,tvb,offset,1,ENC_BIG_ENDIAN);
proto_tree_add_item(flags_tree,hf_diameter_avp_flags_mandatory,tvb,offset,1,ENC_BIG_ENDIAN); proto_tree_add_item(flags_tree,hf_diameter_avp_flags_mandatory,tvb,offset,1,ENC_BIG_ENDIAN);
proto_tree_add_item(flags_tree,hf_diameter_avp_flags_protected,tvb,offset,1,ENC_BIG_ENDIAN); proto_tree_add_item(flags_tree,hf_diameter_avp_flags_protected,tvb,offset,1,ENC_BIG_ENDIAN);
@ -470,8 +475,8 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
proto_item_append_text(avp_item," vnd=%s", val_to_str(vendorid, vnd_short_vs, "%d")); proto_item_append_text(avp_item," vnd=%s", val_to_str(vendorid, vnd_short_vs, "%d"));
pi = proto_tree_add_item(avp_tree,hf_diameter_avp_vendor_id,tvb,offset,4,ENC_BIG_ENDIAN); pi = proto_tree_add_item(avp_tree,hf_diameter_avp_vendor_id,tvb,offset,4,ENC_BIG_ENDIAN);
if (vendor == &unknown_vendor) { if (vendor == &unknown_vendor) {
proto_tree* tu = proto_item_add_subtree(pi,ett_unknown); proto_tree *tu = proto_item_add_subtree(pi,ett_unknown);
proto_item* iu = proto_tree_add_text(tu,tvb,offset,4,"Unknown Vendor, " proto_item *iu = proto_tree_add_text(tu,tvb,offset,4,"Unknown Vendor, "
"if you know whose this is you can add it to dictionary.xml"); "if you know whose this is you can add it to dictionary.xml");
expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown Vendor"); expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown Vendor");
PROTO_ITEM_SET_GENERATED(iu); PROTO_ITEM_SET_GENERATED(iu);
@ -481,7 +486,7 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
if ( len == (guint32)(vendor_flag ? 12 : 8) ) { if ( len == (guint32)(vendor_flag ? 12 : 8) ) {
/* Data is empty so return now */ /* Data is empty so return now */
proto_item* iu = proto_tree_add_text(avp_tree,tvb,offset,0,"No data"); proto_item *iu = proto_tree_add_text(avp_tree,tvb,offset,0,"No data");
expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Data is empty"); expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Data is empty");
PROTO_ITEM_SET_GENERATED(iu); PROTO_ITEM_SET_GENERATED(iu);
return len; return len;
@ -521,13 +526,13 @@ dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset)
return len; return len;
} }
static const char* static const char *
address_rfc_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) address_rfc_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label = (char*)ep_alloc(ITEM_LABEL_LENGTH+1); char *label = (char *)ep_alloc(ITEM_LABEL_LENGTH+1);
address_avp_t* t = a->type_data; address_avp_t *t = a->type_data;
proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN); proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN);
proto_tree* pt = proto_item_add_subtree(pi,t->ett); proto_tree *pt = proto_item_add_subtree(pi,t->ett);
guint32 addr_type = tvb_get_ntohs(tvb,0); guint32 addr_type = tvb_get_ntohs(tvb,0);
gint len = tvb_length_remaining(tvb,2); gint len = tvb_length_remaining(tvb,2);
@ -559,10 +564,10 @@ address_rfc_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
proto_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) proto_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
proto_avp_t* t = a->type_data; proto_avp_t *t = a->type_data;
col_set_writable(c->pinfo->cinfo, FALSE); col_set_writable(c->pinfo->cinfo, FALSE);
@ -576,12 +581,12 @@ proto_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return ""; return "";
} }
static const char* static const char *
time_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) time_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
int len = tvb_length(tvb); int len = tvb_length(tvb);
char* label = ep_alloc(ITEM_LABEL_LENGTH+1); char *label = ep_alloc(ITEM_LABEL_LENGTH+1);
proto_item* pi; proto_item *pi;
if ( len != 4 ) { if ( len != 4 ) {
pi = proto_tree_add_text(c->tree, tvb, 0, 4, "Error! AVP value MUST be 4 bytes"); pi = proto_tree_add_text(c->tree, tvb, 0, 4, "Error! AVP value MUST be 4 bytes");
@ -596,13 +601,13 @@ time_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
address_v16_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) address_v16_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label = ep_alloc(ITEM_LABEL_LENGTH+1); char *label = ep_alloc(ITEM_LABEL_LENGTH+1);
address_avp_t* t = a->type_data; address_avp_t *t = a->type_data;
proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN); proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN);
proto_tree* pt = proto_item_add_subtree(pi,t->ett); proto_tree *pt = proto_item_add_subtree(pi,t->ett);
guint32 len = tvb_length(tvb); guint32 len = tvb_length(tvb);
switch (len) { switch (len) {
@ -625,31 +630,31 @@ address_v16_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
simple_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) simple_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label = ep_alloc(ITEM_LABEL_LENGTH+1); char *label = ep_alloc(ITEM_LABEL_LENGTH+1);
proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN); proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_BIG_ENDIAN);
proto_item_fill_label(PITEM_FINFO(pi), label); proto_item_fill_label(PITEM_FINFO(pi), label);
label = strstr(label,": ")+2; label = strstr(label,": ")+2;
return label; return label;
} }
static const char* static const char *
utf8_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) utf8_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label = ep_alloc(ITEM_LABEL_LENGTH+1); char *label = ep_alloc(ITEM_LABEL_LENGTH+1);
proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_UTF_8|ENC_BIG_ENDIAN); proto_item *pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length(tvb),ENC_UTF_8|ENC_BIG_ENDIAN);
proto_item_fill_label(PITEM_FINFO(pi), label); proto_item_fill_label(PITEM_FINFO(pi), label);
label = strstr(label,": ")+2; label = strstr(label,": ")+2;
return label; return label;
} }
static const char* static const char *
integer32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) integer32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label; char *label;
proto_item* pi; proto_item *pi;
/* Verify length before adding */ /* Verify length before adding */
gint length = tvb_length_remaining(tvb,0); gint length = tvb_length_remaining(tvb,0);
@ -671,11 +676,11 @@ integer32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
integer64_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) integer64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label; char *label;
proto_item* pi; proto_item *pi;
/* Verify length before adding */ /* Verify length before adding */
gint length = tvb_length_remaining(tvb,0); gint length = tvb_length_remaining(tvb,0);
@ -697,11 +702,11 @@ integer64_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
unsigned32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) unsigned32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label; char *label;
proto_item* pi; proto_item *pi;
/* Verify length before adding */ /* Verify length before adding */
gint length = tvb_length_remaining(tvb,0); gint length = tvb_length_remaining(tvb,0);
@ -723,11 +728,11 @@ unsigned32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
unsigned64_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) unsigned64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label; char *label;
proto_item* pi; proto_item *pi;
/* Verify length before adding */ /* Verify length before adding */
gint length = tvb_length_remaining(tvb,0); gint length = tvb_length_remaining(tvb,0);
@ -749,11 +754,11 @@ unsigned64_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
float32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) float32_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label; char *label;
proto_item* pi; proto_item *pi;
/* Verify length before adding */ /* Verify length before adding */
gint length = tvb_length_remaining(tvb,0); gint length = tvb_length_remaining(tvb,0);
@ -775,11 +780,11 @@ float32_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
float64_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) float64_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
char* label; char *label;
proto_item* pi; proto_item *pi;
/* Verify length before adding */ /* Verify length before adding */
gint length = tvb_length_remaining(tvb,0); gint length = tvb_length_remaining(tvb,0);
@ -801,13 +806,13 @@ float64_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return label; return label;
} }
static const char* static const char *
grouped_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) grouped_avp(diam_ctx_t *c, diam_avp_t *a, tvbuff_t *tvb)
{ {
int offset = 0; int offset = 0;
int len = tvb_length(tvb); int len = tvb_length(tvb);
proto_item* pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, ENC_BIG_ENDIAN); proto_item *pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, ENC_BIG_ENDIAN);
proto_tree* pt = c->tree; proto_tree *pt = c->tree;
c->tree = proto_item_add_subtree(pi,a->ett); c->tree = proto_item_add_subtree(pi,a->ett);
@ -821,7 +826,7 @@ grouped_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb)
return NULL; return NULL;
} }
static const char* msgflags_str[] = { static const char *msgflags_str[] = {
"----", "---T", "--E-", "--ET", "----", "---T", "--E-", "--ET",
"-P--", "-P-T", "-PE-", "-PET", "-P--", "-P-T", "-PE-", "-PET",
"R---", "R--T", "R-E-", "R-ET", "R---", "R--T", "R-E-", "R-ET",
@ -829,7 +834,7 @@ static const char* msgflags_str[] = {
}; };
static void static void
dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree) dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{ {
guint32 first_word = tvb_get_ntohl(tvb,0); guint32 first_word = tvb_get_ntohl(tvb,0);
guint32 version = (first_word & 0xff000000) >> 24; guint32 version = (first_word & 0xff000000) >> 24;
@ -843,10 +848,11 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
const char *cmd_str; const char *cmd_str;
guint32 cmd = tvb_get_ntoh24(tvb,5); guint32 cmd = tvb_get_ntoh24(tvb,5);
guint32 fourth = tvb_get_ntohl(tvb,8); guint32 fourth = tvb_get_ntohl(tvb,8);
guint32 hop_by_hop_id = 0; guint32 hop_by_hop_id, end_to_end_id;
conversation_t *conversation; conversation_t *conversation;
diameter_conv_info_t *diameter_conv_info; diameter_conv_info_t *diameter_conv_info;
diameter_req_ans_pair_t *diameter_pair; diameter_req_ans_pair_t *diameter_pair;
emem_tree_t *pdus_tree;
proto_item *it; proto_item *it;
nstime_t ns; nstime_t ns;
void *pd_save; void *pd_save;
@ -865,7 +871,7 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
pi = proto_tree_add_item(diam_tree,hf_diameter_flags,tvb,4,1,ENC_BIG_ENDIAN); pi = proto_tree_add_item(diam_tree,hf_diameter_flags,tvb,4,1,ENC_BIG_ENDIAN);
{ {
proto_tree* pt = proto_item_add_subtree(pi,ett_diameter_flags); proto_tree *pt = proto_item_add_subtree(pi,ett_diameter_flags);
proto_tree_add_item(pt,hf_diameter_flags_request,tvb,4,1,ENC_BIG_ENDIAN); proto_tree_add_item(pt,hf_diameter_flags_request,tvb,4,1,ENC_BIG_ENDIAN);
proto_tree_add_item(pt,hf_diameter_flags_proxyable,tvb,4,1,ENC_BIG_ENDIAN); proto_tree_add_item(pt,hf_diameter_flags_proxyable,tvb,4,1,ENC_BIG_ENDIAN);
proto_tree_add_item(pt,hf_diameter_flags_error,tvb,4,1,ENC_BIG_ENDIAN); proto_tree_add_item(pt,hf_diameter_flags_error,tvb,4,1,ENC_BIG_ENDIAN);
@ -885,7 +891,7 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
switch (version) { switch (version) {
case DIAMETER_V16: { case DIAMETER_V16: {
guint32 vendorid = tvb_get_ntohl(tvb,8); guint32 vendorid = tvb_get_ntohl(tvb,8);
diam_vnd_t* vendor; diam_vnd_t *vendor;
if (! ( vendor = emem_tree_lookup32(dictionary.vnds,vendorid) ) ) { if (! ( vendor = emem_tree_lookup32(dictionary.vnds,vendorid) ) ) {
vendor = &unknown_vendor; vendor = &unknown_vendor;
@ -901,7 +907,7 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
/* Store the application id to be used by subdissectors */ /* Store the application id to be used by subdissectors */
pinfo->private_data = &fourth; pinfo->private_data = &fourth;
cmd_vs = (value_string*)(void*)all_cmds->data; cmd_vs = (value_string *)(void *)all_cmds->data;
app_item = proto_tree_add_item(diam_tree, hf_diameter_application_id, tvb, 8, 4, ENC_BIG_ENDIAN); app_item = proto_tree_add_item(diam_tree, hf_diameter_application_id, tvb, 8, 4, ENC_BIG_ENDIAN);
if (match_strval(fourth, dictionary.applications) == NULL) { if (match_strval(fourth, dictionary.applications) == NULL) {
@ -918,8 +924,8 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
} }
default: default:
{ {
proto_tree* pt = proto_item_add_subtree(version_item,ett_err); proto_tree *pt = proto_item_add_subtree(version_item,ett_err);
proto_item* pi_local = proto_tree_add_text(pt,tvb,0,1,"Unknown Diameter Version (decoding as RFC 3588)"); proto_item *pi_local = proto_tree_add_text(pt,tvb,0,1,"Unknown Diameter Version (decoding as RFC 3588)");
expert_add_info_format(pinfo, pi_local, PI_UNDECODED, PI_WARN, "Unknown Diameter Version"); expert_add_info_format(pinfo, pi_local, PI_UNDECODED, PI_WARN, "Unknown Diameter Version");
PROTO_ITEM_SET_GENERATED(pi); PROTO_ITEM_SET_GENERATED(pi);
c->version_rfc = TRUE; c->version_rfc = TRUE;
@ -944,8 +950,8 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
/* Append name to command item, warn if unknown */ /* Append name to command item, warn if unknown */
proto_item_append_text(cmd_item," %s", cmd_str); proto_item_append_text(cmd_item," %s", cmd_str);
if (strcmp(cmd_str, "Unknown") == 0) { if (strcmp(cmd_str, "Unknown") == 0) {
proto_tree* tu = proto_item_add_subtree(cmd_item,ett_unknown); proto_tree *tu = proto_item_add_subtree(cmd_item,ett_unknown);
proto_item* iu = proto_tree_add_text(tu,tvb, 5 ,3,"Unknown command, " proto_item *iu = proto_tree_add_text(tu,tvb, 5 ,3,"Unknown command, "
"if you know what this is you can add it to dictionary.xml"); "if you know what this is you can add it to dictionary.xml");
expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown command (%u)", cmd); expert_add_info_format(c->pinfo, iu, PI_UNDECODED, PI_WARN, "Unknown command (%u)", cmd);
PROTO_ITEM_SET_GENERATED(iu); PROTO_ITEM_SET_GENERATED(iu);
@ -954,6 +960,7 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
hop_by_hop_id = tvb_get_ntohl(tvb, 12); hop_by_hop_id = tvb_get_ntohl(tvb, 12);
proto_tree_add_item(diam_tree,hf_diameter_hopbyhopid,tvb,12,4,ENC_BIG_ENDIAN); proto_tree_add_item(diam_tree,hf_diameter_hopbyhopid,tvb,12,4,ENC_BIG_ENDIAN);
end_to_end_id = tvb_get_ntohl(tvb, 16);
proto_tree_add_item(diam_tree,hf_diameter_endtoendid,tvb,16,4,ENC_BIG_ENDIAN); proto_tree_add_item(diam_tree,hf_diameter_endtoendid,tvb,16,4,ENC_BIG_ENDIAN);
/* Conversation tracking stuff */ /* Conversation tracking stuff */
@ -967,32 +974,57 @@ dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
diameter_conv_info = conversation_get_proto_data(conversation, proto_diameter); diameter_conv_info = conversation_get_proto_data(conversation, proto_diameter);
if (!diameter_conv_info) { if (!diameter_conv_info) {
diameter_conv_info = se_alloc(sizeof(diameter_conv_info_t)); diameter_conv_info = se_alloc(sizeof(diameter_conv_info_t));
diameter_conv_info->pdus = se_tree_create_non_persistent( diameter_conv_info->pdus_tree = se_tree_create_non_persistent(
EMEM_TREE_TYPE_RED_BLACK, "diameter_pdus"); EMEM_TREE_TYPE_RED_BLACK, "diameter_pdu_trees");
conversation_add_proto_data(conversation, proto_diameter, diameter_conv_info); conversation_add_proto_data(conversation, proto_diameter, diameter_conv_info);
} }
if (!pinfo->fd->flags.visited) { /* pdus_tree is an se_tree keyed by frame number (in order to handle hop-by-hop collisions */
if (flags_bits & DIAM_FLAGS_R) { pdus_tree = se_tree_lookup32(diameter_conv_info->pdus_tree, hop_by_hop_id);
/* This is a request */
diameter_pair = se_alloc(sizeof(diameter_req_ans_pair_t)); if (pdus_tree == NULL && (flags_bits & DIAM_FLAGS_R)) {
diameter_pair->hop_by_hop_id = hop_by_hop_id; /* This is the first request we've seen with this hop-by-hop id */
diameter_pair->cmd_code = cmd; pdus_tree = se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "diameter_pdus");
diameter_pair->result_code = 0; se_tree_insert32(diameter_conv_info->pdus_tree, hop_by_hop_id, pdus_tree);
diameter_pair->cmd_str = cmd_str;
diameter_pair->req_frame = PINFO_FD_NUM(pinfo);
diameter_pair->ans_frame = 0;
diameter_pair->req_time = pinfo->fd->abs_ts;
se_tree_insert32(diameter_conv_info->pdus, hop_by_hop_id, (void *)diameter_pair);
} else {
diameter_pair = se_tree_lookup32(diameter_conv_info->pdus, hop_by_hop_id);
if (diameter_pair) {
diameter_pair->ans_frame = PINFO_FD_NUM(pinfo);
}
}
} else { } else {
diameter_pair = se_tree_lookup32(diameter_conv_info->pdus, hop_by_hop_id); /* If we found nothing with this Answer's hop-by-hop-id then we're done. */
diameter_pair = NULL;
}
if (pdus_tree) {
if (!pinfo->fd->flags.visited) {
if (flags_bits & DIAM_FLAGS_R) {
/* This is a request */
diameter_pair = se_alloc(sizeof(diameter_req_ans_pair_t));
diameter_pair->hop_by_hop_id = hop_by_hop_id;
diameter_pair->end_to_end_id = end_to_end_id;
diameter_pair->cmd_code = cmd;
diameter_pair->result_code = 0;
diameter_pair->cmd_str = cmd_str;
diameter_pair->req_frame = PINFO_FD_NUM(pinfo);
diameter_pair->ans_frame = 0;
diameter_pair->req_time = pinfo->fd->abs_ts;
se_tree_insert32(pdus_tree, PINFO_FD_NUM(pinfo), (void *)diameter_pair);
} else {
/* Look for a request which occurs earlier in the trace than this answer. */
diameter_pair = se_tree_lookup32_le(pdus_tree, PINFO_FD_NUM(pinfo));
/* Verify the end-to-end-id matches before declaring a match */
if (diameter_pair && diameter_pair->end_to_end_id == end_to_end_id) {
diameter_pair->ans_frame = PINFO_FD_NUM(pinfo);
}
}
} else {
/* Look for a request which occurs earlier in the trace than this answer. */
diameter_pair = se_tree_lookup32_le(pdus_tree, PINFO_FD_NUM(pinfo));
/* If the end-to-end ID doesn't match then this is not the request we were
* looking for.
*/
if (diameter_pair && diameter_pair->end_to_end_id != end_to_end_id)
diameter_pair = NULL;
}
} }
if (!diameter_pair) { if (!diameter_pair) {
@ -1105,11 +1137,11 @@ dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
} }
static char* static char *
alnumerize(char* name) alnumerize(char *name)
{ {
char* r = name; char *r = name;
char* w = name; char *w = name;
char c; char c;
for (;(c = *r); r++) { for (;(c = *r); r++) {
@ -1125,8 +1157,8 @@ alnumerize(char* name)
static guint static guint
reginfo(int* hf_ptr, const char* name, const char* abbr, const char* desc, reginfo(int *hf_ptr, const char *name, const char *abbr, const char *desc,
enum ftenum ft, base_display_e base, value_string_ext* vs_ext, enum ftenum ft, base_display_e base, value_string_ext *vs_ext,
guint32 mask) guint32 mask)
{ {
hf_register_info hf = { hf_ptr, { hf_register_info hf = { hf_ptr, {
@ -1148,8 +1180,8 @@ reginfo(int* hf_ptr, const char* name, const char* abbr, const char* desc,
} }
static void static void
basic_avp_reginfo(diam_avp_t* a, const char* name, enum ftenum ft, basic_avp_reginfo(diam_avp_t *a, const char *name, enum ftenum ft,
base_display_e base, value_string_ext* vs_ext) base_display_e base, value_string_ext *vs_ext)
{ {
hf_register_info hf[] = { { &(a->hf_value), hf_register_info hf[] = { { &(a->hf_value),
{ NULL, NULL, ft, base, NULL, 0x0, { NULL, NULL, ft, base, NULL, 0x0,
@ -1158,7 +1190,7 @@ basic_avp_reginfo(diam_avp_t* a, const char* name, enum ftenum ft,
: g_strdup_printf("code=%d", a->code), : g_strdup_printf("code=%d", a->code),
HFILL }} HFILL }}
}; };
gint* ettp = &(a->ett); gint *ettp = &(a->ett);
hf->hfinfo.name = g_strdup_printf("%s",name); hf->hfinfo.name = g_strdup_printf("%s",name);
hf->hfinfo.abbrev = alnumerize(g_strdup_printf("diameter.%s",name)); hf->hfinfo.abbrev = alnumerize(g_strdup_printf("diameter.%s",name));
@ -1170,14 +1202,14 @@ basic_avp_reginfo(diam_avp_t* a, const char* name, enum ftenum ft,
g_ptr_array_add(build_dict.ett,ettp); g_ptr_array_add(build_dict.ett,ettp);
} }
static diam_avp_t* static diam_avp_t *
build_address_avp(const avp_type_t* type _U_, guint32 code, build_address_avp(const avp_type_t *type _U_, guint32 code,
const diam_vnd_t* vendor, const char* name, const diam_vnd_t *vendor, const char *name,
const value_string* vs _U_, void* data _U_) const value_string *vs _U_, void *data _U_)
{ {
diam_avp_t* a = g_malloc0(sizeof(diam_avp_t)); diam_avp_t *a = g_malloc0(sizeof(diam_avp_t));
address_avp_t* t = g_malloc(sizeof(address_avp_t)); address_avp_t *t = g_malloc(sizeof(address_avp_t));
gint* ettp = &(t->ett); gint *ettp = &(t->ett);
a->code = code; a->code = code;
a->vendor = vendor; a->vendor = vendor;
@ -1243,14 +1275,14 @@ RFC3588
return a; return a;
} }
static diam_avp_t* static diam_avp_t *
build_proto_avp(const avp_type_t* type _U_, guint32 code, build_proto_avp(const avp_type_t *type _U_, guint32 code,
const diam_vnd_t* vendor, const char* name _U_, const diam_vnd_t *vendor, const char *name _U_,
const value_string* vs _U_, void* data) const value_string *vs _U_, void *data)
{ {
diam_avp_t* a = g_malloc0(sizeof(diam_avp_t)); diam_avp_t *a = g_malloc0(sizeof(diam_avp_t));
proto_avp_t* t = g_malloc0(sizeof(proto_avp_t)); proto_avp_t *t = g_malloc0(sizeof(proto_avp_t));
gint* ettp = &(a->ett); gint *ettp = &(a->ett);
a->code = code; a->code = code;
a->vendor = vendor; a->vendor = vendor;
@ -1269,11 +1301,11 @@ build_proto_avp(const avp_type_t* type _U_, guint32 code,
return a; return a;
} }
static diam_avp_t* static diam_avp_t *
build_simple_avp(const avp_type_t* type, guint32 code, const diam_vnd_t* vendor, build_simple_avp(const avp_type_t *type, guint32 code, const diam_vnd_t *vendor,
const char* name, const value_string* vs, void* data _U_) const char *name, const value_string *vs, void *data _U_)
{ {
diam_avp_t* a; diam_avp_t *a;
value_string_ext *vs_ext = NULL; value_string_ext *vs_ext = NULL;
base_display_e base; base_display_e base;
guint i = 0; guint i = 0;
@ -1301,7 +1333,7 @@ build_simple_avp(const avp_type_t* type, guint32 code, const diam_vnd_t* vendor,
while (vs[i].strptr) { while (vs[i].strptr) {
i++; i++;
} }
vs_ext = value_string_ext_new((void*)vs, i+1, g_strdup_printf("%s_vals_ext",name)); vs_ext = value_string_ext_new((void *)vs, i+1, g_strdup_printf("%s_vals_ext",name));
base = base|BASE_EXT_STRING; base = base|BASE_EXT_STRING;
} }
@ -1379,8 +1411,8 @@ strcase_hash(gconstpointer key)
static gboolean static gboolean
strcase_equal(gconstpointer ka, gconstpointer kb) strcase_equal(gconstpointer ka, gconstpointer kb)
{ {
const char* a = ka; const char *a = ka;
const char* b = kb; const char *b = kb;
return g_ascii_strcasecmp(a,b) == 0; return g_ascii_strcasecmp(a,b) == 0;
} }
@ -1393,21 +1425,21 @@ strcase_equal(gconstpointer ka, gconstpointer kb)
static int static int
dictionary_load(void) dictionary_load(void)
{ {
ddict_t* d; ddict_t *d;
ddict_application_t* p; ddict_application_t *p;
ddict_vendor_t* v; ddict_vendor_t *v;
ddict_cmd_t* c; ddict_cmd_t *c;
ddict_typedefn_t* t; ddict_typedefn_t *t;
ddict_avp_t* a; ddict_avp_t *a;
gboolean do_debug_parser = getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? TRUE : FALSE; gboolean do_debug_parser = getenv("WIRESHARK_DEBUG_DIAM_DICT_PARSER") ? TRUE : FALSE;
gboolean do_dump_dict = getenv("WIRESHARK_DUMP_DIAM_DICT") ? TRUE : FALSE; gboolean do_dump_dict = getenv("WIRESHARK_DUMP_DIAM_DICT") ? TRUE : FALSE;
char* dir = ep_strdup_printf("%s" G_DIR_SEPARATOR_S "diameter" G_DIR_SEPARATOR_S, get_datafile_dir()); char *dir = ep_strdup_printf("%s" G_DIR_SEPARATOR_S "diameter" G_DIR_SEPARATOR_S, get_datafile_dir());
const avp_type_t* type; const avp_type_t *type;
const avp_type_t* octetstring = &basic_types[0]; const avp_type_t *octetstring = &basic_types[0];
diam_avp_t* avp; diam_avp_t *avp;
GHashTable* vendors = g_hash_table_new(strcase_hash,strcase_equal); GHashTable *vendors = g_hash_table_new(strcase_hash,strcase_equal);
diam_vnd_t* vnd; diam_vnd_t *vnd;
GArray* vnd_shrt_arr = g_array_new(TRUE,TRUE,sizeof(value_string)); GArray *vnd_shrt_arr = g_array_new(TRUE,TRUE,sizeof(value_string));
build_dict.hf = g_array_new(FALSE,TRUE,sizeof(hf_register_info)); build_dict.hf = g_array_new(FALSE,TRUE,sizeof(hf_register_info));
build_dict.ett = g_ptr_array_new(); build_dict.ett = g_ptr_array_new();
@ -1429,7 +1461,7 @@ dictionary_load(void)
/* initialize the types hash with the known basic types */ /* initialize the types hash with the known basic types */
for (type = basic_types; type->name; type++) { for (type = basic_types; type->name; type++) {
g_hash_table_insert(build_dict.types,(gchar *)type->name,(void*)type); g_hash_table_insert(build_dict.types,(gchar *)type->name,(void *)type);
} }
/* load the dictionary */ /* load the dictionary */
@ -1442,7 +1474,7 @@ dictionary_load(void)
/* populate the types */ /* populate the types */
for (t = d->typedefns; t; t = t->next) { for (t = d->typedefns; t; t = t->next) {
const avp_type_t* parent = NULL; const avp_type_t *parent = NULL;
/* try to get the parent type */ /* try to get the parent type */
if (t->name == NULL) { if (t->name == NULL) {
@ -1462,19 +1494,19 @@ dictionary_load(void)
if (!parent) parent = octetstring; if (!parent) parent = octetstring;
/* insert the parent type for this type */ /* insert the parent type for this type */
g_hash_table_insert(build_dict.types,t->name,(void*)parent); g_hash_table_insert(build_dict.types,t->name,(void *)parent);
} }
/* populate the applications */ /* populate the applications */
if ((p = d->applications)) { if ((p = d->applications)) {
GArray* arr = g_array_new(TRUE,TRUE,sizeof(value_string)); GArray *arr = g_array_new(TRUE,TRUE,sizeof(value_string));
for (; p; p = p->next) { for (; p; p = p->next) {
value_string item = {p->code,p->name}; value_string item = {p->code,p->name};
g_array_append_val(arr,item); g_array_append_val(arr,item);
} }
dictionary.applications = (void*)arr->data; dictionary.applications = (void *)arr->data;
g_array_free(arr,FALSE); g_array_free(arr,FALSE);
} }
@ -1502,7 +1534,7 @@ dictionary_load(void)
} }
} }
vnd_short_vs = (void*)vnd_shrt_arr->data; vnd_short_vs = (void *)vnd_shrt_arr->data;
g_array_free(vnd_shrt_arr,FALSE); g_array_free(vnd_shrt_arr,FALSE);
if ((c = d->cmds)) { if ((c = d->cmds)) {
@ -1526,11 +1558,11 @@ dictionary_load(void)
for (a = d->avps; a; a = a->next) { for (a = d->avps; a; a = a->next) {
ddict_enum_t* e; ddict_enum_t *e;
value_string* vs = NULL; value_string *vs = NULL;
const char* vend = a->vendor ? a->vendor : "None"; const char *vend = a->vendor ? a->vendor : "None";
ddict_xmlpi_t* x; ddict_xmlpi_t *x;
void* avp_data = NULL; void *avp_data = NULL;
if (a->name == NULL) { if (a->name == NULL) {
fprintf(stderr,"Diameter Dictionary: Invalid AVP (empty name)\n"); fprintf(stderr,"Diameter Dictionary: Invalid AVP (empty name)\n");
@ -1546,14 +1578,14 @@ dictionary_load(void)
} }
if ((e = a->enums)) { if ((e = a->enums)) {
GArray* arr = g_array_new(TRUE,TRUE,sizeof(value_string)); GArray *arr = g_array_new(TRUE,TRUE,sizeof(value_string));
for (; e; e = e->next) { for (; e; e = e->next) {
value_string item = {e->code,e->name}; value_string item = {e->code,e->name};
g_array_append_val(arr,item); g_array_append_val(arr,item);
} }
g_array_sort(arr, compare_avps); g_array_sort(arr, compare_avps);
vs = (void*)arr->data; vs = (void *)arr->data;
} }
type = NULL; type = NULL;
@ -1770,8 +1802,8 @@ real_proto_register_diameter(void)
proto_diameter = proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter"); proto_diameter = proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter");
proto_register_field_array(proto_diameter, (hf_register_info*)(void*)build_dict.hf->data, build_dict.hf->len); proto_register_field_array(proto_diameter, (hf_register_info *)(void *)build_dict.hf->data, build_dict.hf->len);
proto_register_subtree_array((gint**)build_dict.ett->pdata, build_dict.ett->len); proto_register_subtree_array((gint **)build_dict.ett->pdata, build_dict.ett->len);
g_array_free(build_dict.hf,FALSE); g_array_free(build_dict.hf,FALSE);
g_ptr_array_free(build_dict.ett,TRUE); g_ptr_array_free(build_dict.ett,TRUE);