From b0bd83c868af357fffc971157f4bae2b7060073d Mon Sep 17 00:00:00 2001 From: Luis Ontanon Date: Mon, 16 Jul 2007 05:41:58 +0000 Subject: [PATCH] Rewrite of the diameter dissector to use the dictionary for creating hfids, drop libxml dependency. The work is still incomplete (anything but strings and numbers appears as bytes) but I want others to start testing it. TODO: builders and decoders for: - (ntp) timestamps - addresses - diameteruris - diameteridentities - ipfilterrules - qosfilterrules - mipregistrationrequests svn path=/trunk/; revision=22318 --- epan/diam_dict.h | 81 + epan/diam_dict.l | 759 ++++++++ epan/dissectors/packet-diameter.c | 2946 +++++++---------------------- 3 files changed, 1537 insertions(+), 2249 deletions(-) create mode 100644 epan/diam_dict.h create mode 100644 epan/diam_dict.l diff --git a/epan/diam_dict.h b/epan/diam_dict.h new file mode 100644 index 0000000000..8e49bd9b26 --- /dev/null +++ b/epan/diam_dict.h @@ -0,0 +1,81 @@ +/* + ** diam_dict.h + ** Diameter Dictionary Import Routines + ** + ** $Id$ + ** + ** (c) 2007, Luis E. Garcia Ontanon + ** + ** This library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Library General Public + ** License as published by the Free Software Foundation; either + ** version 2 of the License, or (at your option) any later version. + ** + ** This library 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 + ** Library General Public License for more details. + ** + ** You should have received a copy of the GNU Library General Public + ** License along with this library; if not, write to the + ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, + ** Boston, MA 02111-1307, USA. + */ + +#ifndef _DIAM_DICT_H_ +#define _DIAM_DICT_H_ + +struct _ddict_namecode_t { + char* name; + unsigned code; + struct _ddict_namecode_t* next; +}; + +typedef struct _ddict_namecode_t ddict_gavp_t; +typedef struct _ddict_namecode_t ddict_enum_t; +typedef struct _ddict_namecode_t ddict_application_t; + +typedef struct _ddict_vendor_t { + char* name; + char* desc; + unsigned code; + struct _ddict_vendor_t* next; +} ddict_vendor_t; + +typedef struct _ddict_avp_t { + char* name; + char* description; + char* vendor; + char* type; + unsigned code; + ddict_gavp_t* gavps; + ddict_enum_t* enums; + struct _ddict_avp_t* next; +} ddict_avp_t; + +typedef struct _ddict_typedefn_t { + char* name; + char* parent; + struct _ddict_typedefn_t* next; +} ddict_typedefn_t; + +typedef struct _ddict_cmd_t { + char* name; + char* vendor; + unsigned code; + struct _ddict_cmd_t* next; +} ddict_cmd_t; + +typedef struct _ddict_t { + ddict_application_t* applications; + ddict_vendor_t* vendors; + ddict_cmd_t* cmds; + ddict_typedefn_t* typedefns; + ddict_avp_t* avps; +} ddict_t; + +extern void ddict_print(FILE* fh, ddict_t* d); +extern ddict_t* ddict_scan(const char* directory, const char* filename); +extern void ddict_free(ddict_t* d); + +#endif diff --git a/epan/diam_dict.l b/epan/diam_dict.l new file mode 100644 index 0000000000..6c90e48fe9 --- /dev/null +++ b/epan/diam_dict.l @@ -0,0 +1,759 @@ +%option noyywrap +%option nounput +%option never-interactive +%option prefix="DiamDict" +%option caseless +%option stack + +%option outfile="diam_dict.c" + +%{ + /* + ** diam_dict.h + ** Diameter Dictionary Import Routines + ** + ** $Id$ + ** + ** (c) 2007, Luis E. Garcia Ontanon + ** + ** This library is free software; you can redistribute it and/or + ** modify it under the terms of the GNU Library General Public + ** License as published by the Free Software Foundation; either + ** version 2 of the License, or (at your option) any later version. + ** + ** This library 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 + ** Library General Public License for more details. + ** + ** You should have received a copy of the GNU Library General Public + ** License along with this library; 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 + +#include +#include +#include +#include +#include "diam_dict.h" + +typedef struct entity_t { + char* name; + char* file; + struct entity_t* next; +} entity_t; + +#define ATTR_UINT(cont) do { D(("attr_uint " #cont "\t" )); attr_uint = &(cont); yy_push_state(GET_UINT_ATTR); } while(0) +#define ATTR_STR(cont) do { D(("attr_str " #cont "\t" )); attr_str = &(cont); yy_push_state(GET_ATTR); } while(0) +#define IGNORE() do { D(("ignore: %s\t",yytext)); yy_push_state(IGNORE_ATTR); } while(0) + +#ifdef DEBUG_DIAM_DICT +#define D(args) do { printf args ; fflush(stdout); } while(0) +#else +#define D(args) +#endif + +#ifdef _WIN32 +#define DDICT_DIRSEP "\\" +#else +#define DDICT_DIRSEP "/" +#endif + +#define MAX_INCLUDE_DEPTH 10 +#define YY_INPUT(buf,result,max_size) { result = current_yyinput(buf,max_size); } +#define ECHO +#define APPEND(txt,len) append_to_buffer(txt,len) + +static entity_t ents; +static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +static int include_stack_ptr = 0; +static size_t (*current_yyinput)(char*,size_t); +static const char* sys_dir; +static ddict_t* dict; +static ddict_application_t* appl; +static ddict_avp_t* avp; +static ddict_enum_t* enumitem; +static ddict_gavp_t* gavp; +static ddict_typedefn_t* typedefn; +static ddict_cmd_t* cmd; +static ddict_vendor_t* vnd; + +static ddict_application_t* last_appl; +static ddict_avp_t* last_avp; +static ddict_enum_t* last_enumitem; +static ddict_gavp_t* last_gavp; +static ddict_typedefn_t* last_typedefn; +static ddict_cmd_t* last_cmd; +static ddict_vendor_t* last_vnd; + +static char** attr_str; +static unsigned* attr_uint; + +static void append_to_buffer(char* txt, int len); +static FILE* ddict_open(const char*, const char*); + +%} + + +xmlpi_start [[:blank:] \r\n]*<\?[[:blank:] \r\n]* +xmlpi_end [[:blank:] \r\n]*\?>[[:blank:] \r\n]* + +comment_start [[:blank:] \r\n]*[[:blank:] \r\n]* +open_tag [[:blank:] \r\n]*<[[:blank:] \r\n]* +end_tag [[:blank:] \r\n]*\/>[[:blank:] \r\n]* +close_tag [[:blank:] \r\n]*>[[:blank:] \r\n]* +open_closetag [[:blank:] \r\n]*<\/[[:blank:] \r\n]* +equals [[:blank:] \r\n]*=[[:blank:] \r\n]* +whitespace [[:blank:] \r\n]* +dquoted \042[^\042]*\042 + +doctype [[:blank:] \r\n]*[[:blank:] \r\n]* + +start_entity [[:blank:] \r\n]*<\!ENTITY[[:blank:] \r\n]* +system [[:blank:] \r\n]*SYSTEM[[:blank:] \r\n]*\042 +entityname [a-z0-9]+ +ndquot [^\042]+ +end_entity \042[[:blank:] \r\n]*>[[:blank:] \r\n]* + +entity \&[a-z0-9]+; + +any . + + + + +stop > +stop_end \/> +dquot \042 +number [-]?[0-9]* + +dictionary_start +dictionary_end <\/dictionary> + +base_start *]*> +base_end <\/base> + +applictation_start + +command_start + +typedefn_start + +type_start +grouped_end <\/grouped> + +vendor_start {doctype} ; +{doctype_end} ; + +{comment_start} BEGIN LOADING_COMMENT; +. ; +{comment_end} BEGIN LOADING; + +{xmlpi_start} BEGIN LOADING_XMLPI; +. ; +{xmlpi_end} BEGIN LOADING; + +{start_entity} BEGIN ENTITY; +{entityname} { + entity_t* e = malloc(sizeof(entity_t)); + e->name = strdup(yytext); + e->next = ents.next; + ents.next = e; + BEGIN GET_SYSTEM; + }; +{system} BEGIN GET_FILE; +{ndquot} { + ents.next->file = strdup(yytext); + BEGIN END_ENTITY; + } +{end_entity} BEGIN LOADING; + +{open_tag} APPEND("<",1); + +{close_tag} APPEND(">",1); + +{end_tag} APPEND("/>",2); + +{open_closetag} APPEND("{whitespace} APPEND(" ",1); + +{dquoted} APPEND(yytext,yyleng); + +{equals} APPEND("=",1); + +{any} APPEND(yytext,yyleng); + +{entity} { + char* p = ++yytext; + entity_t* e; + + while(*p != ';') p++; + + *p = '\0'; + + D(("looking for entity: %s\n",yytext)); + + if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) { + fprintf(stderr, "included files nested to deeply\n"); + yyterminate(); + } + + include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; + + + for (e = ents.next; e; e = e->next) { + if (strcmp(e->name,yytext) == 0) { + yyin = ddict_open(sys_dir,e->file); + D(("entity: %s filename: %s yyin: %p\n",e->name,e->file,yyin)); + if (!yyin) { + if (errno) { + fprintf(stderr, "Could not open file: '%s', error: %s\n", e->file, strerror(errno) ); + yyterminate(); + } + } else { + yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) ); + BEGIN LOADING; + } + break; + } + } + + if (!e) { + fprintf(stderr, "Could not find entity: '%s'", e->name ); + yyterminate(); + } + +} + +<> { + if (!yyin) yyterminate(); + + fclose(yyin); + D(("closing: %p %i\n",yyin,include_stack_ptr)); + + if ( --include_stack_ptr < 0 ) { + D(("DONE READING\n")); + yyin = NULL; + yyterminate(); + } else { + yy_delete_buffer( YY_CURRENT_BUFFER ); + yy_switch_to_buffer(include_stack[include_stack_ptr]); + BEGIN LOADING; + } +} + + +{ndquot} { + *attr_str = strdup(yytext); + D(("%s\n",yytext)); + attr_str = NULL; + BEGIN END_ATTR; +} + +{number} { + *attr_uint = strtoul(yytext,NULL,10); + D(("%s\n",yytext);); + attr_uint = NULL; + BEGIN END_ATTR; +} + +{dquot} { yy_pop_state(); } + +. { + /* XXX: should go?*/ + D(("{%s}",yytext)); +} + +{ignored_quoted} { + D(("=>%s<=\n",yytext)); + yy_pop_state(); +} + +{dictionary_start} { + D(("dictionary_start\n")); + dict = malloc(sizeof(ddict_t)); + dict->applications = NULL; + dict->cmds = NULL; + dict->vendors = NULL; + dict->typedefns = NULL; + dict->avps = NULL; + + BEGIN IN_DICT; +} + +{base_start} { + D(("base_start\n")); + BEGIN IN_APPL; +} + +{applictation_start} { + D(("applictation_start\n")); + + appl = malloc(sizeof(ddict_application_t)); + appl->name = NULL; + appl->code = 0; + appl->next = NULL; + + if (!dict->applications) last_appl = dict->applications = appl; + else last_appl = last_appl->next = appl; + + BEGIN APPL_ATTRS; +} + +{name_attr} { ATTR_STR(appl->name); } +{id_attr} { ATTR_UINT(appl->code); } + +{stop} BEGIN IN_APPL; +{stop_end} BEGIN IN_DICT; + +{command_end} ; + +{command_start} { + D(("command_start\n")); + + cmd = malloc(sizeof(ddict_cmd_t)); + cmd->name = NULL; + cmd->vendor = NULL; + cmd->code = 0; + cmd->next = NULL; + + if (!dict->cmds) last_cmd = dict->cmds = cmd; + else last_cmd = last_cmd->next = cmd; + + BEGIN COMMAND_ATTRS; +} + +{name_attr} { ATTR_STR(cmd->name); } +{vendor_attr} { ATTR_STR(cmd->vendor); } +{code_attr} { ATTR_UINT(cmd->code); } +{stop} | +{stop_end} { BEGIN IN_APPL; } + +{vendor_start} { + D(("vendor_start\n")); + + vnd = malloc(sizeof(ddict_vendor_t)); + vnd->name = NULL; + vnd->code = 0; + vnd->next = NULL; + + if (!dict->vendors) last_vnd = dict->vendors = vnd; + else last_vnd = last_vnd->next = vnd; + + BEGIN VENDOR_ATTRS; +} + +{name_attr} { ATTR_STR(vnd->desc); } +{vendor_attr} { ATTR_STR(vnd->name); } +{code_attr} { ATTR_UINT(vnd->code); } +{stop} | +{stop_end} { BEGIN IN_APPL; } + +{typedefn_start} { + D(("typedefn_start\n")); + + typedefn = malloc(sizeof(ddict_typedefn_t)); + typedefn->name = NULL; + typedefn->parent = NULL; + typedefn->next = NULL; + + if (!dict->typedefns) last_typedefn = dict->typedefns = typedefn; + else last_typedefn = last_typedefn->next = typedefn; + + BEGIN TYPEDEFN_ATTRS; +} + +{typename_attr} { ATTR_STR(typedefn->name); } +{typeparent_attr} { ATTR_STR(typedefn->parent); } +{stop} | +{stop_end} { BEGIN IN_APPL; } + + +{avp_start} { + D(("avp_start\n")); + + avp = malloc(sizeof(ddict_avp_t)); + avp->name = NULL; + avp->vendor = NULL; + avp->code = 0; + avp->type = NULL; + avp->enums = NULL; + avp->gavps = NULL; + avp->next = NULL; + + if (! dict->avps ) last_avp = dict->avps = avp; + else last_avp = last_avp->next = avp; + + BEGIN AVP_ATTRS; +} + +{name_attr} { ATTR_STR(avp->name); } +{description_attr} { ATTR_STR(avp->description); } +{vendor_attr} { ATTR_STR(avp->vendor); } +{code_attr} { ATTR_UINT(avp->code); } +{stop} { BEGIN IN_AVP; } +{stop_end} { BEGIN IN_APPL; } + + +{grouped_start} { avp->type = strdup("Grouped"); }; +{grouped_end} ; + +{type_start} { BEGIN TYPE_ATTRS; } +{typename_attr} { ATTR_STR(avp->type); } + +{gavp_start} { + D(("gavp_start\n")); + + gavp = malloc(sizeof(ddict_gavp_t)); + gavp->name = NULL; + gavp->code = 0; + gavp->next = NULL; + + if (!avp->gavps) last_gavp = avp->gavps = gavp; + else last_gavp = last_gavp->next = gavp; + + BEGIN GAVP_ATTRS; +} + + +{name_attr} { ATTR_STR(gavp->name); } + + +{enum_start} { + D(("enum_start\n")); + + enumitem = malloc(sizeof(ddict_enum_t)); + enumitem->name = NULL; + enumitem->code = 0; + enumitem->next = NULL; + + if (!avp->enums) last_enumitem = avp->enums = enumitem; + else last_enumitem = last_enumitem->next = enumitem; + + BEGIN ENUM_ATTRS; +} + + +{name_attr} { ATTR_STR(enumitem->name); } +{code_attr} { ATTR_UINT(enumitem->code); } + +{stop} { BEGIN IN_AVP; } +{stop_end} { BEGIN IN_AVP; } + +{avp_end} { D(("avp_end")); BEGIN IN_APPL; } + +{application_end} | +{base_end} { + BEGIN IN_DICT; +} + +{dictionary_end} { + yyterminate(); +} + +{ignored_attr} IGNORE(); + +. ; + + + + + + +%% + +static char* strbuf = NULL; +static char* write_ptr = NULL; +static char* read_ptr = NULL; + +static unsigned size_strbuf = 8192; +static unsigned len_strbuf = 0; + +extern void ddict_unused(void); +void ddict_unused(void) { + yy_top_state(); +} + +static void append_to_buffer(char* txt, int len) { + + if (strbuf == NULL) { + read_ptr = write_ptr = strbuf = malloc(size_strbuf); + } + + if ( (len_strbuf + len) >= size_strbuf ) { + read_ptr = strbuf = realloc(strbuf,size_strbuf *= 2); + } + + write_ptr = strbuf + len_strbuf; + strncpy(write_ptr,txt,len); + len_strbuf += len; + +} + +static size_t file_input(char* buf, size_t max) { + size_t read; + + read = fread(buf,1,max,yyin); + + if ( read == max ) { + return max; + } else if (read > 0) { + return read; + } else { + return YY_NULL; + } +} + + +static size_t string_input(char* buf, size_t max) { + if (read_ptr >= write_ptr ) { + return YY_NULL; + } else if ( read_ptr + max > write_ptr ) { + max = write_ptr - read_ptr; + } + + memcpy(buf,read_ptr,max); + read_ptr += max; + + return max; +} + +static FILE* ddict_open(const char* system_directory, const char* filename) { + FILE* fh; + char* fname; + + if (system_directory) { + int len = strlen(system_directory) + strlen(filename) + strlen(DDICT_DIRSEP) + 1; + fname = malloc(len); + snprintf(fname, len, "%s%s%s",system_directory,DDICT_DIRSEP,filename); + } else { + fname = strdup(filename); + } + + fh = fopen(fname,"r"); + + D(("fname: %s fh: %p\n",fname,fh)); + + free(fname); + + + return fh; +} + +ddict_t* ddict_scan(const char* system_directory, const char* filename) { + + sys_dir = system_directory; + + yyin = ddict_open(sys_dir,filename); + + write_ptr = NULL; + read_ptr = NULL; + + ents.next = NULL; + current_yyinput = file_input; + BEGIN LOADING; + yylex(); + + D(("\n---------------\n%s\n------- %d -------\n",strbuf,len_strbuf)); + + dict = NULL; + appl = NULL; + avp = NULL; + enumitem = NULL; + gavp = NULL; + typedefn = NULL; + cmd = NULL; + vnd = NULL; + + last_appl = NULL; + last_avp = NULL; + last_enumitem = NULL; + last_gavp = NULL; + last_typedefn = NULL; + last_cmd = NULL; + last_vnd = NULL; + + current_yyinput = string_input; + + BEGIN OUTSIDE; + yylex(); + + free(strbuf); + strbuf = NULL; + size_strbuf = 8192; + + return dict; +} + +void ddict_free(ddict_t* d) { + ddict_application_t *p, *pn; + ddict_vendor_t *v, *vn; + ddict_cmd_t *c, *cn; + ddict_typedefn_t *t, *tn; + ddict_avp_t *a, *an; + +#define FREE_NAMEANDOBJ(n) do { if(n->name) free(n->name); free(n); } while(0) + + for (p = d->applications; p; p = pn ) { + pn = p->next; + FREE_NAMEANDOBJ(p); + } + + for (v = d->vendors; v; v = vn) { + vn = v->next; + if (!v->desc) free(v->desc); + FREE_NAMEANDOBJ(v); + } + + for (c = d->cmds; c; c = cn ) { + cn = c->next; + FREE_NAMEANDOBJ(c); + } + + for (t = d->typedefns; t; t = tn) { + tn = t->next; + if (!t->parent) free(t->parent); + FREE_NAMEANDOBJ(t); + } + + for (a = d->avps; a; a = an) { + ddict_gavp_t* g, *gn; + ddict_enum_t* e, *en; + an = a->next; + + for (g = a->gavps; g; g = gn) { + gn = g->next; + FREE_NAMEANDOBJ(g); + } + + for (e = a->enums; e; e = en) { + en = e->next; + FREE_NAMEANDOBJ(e); + } + + if (!a->vendor) free(a->vendor); + if (!a->type) free(a->type); + if (!a->description) free(a->description); + FREE_NAMEANDOBJ(a); + } + + free(d); +} + +void ddict_print(FILE* fh, ddict_t* d) { + ddict_application_t* p; + ddict_vendor_t* v; + ddict_cmd_t* c; + ddict_typedefn_t* t; + ddict_avp_t* a; + + + for (p = d->applications; p; p = p->next) { + fprintf(fh,"Application: %s[%u]:\n", + p->name ? p->name : "-", + p->code); + } + + for (v = d->vendors; v; v = v->next) { + fprintf(fh,"Vendor: %s[%u]:\n", + v->name ? v->name : "-", + v->code); + } + + for (c = d->cmds; c; c = c->next) { + fprintf(fh,"Command: %s[%u] \n", + c->name ? c->name : "-", + c->code); + } + + for (t = d->typedefns; t; t = t->next) { + fprintf(fh,"Type: %s -> %s \n", + t->name ? t->name : "-", + t->parent ? t->parent : "" ); + } + + for (a = d->avps; a; a = a->next) { + ddict_gavp_t* g; + ddict_enum_t* e; + fprintf(fh,"AVP: %s[%u:%s] %s %s\n", + a->name ? a->name : "-", + a->code, + a->vendor ? a->vendor : "None", + a->type ? a->type : "-", + a->description ? a->description : ""); + + for (g = a->gavps; g; g = g->next) { + fprintf(fh,"\tGAVP: %s\n", + g->name ? g->name : "-" ); + } + + for (e = a->enums; e; e = e->next) { + fprintf(fh,"\tEnum: %s[%u]\n", + e->name ? e->name : "-", + e->code); + } + } +} + +#ifdef TEST_DIAM_DICT_STANDALONE +int main(int argc, char** argv) { + ddict_t* d; + char* dname = NULL; + char* fname; + int i = 1; + + switch (argc) { + case 3: + dname = argv[i++]; + case 2: + fname = argv[i]; + break; + default: + fprintf(stderr,"%s: usage [dictionary_dir] dictionary_filename\n",argv[0]); + return 1; + } + + d = ddict_scan(dname,fname); + + ddict_print(stdout, d); + + return 0; +} +#endif diff --git a/epan/dissectors/packet-diameter.c b/epan/dissectors/packet-diameter.c index 16521a2029..b84cd50a09 100644 --- a/epan/dissectors/packet-diameter.c +++ b/epan/dissectors/packet-diameter.c @@ -4,6 +4,7 @@ * $Id$ * * Copyright (c) 2001 by David Frascone + * Copyright (c) 2007 by Luis E. Garcia Ontanon * * Wireshark - Network traffic analyzer * By Gerald Combs @@ -58,222 +59,13 @@ #include #include "packet-tcp.h" #include "packet-sip.h" - -/* This must be defined before we include packet-diameter-defs.h */ - -/* Valid data types */ -typedef enum { - /* Base Types */ - DIAMETER_OCTET_STRING = 1, - DIAMETER_INTEGER32, - DIAMETER_INTEGER64, - DIAMETER_UNSIGNED32, - DIAMETER_UNSIGNED32ENUM, - DIAMETER_UNSIGNED64, - DIAMETER_FLOAT32, - DIAMETER_FLOAT64, - DIAMETER_FLOAT128, - DIAMETER_GROUPED, - - /* Derived Types */ - DIAMETER_IP_ADDRESS, /* OctetString */ - DIAMETER_TIME, /* Integer 32 */ - DIAMETER_UTF8STRING, /* OctetString */ - DIAMETER_IDENTITY, /* OctetString */ - DIAMETER_ENUMERATED, /* Integer 32 */ - DIAMETER_IP_FILTER_RULE, /* OctetString */ - DIAMETER_QOS_FILTER_RULE, /* OctetString */ - DIAMETER_MIP_REG_REQ, /* OctetString */ - DIAMETER_VENDOR_ID, /* Integer32 */ - DIAMETER_APPLICATION_ID, /* Integer32 */ - DIAMETER_URI, /* OctetString */ - DIAMETER_SESSION_ID, /* OctetString */ - DIAMETER_PUBLIC_ID, /* OctetString */ - DIAMETER_PRIVATE_ID /* OctetString */ -} diameterDataType; - - -static const value_string TypeValues[]={ - { DIAMETER_OCTET_STRING, "OctetString" }, - { DIAMETER_INTEGER32, "Integer32" }, - { DIAMETER_INTEGER64, "Integer64" }, - { DIAMETER_UNSIGNED32, "Unsigned32" }, - { DIAMETER_UNSIGNED32ENUM, "Unsigned32" }, /* This is needed to get value translation for Uint32:s with a value*/ - { DIAMETER_UNSIGNED64, "Unsigned64" }, - { DIAMETER_FLOAT32, "Float32" }, - { DIAMETER_FLOAT64, "Float64" }, - { DIAMETER_FLOAT128, "Float128" }, - { DIAMETER_GROUPED, "Grouped" }, - { DIAMETER_IP_ADDRESS, "IpAddress" }, - { DIAMETER_TIME, "Time" }, - { DIAMETER_UTF8STRING, "UTF8String" }, - { DIAMETER_IDENTITY, "DiameterIdentity" }, - { DIAMETER_ENUMERATED, "Enumerated" }, - { DIAMETER_IP_FILTER_RULE, "IPFilterRule" }, - { DIAMETER_QOS_FILTER_RULE, "QOSFilterRule" }, - { DIAMETER_MIP_REG_REQ, "MIPRegistrationRequest"}, - { DIAMETER_VENDOR_ID, "VendorId"}, - { DIAMETER_APPLICATION_ID, "AppId"}, - { DIAMETER_URI, "DiameterURI"}, - { DIAMETER_SESSION_ID, "Session-Id"}, - { DIAMETER_PUBLIC_ID, "Public-Id"}, - { DIAMETER_PRIVATE_ID, "Private-Id"}, - - {0, (char *)NULL} -}; - -typedef struct value_name { - guint32 value; - gchar *name; - struct value_name *next; -} ValueName; - -typedef struct old_avp_info { - guint32 code; - const gchar *name; - diameterDataType type; - const value_string *values; -} oldAvpInfo; - -typedef struct avp_info { - guint32 code; - gchar *name; - gchar *vendorName; - diameterDataType type; - ValueName *values; - struct avp_info *next; -} avpInfo; - -typedef struct command_code { - guint32 code; - gchar *name; - gchar *vendorName; - struct command_code *next; -} CommandCode; - -typedef struct vendor_id { - guint32 id; - gchar *name; - gchar *longName; - struct vendor_id *next; -} VendorId; - -typedef struct application_id { - guint32 id; - gchar *name; - struct application_id *next; -} ApplicationId; - -static avpInfo *avpListHead=NULL; -static VendorId *vendorListHead=NULL; -static CommandCode *commandListHead=NULL; -static ApplicationId *ApplicationIdHead=NULL; - - -#include "packet-diameter-defs.h" +#include "diam_dict.h" #define NTP_TIME_DIFF (2208988800U) #define TCP_PORT_DIAMETER 3868 #define SCTP_PORT_DIAMETER 3868 -static const true_false_string reserved_set = { - "*** Error! Reserved Bit is Set", - "Ok" -}; - -static int proto_diameter = -1; -static int hf_diameter_length = -1; -static int hf_diameter_code = -1; -static int hf_diameter_hopbyhopid =-1; -static int hf_diameter_endtoendid =-1; -static int hf_diameter_version = -1; -static int hf_diameter_vendor_id = -1; -static int hf_diameter_application_id = -1; -static int hf_diameter_flags = -1; -static int hf_diameter_flags_request = -1; -static int hf_diameter_flags_proxyable = -1; -static int hf_diameter_flags_error = -1; -static int hf_diameter_flags_T = -1; -static int hf_diameter_flags_reserved4 = -1; -static int hf_diameter_flags_reserved5 = -1; -static int hf_diameter_flags_reserved6 = -1; -static int hf_diameter_flags_reserved7 = -1; - -static int hf_diameter_avp = -1; -static int hf_diameter_avp_code = -1; -static int hf_diameter_avp_length = -1; -static int hf_diameter_avp_flags = -1; -static int hf_diameter_avp_flags_vendor_specific = -1; -static int hf_diameter_avp_flags_mandatory = -1; -static int hf_diameter_avp_flags_protected = -1; -static int hf_diameter_avp_flags_reserved3 = -1; -static int hf_diameter_avp_flags_reserved4 = -1; -static int hf_diameter_avp_flags_reserved5 = -1; -static int hf_diameter_avp_flags_reserved6 = -1; -static int hf_diameter_avp_flags_reserved7 = -1; -static int hf_diameter_avp_vendor_id = -1; - - -static int hf_diameter_avp_data_uint32 = -1; -static int hf_diameter_avp_data_int32 = -1; -static int hf_diameter_avp_data_uint64 = -1; -static int hf_diameter_avp_data_int64 = -1; -static int hf_diameter_avp_data_bytes = -1; -static int hf_diameter_avp_data_string = -1; -static int hf_diameter_avp_data_addrfamily = -1; -static int hf_diameter_avp_data_v4addr = -1; -static int hf_diameter_avp_data_v6addr = -1; -static int hf_diameter_avp_data_time = -1; -static int hf_diameter_avp_diameter_uri = -1; -static int hf_diameter_avp_session_id = -1; -static int hf_diameter_avp_public_id = -1; -static int hf_diameter_avp_private_id = -1; - -static gint ett_diameter = -1; -static gint ett_diameter_flags = -1; -static gint ett_diameter_avp = -1; -static gint ett_diameter_avp_flags = -1; -static gint ett_diameter_avpinfo = -1; - -static guint gbl_diameterTcpPort=TCP_PORT_DIAMETER; -static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER; - -/* desegmentation of Diameter over TCP */ -static gboolean gbl_diameter_desegment = TRUE; - -/* Allow zero as a valid application ID */ -static gboolean allow_zero_as_app_id = TRUE; - -/* Suppress console output at unknown AVP:s,Flags etc */ -static gboolean suppress_console_output = TRUE; - -static gboolean gbl_use_xml_dictionary = TRUE; -#define DICT_FN "diameter/dictionary.xml" -static const gchar *gbl_diameterDictionary; - -typedef struct _e_diameterhdr_v16 { - guint32 versionLength; - guint32 flagsCmdCode; - guint32 vendorId; - guint32 hopByHopId; - guint32 endToEndId; -} e_diameterhdr_v16; - -typedef struct _e_diameterhdr_rfc { - guint32 versionLength; - guint32 flagsCmdCode; - guint32 applicationId; - guint32 hopByHopId; - guint32 endToEndId; -} e_diameterhdr_rfc; - -typedef struct _e_avphdr { - guint32 avp_code; - guint32 avp_flagsLength; - guint32 avp_vendorId; /* optional */ -} e_avphdr; - /* Diameter Header Flags */ /* RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC */ #define DIAM_FLAGS_R 0x80 @@ -304,2096 +96,787 @@ typedef struct _e_avphdr { #define AVP_FLAGS_RESERVED7 0x01 #define AVP_FLAGS_RESERVED 0x1f /* 00011111 -- V M P X X X X X */ -#define MIN_AVP_SIZE (sizeof(e_avphdr) - sizeof(guint32)) -#define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr_rfc)) +#define DIAMETER_V16 16 +#define DIAMETER_RFC 1 -static Version_Type gbl_version = DIAMETER_RFC; +typedef struct _diam_ctx_t { + proto_tree* tree; + emem_tree_t* avps; + gboolean version_rfc; +} diam_ctx_t; -static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); -static gchar *diameter_vendor_to_str(guint32 vendorId, gboolean longName); +typedef struct _diam_avp_t diam_avp_t; +typedef struct _avp_type_t avp_type_t; -/* - * This routine will do a push-parse of the passed in - * filename. This was taken almost verbatum from - * the xmlsoft examples. - */ -static xmlDocPtr -xmlParseFilePush( const char *filename, int checkValid -#ifndef WIRESHARK_XML_DO_VALIDITY_CHECKING - _U_ -#endif -) { - FILE *f; - xmlDocPtr doc=NULL; -#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING - int valid=0; -#endif - int res, size = 1024; - char chars[1024]; - xmlParserCtxtPtr ctxt; +typedef const char* (*diam_avp_dissector_t)(diam_ctx_t*, diam_avp_t*, tvbuff_t*); -#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING - /* I wonder what kind of a performance hit this is? */ - *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid; -#endif - - f = fopen(filename, "r"); - if (f == NULL) { - report_open_failure(filename, errno, FALSE); - return NULL; - } - - res = fread(chars, 1, 4, f); - if (res > 0) { - ctxt = XmlStub.xmlCreatePushParserCtxt(NULL, NULL, - chars, res, filename); - while ((res = fread(chars, 1, size-1, f)) > 0) { - XmlStub.xmlParseChunk(ctxt, chars, res, 0); - } - XmlStub.xmlParseChunk(ctxt, chars, 0, 1); - doc = ctxt->myDoc; -#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING - valid=ctxt->valid; -#endif - XmlStub.xmlFreeParserCtxt(ctxt); - } - fclose(f); - -#ifdef WIRESHARK_XML_DO_VALIDITY_CHECKING - /* Check valid */ - if (!valid) { - report_failure( "Error! Invalid xml in %s! Failed DTD check!", - filename); - return NULL; - } -#endif - - return doc; -} /* xmlParseFilePush */ - -/* - * This routine will add a static avp to the avp list. It is - * only called when the XML dictionary fails to load properly. - */ -static int -addStaticAVP(int code, const gchar *name, diameterDataType type, const value_string *values) -{ - avpInfo *entry; - ValueName *vEntry=NULL; - int i; - - /* Parse our values array, if we have one */ - if (values) { - for (i=0; values[i].strptr != NULL; i++) { - ValueName *ve = NULL; - - ve = g_malloc(sizeof(ValueName)); - ve->name = strdup(values[i].strptr); - ve->value = values[i].value; - ve->next = vEntry; - vEntry = ve; - } - } /* if values */ - - /* And, create the entry */ - entry = (avpInfo *)g_malloc(sizeof(avpInfo)); - entry->name = g_strdup(name); - entry->code = code; - entry->vendorName = NULL; - entry->type = type; - entry->values = vEntry; - /* Unsigned32 might have values to ( Result-code 268 ) */ - if (vEntry){ - switch(type){ - case DIAMETER_UNSIGNED32: - entry->type = DIAMETER_UNSIGNED32ENUM; - break; - case DIAMETER_VENDOR_ID: - /* Ignore data from the xml file, use sminmpec.h vals */ - break; - default: - entry->type = DIAMETER_ENUMERATED; - } - } - - - /* And, add it to the list */ - entry->next = avpListHead; - avpListHead = entry; - - return (0); - -} /* addStaticAVP */ -/* - * This routine will add a Vendor avp to the avp list. It is - * only called when the XML dictionary fails to load properly. - */ -static int -addVendorAVP(int code, const gchar *name, diameterDataType type, const value_string *values,int vendorId) -{ - avpInfo *entry; - ValueName *vEntry=NULL; - gchar *vendorName; - int i; - - /* Parse our values array, if we have one */ - if (values) { - for (i=0; values[i].strptr != NULL; i++) { - ValueName *ve = NULL; - - ve = g_malloc(sizeof(ValueName)); - ve->name = strdup(values[i].strptr); - ve->value = values[i].value; - ve->next = vEntry; - vEntry = ve; - } - } /* if values */ - - /* And, create the entry */ - entry = (avpInfo *)g_malloc(sizeof(avpInfo)); - entry->name = g_strdup(name); - entry->code = code; - - vendorName = diameter_vendor_to_str(vendorId, FALSE); +struct _diam_avp_t { + guint32 code; + guint32 vendor; + diam_avp_dissector_t dissector_v16; + diam_avp_dissector_t dissector_rfc; - if (vendorName) - entry->vendorName = g_strdup(vendorName); - else - entry->vendorName = NULL; - entry->type = type; - entry->values = vEntry; + gint ett; + int hf_value; + void* type_data; +}; - /* Unsigned32 might have values to ( Result-code 268 ) */ - if (vEntry){ - switch(type){ - case DIAMETER_UNSIGNED32: - entry->type = DIAMETER_UNSIGNED32ENUM; - break; - case DIAMETER_VENDOR_ID: - /* Ignore data from the xml file, use sminmpec.h vals */ - break; - default: - entry->type = DIAMETER_ENUMERATED; +typedef struct _diam_vnd_t { + guint32 code; + GArray* vs_avps; + GArray* vs_cmds; +} diam_vnd_t; + +#define VND_AVP_VS(v) ((value_string*)((v)->vs_avps->data)) +#define VND_CMD_VS(v) ((value_string*)((v)->vs_cmds->data)) + +typedef struct _diam_dictionary_t { + emem_tree_t* avps; + emem_tree_t* vnds; + value_string* applications; + value_string* commands; +} diam_dictionary_t; + +typedef diam_avp_t* (*avp_constructor_t)(const avp_type_t*, guint32 code, guint32 vendor, const char* name, value_string* vs); + +struct _avp_type_t { + char* name; + diam_avp_dissector_t v16; + diam_avp_dissector_t rfc; + enum ftenum ft; + base_display_e base; + avp_constructor_t build; +}; + +struct _build_dict { + GArray* hf; + GArray* ett; + GHashTable* types; + GHashTable* avps; +}; + +static const char* simple_avp(diam_ctx_t*, diam_avp_t*, tvbuff_t*); + +static diam_avp_t unknown_avp = {0, 0, simple_avp, simple_avp, -1, -1, NULL }; +static value_string no_vs[] = {{0, NULL} }; +static GArray no_garr = { (void*)no_vs, 1 }; +static diam_vnd_t unknown_vendor = { 0, &no_garr, &no_garr }; +static diam_vnd_t no_vnd = { 0, NULL, NULL }; +static diam_dictionary_t dictionary = { NULL, NULL, NULL, NULL }; +static struct _build_dict build_dict; +static value_string* vnd_short_vs; +static const true_false_string reserved_set = { + "Set", + "Unset" +}; + +static int proto_diameter = -1; +static int hf_diameter_length = -1; +static int hf_diameter_code = -1; +static int hf_diameter_hopbyhopid =-1; +static int hf_diameter_endtoendid =-1; +static int hf_diameter_version = -1; +static int hf_diameter_vendor_id = -1; +static int hf_diameter_application_id = -1; +static int hf_diameter_flags = -1; +static int hf_diameter_flags_request = -1; +static int hf_diameter_flags_proxyable = -1; +static int hf_diameter_flags_error = -1; +static int hf_diameter_flags_T = -1; +static int hf_diameter_flags_reserved4 = -1; +static int hf_diameter_flags_reserved5 = -1; +static int hf_diameter_flags_reserved6 = -1; +static int hf_diameter_flags_reserved7 = -1; + +static int hf_diameter_avp = -1; +static int hf_diameter_avp_len = -1; +static int hf_diameter_avp_code = -1; +static int hf_diameter_avp_flags = -1; +static int hf_diameter_avp_flags_vendor_specific = -1; +static int hf_diameter_avp_flags_mandatory = -1; +static int hf_diameter_avp_flags_protected = -1; +static int hf_diameter_avp_flags_reserved3 = -1; +static int hf_diameter_avp_flags_reserved4 = -1; +static int hf_diameter_avp_flags_reserved5 = -1; +static int hf_diameter_avp_flags_reserved6 = -1; +static int hf_diameter_avp_flags_reserved7 = -1; +static int hf_diameter_avp_vendor_id = -1; + +static gint ett_diameter = -1; +static gint ett_diameter_flags = -1; +static gint ett_diameter_avp_flags = -1; +static gint ett_diameter_avpinfo = -1; + +static guint gbl_diameterTcpPort=TCP_PORT_DIAMETER; +static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER; + +/* desegmentation of Diameter over TCP */ +static gboolean gbl_diameter_desegment = TRUE; + +static const char* avpflags_str[] = { + "---", + "--P", + "-M-", + "-MP", + "V--", + "V-P", + "VM-", + "VMP", +}; + +static int dissect_diameter_avp(diam_ctx_t* c, tvbuff_t* tvb, int offset) { + guint32 code = tvb_get_ntohl(tvb,offset); + guint32 len = tvb_get_ntohl(tvb,offset+4); + guint32 vendor_flag = len & 0x80000000; + guint32 flags_bits_idx = (len & 0xE0000000) >> 29; + guint32 flags_bits = (len & 0xFF000000) >> 24; + guint32 vendorid = vendor_flag ? tvb_get_ntohl(tvb,offset+8) : 0; + emem_tree_key_t k[] = { + {1,&code}, + {1,&vendorid}, + {0,NULL} + }; + diam_avp_t* a = emem_tree_lookup32_array(dictionary.avps,k); + proto_item *pi, *avp_item; + proto_tree *avp_tree, *save_tree; + tvbuff_t* subtvb; + diam_vnd_t* vendor = vendor_flag ? &no_vnd : emem_tree_lookup32(dictionary.vnds,vendorid); + value_string* vendor_avp_vs; + const char* code_str; + const char* avp_str; + + len &= 0x00ffffff; + + if (!a) a = &unknown_avp; + if (! vendor) vendor = &unknown_vendor; + + vendor_avp_vs = VND_AVP_VS(vendor); + + avp_item = proto_tree_add_item(c->tree,hf_diameter_avp,tvb,offset,len,FALSE); + avp_tree = proto_item_add_subtree(avp_item,a->ett); + + pi = proto_tree_add_item(avp_tree,hf_diameter_avp_code,tvb,offset,4,FALSE); + code_str = val_to_str(code, vendor_avp_vs, "Unknown"); + proto_item_append_text(pi," %s", code_str); + offset += 4; + + proto_item_set_text(avp_item,"AVP: %s(%u) l=%u f=%s", code_str, code, len, avpflags_str[flags_bits_idx]); + + pi = proto_tree_add_item(avp_tree,hf_diameter_avp_flags,tvb,offset,1,FALSE); + { + 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,FALSE); + proto_tree_add_item(flags_tree,hf_diameter_avp_flags_mandatory,tvb,offset,1,FALSE); + proto_tree_add_item(flags_tree,hf_diameter_avp_flags_protected,tvb,offset,1,FALSE); + pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved3,tvb,offset,1,FALSE); + if(flags_bits & 0x10) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved4,tvb,offset,1,FALSE); + if(flags_bits & 0x08) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + pi = proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved5,tvb,offset,1,FALSE); + if(flags_bits & 0x04) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved6,tvb,offset,1,FALSE); + if(flags_bits & 0x02) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + proto_tree_add_item(flags_tree,hf_diameter_avp_flags_reserved7,tvb,offset,1,FALSE); + if(flags_bits & 0x01) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); } - } - - /* And, add it to the list */ - entry->next = avpListHead; - avpListHead = entry; - - return (0); - -} /* addStaticAVP */ -/* - * This routine will parse an XML avp entry, and add it to our - * avp list. If any values are present in the avp, it will - * add them too. - */ -static int -xmlParseAVP(xmlNodePtr cur) -{ - char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL, - *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL, - *constrained=NULL; - char *type=NULL; - avpInfo *entry; - guint32 avpType=0; - ValueName *vEntry=NULL; - int i; - - /* First, get our properties */ - name = XmlStub.xmlGetProp(cur, "name"); - description = XmlStub.xmlGetProp(cur, "description"); - code = XmlStub.xmlGetProp(cur, "code"); - mayEncrypt = XmlStub.xmlGetProp(cur, "may-encrypt"); - mandatory = XmlStub.xmlGetProp(cur, "mandatory"); - protected = XmlStub.xmlGetProp(cur, "protected"); - vendorBit = XmlStub.xmlGetProp(cur, "vendor-bit"); - vendorName = XmlStub.xmlGetProp(cur, "vendor-id"); - constrained = XmlStub.xmlGetProp(cur, "constrained"); - - cur = cur->xmlChildrenNode; - - while (cur != NULL ) { - if (strcasecmp((const char *)cur->name, "type") == 0) { - type = XmlStub.xmlGetProp(cur, "type-name"); - } else if (strcasecmp((const char *)cur->name, "enum") == 0) { - char *valueName=NULL, *valueCode=NULL; - ValueName *ve = NULL; - valueName = XmlStub.xmlGetProp(cur, "name"); - valueCode = XmlStub.xmlGetProp(cur, "code"); - - if (!valueName || !valueCode) { - report_failure( "Error, bad value on avp %s", name); - return (-1); - } - - ve = g_malloc(sizeof(ValueName)); - ve->name = strdup(valueName); - ve->value = atol(valueCode); - - ve->next = vEntry; - vEntry = ve; - } else if (strcasecmp((const char *)cur->name, "grouped") == 0) { - /* WORK Recurse here for grouped AVPs */ - type = "grouped"; + offset += 1; + + proto_tree_add_item(avp_tree,hf_diameter_avp_len,tvb,offset,3,FALSE); + offset += 3; + + if (vendor_flag) { + proto_item_append_text(avp_item," vnd=%s", val_to_str(vendorid, vnd_short_vs, "%d")); + proto_tree_add_item(avp_tree,hf_diameter_avp_vendor_id,tvb,offset,4,FALSE); + offset += 4; } - cur=cur->next; - } /* while */ - - /* - * Check for the AVP Type. - */ - if (type) { - for (i = 0; TypeValues[i].strptr; i++) { - if (!strcasecmp(type, TypeValues[i].strptr)) { - avpType = TypeValues[i].value; - break; - } - } - - if (TypeValues[i].strptr == NULL) { - report_failure( "Invalid Type field in dictionary! avp %s (%s)", name, type); - return (-1); - } - } else if (!vEntry) { - report_failure("Missing type/enum field in dictionary avpName=%s", - name); - return (-1); - } - - /* WORK - Handle flags -- for validation later */ - - - /* And, create the entry */ - entry = (avpInfo *)g_malloc(sizeof(avpInfo)); - entry->name = g_strdup(name); - entry->code = atol(code); - if (vendorName) - entry->vendorName = g_strdup(vendorName); - else - entry->vendorName = NULL; - entry->type = avpType; - entry->values = vEntry; - /* Unsigned32 might have values to ( Result-code 268 ) */ - if (vEntry) - switch(avpType){ - case DIAMETER_UNSIGNED32: - entry->type = DIAMETER_UNSIGNED32ENUM; - break; - case DIAMETER_VENDOR_ID: - /* Ignore data from the xml file, use sminmpec.h vals */ - break; - default: - entry->type = DIAMETER_ENUMERATED; - } - - /* And, add it to the list */ - entry->next = avpListHead; - avpListHead = entry; - - return (0); -} /* xmlParseAVP */ - -/* - * This routine will add a command to the list of commands. - */ -static int -addCommand(int code, const char *name, char *vendorId) -{ - CommandCode *entry; - - /* - * Allocate the memory required for the dictionary. - */ - entry = (CommandCode *) g_malloc(sizeof (CommandCode)); - - if (entry == NULL) { - report_failure("Unable to allocate memory"); - return (-1); - } - - /* - * Allocate memory for the AVPName and copy the name to the - * structure - */ - entry->name = g_strdup(name); - entry->code = code; - if (vendorId) - entry->vendorName = g_strdup(vendorId); - else - entry->vendorName = "None"; - - /* Add the entry to the list */ - entry->next = commandListHead; - commandListHead = entry; - - return 0; -} /* addCommand */ - -/* - * This routine will parse the XML command, and add it to our - * list of commands. - */ -static int -xmlParseCommand(xmlNodePtr cur) -{ - char *name, *code, *vendorIdString; - - /* - * Get the Attributes - */ - name = XmlStub.xmlGetProp(cur, "name"); - code = XmlStub.xmlGetProp(cur, "code"); - /* - g_warning("xmlParseCommand Name: %s code %s",name,code); - */ - if (!name || !code) { - report_failure("Invalid command. Name or code missing!"); - return -1; - } - vendorIdString = XmlStub.xmlGetProp(cur, "vendor-id"); - - if (!vendorIdString || !strcasecmp(vendorIdString, "None")) { - vendorIdString = NULL; - } - - return (addCommand(atoi(code), name, vendorIdString)); -} /* xmlParseCommand */ - -/* This routine adds an application to the name<-> id table */ -static int -dictionaryAddApplication(char *name, guint32 id) -{ - ApplicationId *entry; - - if (!name || (id == 0 && !allow_zero_as_app_id)) { - report_failure( "Diameter Error: Invalid application (name=%s, id=%d)", - name, id); - return (-1); - } /* Sanity Checks */ - - entry = g_malloc(sizeof(ApplicationId)); - if (!entry) { - report_failure( "Unable to allocate memory"); - return (-1); - } - - entry->name = g_strdup(name); - entry->id = id; - - /* Add it to the list */ - entry->next = ApplicationIdHead; - ApplicationIdHead = entry; - - return 0; -} /* dictionaryAddApplication */ - -/* - * This routine will add a vendor to the vendors list - */ -static int -addVendor(int id, const gchar *name, const gchar *longName) -{ - VendorId *vendor; - - /* add entry */ - vendor=g_malloc(sizeof(VendorId)); - if (!vendor) { - return (-1); - } - - vendor->id = id; - vendor->name = g_strdup(name); - vendor->longName = g_strdup(longName); - vendor->next = vendorListHead; - vendorListHead = vendor; - - return 0; -} /* addVendor */ - -/* - * This routine will pars in a XML vendor entry. - */ -static int -xmlParseVendor(xmlNodePtr cur) -{ - char *name=NULL, *code=NULL, *id=NULL; - - /* First, get our properties */ - id = XmlStub.xmlGetProp(cur, "vendor-id"); - name = XmlStub.xmlGetProp(cur, "name"); - code = XmlStub.xmlGetProp(cur, "code"); - - if (!id || !name || !code) { - report_failure( "Invalid vendor section. vendor-id, name, and code must be specified"); - return -1; - } - - return (addVendor(atoi(code), id, name)); - -} /* addVendor */ - -/* - * This routine will either parse in the base protocol, or an application. - */ -static int -xmlDictionaryParseSegment(xmlNodePtr cur, int base) -{ - if (!base) { - char *name; - char *id; - - /* Add our application */ - id = XmlStub.xmlGetProp(cur, "id"); - name = XmlStub.xmlGetProp(cur, "name"); - - if (!name || !id) { - /* ERROR!!! */ - report_failure("Diameter: Invalid application!: name=\"%s\", id=\"%s\"", - name?name:"NULL", id?id:"NULL"); - return -1; - } - /* Add the application */ - if (dictionaryAddApplication(name, (guint32)atol(id)) != 0) { - /* ERROR! */ - return -1; - } - } - - - /* - * Get segment values - */ - cur = cur->xmlChildrenNode; - while (cur != NULL) { - if (strcasecmp((const char *)cur->name, "avp") == 0) { - /* we have an avp!!! */ - xmlParseAVP(cur); - } else if (strcasecmp((const char *)cur->name, "vendor") == 0) { - /* we have a vendor */ - xmlParseVendor(cur); - /* For now, ignore typedefn and text */ - } else if (strcasecmp((const char *)cur->name, "command") == 0) { - /* Found a command */ - xmlParseCommand(cur); - } else if (strcasecmp((const char *)cur->name, "text") == 0) { - } else if (strcasecmp((const char *)cur->name, "comment") == 0) { - } else if (strcasecmp((const char *)cur->name, "typedefn") == 0) { - /* WORK -- parse in valid types . . . */ + + if ( len == (vendor_flag ? 12 : 8) ) return len; + + subtvb = tvb_new_subset(tvb,offset,len-(8+(vendor_flag?4:0)),len-(8+(vendor_flag?4:0))); + + save_tree = c->tree; + c->tree = avp_tree; + if (c->version_rfc) { + avp_str = a->dissector_rfc(c,a,subtvb); } else { - /* IF we got here, we're an error */ - report_failure("Error! expecting an avp or a typedefn (got \"%s\")", - cur->name); - return (-1); + avp_str = a->dissector_v16(c,a,subtvb); } - cur = cur->next; - } /* while */ - return 0; -} /* xmlDictionaryParseSegment */ + c->tree = save_tree; + + if (avp_str) proto_item_append_text(avp_item," val=%s", avp_str); -/* - * The main xml parse routine. This will walk through an XML - * dictionary that has been parsed by libxml. - */ -static int -xmlDictionaryParse(xmlNodePtr cur) -{ - /* We should expect a base protocol, followed by multiple applications */ - while (cur != NULL) { - if (strcasecmp((const char *)cur->name, "base") == 0) { - /* Base protocol. Descend and parse */ - xmlDictionaryParseSegment(cur, 1); - } else if (strcasecmp((const char *)cur->name, "application") == 0) { - /* Application. Descend and parse */ - xmlDictionaryParseSegment(cur, 0); - } else if (strcasecmp((const char *)cur->name, "text") == 0) { - /* Ignore text */ - } else if (strcasecmp((const char *)cur->name, "comment") == 0) { - /* Ignore text */ - } else { - report_failure( "Diameter: XML Expecting a base or an application (got \"%s\")", - cur->name); - return (-1); - } - cur = cur->next; - } - - return 0; - -} /* xmlDictionaryParse */ - -/* - * This routine will call libxml to parse in the dictionary. - */ -static int -loadXMLDictionary(void) -{ - xmlDocPtr doc; - xmlNodePtr cur; - - /* - * build an XML tree from the file; - */ - XmlStub.xmlKeepBlanksDefault(0); /* Strip leading and trailing blanks */ - XmlStub.xmlSubstituteEntitiesDefault(1); /* Substitute entities automagically */ - doc = xmlParseFilePush(gbl_diameterDictionary, 1); /* Parse the XML (do validity checks)*/ - - /* Check for invalid xml. - Note that xmlParseFilePush reports details of problems found, - and it should be obvious from the default filename that the error relates - to Diameter. - */ - if (doc == NULL) { - return -1; - } - - /* - * Check the document is of the right kind - */ - cur = XmlStub.xmlDocGetRootElement(doc); - if (cur == NULL) { - report_failure("Diameter: Error: \"%s\": empty document", - gbl_diameterDictionary); - XmlStub.xmlFreeDoc(doc); - return -1; - } - if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) { - report_failure("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary", - gbl_diameterDictionary); - XmlStub.xmlFreeDoc(doc); - return -1; - } - - /* - * Ok, the dictionary has been parsed by libxml, and is valid. - * All we have to do now is read in our information. - */ - if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) { - /* Error has already been printed */ - return -1; - } - - /* Once we're done parsing, free up the xml memory */ - XmlStub.xmlFreeDoc(doc); - - return 0; - -} /* loadXMLDictionary */ - -/* - * Fallback routine. In the event of ANY error when loading the XML - * dictionary, this routine will populate the new avp list structures - * with the old static data from packet-diameter-defs.h - */ -static void -initializeDictionaryDefaults(void) -{ - int i; - - /* Add static vendors to list */ - for(i=0; sminmpec_values[i].strptr; i++) { - addVendor(sminmpec_values[i].value, - sminmpec_values[i].strptr, - sminmpec_values[i].strptr); - - } - /* Add static commands to list. */ - for(i=0; diameter_command_code_vals[i].strptr; i++) { - addCommand(diameter_command_code_vals[i].value, - diameter_command_code_vals[i].strptr, NULL); - } - - /* Add static AVPs to list */ - for (i=0; old_diameter_avps[i].name; i++) { - addStaticAVP(old_diameter_avps[i].code, - old_diameter_avps[i].name, - old_diameter_avps[i].type, - old_diameter_avps[i].values); - } - /* Add 3GPP AVPs to list */ - for (i=0; ThreeGPP_vendor_diameter_avps[i].name; i++) { - addVendorAVP(ThreeGPP_vendor_diameter_avps[i].code, - ThreeGPP_vendor_diameter_avps[i].name, - ThreeGPP_vendor_diameter_avps[i].type, - ThreeGPP_vendor_diameter_avps[i].values, - VENDOR_THE3GPP); - } - -} /* initializeDictionaryDefaults */ - -/* - * This routine will attempt to load the XML dictionary if configured to. - * Otherwise, or if load fails, it will call initializeDictionaryDefaults - * to load in our static dictionary instead. - */ -static void -initializeDictionary(void) -{ - /* - * First, empty the dictionary of any previous contents - */ - - ApplicationId *tmpApplicationId = ApplicationIdHead; - VendorId *tmpVendorId = vendorListHead; - CommandCode *tmpCommandCode = commandListHead; - avpInfo *tmpAvpInfo = avpListHead; - - /* ApplicationId list */ - while (tmpApplicationId != NULL) { - g_free(tmpApplicationId->name); - tmpApplicationId = tmpApplicationId->next; - } - ApplicationIdHead = NULL; - - /* VendorId list */ - while (tmpVendorId != NULL) { - g_free(tmpVendorId->name); - g_free(tmpVendorId->longName); - tmpVendorId = tmpVendorId->next; - } - vendorListHead = NULL; - - /* CommandCode list */ - while (tmpCommandCode != NULL) { - g_free(tmpCommandCode->name); - g_free(tmpCommandCode->vendorName); - tmpCommandCode = tmpCommandCode->next; - } - commandListHead = NULL; - - /* avpInfo list */ - while (tmpAvpInfo != NULL) { - ValueName *valueNamePtr = tmpAvpInfo->values; - g_free(tmpAvpInfo->name); - g_free(tmpAvpInfo->vendorName); - while (valueNamePtr) { - g_free(valueNamePtr->name); - valueNamePtr = valueNamePtr->next; - } - tmpAvpInfo = tmpAvpInfo->next; - } - avpListHead = NULL; - - - /* - * Using ugly ordering here. If loadLibXML succeeds, then - * loadXMLDictionary will be called. This is one of the few times when - * I think this is prettier than the nested if alternative. - */ - if (gbl_use_xml_dictionary) { - if (loadLibXML() || (loadXMLDictionary() != 0)) { - /* Something failed. Use the static dictionary */ - report_failure("Diameter: Using static dictionary! (Unable to use XML)"); - initializeDictionaryDefaults(); - } - } - else { - initializeDictionaryDefaults(); - } - -} /* initializeDictionary */ - - - -/* - * These routines manipulate the diameter structures. - */ - -/* return vendor string, based on the id */ -static gchar * -diameter_vendor_to_str(guint32 vendorId, gboolean longName) { - VendorId *probe; - gchar *buffer; - - for (probe=vendorListHead; probe; probe=probe->next) { - if (vendorId == probe->id) { - if (longName) - return probe->longName; - else - return probe->name; - } - } - - buffer=ep_alloc(64); - g_snprintf(buffer, 64, "Vendor 0x%08x", vendorId); - return buffer; -} /*diameter_vendor_to_str */ - -/* return command string, based on the code */ -static gchar * -diameter_command_to_str(guint32 commandCode, guint32 vendorId) -{ - CommandCode *probe; - gchar *buffer=NULL; - gchar *vendorName=NULL; - - switch(gbl_version) { - case DIAMETER_V16: - /* In draft-v16 version, command code is depending on vendorID */ - if (vendorId) - vendorName = diameter_vendor_to_str(vendorId, FALSE); - - for (probe=commandListHead; probe; probe=probe->next) { - if (commandCode == probe->code) { - if (vendorId) { -/* g_warning("Command: Comparing \"%s\" to \"%s\"", */ -/* vendorName?vendorName:"(null)", */ -/* probe->vendorName?probe->vendorName:"(null)"); */ - /* Now check the vendor name */ - if (!strcmp(vendorName, probe->vendorName)) - /* We found it */ - return probe->name; - } else { - /* With no vendor id, the Command's entry should be "None" */ - if (!strcmp(probe->vendorName, "None")) { - /* We found it */ - return probe->name; - } - } - } - } - - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Unable to find name for command code 0x%08x (%u), Vendor \"%u\"!", - commandCode, commandCode, vendorId); - buffer=ep_alloc(64); - g_snprintf(buffer, 64, - "Cmd-0x%08x", commandCode); - break; - case DIAMETER_RFC: - /* In RFC3588 version, command code is independant on vendorID */ - for (probe=commandListHead; probe; probe=probe->next) { - if (commandCode == probe->code) { - /* We found it */ - return probe->name; - } - } - - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Unable to find name for command code 0x%08x (%u)!", - commandCode, commandCode); - buffer=ep_alloc(64); - g_snprintf(buffer, 64, - "Cmd-0x%08x", commandCode); - break; - } - return buffer; -}/*diameter_command_to_str */ - -/* return application string, based on the id */ -static gchar * -diameter_app_to_str(guint32 appId) { - ApplicationId *probe; - gchar *buffer; - - for (probe=ApplicationIdHead; probe; probe=probe->next) { - if (appId == probe->id) { - return probe->name; - } - } - - buffer=ep_alloc(64); - g_snprintf(buffer, 64, "Unknown"); - return buffer; -} /*diameter_app_to_str */ - -/* return an avp type, based on the code */ -static diameterDataType -diameter_avp_get_type(guint32 avpCode, guint32 vendorId){ - avpInfo *probe; - gchar *vendorName=NULL; - - if (vendorId) - vendorName = diameter_vendor_to_str(vendorId, FALSE); - - for (probe=avpListHead; probe; probe=probe->next) { - if (avpCode == probe->code) { - - if (vendorId) { -/* g_warning("AvpType: Comparing \"%s\" to \"%s\"", */ -/* vendorName?vendorName:"(null)", */ -/* probe->vendorName?probe->vendorName:"(null)"); */ - /* Now check the vendor name */ - if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) - /* We found it! */ - return probe->type; - } else { - /* No Vendor ID -- vendorName should be null */ - if (!probe->vendorName) - /* We found it! */ - return probe->type; - } - } - } - - /* If we don't find it, assume it's data */ - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Unable to find type for avpCode %u, Vendor %u!", avpCode, - vendorId); - return DIAMETER_OCTET_STRING; -} /* diameter_avp_get_type */ - -/* return an avp name from the code */ -static gchar * -diameter_avp_get_name(guint32 avpCode, guint32 vendorId, gboolean *AVPFound) -{ - gchar *buffer; - avpInfo *probe; - gchar *vendorName=NULL; - *AVPFound = TRUE; /* will set to FALSE only if fail to match */ - - if (vendorId) - vendorName = diameter_vendor_to_str(vendorId, FALSE); - - for (probe=avpListHead; probe; probe=probe->next) { - if (avpCode == probe->code) { - if (vendorId) { - /* Now check the vendor name */ - if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) - /* We found it! */ - return probe->name; - else { - /* Print explanation */ - if (!suppress_console_output) { - g_warning("AVP %u: Found vendor name (%s) didn't match definition (%s)", - avpCode, - vendorName ? vendorName : "(null)", - probe->vendorName ? probe->vendorName : "(null)"); - } - } - } - else { - /* No Vendor ID -- vendorName should be null */ - if (!probe->vendorName) - /* We found it! */ - return probe->name; - else { - /* Print explanation */ - if (!suppress_console_output) { - g_warning("AVP %u: No vendorId found in AVP, but definition has one (%s)", - avpCode, probe->vendorName ? probe->vendorName : "(null)"); - } - } - } - } - } - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Unable to find name for AVP 0x%08x (%u), Vendor %u!", - avpCode, avpCode, vendorId); - - /* If we don't find it, build & return an error name string */ - buffer=ep_alloc(64); - g_snprintf(buffer, 64, "Unknown AVP:0x%08x (%d)", avpCode, avpCode); - *AVPFound = FALSE; - return buffer; -} /* diameter_avp_get_name */ - -static const gchar * -diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue) -{ - avpInfo *probe; - gchar *vendorName=NULL; - - if (vendorId) - vendorName = diameter_vendor_to_str(vendorId, FALSE); - - for (probe=avpListHead; probe; probe=probe->next) { - if (avpCode == probe->code) { - if (vendorId) { -/* g_warning("AvpValue: Comparing \"%s\" to \"%s\"", */ -/* vendorName?vendorName:"(null)", */ -/* probe->vendorName?probe->vendorName:"(null)"); */ - /* Now check the vendor name */ - if (probe->vendorName && (!strcmp(vendorName, probe->vendorName))) { - ValueName *vprobe; - for(vprobe=probe->values; vprobe; vprobe=vprobe->next) { - if (avpValue == vprobe->value) { - return vprobe->name; - } - } - return "(Unknown value)"; - } - } else { - if (!probe->vendorName) { - ValueName *vprobe; - for(vprobe=probe->values; vprobe; vprobe=vprobe->next) { - if (avpValue == vprobe->value) { - return vprobe->name; - } - } - return "(Unknown value)"; - } - } - } - } - /* We didn't find the avp */ - return "(Unknown AVP)"; -} /* diameter_avp_get_value */ - - -/* Code to actually dissect the packets */ - -static gboolean -check_diameter(tvbuff_t *tvb) -{ - if (!tvb_bytes_exist(tvb, 0, 1)) - return FALSE; /* not enough bytes to check the version */ - if (tvb_get_guint8(tvb, 0) != 1) - return FALSE; /* not version 1 */ - - /* XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE? - Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits - are set? */ - return TRUE; + return len; } -/* - * Main dissector - */ -static void -dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) -{ - /* Set up structures needed to add the protocol subtree and manage it */ - proto_item *ti; - proto_item *tf; - proto_tree *flags_tree; - tvbuff_t *avp_tvb; - proto_tree *diameter_tree; - e_diameterhdr_v16 dh; - e_diameterhdr_rfc dh2; - int offset=0; - size_t avplength=0; - proto_tree *avp_tree; - proto_item *avptf; - int BadPacket = FALSE; - guint32 commandCode=0, pktLength=0; - guint8 version=0, flags=0; - const gchar *flagstr=""; - const gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" }; - const gchar *commandString=NULL, *vendorName=NULL, *applicationName=NULL, *commandStringType=NULL; - gint i; - guint bpos; - static int initialized=FALSE; +static const char* simple_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) { + char* label = ep_alloc(ITEM_LABEL_LENGTH+1); + proto_item* pi = proto_tree_add_item(c->tree,a->hf_value,tvb,0,tvb_length_remaining(tvb,0),FALSE); + proto_item_fill_label(pi->finfo, label); + label = strstr(label,": ")+2; + return label; +} - /* Keep track of preference settings affecting dictionary source */ - static gboolean previous_use_xml_dictionary=FALSE; - #define MAX_DICT_NAME_SIZE 256 - static gchar previous_diameterDictionary[MAX_DICT_NAME_SIZE]; - - /* - * Only parse in dictionary if there are diameter packets to - * dissect. - * Keeps track of preference settings and frees/reinitializes the - * dictionary when appropriate. - */ - if (!initialized || - (gbl_use_xml_dictionary != previous_use_xml_dictionary) || - (strncmp(gbl_diameterDictionary, - previous_diameterDictionary, - MAX_DICT_NAME_SIZE) != 0)) { - /* Populate dictionary according to preferences */ - initializeDictionary(); - initialized=TRUE; - - /* Record current preference settings */ - previous_use_xml_dictionary = gbl_use_xml_dictionary; - strncpy(previous_diameterDictionary, gbl_diameterDictionary, MAX_DICT_NAME_SIZE); - } - - /* Make entries in Protocol column and Info column on summary display */ - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "Diameter"); - if (check_col(pinfo->cinfo, COL_INFO)) - col_clear(pinfo->cinfo, COL_INFO); - - /* Copy our header */ - switch(gbl_version) { - case DIAMETER_V16: - tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh)); - /* Fix byte ordering in our static structure */ - dh.versionLength = g_ntohl(dh.versionLength); - dh.flagsCmdCode = g_ntohl(dh.flagsCmdCode); - dh.vendorId = g_ntohl(dh.vendorId); - dh.hopByHopId = g_ntohl(dh.hopByHopId); - dh.endToEndId = g_ntohl(dh.endToEndId); - if (dh.vendorId) { - vendorName=diameter_vendor_to_str(dh.vendorId, TRUE); - } else { - vendorName="None"; - } - /* Do the bit twiddling */ - version = (guint8) DIAM_GET_VERSION(dh); - pktLength = DIAM_GET_LENGTH(dh); - flags = (guint8) DIAM_GET_FLAGS(dh); - commandCode = DIAM_GET_COMMAND(dh); - break; - case DIAMETER_RFC: - tvb_memcpy(tvb, (guint8*) &dh2, offset, sizeof(dh2)); - /* Fix byte ordering in our static structure */ - dh2.versionLength = g_ntohl(dh2.versionLength); - dh2.flagsCmdCode = g_ntohl(dh2.flagsCmdCode); - dh2.applicationId = g_ntohl(dh2.applicationId); - dh2.hopByHopId = g_ntohl(dh2.hopByHopId); - dh2.endToEndId = g_ntohl(dh2.endToEndId); - if (dh2.applicationId) { - applicationName=diameter_app_to_str(dh2.applicationId); - /* If not found, it might be a vendor ID? */ - if (strcmp(applicationName, "Unknown") == 0){ - applicationName=diameter_vendor_to_str(dh2.applicationId,FALSE); - } - } else { - applicationName="None"; - } - /* Do the bit twiddling */ - version = (guint8) DIAM_GET_VERSION(dh2); - pktLength = DIAM_GET_LENGTH(dh2); - flags = (guint8) DIAM_GET_FLAGS(dh2); - commandCode = DIAM_GET_COMMAND(dh2); - break; - } - - - /* Set up our flags */ - if (check_col(pinfo->cinfo, COL_INFO) || tree) { - char *flagbuf; - int fslen; - -#define FLAG_STR_LEN 64 - flagbuf=ep_alloc(FLAG_STR_LEN); - flagbuf[0]=0; - fslen=0; - for (i = 0; i < 8; i++) { - bpos = 1 << i; - if (flags & bpos) { - if (flagbuf[0]) { - fslen+=MIN(FLAG_STR_LEN-fslen, - g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, ", ")); - } - fslen+=MIN(FLAG_STR_LEN-fslen, - g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, "%s", fstr[i])); - } +static const char* grouped_avp(diam_ctx_t* c, diam_avp_t* a, tvbuff_t* tvb) { + int offset = 0; + int len = tvb_length_remaining(tvb,0); + proto_item* pi = proto_tree_add_item(c->tree, a->hf_value, tvb , 0 , -1, FALSE); + proto_tree* pt = c->tree; + + c->tree = proto_item_add_subtree(pi,a->ett); + + while (offset < len) { + offset += dissect_diameter_avp(c, tvb, offset); + offset += (offset % 4) ? 4 - (offset % 4) : 0 ; } - flagstr = flagbuf; - if (flagstr[0] == 0) { - flagstr=""; + + c->tree = pt; + + return NULL; +} + +static void dissect_diameter_common(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree) { + guint32 first_word = tvb_get_ntohl(tvb,0); + guint32 version = (first_word & 0xff000000) >> 24; + guint32 flags_bits = (tvb_get_ntohl(tvb,4) & 0xff000000) >> 24; + int packet_len = first_word & 0x00ffffff; + proto_item *pi; + proto_item *cmd_item, *version_item; + diam_ctx_t* c = ep_alloc0(sizeof(diam_ctx_t)); + int offset; + value_string* cmd_vs; + const char* cmd_str; + guint32 cmd = tvb_get_ntoh24(tvb,5); + guint32 fourth = tvb_get_ntohl(tvb,8); + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "DIAMETER"); + + pi = proto_tree_add_item(tree,proto_diameter,tvb,0,-1,FALSE); + tree = proto_item_add_subtree(pi,ett_diameter); + + c->tree = tree; + + version_item = proto_tree_add_item(tree,hf_diameter_version,tvb,0,1,FALSE); + proto_tree_add_item(tree,hf_diameter_length,tvb,1,3,FALSE); + + pi = proto_tree_add_item(tree,hf_diameter_flags,tvb,4,1,FALSE); + { + proto_tree* pt = proto_item_add_subtree(pi,ett_diameter_flags); + proto_tree_add_item(pt,hf_diameter_flags_request,tvb,4,1,FALSE); + proto_tree_add_item(pt,hf_diameter_flags_proxyable,tvb,4,1,FALSE); + proto_tree_add_item(pt,hf_diameter_flags_error,tvb,4,1,FALSE); + proto_tree_add_item(pt,hf_diameter_flags_T,tvb,4,1,FALSE); + proto_tree_add_item(pt,hf_diameter_flags_reserved4,tvb,4,1,FALSE); + if(flags_bits & 0x08) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + pi = proto_tree_add_item(pt,hf_diameter_flags_reserved5,tvb,4,1,FALSE); + if(flags_bits & 0x04) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + pi = proto_tree_add_item(pt,hf_diameter_flags_reserved6,tvb,4,1,FALSE); + if(flags_bits & 0x02) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); + pi = proto_tree_add_item(pt,hf_diameter_flags_reserved7,tvb,4,1,FALSE); + if(flags_bits & 0x01) proto_item_set_expert_flags(pi, PI_MALFORMED, PI_WARN); } - } - - /* Set up our commandString */ - switch(gbl_version) { - case DIAMETER_V16: - commandString=diameter_command_to_str(commandCode, dh.vendorId); - break; - case DIAMETER_RFC: - /* FIXME: in RFC, is applicationID needed to decode the command code? */ - commandString=diameter_command_to_str(commandCode, dh2.applicationId); - break; - } - - if (flags & DIAM_FLAGS_R) - commandStringType="Request"; - else - commandStringType="Answer"; - - /* Short packet. Should have at LEAST one avp */ - if (pktLength < MIN_DIAMETER_SIZE) { - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))", - pktLength, (unsigned long)MIN_DIAMETER_SIZE); - BadPacket = TRUE; - } - - /* And, check our reserved flags/version */ - if ((flags & DIAM_FLAGS_RESERVED) || - (version != 1)) { - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)", - flags, version); - BadPacket = TRUE; - } - - if (check_col(pinfo->cinfo, COL_INFO)) { - switch(gbl_version) { - case DIAMETER_V16: - col_add_fstr(pinfo->cinfo, COL_INFO, - "%s%s%s%s%s-%s vendor=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d", - (BadPacket)?"***** Bad Packet!: ":"", - (flags & DIAM_FLAGS_P)?"Proxyable ":"", - (flags & DIAM_FLAGS_E)?" Error":"", - ((BadPacket || - (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ? - ": " : ""), - commandString, commandStringType, vendorName, - dh.hopByHopId, dh.endToEndId, - (flags & DIAM_FLAGS_R)?1:0, - (flags & DIAM_FLAGS_P)?1:0, - (flags & DIAM_FLAGS_E)?1:0); - break; - case DIAMETER_RFC: - col_add_fstr(pinfo->cinfo, COL_INFO, - "%s%s%s%s%s-%s app=%s (hop-id=%u) (end-id=%u) RPE=%d%d%d", - (BadPacket)?"***** Bad Packet!: ":"", - (flags & DIAM_FLAGS_P)?"Proxyable ":"", - (flags & DIAM_FLAGS_E)?" Error":"", - ((BadPacket || - (flags & (DIAM_FLAGS_P|DIAM_FLAGS_E))) ? - ": " : ""), - commandString, commandStringType, applicationName, - dh2.hopByHopId, dh2.endToEndId, - (flags & DIAM_FLAGS_R)?1:0, - (flags & DIAM_FLAGS_P)?1:0, - (flags & DIAM_FLAGS_E)?1:0); - break; - } - } - - - /* In the interest of speed, if "tree" is NULL, don't do any work not - necessary to generate protocol tree items. */ - if (tree) { - - /* create display subtree for the protocol */ - ti = proto_tree_add_item(tree, proto_diameter, tvb, offset, - MAX(pktLength,MIN_DIAMETER_SIZE), FALSE); - diameter_tree = proto_item_add_subtree(ti, ett_diameter); - - /* Version */ - proto_tree_add_uint(diameter_tree, - hf_diameter_version, - tvb, offset, 1, - version); - - offset+=1; - - /* Length */ - proto_tree_add_uint(diameter_tree, - hf_diameter_length, tvb, - offset, 3, pktLength); - offset += 3; - - /* Flags */ - tf = proto_tree_add_uint_format_value(diameter_tree, hf_diameter_flags, tvb, - offset, 1, flags, "0x%02x (%s)", flags, - flagstr); - flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_request, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_proxyable, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_error, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_T, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved4, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved5, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved6, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_flags_reserved7, tvb, offset, 1, flags); - - offset += 1; - - /* Command Code */ - proto_tree_add_uint_format_value(diameter_tree, hf_diameter_code, - tvb, offset, 3, commandCode, "%s-%s (%d)", - commandString, commandStringType, commandCode); - offset += 3; - - switch(gbl_version) { - case DIAMETER_V16: - - /* Vendor Id */ - proto_tree_add_item(diameter_tree, hf_diameter_vendor_id, tvb, offset, 4, FALSE); - offset += 4; - /* Hop-by-hop Identifier */ - proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid, - tvb, offset, 4, dh.hopByHopId); - offset += 4; - /* End-to-end Identifier */ - proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid, - tvb, offset, 4, dh.endToEndId); - offset += 4; + + cmd_item = proto_tree_add_item(tree,hf_diameter_code,tvb,5,3,FALSE); + + switch (version) { + case DIAMETER_V16: { + guint32 vendorid = tvb_get_ntohl(tvb,8); + diam_vnd_t* vendor; + + if (! ( vendor = emem_tree_lookup32(dictionary.vnds,vendorid) ) ) { + vendor = &unknown_vendor; + } + + cmd_vs = VND_CMD_VS(vendor); + proto_tree_add_item(tree, hf_diameter_vendor_id,tvb,8,4,FALSE); + + c->version_rfc = FALSE; + break; + } + case DIAMETER_RFC: { + cmd_vs = VND_CMD_VS(&no_vnd); + proto_tree_add_item(tree, hf_diameter_application_id,tvb,8,4,FALSE); + c->version_rfc = TRUE; + break; + } + default: + expert_add_info_format(pinfo, version_item, PI_UNDECODED, PI_WARN, "Unknown Diameter Version"); + c->version_rfc = TRUE; + cmd_vs = VND_CMD_VS(&no_vnd); break; - case DIAMETER_RFC: - /* Application Id */ - proto_tree_add_item(diameter_tree, hf_diameter_application_id, tvb, offset, 4, FALSE); - offset += 4; - /* Hop-by-hop Identifier */ - proto_tree_add_uint(diameter_tree, hf_diameter_hopbyhopid, - tvb, offset, 4, dh2.hopByHopId); - offset += 4; - /* End-to-end Identifier */ - proto_tree_add_uint(diameter_tree, hf_diameter_endtoendid, - tvb, offset, 4, dh2.endToEndId); - offset += 4; - break; - } - - - /* If we have a bad packet, don't bother trying to parse the AVPs */ - if (BadPacket) { - return; } + cmd_str = val_to_str(cmd, cmd_vs, "Unknown"); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, + "cmd=%s(%d) %s=%s(%d) h2h=%x e2e=%x", + cmd_str, + cmd, + c->version_rfc ? "appl" : "vend", + val_to_str(fourth, c->version_rfc ? dictionary.applications : vnd_short_vs, "Unknown"), + fourth, + tvb_get_ntohl(tvb,12), + tvb_get_ntohl(tvb,16)); + + proto_item_append_text(cmd_item," %s", cmd_str); - /* Start looking at the AVPS */ - /* Make the next tvbuff */ - - /* Update the lengths */ - switch(gbl_version) { - case DIAMETER_V16: - avplength= pktLength - sizeof(e_diameterhdr_v16); - break; - case DIAMETER_RFC: - avplength= pktLength - sizeof(e_diameterhdr_rfc); - break; + proto_tree_add_item(tree,hf_diameter_hopbyhopid,tvb,12,4,FALSE); + proto_tree_add_item(tree,hf_diameter_endtoendid,tvb,16,4,FALSE); + + offset = 20; + + while (offset < packet_len) { + offset += dissect_diameter_avp(c, tvb, offset); + offset += (offset % 4) ? 4 - (offset % 4) : 0 ; } - - avp_tvb = tvb_new_subset(tvb, offset, avplength, avplength); - avptf = proto_tree_add_text(diameter_tree, - tvb, offset, avplength, - "Attribute Value Pairs"); - - avp_tree = proto_item_add_subtree(avptf, - ett_diameter_avp); - if (avp_tree != NULL) { - dissect_avps( avp_tvb, pinfo, avp_tree); - } - return; - } -} /* dissect_diameter_common */ - + +} static guint get_diameter_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset) { - /* Get the length of the Diameter packet. */ - return tvb_get_ntoh24(tvb, offset + 1); + /* Get the length of the Diameter packet. */ + return tvb_get_ntoh24(tvb, offset + 1); +} + +static gboolean +check_diameter(tvbuff_t *tvb) +{ + if (!tvb_bytes_exist(tvb, 0, 1)) + return FALSE; /* not enough bytes to check the version */ + + if (tvb_get_guint8(tvb, 0) != 1) + return FALSE; /* not version 1 */ + + /* + * XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE? + * Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits + * are set? + */ + return TRUE; } static int dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - if (!check_diameter(tvb)) - return 0; - dissect_diameter_common(tvb, pinfo, tree); - return tvb_length(tvb); + if (!check_diameter(tvb)) + return 0; + dissect_diameter_common(tvb, pinfo, tree); + return tvb_length(tvb); } static void dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4, - get_diameter_pdu_len, dissect_diameter_common); + tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4, + get_diameter_pdu_len, dissect_diameter_common); } /* dissect_diameter_tcp */ -/* - * Call the mip_dissector, after saving our pinfo variables - * so it doesn't write to our column display. - */ -static void -safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - size_t offset, size_t length) -{ - static dissector_handle_t mip_handle; - static int mipInitialized=FALSE; - tvbuff_t *mip_tvb; - address save_dl_src; - address save_dl_dst; - address save_net_src; - address save_net_dst; - address save_src; - address save_dst; - gboolean save_in_error_pkt; - if (!mipInitialized) { - mip_handle = find_dissector("mip"); - mipInitialized=TRUE; - } - - mip_tvb = tvb_new_subset(tvb, offset, - MIN(length, tvb_length(tvb)-offset), - length); - - /* The contained packet is a MIP registration request; - dissect it with the MIP dissector. */ - col_set_writable(pinfo->cinfo, FALSE); - - /* Also, save the current values of the addresses, and restore - them when we're finished dissecting the contained packet, so - that the address columns in the summary don't reflect the - contained packet, but reflect this packet instead. */ - save_dl_src = pinfo->dl_src; - save_dl_dst = pinfo->dl_dst; - save_net_src = pinfo->net_src; - save_net_dst = pinfo->net_dst; - save_src = pinfo->src; - save_dst = pinfo->dst; - save_in_error_pkt = pinfo->in_error_pkt; - - call_dissector(mip_handle, mip_tvb, pinfo, tree); - - /* Restore the "we're inside an error packet" flag. */ - pinfo->in_error_pkt = save_in_error_pkt; - pinfo->dl_src = save_dl_src; - pinfo->dl_dst = save_dl_dst; - pinfo->net_src = save_net_src; - pinfo->net_dst = save_net_dst; - pinfo->src = save_src; - pinfo->dst = save_dst; - - -} /* safe_dissect_mip */ - -/* - * This function will dissect the AVPs in a diameter packet. It handles - * all normal types, and even recursively calls itself for grouped AVPs - */ -static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree) -{ - /* adds the attribute value pairs to the tree */ - e_avphdr avph; - const gchar *avpTypeString; - const gchar *avpNameString; - const gchar *valstr; - guint32 vendorId=0; - const gchar *vendorName; - int hdrLength; - int fixAmt; - proto_tree *avpi_tree; - size_t offset = 0; - tvbuff_t *group_tvb; - proto_tree *group_tree; - proto_item *grouptf; - proto_item *avptf; - char *buffer; - int BadPacket = FALSE; - guint32 avpLength; - guint8 flags; - proto_item *tf; - proto_tree *flags_tree; - - gint32 packetLength; - size_t avpDataLength; - int avpType; - const gchar *flagstr=""; - const gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" }; - gint i; - guint bpos; - - packetLength = tvb_length(tvb); +static char* alnumerize(char* name) { + char* r = name; + char* w = name; + char c; - /* Check for invalid packet lengths */ - if (packetLength <= 0) { - proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb), - "No Attribute Value Pairs Found"); - return; + for (;(c = *r); r++) { + if (isalnum(c) || c == '_' || c == '-' || c == '.') { + *(w++) = c; + } } + + *w = '\0'; - /* Spin around until we run out of packet */ - while (packetLength > 0 ) - { - gboolean AVP_code_found; + return name; +} + + +guint reginfo(int* hf_ptr, + const char* name, + const char* abbr, + const char* desc, + enum ftenum ft, + base_display_e base, + value_string* vs, + guint32 mask) { + hf_register_info hf = { hf_ptr, { + name ? g_strdup(name) : g_strdup(abbr), + g_strdup(abbr), + ft, + base, + VALS(vs), + mask, + desc ? g_strdup(desc) : "", + HFILL }}; + + g_array_append_vals(build_dict.hf,&hf,1); + return build_dict.hf->len - 1; +} + +void basic_avp_reginfo(diam_avp_t* a, const char* name, enum ftenum ft, base_display_e base, value_string* vs) { + hf_register_info hf[] = { + { &(a->hf_value), { NULL, NULL, ft, base, VALS(vs), 0x0, "", HFILL }} + }; + gint* ettp = &(a->ett); + + hf->hfinfo.name = g_strdup_printf("%s",name); + hf->hfinfo.abbrev = alnumerize(g_strdup_printf("diameter.%s",name)); + + g_array_append_vals(build_dict.hf,hf,1); + g_array_append_vals(build_dict.ett,&ettp,1); +} + +static diam_avp_t* build_simple_avp(const avp_type_t* type, + guint32 code, + guint32 vendor, + const char* name, + value_string* vs) { + diam_avp_t* a = g_malloc0(sizeof(diam_avp_t)); + a->code = code; + a->vendor = vendor; + a->dissector_v16 = type->v16; + a->dissector_rfc = type->rfc; + a->ett = -1; + a->hf_value = -1; + + basic_avp_reginfo(a,name,type->ft,type->base,vs); + + return a; +} + + +static const avp_type_t basic_types[] = { + {"octetstring" , simple_avp , simple_avp , FT_BYTES , BASE_NONE , build_simple_avp }, + {"utf8string" , simple_avp , simple_avp , FT_STRING , BASE_NONE , build_simple_avp }, + {"grouped" , grouped_avp , grouped_avp , FT_BYTES , BASE_NONE , build_simple_avp }, + {"integer32" , simple_avp , simple_avp , FT_INT32 , BASE_DEC , build_simple_avp }, + {"unsigned32" , simple_avp , simple_avp , FT_UINT32 , BASE_DEC , build_simple_avp }, + {"time" , simple_avp , simple_avp , FT_BYTES , BASE_DEC , build_simple_avp }, + {"integer64" , simple_avp , simple_avp , FT_INT64 , BASE_DEC , build_simple_avp }, + {"unsigned64" , simple_avp , simple_avp , FT_UINT64 , BASE_DEC , build_simple_avp }, + {"float32" , simple_avp , simple_avp , FT_FLOAT , BASE_DEC , build_simple_avp }, + {"float64" , simple_avp , simple_avp , FT_DOUBLE , BASE_DEC , build_simple_avp }, +/* {"ipaddress" , simple_avp , simple_avp , FT_NONE , BASE_NONE , build_simple_avp }, + {"diameteruri" , simple_avp , simple_avp , FT_STRING , BASE_NONE , build_simple_avp }, + {"diameteridentity" , simple_avp , simple_avp , FT_BYTES , BASE_NONE , build_simple_avp }, + {"ipfilterrule" , simple_avp , simple_avp , FT_BYTES , BASE_NONE , build_simple_avp }, + {"qosfilterrule" , simple_avp , simple_avp , FT_BYTES , BASE_NONE , build_simple_avp }, + {"mipregistrationrequest" , simple_avp , simple_avp , FT_BYTES , BASE_NONE , build_simple_avp }, */ + {NULL, NULL, NULL, FT_NONE, BASE_NONE, NULL } +}; + +static guint strcase_hash(gconstpointer key) { + char* k = ep_strdup(key); + g_strdown(k); + return g_str_hash(k); +} + +static gboolean strcase_equal(gconstpointer ka, gconstpointer kb) { + char* a = ep_strdup(ka); + char* b = ep_strdup(kb); + g_strdown(a); + g_strdown(b); + return g_str_equal(a,b); +} + +extern int dictionary_load(void); +extern int dictionary_load(void) { + ddict_t* d; + ddict_application_t* p; + ddict_vendor_t* v; + ddict_cmd_t* c; + ddict_typedefn_t* t; + ddict_avp_t* a; + 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* bytes = basic_types; + diam_avp_t* avp; + GHashTable* vendors = g_hash_table_new(strcase_hash,strcase_equal); + diam_vnd_t* vnd; + 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.ett = g_array_new(FALSE,TRUE,sizeof(gint*)); + build_dict.types = g_hash_table_new(strcase_hash,strcase_equal); + build_dict.avps = g_hash_table_new(strcase_hash,strcase_equal); - /* Check for short packet */ - if (packetLength < (long)MIN_AVP_SIZE) { - if ( suppress_console_output == FALSE ) - g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))", - packetLength, (long)MIN_AVP_SIZE); - BadPacket = TRUE; - /* Don't even bother trying to parse a short packet. */ - return; - } - - /* Copy our header */ - tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength)); - /* Fix the byte ordering */ - avph.avp_code = g_ntohl(avph.avp_code); - avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength); + dictionary.vnds = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"diameter_vnds"); + dictionary.avps = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK,"diameter_avps"); - flags = (avph.avp_flagsLength & 0xff000000) >> 24; - avpLength = avph.avp_flagsLength & 0x00ffffff; - - /* Set up our flags string */ - if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) { - char *flagbuf; - int fslen; - -#define FLAG_STR_LEN 64 - flagbuf=ep_alloc(FLAG_STR_LEN); - flagbuf[0]=0; - fslen=0; - for (i = 0; i < 8; i++) { - bpos = 1 << i; - if (flags & bpos) { - if (flagbuf[0]) { - fslen+=MIN(FLAG_STR_LEN-fslen, - g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, ", ")); - } - fslen+=MIN(FLAG_STR_LEN-fslen, - g_snprintf(flagbuf+fslen, FLAG_STR_LEN-fslen, "%s", fstr[i])); - } - } - flagstr = flagbuf; - if (flagstr[0] == 0) { - flagstr=""; - } - } - - /* Dissect our vendor id if it exists and set hdr length */ - if (flags & AVP_FLAGS_V) { - vendorId = g_ntohl(avph.avp_vendorId); - /* Vendor id */ - hdrLength = sizeof(e_avphdr); - } else { - /* No vendor */ - hdrLength = sizeof(e_avphdr) - sizeof(guint32); - vendorId = 0; - } - - if (vendorId) { - vendorName=diameter_vendor_to_str(vendorId, TRUE); - } else { - vendorName=""; - } - - /* Check for bad length */ - if (avpLength < MIN_AVP_SIZE || - ((long)avpLength > packetLength)) - { - if ( suppress_console_output == FALSE ) - g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, " - "min: %ld bytes, packetLen: %d", - (long)avpLength, (long)MIN_AVP_SIZE, packetLength); - BadPacket = TRUE; - } - - /* Check for bad flags */ - if (flags & AVP_FLAGS_RESERVED) { - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x," - " resFl=0x%x", - flags, AVP_FLAGS_RESERVED); - /* For now, don't set bad packet, since I'm accidentally setting a wrong bit - BadPacket = TRUE; - */ - } - - /* - * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte - * boundries) - */ - fixAmt = 4 - (avpLength % 4); - if (fixAmt == 4) - fixAmt = 0; - - /* shrink our packetLength */ - packetLength = packetLength - (avpLength + fixAmt); - - /* Check for out of bounds */ - if (packetLength < 0) { - if ( suppress_console_output == FALSE ) - g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ", - packetLength); - BadPacket = TRUE; - } - - /* Make avp Name & type */ - avpTypeString=val_to_str(diameter_avp_get_type(avph.avp_code,vendorId), - TypeValues, - "Unknown-Type: 0x%08x"); - avpNameString=diameter_avp_get_name(avph.avp_code, vendorId, &AVP_code_found); - - avptf = proto_tree_add_bytes_format(avp_tree, hf_diameter_avp, tvb, - offset, avpLength + fixAmt, - tvb_get_ptr(tvb, offset, avpLength + fixAmt), - "%s (%s) l:0x%x (%d bytes) (%d padded bytes)", - avpNameString, avpTypeString, avpLength, - avpLength, avpLength+fixAmt); - - avpi_tree = proto_item_add_subtree(avptf, ett_diameter_avpinfo); - - if (avpi_tree !=NULL) - { - /* Command Code */ - proto_item *ti; - ti = proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_code, - tvb, offset, 4, avph.avp_code, "%s (%u)", - avpNameString,avph.avp_code); - if (!AVP_code_found) - { - expert_add_info_format(pinfo, ti, - PI_UNDECODED, PI_NOTE, - "AVP info not available (code %u)", - avph.avp_code); - } - offset += 4; - - tf = proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_flags, tvb, - offset, 1, flags, "0x%02x (%s)", flags, - flagstr); - flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags); - proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags); - offset += 1; - - proto_tree_add_uint(avpi_tree, hf_diameter_avp_length, - tvb, offset, 3, avpLength); - offset += 3; - - if (flags & AVP_FLAGS_V) { - proto_tree_add_uint_format_value(avpi_tree, hf_diameter_avp_vendor_id, - tvb, offset, 4, vendorId, "%s (%u)", vendorName, vendorId); - offset += 4; - } - - avpDataLength = avpLength - hdrLength; - - /* - * If we've got a bad packet, just highlight the data. Don't try - * to parse it, and, don't move to next AVP. - */ - if (BadPacket) { - offset -= hdrLength; - proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, tvb_length(tvb) - offset, - tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset), - "Bad AVP (Suspect Data Not Dissected)"); - return; - } - - avpType=diameter_avp_get_type(avph.avp_code,vendorId); - - switch(avpType) - { - case DIAMETER_GROUPED: - buffer=ep_alloc(256); - g_snprintf(buffer, 256, "%s Grouped AVPs", avpNameString); - /* Recursively call ourselves */ - grouptf = proto_tree_add_text(avpi_tree, - tvb, offset, tvb_length(tvb), - buffer); - - group_tree = proto_item_add_subtree(grouptf, ett_diameter_avp); - - group_tvb = tvb_new_subset(tvb, offset, - MIN(avpDataLength, tvb_length(tvb)-offset), - avpDataLength); - if (group_tree != NULL) { - dissect_avps( group_tvb, pinfo, group_tree); - } - break; - - case DIAMETER_IDENTITY: - { - const guint8 *data; - - data = tvb_get_ptr(tvb, offset, avpDataLength); - proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string, - tvb, offset, avpDataLength, data, - "Identity: %*.*s", - (int)avpDataLength, - (int)avpDataLength, data); - } - break; - case DIAMETER_UTF8STRING: - { - const guint8 *data; + no_vnd.vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string)); + no_vnd.vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string)); - data = tvb_get_ptr(tvb, offset, avpDataLength); - proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string, - tvb, offset, avpDataLength, data, - "UTF8String: %*.*s", - (int)avpDataLength, - (int)avpDataLength, data); - } - break; - case DIAMETER_IP_ADDRESS: - { - switch(gbl_version) - { - case DIAMETER_V16: - if (avpDataLength == 4) { - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr, - tvb, offset, avpDataLength, FALSE); - } else if (avpDataLength == 16) { - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr, - tvb, offset, avpDataLength, FALSE); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Address Length (Address in RFC3588 format?)"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Address Length (%u)", - avpDataLength); - } - break; - case DIAMETER_RFC: - /* Indicate the address family */ - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_addrfamily, - tvb, offset, 2, FALSE); - if (tvb_get_ntohs(tvb, offset) == 0x0001) { - /* IPv4 */ - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr, - tvb, offset+2, 4, FALSE); - if (avpDataLength != 6) { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad IPv4 AVP Length (%u, expected %u)", - avpLength, hdrLength+6); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_WARN, - "Bad IPv4 AVP Length (%u, expected %u)", - avpLength, hdrLength+6); - } - } else if (tvb_get_ntohs(tvb, offset) == 0x0002) { - /* IPv6 */ - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v6addr, - tvb, offset+2, 16, FALSE); - if (avpDataLength != 18) { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad IPv6 AVP Length (%u, expected %u)", - avpLength, hdrLength+18); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_WARN, - "Bad IPv6 AVP length (%u, expected %u)", - avpLength, hdrLength+18); - } - } else { - proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Can't Parse Address Family %d (Address in draft v16 format?)", - (int)tvb_get_ntohs(tvb, offset)); - } - break; - } - } - break; + pe_tree_insert32(dictionary.vnds,0,&no_vnd); + g_hash_table_insert(vendors,"None",&no_vnd); - case DIAMETER_INTEGER32: - if (avpDataLength == 4) { - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32, - tvb, offset, avpDataLength, FALSE); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Integer32 Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Integer32 Length (%u)", - avpDataLength); - } - break; - - case DIAMETER_UNSIGNED32: - if (avpDataLength == 4) { - guint32 data; + /* initialize the types hash with the known basic types */ + for (type = basic_types; type->name; type++) { + g_hash_table_insert(build_dict.types,type->name,(void*)type); + } + + /* load the dictionary */ + d = ddict_scan(dir,"dictionary.xml"); + + /* populate the types */ + for (t = d->typedefns; t; t = t->next) { + const avp_type_t* parent = NULL; + /* try to get the parent type */ - data = tvb_get_ntohl(tvb, offset); - proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32, - tvb, offset, avpDataLength, data, - "Value: 0x%08x (%u)", data, data); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Unsigned32 Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Unsigned32 Length (%u)", - avpDataLength); - } - break; - - case DIAMETER_UNSIGNED32ENUM: - if (avpDataLength == 4) { - guint32 data; + if (g_hash_table_lookup(build_dict.types,t->name)) + continue; + + if (t->parent) { + parent = g_hash_table_lookup(build_dict.types,t->parent); + } + + if (!parent) parent = bytes; + + /* insert the parent type for this type */ + g_hash_table_insert(build_dict.types,t->name,(void*)parent); + } + + /* populate the applications */ + if ((p = d->applications)) { + GArray* arr = g_array_new(TRUE,TRUE,sizeof(value_string)); + + for (; p; p = p->next) { + value_string item = {p->code,p->name}; + g_array_append_val(arr,item); + } + + dictionary.applications = (void*)arr->data; + g_array_free(arr,FALSE); + } + + if ((v = d->vendors)) { + for ( ; v; v = v->next) { + value_string item = {v->code,v->name}; - data = tvb_get_ntohl(tvb, offset); - valstr = diameter_avp_get_value(avph.avp_code, vendorId, data); - proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32, - tvb, offset, avpDataLength, data, - "Value: 0x%08x (%u): %s", data, - data, valstr); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Enumerated Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Enumerated Length (%u)", - avpDataLength); - } - break; + if (g_hash_table_lookup(vendors,v->name)) + continue; - case DIAMETER_INTEGER64: - if (avpDataLength == 8) { - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64, - tvb, offset, 8, FALSE); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Integer64 Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Integer64 Length (%u)", - avpDataLength); - } - break; + g_array_append_val(vnd_shrt_arr,item); - case DIAMETER_UNSIGNED64: - if (avpDataLength == 8) { - proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64, - tvb, offset, 8, FALSE); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Unsigned64 Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Unsigned64 Length (%u)", - avpDataLength); - } - break; + vnd = g_malloc(sizeof(diam_vnd_t)); + vnd->code = v->code; + vnd->vs_cmds = g_array_new(TRUE,TRUE,sizeof(value_string)); + vnd->vs_avps = g_array_new(TRUE,TRUE,sizeof(value_string)); + pe_tree_insert32(dictionary.vnds,vnd->code,vnd); + g_hash_table_insert(vendors,v->name,vnd); + } + } + + vnd_short_vs = (void*)vnd_shrt_arr->data; + g_array_free(vnd_shrt_arr,FALSE); - case DIAMETER_TIME: - if (avpDataLength == 4) { - guint32 ntp_timestamp_secs; - nstime_t data; - struct tm *gmtp; + if ((c = d->cmds)) { + for (; c; c = c->next) { + if ((vnd = g_hash_table_lookup(vendors,c->vendor))) { + value_string item = {c->code,c->name}; + g_array_append_val(vnd->vs_cmds,item); + } else { + g_warning("Diameter Dictionary: No Vendor: %s",c->vendor); + } + } + } + + + for (a = d->avps; a; a = a->next) { + ddict_enum_t* e; + value_string* vs = NULL; + const char* vend = a->vendor ? a->vendor : "None"; + + if ((vnd = g_hash_table_lookup(vendors,vend))) { + value_string vndvs = {a->code,a->name}; + g_array_append_val(vnd->vs_avps,vndvs); + } else { + g_warning("Diameter Dictionary: No Vendor: %s",vend); + vnd = &unknown_vendor; + } - ntp_timestamp_secs = tvb_get_ntohl(tvb, offset); - /* Present the time as UTC, Time before 00:00:00 UTC, January 1, 1970 can't be presented correctly */ - if ( ntp_timestamp_secs >= NTP_TIME_DIFF){ - data.secs = ntp_timestamp_secs - NTP_TIME_DIFF; - data.nsecs = 0; + if ((e = a->enums)) { + GArray* arr = g_array_new(TRUE,TRUE,sizeof(value_string)); + + for (; e; e = e->next) { + value_string item = {e->code,e->name}; + g_array_append_val(arr,item); + } + vs = (void*)arr->data; + } - gmtp = gmtime(&data.secs); - buffer=ep_alloc(64); - strftime(buffer, 64, "%a, %d %b %Y %H:%M:%S UTC", gmtp); + if (! a->type || ! ( type = g_hash_table_lookup(build_dict.types,a->type) ) ) { + type = bytes; + } - proto_tree_add_time_format(avpi_tree, hf_diameter_avp_data_time, - tvb, offset, avpDataLength, &data, - "Time: %s", buffer); - }else{ - proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Time before 00:00:00 UTC, January 1, 1970"); - } - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Time Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Time Length (%u)", - avpDataLength); - } - break; - - case DIAMETER_ENUMERATED: - if (avpDataLength == 4) { - guint32 data; + avp = type->build( type, a->code, vnd->code, a->name, vs); + g_hash_table_insert(build_dict.avps, a->name, avp); - data = tvb_get_ntohl(tvb, offset); - valstr = diameter_avp_get_value(avph.avp_code, vendorId, data); - proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32, - tvb, offset, avpDataLength, data, - "Value: 0x%08x (%u): %s", data, - data, valstr); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Enumerated Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Enumerated Length (%u)", - avpDataLength); - } - break; - - case DIAMETER_VENDOR_ID: - if (avpDataLength == 4) { - proto_tree_add_item(avpi_tree, hf_diameter_vendor_id, tvb, offset, avpDataLength, FALSE); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Vendor ID Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Vendor ID Length (%u)", - avpDataLength); - } - break; - - case DIAMETER_APPLICATION_ID: - if (avpDataLength == 4) { - guint32 data; - - data = tvb_get_ntohl(tvb, offset); - valstr = diameter_app_to_str(data); - proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32, - tvb, offset, avpDataLength, data, - "Application ID: %s %d (0x%08x)", - valstr, data, data); - } else { - ti = proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Error! Bad Application ID Length"); - expert_add_info_format(pinfo, ti, - PI_MALFORMED, PI_NOTE, - "Bad Application ID Length (%u)", - avpDataLength); - } - break; - - case DIAMETER_MIP_REG_REQ: - safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength); - break; - - case DIAMETER_URI: - proto_tree_add_item(avpi_tree, hf_diameter_avp_diameter_uri, - tvb, offset, avpDataLength, FALSE); - break; - - case DIAMETER_SESSION_ID: - proto_tree_add_item(avpi_tree, hf_diameter_avp_session_id, - tvb, offset, avpDataLength, FALSE); - break; - - case DIAMETER_PUBLIC_ID: - { - proto_tree_add_item(avpi_tree, hf_diameter_avp_public_id, - tvb, offset, avpDataLength, FALSE); - /* This is a SIP address, to be able to filter the SIP messages - * belonging to this Diameter session add this to the SIP filter. - */ - dfilter_store_sip_from_addr(tvb, avpi_tree, offset, avpDataLength); - } - break; - case DIAMETER_PRIVATE_ID: - proto_tree_add_item(avpi_tree, hf_diameter_avp_private_id, - tvb, offset, avpDataLength, FALSE); - break; - - default: - case DIAMETER_OCTET_STRING: - proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes, - tvb, offset, avpDataLength, - tvb_get_ptr(tvb, offset, avpDataLength), - "Hex Data Highlighted Below"); - break; - } /* switch type */ - } /* avpi_tree != null */ - offset += (avpLength - hdrLength); - offset += fixAmt; /* fix byte alignment */ - } /* loop */ -} /* dissect_avps */ - + { + emem_tree_key_t k[] = { + { 1, &(a->code) }, + { 1, &(vnd->code) }, + { 0 , NULL } + }; + pe_tree_insert32_array(dictionary.avps,k,avp); + } + } + + g_hash_table_destroy(build_dict.types); + g_hash_table_destroy(build_dict.avps); + g_hash_table_destroy(vendors); + + return 1; +} void proto_reg_handoff_diameter(void) { - static int Initialized=FALSE; - static int TcpPort=0; - static int SctpPort=0; - static dissector_handle_t diameter_tcp_handle; - static dissector_handle_t diameter_handle; - - if (!Initialized) { - diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp, - proto_diameter); - diameter_handle = new_create_dissector_handle(dissect_diameter, - proto_diameter); - Initialized=TRUE; - } else { - dissector_delete("tcp.port", TcpPort, diameter_tcp_handle); - dissector_delete("sctp.port", SctpPort, diameter_handle); - } - - /* set port for future deletes */ - TcpPort=gbl_diameterTcpPort; - SctpPort=gbl_diameterSctpPort; - - /* g_warning ("Diameter: Adding tcp dissector to port %d", - gbl_diameterTcpPort); */ - dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle); - dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle); + static int Initialized=FALSE; + static int TcpPort=0; + static int SctpPort=0; + static dissector_handle_t diameter_tcp_handle; + static dissector_handle_t diameter_handle; + + if (!Initialized) { + diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp, + proto_diameter); + diameter_handle = new_create_dissector_handle(dissect_diameter, + proto_diameter); + Initialized=TRUE; + } else { + dissector_delete("tcp.port", TcpPort, diameter_tcp_handle); + dissector_delete("sctp.port", SctpPort, diameter_handle); + } + + /* set port for future deletes */ + TcpPort=gbl_diameterTcpPort; + SctpPort=gbl_diameterSctpPort; + + /* g_warning ("Diameter: Adding tcp dissector to port %d", + gbl_diameterTcpPort); */ + dissector_add("tcp.port", gbl_diameterTcpPort, diameter_tcp_handle); + dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle); } /* registration with the filtering engine */ void proto_register_diameter(void) { - static hf_register_info hf[] = { - { &hf_diameter_version, + module_t *diameter_module; + int to_load_dict_before_hf = dictionary_load(); + hf_register_info hf_base[] = { + { &hf_diameter_version, { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00, - "", HFILL }}, - { &hf_diameter_length, + "", HFILL }}, + { &hf_diameter_length, { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0, - "", HFILL }}, - - { &hf_diameter_flags, + "", HFILL }}, + { &hf_diameter_flags, { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0, - "", HFILL }}, - { &hf_diameter_flags_request, + "", HFILL }}, + { &hf_diameter_flags_request, { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R, - "", HFILL }}, - { &hf_diameter_flags_proxyable, + "", HFILL }}, + { &hf_diameter_flags_proxyable, { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P, - "", HFILL }}, - { &hf_diameter_flags_error, + "", HFILL }}, + { &hf_diameter_flags_error, { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E, - "", HFILL }}, - { &hf_diameter_flags_T, + "", HFILL }}, + { &hf_diameter_flags_T, { "T(Potentially re-transmitted message)","diameter.flags.T", FT_BOOLEAN, 8, TFS(&flags_set_truth),DIAM_FLAGS_T, - "", HFILL }}, - { &hf_diameter_flags_reserved4, + "", HFILL }}, + { &hf_diameter_flags_reserved4, { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set), - DIAM_FLAGS_RESERVED4, "", HFILL }}, - { &hf_diameter_flags_reserved5, + DIAM_FLAGS_RESERVED4, "", HFILL }}, + { &hf_diameter_flags_reserved5, { "Reserved","diameter.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set), - DIAM_FLAGS_RESERVED5, "", HFILL }}, - { &hf_diameter_flags_reserved6, + DIAM_FLAGS_RESERVED5, "", HFILL }}, + { &hf_diameter_flags_reserved6, { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set), - DIAM_FLAGS_RESERVED6, "", HFILL }}, - { &hf_diameter_flags_reserved7, + DIAM_FLAGS_RESERVED6, "", HFILL }}, + { &hf_diameter_flags_reserved7, { "Reserved","diameter.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set), - DIAM_FLAGS_RESERVED7, "", HFILL }}, - - { &hf_diameter_code, - { "Command Code","diameter.code", FT_UINT24, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_vendor_id, + DIAM_FLAGS_RESERVED7, "", HFILL }}, + { &hf_diameter_vendor_id, { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, VALS(sminmpec_values), - 0x0,"", HFILL }}, - { &hf_diameter_application_id, - { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC, VALS(diameter_application_id_vals), - 0x0,"", HFILL }}, - { &hf_diameter_hopbyhopid, + 0x0,"", HFILL }}, + { &hf_diameter_application_id, + { "ApplicationId", "diameter.applicationId", FT_UINT32, BASE_DEC, dictionary.applications, + 0x0,"", HFILL }}, + { &hf_diameter_hopbyhopid, { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32, - BASE_HEX, NULL, 0x0, "", HFILL }}, - { &hf_diameter_endtoendid, + BASE_HEX, NULL, 0x0, "", HFILL }}, + { &hf_diameter_endtoendid, { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32, - BASE_HEX, NULL, 0x0, "", HFILL }}, - - { &hf_diameter_avp, + BASE_HEX, NULL, 0x0, "", HFILL }}, + { &hf_diameter_avp, { "AVP","diameter.avp", FT_BYTES, BASE_HEX, - NULL, 0x0, "", HFILL }}, - - { &hf_diameter_avp_code, - { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_length, - { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC, - NULL, 0x0, "", HFILL }}, - - - { &hf_diameter_avp_flags, + NULL, 0x0, "", HFILL }}, + { &hf_diameter_avp_len, + { "AVP Length","diameter.avp.len", FT_UINT24, BASE_DEC, + NULL, 0x0, "", HFILL }}, + { &hf_diameter_avp_flags, { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_flags_vendor_specific, + NULL, 0x0, "", HFILL }}, + { &hf_diameter_avp_flags_vendor_specific, { "Vendor-Specific", "diameter.flags.vendorspecific", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_V, - "", HFILL }}, - { &hf_diameter_avp_flags_mandatory, + "", HFILL }}, + { &hf_diameter_avp_flags_mandatory, { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M, - "", HFILL }}, - { &hf_diameter_avp_flags_protected, + "", HFILL }}, + { &hf_diameter_avp_flags_protected, { "Protected","diameter.avp.flags.protected", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_P, - "", HFILL }}, - { &hf_diameter_avp_flags_reserved3, + "", HFILL }}, + { &hf_diameter_avp_flags_reserved3, { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set), - AVP_FLAGS_RESERVED3, "", HFILL }}, - { &hf_diameter_avp_flags_reserved4, + AVP_FLAGS_RESERVED3, "", HFILL }}, + { &hf_diameter_avp_flags_reserved4, { "Reserved","diameter.avp.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set), - AVP_FLAGS_RESERVED4, "", HFILL }}, - { &hf_diameter_avp_flags_reserved5, + AVP_FLAGS_RESERVED4, "", HFILL }}, + { &hf_diameter_avp_flags_reserved5, { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set), - AVP_FLAGS_RESERVED5, "", HFILL }}, - { &hf_diameter_avp_flags_reserved6, + AVP_FLAGS_RESERVED5, "", HFILL }}, + { &hf_diameter_avp_flags_reserved6, { "Reserved","diameter.avp.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set), - AVP_FLAGS_RESERVED6, "", HFILL }}, - { &hf_diameter_avp_flags_reserved7, + AVP_FLAGS_RESERVED6, "", HFILL }}, + { &hf_diameter_avp_flags_reserved7, { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set), - AVP_FLAGS_RESERVED7, "", HFILL }}, - { &hf_diameter_avp_vendor_id, + AVP_FLAGS_RESERVED7, "", HFILL }}, + { &hf_diameter_avp_vendor_id, { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_uint64, - { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_int64, - { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_uint32, - { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_int32, - { "Value","diameter.avp.data.int32", FT_INT32, BASE_DEC, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_bytes, - { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_string, - { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_addrfamily, - { "Address Family","diameter.avp.data.addrfamily", FT_UINT16, BASE_DEC, - VALS(diameter_avp_data_addrfamily_vals), 0x0, "", HFILL }}, - { &hf_diameter_avp_data_v4addr, - { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_v6addr, - { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_data_time, - { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_diameter_uri, - { "Diameter URI","diameter.avp.diameter_uri", FT_STRING, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_session_id, - { "Session ID","diameter.avp.session_id", FT_STRING, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_public_id, - { "Public ID","diameter.avp.public_id", FT_STRING, BASE_NONE, - NULL, 0x0, "", HFILL }}, - { &hf_diameter_avp_private_id, - { "Private ID","diameter.avp.private_id", FT_STRING, BASE_NONE, - NULL, 0x0, "", HFILL }}, - + VALS(sminmpec_values), 0x0, "", HFILL }}, + { &(unknown_avp.hf_value), + { "Value","diameter.avp.unknown", FT_BYTES, BASE_NONE, + NULL, 0x0, "", HFILL }}, + { &hf_diameter_code, + { "Command Code", "diameter.cmd.code", FT_UINT32, BASE_DEC, NULL, 0, "", HFILL }}, + { &hf_diameter_avp_code, + { "AVP Code", "diameter.avp.code", FT_UINT32, BASE_DEC, NULL, 0, "", HFILL }}, }; - static gint *ett[] = { + gint *ett_base[] = { &ett_diameter, &ett_diameter_flags, - &ett_diameter_avp, &ett_diameter_avp_flags, - &ett_diameter_avpinfo + &ett_diameter_avpinfo, + &(unknown_avp.ett) }; - module_t *diameter_module; - gchar *default_diameterDictionary; - + + + g_array_append_vals(build_dict.hf, hf_base, array_length(hf_base)); + g_array_append_vals(build_dict.ett, ett_base, array_length(ett_base)); + proto_diameter = proto_register_protocol ("Diameter Protocol", "DIAMETER", "diameter"); - proto_register_field_array(proto_diameter, hf, array_length(hf)); - proto_register_subtree_array(ett, array_length(ett)); + + + proto_register_field_array(proto_diameter, (hf_register_info*)build_dict.hf->data, build_dict.hf->len); + proto_register_subtree_array((gint**)build_dict.ett->data, build_dict.ett->len); + + g_array_free(build_dict.hf,FALSE); + g_array_free(build_dict.ett,TRUE); /* Allow dissector to find be found by name. */ new_register_dissector("diameter", dissect_diameter, proto_diameter); @@ -2401,50 +884,20 @@ proto_register_diameter(void) /* Register a configuration option for port */ diameter_module = prefs_register_protocol(proto_diameter, proto_reg_handoff_diameter); - /* Register a configuration option for Diameter version */ - prefs_register_enum_preference(diameter_module, "version", "Diameter version", "Standard version used for decoding", (gint *)&gbl_version, options, FALSE); + + prefs_register_obsolete_preference(diameter_module, "version"); prefs_register_uint_preference(diameter_module, "tcp.port", "Diameter TCP Port", "Set the TCP port for Diameter messages", 10, &gbl_diameterTcpPort); + prefs_register_uint_preference(diameter_module, "sctp.port", "Diameter SCTP Port", "Set the SCTP port for Diameter messages", 10, &gbl_diameterSctpPort); - /* - * Build our default dictionary filename - */ - default_diameterDictionary = get_datafile_path(DICT_FN); - - /* - * Now register the dictionary filename as a preference, - * so it can be changed. - */ - gbl_diameterDictionary = default_diameterDictionary; - prefs_register_string_preference(diameter_module, "dictionary.name", - "Diameter XML Dictionary", - "Set the dictionary used for Diameter messages", - &gbl_diameterDictionary); - - /* - * We don't need the default dictionary, so free it (a copy was made - * of it in "gbl_diameterDictionary" by - * "prefs_register_string_preference()"). - */ - g_free(default_diameterDictionary); - - /* - * Make use of the dictionary optional. Avoids error popups if xml library - * or dictionary file aren't available. - */ - prefs_register_bool_preference(diameter_module, "dictionary.use", - "Attempt to load/use Diameter XML Dictionary", - "Only attempt to load and use the Diameter XML " - "Dictionary when this option is selected", - &gbl_use_xml_dictionary); /* Desegmentation */ prefs_register_bool_preference(diameter_module, "desegment", @@ -2452,21 +905,16 @@ proto_register_diameter(void) "Whether the Diameter dissector should reassemble messages spanning multiple TCP segments." " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", &gbl_diameter_desegment); - /* Allow zero as valid application ID */ - prefs_register_bool_preference(diameter_module, "allow_zero_as_app_id", - "Allow 0 as valid application ID", - "If set, the value 0 (zero) can be used as a valid " - "application ID. This is used in experimental cases.", - &allow_zero_as_app_id); - /* Register some preferences we no longer support, so we can report - them as obsolete rather than just illegal. */ - /* Suppress console output or not */ - prefs_register_bool_preference(diameter_module, "suppress_console_output", - "Suppress console output for unknown AVP:s Flags etc.", - "If console output for errors should be suppressed or not", - &suppress_console_output); + /* Register some preferences we no longer support, so we can report them as obsolete rather than just illegal. */ prefs_register_obsolete_preference(diameter_module, "udp.port"); prefs_register_obsolete_preference(diameter_module, "command_in_header"); + prefs_register_obsolete_preference(diameter_module, "dictionary.name"); + prefs_register_obsolete_preference(diameter_module, "dictionary.use"); + prefs_register_obsolete_preference(diameter_module, "allow_zero_as_app_id"); + prefs_register_obsolete_preference(diameter_module, "suppress_console_output"); + + to_load_dict_before_hf=0; } /* proto_register_diameter */ +