From Aaron Woo (via Jeff Weston): Optimized Link State Routing Protocol
[obnox/wireshark/wip.git] / packet-diameter.c
index 3df51310951a5482ab04c47255dd023e4ff6ad30..4963ea6dacdf4aa3718f21fe43ab9ff0cf3ec496 100644 (file)
@@ -1,13 +1,14 @@
 /* packet-diameter.c
- * Routines for DIAMETER packet disassembly
+ * Routines for Diameter packet disassembly
  *
- * $Id: packet-diameter.c,v 1.16 2001/02/19 23:14:01 guy Exp $
+ * $Id: packet-diameter.c,v 1.56 2003/10/29 21:19:44 guy Exp $
  *
  * Copyright (c) 2001 by David Frascone <dave@frascone.com>
  *
  * Ethereal - Network traffic analyzer
- * By Johan Feyaerts
- * Copyright 1999 Johan Feyaerts
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
 #include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include <time.h>
 #include <glib.h>
-#include "packet.h"
-#include "resolv.h"
+#include <epan/filesystem.h>
+#include "xmlstub.h"
+#include <epan/packet.h>
+#include <epan/resolv.h>
 #include "prefs.h"
 
-/* This must be defined before we include packet-diameter-defs.h s*/
-typedef struct _value_value_pair {
-        guint32 val1;
-        guint32 val2;
-} value_value_pair;
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+/* This must be defined before we include packet-diameter-defs.h */
 
 /* Valid data types */
 typedef enum {
-       DIAMETER_DATA=1,
-       DIAMETER_STRING,
-       DIAMETER_ADDRESS,
-       DIAMETER_INTEGER32,
-       DIAMETER_INTEGER64,
-       DIAMETER_UNSIGNED32,
-       DIAMETER_UNSIGNED64,
-       DIAMETER_FLOAT32,
-       DIAMETER_FLOAT64,
-       DIAMETER_FLOAT128,
-       DIAMETER_TIME,
-       DIAMETER_GROUPED
-} diameterDataTypes;
-
-#include "packet-diameter.h"
+  /* Base Types */
+  DIAMETER_OCTET_STRING = 1,
+  DIAMETER_INTEGER32,
+  DIAMETER_INTEGER64,
+  DIAMETER_UNSIGNED32,
+  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
+
+} diameterDataType;
+
+
+static value_string TypeValues[]={
+  {  DIAMETER_OCTET_STRING,    "OctetString" },
+  {  DIAMETER_INTEGER32,       "Integer32" },
+  {  DIAMETER_INTEGER64,       "Integer64" },
+  {  DIAMETER_UNSIGNED32,      "Unsigned32" },
+  {  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"},
+  {0, (char *)NULL}
+};
+
+typedef struct value_name {
+  guint32            value;
+  gchar             *name;
+  struct value_name *next;
+} ValueName;
+
+typedef struct old_avp_info {
+  guint32           code;
+  gchar            *name;
+  diameterDataType  type;
+  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"
 
 #define  NTP_TIME_DIFF                   (2208988800UL)
 
-#undef SCTP_DISSECTORS_ENABLED
-
 #define TCP_PORT_DIAMETER      1812
-#ifdef SCTP_DISSECTORS_ENABLED
 #define SCTP_PORT_DIAMETER     1812
-#endif
 
+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_id =-1;
-static int hf_diameter_reserved = -1;
-static int hf_diameter_flags = -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_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_reserved3 = -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_code = -1;
 static int hf_diameter_avp_length = -1;
-static int hf_diameter_avp_reserved = -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;
-#if 0
 static int hf_diameter_avp_data_uint64 = -1;
 static int hf_diameter_avp_data_int64 = -1;
-#endif
 static int hf_diameter_avp_data_bytes = -1;
 static int hf_diameter_avp_data_string = -1;
 static int hf_diameter_avp_data_v4addr = -1;
@@ -108,731 +198,1727 @@ static int hf_diameter_avp_data_v6addr = -1;
 static int hf_diameter_avp_data_time = -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 char gbl_diameterString[200];
 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
-#ifdef SCTP_DISSECTORS_ENABLED
 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
-#endif
+
+/* desegmentation of Diameter over TCP */
+static gboolean gbl_diameter_desegment = TRUE;
+
+#define DICT_FN  "diameter/dictionary.xml"
+static gchar *gbl_diameterDictionary;
 
 typedef struct _e_diameterhdr {
-       guint8 reserved;
-       guint8 flagsVer;
-       guint16 pktLength;
-       guint32 identifier;
-       guint32 commandCode;
-       guint32 vendorId;
+  guint32  versionLength;
+  guint32  flagsCmdCode;
+  guint32  vendorId;
+  guint32  hopByHopId;
+  guint32  endToEndId;
 } e_diameterhdr;
 
 typedef struct _e_avphdr {
-       guint32 avp_code;
-       guint16 avp_length;
-       guint8  avp_reserved;
-       guint8  avp_flags;
-       guint32 avp_vendorId;           /* optional */
+  guint32 avp_code;
+  guint32 avp_flagsLength;
+  guint32 avp_vendorId;           /* optional */
 } e_avphdr;
 
-#define AUTHENTICATOR_LENGTH 12
-
 /* Diameter Header Flags */
+/*                                      RPrrrrrrCCCCCCCCCCCCCCCCCCCCCCCC  */
+#define DIAM_FLAGS_R 0x80
+#define DIAM_FLAGS_P 0x40
 #define DIAM_FLAGS_E 0x20
-#define DIAM_FLAGS_I 0x10
-#define DIAM_FLAGS_R 0x08
-#define DIAM_FLAGS_RESERVED 0xc0         /* 11000000  -- X X E I R V V V */
+#define DIAM_FLAGS_RESERVED3 0x10
+#define DIAM_FLAGS_RESERVED4 0x08
+#define DIAM_FLAGS_RESERVED5 0x04
+#define DIAM_FLAGS_RESERVED6 0x02
+#define DIAM_FLAGS_RESERVED7 0x01
+#define DIAM_FLAGS_RESERVED  0x1f
+
+#define DIAM_LENGTH_MASK  0x00ffffffl
+#define DIAM_COMMAND_MASK DIAM_LENGTH_MASK
+#define DIAM_GET_FLAGS(dh)                ((dh.flagsCmdCode & ~DIAM_COMMAND_MASK) >> 24)
+#define DIAM_GET_VERSION(dh)              ((dh.versionLength & (~DIAM_LENGTH_MASK)) >> 24)
+#define DIAM_GET_COMMAND(dh)              (dh.flagsCmdCode & DIAM_COMMAND_MASK)
+#define DIAM_GET_LENGTH(dh)               (dh.versionLength & DIAM_LENGTH_MASK)
 
 /* Diameter AVP Flags */
-#define AVP_FLAGS_P 0x0020
-#define AVP_FLAGS_V 0x0004
-#define AVP_FLAGS_M 0x0001
-#define AVP_FLAGS_RESERVED 0xea          /* 11101010  -- X X X P X V X M */
+#define AVP_FLAGS_P 0x20
+#define AVP_FLAGS_V 0x80
+#define AVP_FLAGS_M 0x40
+#define AVP_FLAGS_RESERVED3 0x10
+#define AVP_FLAGS_RESERVED4 0x08
+#define AVP_FLAGS_RESERVED5 0x04
+#define AVP_FLAGS_RESERVED6 0x02
+#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) + MIN_AVP_SIZE)
+#define MIN_DIAMETER_SIZE (sizeof(e_diameterhdr))
 
-static gchar *rd_value_to_str(e_avphdr *avph,const u_char *input, int length);
 static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
-static guint32 match_numval(guint32 val, const value_value_pair *vs);
 
-/* Code to actually dissect the packets */
 
 /*
- * Main dissector
+ * This routine will do a push-parse of the passed in
+ * filename.  This was taken almost verbatum from
+ * the xmlsoft examples.
  */
-static void dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
-{
+static xmlDocPtr
+xmlParseFilePush( char *filename, int checkValid) {
+  FILE *f;
+  xmlDocPtr doc=NULL;
+  int valid=0;
+  int res, size = 1024;
+  char chars[1024];
+  xmlParserCtxtPtr ctxt;
+
+  /* I wonder what kind of a performance hit this is? */
+  *XmlStub.xmlDoValidityCheckingDefaultValue = checkValid;
+
+  f = fopen(filename, "r");
+  if (f == NULL) {
+       g_warning("Diameter: Unable to open %s", filename);
+       return NULL;
+  }
 
-/* Set up structures needed to add the protocol subtree and manage it */
-       proto_item *ti;
-       tvbuff_t        *avp_tvb;
-       proto_tree *diameter_tree;
-       e_diameterhdr dh;
-       char *codestrval;
-       size_t offset=0;
-       size_t avplength;
-       proto_tree *avp_tree;
-       proto_item *avptf;
-       int BadPacket = FALSE;
-       
-/* Make entries in Protocol column and Info column on summary display */
-       if (check_col(pinfo->fd, COL_PROTOCOL)) 
-               col_add_str(pinfo->fd, COL_PROTOCOL, "Diameter");
-       
-       /* Copy our header */
-       tvb_memcpy(tvb, (guint8*) &dh, offset, sizeof(dh));
-       
-       /* Fix byte ordering in our static structure */
-       dh.pktLength = ntohs(dh.pktLength);
-       dh.identifier = ntohl(dh.identifier);
-       
-       dh.commandCode = ntohl(dh.commandCode);
-       dh.vendorId = ntohl(dh.vendorId);
-       
-       codestrval=  match_strval(dh.commandCode,diameter_command_code_vals);
-       if (codestrval==NULL) {
-               codestrval="Unknown Command Code";
+  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;
+       valid=ctxt->valid;
+       XmlStub.xmlFreeParserCtxt(ctxt);
+  }
+  fclose(f);
+
+  /* Check valid */
+  if (!valid) {
+       g_warning( "Error!  Invalid xml in %s!  Failed DTD check!",
+                          filename);
+       return NULL;
+  }
+  return doc;
+} /* xmlParseFilePush */
 
-       /* Short packet.  Should have at LEAST one avp */
-       if (dh.pktLength < MIN_DIAMETER_SIZE) {
-               BadPacket = TRUE;
+/*
+ * 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, gchar *name, diameterDataType type, 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;
+  if (vEntry)
+       entry->type = DIAMETER_INTEGER32;
+
+  /* And, add it to the list */
+  entry->next = avpListHead;
+  avpListHead = entry;
 
-       /* And, check our reserved flags/version */
-       if (dh.reserved || (dh.flagsVer & DIAM_FLAGS_RESERVED) ||
-               ((dh.flagsVer & 0x7) != 1)) {
-               BadPacket = TRUE;
+  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(cur->name, "type") == 0) {
+         type = XmlStub.xmlGetProp(cur, "type-name");
+       } else if (strcasecmp(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) {
+               g_warning( "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(cur->name, "grouped") == 0) {
+         /* WORK Recurse here for grouped AVPs */
+         type = "grouped";
+       }
+       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 (check_col(pinfo->fd, COL_INFO)) {
-               col_add_fstr(pinfo->fd, COL_INFO,
-                   "%s%s(%d) vendor=%d (id=%d) EIR=%d%d%d",
-                   (BadPacket)?"***** Bad Packet!: ":"",
-                   codestrval, dh.commandCode, dh.vendorId,
-                   dh.identifier,
-                   (dh.flagsVer & DIAM_FLAGS_E)?1:0,
-                   (dh.flagsVer & DIAM_FLAGS_I)?1:0,
-                   (dh.flagsVer & DIAM_FLAGS_R)?1:0);
+       if (TypeValues[i].strptr == NULL) {
+         g_warning( "Invalid Type field in dictionary! avp %s (%s)",  name, type);
+         return (-1);
        }
-       
-
-/* 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, tvb_length(tvb), FALSE);
-               diameter_tree = proto_item_add_subtree(ti, ett_diameter);
-
-               /* Reserved */
-               proto_tree_add_uint(diameter_tree, hf_diameter_reserved, tvb, offset, 1, dh.reserved);
-               offset +=1;
-
-               /* Flags */
-               proto_tree_add_uint_format(diameter_tree,
-                   hf_diameter_flags,
-                   tvb, offset, 1,
-                   dh.flagsVer,
-                   "Packet flags: 0x%02x  E:%d I:%d R:%d",
-                   (dh.flagsVer&0xf8)>>3,
-                   (dh.flagsVer & DIAM_FLAGS_E)?1:0,
-                   (dh.flagsVer & DIAM_FLAGS_I)?1:0,
-                   (dh.flagsVer & DIAM_FLAGS_R)?1:0);
-
-               /* Version */
-               proto_tree_add_uint(diameter_tree,
-                   hf_diameter_version,
-                   tvb, offset, 1,
-                   dh.flagsVer);
-
-               offset+=1;
-
-               
-               /* Length */
-               proto_tree_add_uint(diameter_tree,
-                   hf_diameter_length, tvb,
-                   offset, 2, dh.pktLength);
-               offset +=2;
-
-               /* Identifier */
-               proto_tree_add_uint(diameter_tree, hf_diameter_id,
-                   tvb, offset, 4, dh.identifier);
-               offset += 4;
+  } else if (!vEntry) {
+       g_warning("Missing type/enum field in dictionary avpName=%s",
+                         name);
+       return (-1);
+  }
 
-               /* Command Code */
-               proto_tree_add_uint(diameter_tree, hf_diameter_code,
-                   tvb, offset, 4, dh.commandCode);
-               offset += 4;
+  /* WORK - Handle flags  -- for validation later */
 
-               /* Vendor Id */
-               proto_tree_add_uint(diameter_tree,hf_diameter_vendor_id,
-                   tvb, offset, 4,
-                   dh.vendorId);
-               offset += 4;
 
-               /* If we have a bad packet, don't bother trying to parse the AVPs */
-               if (BadPacket) {
-                       return;
-               }
+  /* 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;
+  if (vEntry)
+       entry->type = DIAMETER_INTEGER32;
 
-               /* Start looking at the AVPS */
-               /* Make the next tvbuff */
-
-               /* Update the lengths */
-               avplength= dh.pktLength - sizeof(e_diameterhdr);
-    
-               avp_tvb = tvb_new_subset(tvb, offset, -1, avplength);
-               avptf = proto_tree_add_text(diameter_tree,
-                   tvb, offset, tvb_length(tvb),
-                   "Attribute Value Pairs");
-               
-               avp_tree = proto_item_add_subtree(avptf,
-                   ett_diameter_avp);
-               if (avp_tree != NULL) {
-                       dissect_avps( avp_tvb, pinfo, avp_tree);
-               }
+  /* 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, char *name, char *vendorId)
+{
+  CommandCode *entry;
+
+  /*
+   * Allocate the memory required for the dictionary.
+   */
+  entry = (CommandCode *) g_malloc(sizeof (CommandCode));
+
+  if (entry == NULL) {
+       g_warning("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");
+  if (!name || !code) {
+       g_warning("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, int id)
+{
+  ApplicationId *entry;
+
+  if (!name || (id <= 0)) {
+       g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
+                          name, id);
+       return (-1);
+  } /* Sanity Checks */
+
+  entry = g_malloc(sizeof(ApplicationId));
+  if (!entry) {
+       g_warning( "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, gchar *name, 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) {
+       g_warning( "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!!! */
+         g_warning("Diameter: Invalid application!: name=\"%s\", id=\"%s\"",
+                               name?name:"NULL", id?id:"NULL");
+         return -1;
+       }
+
+       /* Add the application */
+       if (dictionaryAddApplication(name, atol(id)) != 0) {
+         /* ERROR! */
+         return -1;
+       }
+  }
+
+
+  /*
+   * Get segment values
+   */
+  cur = cur->xmlChildrenNode;
+  while (cur != NULL) {
+       if (strcasecmp(cur->name, "avp") == 0) {
+         /* we have an avp!!! */
+         xmlParseAVP(cur);
+       } else if (strcasecmp(cur->name, "vendor") == 0) {
+         /* we have a vendor */
+         xmlParseVendor(cur);
+         /* For now, ignore typedefn and text */
+       } else if (strcasecmp(cur->name, "command") == 0) {
+         /* Found a command */
+         xmlParseCommand(cur);
+       } else if (strcasecmp(cur->name, "text") == 0) {
+       } else if (strcasecmp(cur->name, "comment") == 0) {
+       } else if (strcasecmp(cur->name, "typedefn") == 0) {
+         /* WORK -- parse in valid types . . . */
+       } else {
+         /* IF we got here, we're an error */
+         g_warning("Error!  expecting an avp or a typedefn (got \"%s\")",
+                               cur->name);
+         return (-1);
        }
-} /* dissect_diameter */
+       cur = cur->next;
+  } /* while */
+  return 0;
+} /* xmlDictionaryParseSegment */
 
 /*
- * This function will dissect the AVPs in a diameter packet.  It handles
- * all normal types, and even recursively calls itself for grouped AVPs
+ * The main xml parse routine.  This will walk through an XML
+ * dictionary that has been parsed by libxml.
  */
-static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
+static int
+xmlDictionaryParse(xmlNodePtr cur)
 {
-/* adds the attribute value pairs to the tree */
-       e_avphdr avph;
-       gchar *avptpstrval;
-       gchar *valstr;
-       guint32 vendorId=0;
-       int hdrLength;
-       int fixAmt;
-       proto_tree *avpi_tree;
-       int vendorOffset;
-       size_t offset = 0 ;
-       char dataBuffer[4096];
-       tvbuff_t        *group_tvb;
-       proto_tree *group_tree;
-       proto_item *grouptf;
-       proto_item *avptf;
-       char buffer[1024];
-       int BadPacket = FALSE;
-       
-       size_t packetLength;
-       size_t avpDataLength;
-       int avpType;
-
-       packetLength = tvb_length(tvb);
-
-       /* 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;
+  /* We should expect a base protocol, followed by multiple applicaitons */
+  while (cur != NULL) {
+       if (strcasecmp(cur->name, "base") == 0) {
+         /* Base protocol.  Descend and parse */
+         xmlDictionaryParseSegment(cur, 1);
+       } else if (strcasecmp(cur->name, "application") == 0) {
+         /* Application.  Descend and parse */
+         xmlDictionaryParseSegment(cur, 0);
+       } else if (strcasecmp(cur->name, "text") == 0) {
+         /* Ignore text */
+       } else {
+         g_warning( "Diameter: XML Expecting a base or an application  (got \"%s\")",
+                                cur->name);
+         return (-1);
        }
-       
-
-       /* Spin around until we run out of packet */
-       while (packetLength > 0 ) {
-               vendorOffset = 0;
-               
-               /* Check for short packet */
-               if (packetLength < MIN_AVP_SIZE) {
-                       BadPacket = TRUE;
-                       /* Don't even bother trying to parse a short packet. */
-                       return;
-               }
+       cur = cur->next;
+  }
 
-               /* Copy our header */
-               tvb_memcpy(tvb, (guint8*) &avph, offset, sizeof(avph));
+  return 0;
 
-               /* Fix the byte ordering */
-               avph.avp_code = ntohl(avph.avp_code);
-               avph.avp_length = ntohs(avph.avp_length);
+} /* xmlDictionaryParse */
 
-               /* Dissect our vendor id if it exists  and set hdr length*/
-               if (avph.avp_flags & AVP_FLAGS_V) {
-                       vendorId = ntohl(avph.avp_vendorId);
-                       /* Vendor id */
-                       hdrLength = sizeof(e_avphdr);
-               } else {
-                       /* No vendor */
-                       hdrLength = sizeof(e_avphdr) - 
-                           sizeof(guint32);
-               }
+/*
+ * This routine will call libxml to parse in the dictionary.
+ */
+static int
+loadXMLDictionary()
+{
+  xmlDocPtr doc;
+  xmlNodePtr cur;
+
+  /*
+   * build an XML tree from a 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 */
+  if (doc == NULL) {
+       g_warning("Diameter: Unable to parse xmldictionary %s",
+                         gbl_diameterDictionary);
+       return -1;
+  }
 
-               /* Check for bad length */
-               if (avph.avp_length < MIN_AVP_SIZE || 
-                   (avph.avp_length > packetLength)) {
-                       BadPacket = TRUE;
-               }
+  /*
+   * Check the document is of the right kind
+   */
+  cur = XmlStub.xmlDocGetRootElement(doc);
+  if (cur == NULL) {
+       g_warning("Diameter: Error: \"%s\": empty document",
+                         gbl_diameterDictionary);
+       XmlStub.xmlFreeDoc(doc);
+       return -1;
+  }
+  if (XmlStub.xmlStrcmp(cur->name, (const xmlChar *) "dictionary")) {
+       g_warning("Diameter: Error: \"%s\": document of the wrong type, root node != dictionary",
+                         gbl_diameterDictionary);
+       XmlStub.xmlFreeDoc(doc);
+       return -1;
+  }
 
-               /* Check for bad flags */
-               if (avph.avp_reserved || 
-                   (avph.avp_flags & AVP_FLAGS_RESERVED)) {
-                       BadPacket = TRUE;
-               }
-               
-               /*
-                * Fix byte-alignment (Diameter AVPs are sent on 4 byte
-                * boundries)
-                */
-               fixAmt = 4 - (avph.avp_length % 4);
-               if (fixAmt == 4) fixAmt = 0;
-
-               packetLength = packetLength - (avph.avp_length + fixAmt);
-
-               /* Check for out of bounds */
-               if (packetLength < 0) {
-                       BadPacket = TRUE;
+  /*
+   * 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()
+{
+  int i;
+
+  /* Add static vendors to list */
+  for(i=0; diameter_vendor_specific_vendors[i].strptr; i++) {
+       addVendor(diameter_vendor_specific_vendors[i].value,
+                         diameter_vendor_specific_vendors[i].strptr,
+                         diameter_vendor_specific_vendors[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);
+  }
+
+} /* initializeDictionaryDefaults */
+
+/*
+ * This routine will attempt to load the XML dictionary, and on
+ * failure, will call initializeDictionaryDefaults to load in
+ * our static dictionary.
+ */
+static void
+initializeDictionary()
+{
+  /*
+   * 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 (loadLibXML() ||
+         (loadXMLDictionary() != 0)) {
+       /* Something failed.  Use the static dictionary */
+       g_warning("Diameter: Using static dictionary! (Unable to use XML)");
+       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;
+  static gchar buffer[64];
+
+  for (probe=vendorListHead; probe; probe=probe->next) {
+       if (vendorId == probe->id) {
+         if (longName)
+               return probe->longName;
+         else
+               return probe->name;
+       }
+  }
+
+  snprintf(buffer, sizeof(buffer),
+                  "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;
+  static gchar buffer[64];
+  gchar *vendorName=NULL;
+
+  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;
                }
+         }
+       }
+  }
 
-               avptpstrval = match_strval(avph.avp_code, diameter_attrib_type_vals);
-               if (avptpstrval == NULL) avptpstrval="Unknown Type";
-
-               avptf = proto_tree_add_text(avp_tree, tvb,
-                   offset, avph.avp_length,
-                   "%s(%d) l:0x%x (%d bytes)",
-                   avptpstrval, avph.avp_code, avph.avp_length,
-                   avph.avp_length);
-               avpi_tree = proto_item_add_subtree(avptf,
-                   ett_diameter_avpinfo);
-
-               if (avpi_tree !=NULL) {
-                       /* Command Code */
-                       proto_tree_add_uint(avpi_tree, hf_diameter_avp_code,
-                           tvb, offset, 4, avph.avp_code);
-                       offset += 4;
-               
-                       proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
-                           tvb, offset, 2, avph.avp_length);
-                       offset += 2;
-
-                       proto_tree_add_uint(avpi_tree, hf_diameter_avp_reserved,
-                           tvb, offset, 1, avph.avp_reserved);
-                       offset += 1;
-
-                       proto_tree_add_uint_format(avpi_tree,
-                           hf_diameter_avp_flags, tvb,
-                           offset, 1, avph.avp_flags,
-                           "Flags: P:%d V:%d M:%d",
-                           (avph.avp_flags & AVP_FLAGS_P)?1:0,
-                           (avph.avp_flags & AVP_FLAGS_V)?1:0,
-                           (avph.avp_flags & AVP_FLAGS_M)?1:0);
-                       offset += 1;
-
-                       if (avph.avp_flags & AVP_FLAGS_V) {
-                               proto_tree_add_uint(avpi_tree, hf_diameter_avp_vendor_id,
-                                   tvb, offset, 4, avph.avp_vendorId);
-                               offset += 4;
-                       }
+  g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
+                       commandCode, vendorId);
+  snprintf(buffer, sizeof(buffer),
+                  "Cmd-0x%08x", commandCode);
+  return buffer;
+}/*diameter_command_to_str */
+
+/* return application string, based on the id */
+static gchar *
+diameter_app_to_str(guint32 vendorId) {
+  ApplicationId *probe;
+  static gchar buffer[64];
+
+  for (probe=ApplicationIdHead; probe; probe=probe->next) {
+       if (vendorId == probe->id) {
+         return probe->name;
+       }
+  }
 
-                       avpDataLength = avph.avp_length - 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, dataBuffer,
-                                   "Bad AVP (Suspect Data Not Dissected)");
-                               return;
-                       }
+  snprintf(buffer, sizeof(buffer),
+                  "AppId 0x%08x", vendorId);
+  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 */
+  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)
+{
+  static gchar buffer[64];
+  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("AvpName: 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->name;
+         } else {
+               /* No Vendor ID -- vendorName should be null */
+               if (!probe->vendorName)
+                 /* We found it! */
+                 return probe->name;
+         }
+       }
+  }
+
+  g_warning("Diameter: Unable to find name for AVP 0x%08x, Vendor %u!",
+                       avpCode, vendorId);
 
-                       avpType=match_numval(avph.avp_code, diameter_printinfo);
-                       tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095,
-                                      avph.avp_length - hdrLength));
-                       
-                       switch(avpType) {
-                       case DIAMETER_GROUPED:
-                               sprintf(buffer, "%s Grouped AVPs", avptpstrval);
-                               /* 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_STRING:
-                               proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
-                                   tvb, offset, avpDataLength, dataBuffer,
-                                   "String: %*.*s", (int)avpDataLength, (int)avpDataLength,
-                                   dataBuffer);
-                               break;
-                       case DIAMETER_ADDRESS:
-                               if (avpDataLength == 4) {
-                                       guint32 ipv4Address = ntohl((*(guint32*)dataBuffer));
-                                       proto_tree_add_ipv4_format(avpi_tree, hf_diameter_avp_data_v4addr,
-                                           tvb, offset, avpDataLength, ipv4Address,
-                                           "IPv4 Address: %u.%u.%u.%u",
-                                           (ipv4Address&0xff000000)>>24,
-                                           (ipv4Address&0xff0000)>>16,
-                                           (ipv4Address&0xff00)>>8,
-                                           (ipv4Address&0xff));
-                               } else if (avpDataLength == 16) {
-                                       proto_tree_add_ipv6_format(avpi_tree, hf_diameter_avp_data_v6addr,
-                                           tvb, offset, avpDataLength, dataBuffer, 
-                                           "IPv6 Address: %04x:%04x:%04x:%04x",
-                                           *((guint32*)dataBuffer),
-                                           *((guint32*)&dataBuffer[4]),
-                                           *((guint32*)&dataBuffer[8]),
-                                           *((guint32*)&dataBuffer[12]));
-                               } else {
-                                       proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
-                                           tvb, offset, avpDataLength, dataBuffer,
-                                           "Error!  Bad Address Length");
-                               }
-                               break;
-
-                       case DIAMETER_INTEGER32:
-                       case DIAMETER_UNSIGNED32:
-                       case DIAMETER_INTEGER64:
-                       case DIAMETER_UNSIGNED64:
-                               valstr=rd_value_to_str(&avph, dataBuffer, offset);
-                               
-                               proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32,
-                                   tvb, offset, avpDataLength, (*(guint32*)dataBuffer),
-                                   "Value: %s",  valstr);
-
-                               break;
-
-                       case DIAMETER_TIME:
-                               valstr=rd_value_to_str(&avph, dataBuffer, offset);
-
-                               proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
-                                   tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr);
-                               break;
-                               
-                       default:
-                       case DIAMETER_DATA:
-                               proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
-                                   tvb, offset, avpDataLength, dataBuffer,
-                                   "Data");
-                               break;
-                               
+  /* If we don't find it, build a name string */
+  sprintf(buffer, "Unknown AVP:0x%08x", avpCode);
+  return buffer;
+} /* diameter_avp_get_name */
+static gchar *
+diameter_avp_get_value(guint32 avpCode, guint32 vendorId, guint32 avpValue)
+{
+  static gchar buffer[64];
+
+  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;
+                       }
+                 }
+                 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
+                 return buffer;
+               }
+         } else {
+               if (!probe->vendorName) {
+                 ValueName *vprobe;
+                 for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
+                       if (avpValue == vprobe->value) {
+                         return vprobe->name;
                        }
-                       offset += avph.avp_length - hdrLength;
+                 }
+                 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
+                 return buffer;
                }
-               offset += fixAmt; /* fix byte alignment */
+         }
        }
-} /* dissect_avps */
+  }
+  /* If we don't find the avp, build a value string */
+  sprintf(buffer, "Unknown AVP! Value: 0x%08x", avpValue);
+  return buffer;
+} /* diameter_avp_get_value */
 
-/* Generic routine to work with value value pairs */
-static guint32 match_numval(guint32 val, const value_value_pair *vs)
+
+/* Code to actually dissect the packets */
+
+/*
+ * Main dissector
+ */
+static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
+                                                                          proto_tree *tree)
 {
-  guint32 i = 0;
 
-  while (vs[i].val1) {
-    if (vs[i].val1 == val)
-      return(vs[i].val2);
-    i++;
+  /* 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    dh;
+  size_t           offset=0;
+  size_t           avplength;
+  proto_tree      *avp_tree;
+  proto_item      *avptf;
+  int              BadPacket = FALSE;
+  guint32          commandCode, pktLength;
+  guint8           version, flags;
+  gchar            flagstr[64] = "<None>";
+  gchar           *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
+  gchar            commandString[64], vendorName[64];
+  gint        i;
+  guint      bpos;
+  static  int initialized=FALSE;
+
+  /* set our offset */
+  offset=start;
+
+  /*
+   * Only parse in dictionary if there are diameter packets to
+   * dissect.
+   */
+  if (!initialized) {
+         /* Read in our dictionary, if it exists. */
+         initializeDictionary();
+         initialized=TRUE;
   }
 
-  return(0);
-}
+  /* 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 */
+  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) {
+       strcpy(vendorName,
+                  diameter_vendor_to_str(dh.vendorId, TRUE));
+  } else {
+       strcpy(vendorName, "None");
+  }
+
+
+  /* Do the bit twiddling */
+  version = DIAM_GET_VERSION(dh);
+  pktLength = DIAM_GET_LENGTH(dh);
+  flags = DIAM_GET_FLAGS(dh);
+  commandCode = DIAM_GET_COMMAND(dh);
+
+  /* Set up our flags */
+  if (check_col(pinfo->cinfo, COL_INFO) || tree) {
+       flagstr[0]=0;
+       for (i = 0; i < 8; i++) {
+         bpos = 1 << i;
+         if (flags & bpos) {
+               if (flagstr[0]) {
+                 strcat(flagstr, ", ");
+               }
+               strcat(flagstr, fstr[i]);
+         }
+       }
+       if (strlen(flagstr) == 0) {
+         strcpy(flagstr,"<None>");
+       }
+  }
+
+  /* Set up our commandString */
+  strcpy(commandString, diameter_command_to_str(commandCode, dh.vendorId));
+  if (flags & DIAM_FLAGS_R)
+       strcat(commandString, "-Request");
+  else
+       strcat(commandString, "-Answer");
+
+  /* Short packet.  Should have at LEAST one avp */
+  if (pktLength < MIN_DIAMETER_SIZE) {
+       g_warning("Diameter: Packet too short: %u bytes less than min size (%lu bytes))",
+                         pktLength, (unsigned long)MIN_DIAMETER_SIZE);
+       BadPacket = TRUE;
+  }
 
-static gchar *rd_match_strval(guint32 val, const value_string *vs) {
-       gchar           *result;
-       result=match_strval(val,vs);
-       if (result == NULL ) {
-               result="Undefined";
+  /* And, check our reserved flags/version */
+  if ((flags & DIAM_FLAGS_RESERVED) ||
+         (version != 1)) {
+       g_warning("Diameter: Bad packet: Bad Flags(0x%x) or Version(%u)",
+                         flags, version);
+       BadPacket = TRUE;
+  }
+
+  if (check_col(pinfo->cinfo, COL_INFO)) {
+       col_add_fstr(pinfo->cinfo, COL_INFO,
+                                "%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, vendorName,
+                                dh.hopByHopId, dh.endToEndId,
+                                (flags & DIAM_FLAGS_R)?1:0,
+                                (flags & DIAM_FLAGS_P)?1:0,
+                                (flags & DIAM_FLAGS_E)?1:0);
+  }
+
+
+  /* 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(diameter_tree, hf_diameter_flags, tvb,
+                                                                       offset , 1, flags, "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_reserved3, 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(diameter_tree, hf_diameter_code,
+                                                          tvb, offset, 3, commandCode, "Command Code: %s", commandString);
+       offset += 3;
+
+       /* Vendor Id */
+       proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
+                                                          tvb, offset, 4,      dh.vendorId, "Vendor-Id: %s", vendorName);
+       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;
+
+       /* If we have a bad packet, don't bother trying to parse the AVPs */
+       if (BadPacket) {
+         return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
        }
-       return result;
+
+       /* Start looking at the AVPS */
+       /* Make the next tvbuff */
+
+       /* Update the lengths */
+       avplength= pktLength - sizeof(e_diameterhdr);
+
+       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 MAX((offset + avplength), MIN_DIAMETER_SIZE);
+  }
+  return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
+
+} /* dissect_diameter_common */
+
+static void
+dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_diameter_common(tvb, 0, pinfo, tree);
 }
-static char *customValCheck(int code, int value)
+
+static void
+dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       switch (code) {
-       case DIAMETER_ATT_QOS_SERVICE_TYPE:
-               return rd_match_strval(value, diameter_qos_service_type_vals);
-               break;
-       case DIAMETER_ATT_SERVICE_TYPE:
-               return rd_match_strval(value, diameter_service_type_vals);
-               break;
-       case DIAMETER_ATT_PROHIBIT:
-               return rd_match_strval(value, diameter_prohibit_vals);
-               break;
-       case DIAMETER_ATT_PROMPT:
-               return rd_match_strval(value, diameter_prompt_vals);
-               break;
-       case DIAMETER_ATT_SOURCE_PORT:
-               return rd_match_strval(value, diameter_source_port_vals);
-               break;
-       case DIAMETER_ATT_NAS_PORT_TYPE:
-               return rd_match_strval(value, diameter_nas_port_type_vals);
-               break;
-       case DIAMETER_ATT_INTERFACE_ADDRESS:
-               return rd_match_strval(value, diameter_interface_address_vals);
-               break;
-       case DIAMETER_ATT_FRAMED_ROUTING:
-               return rd_match_strval(value, diameter_framed_routing_vals);
-               break;
-       case DIAMETER_ATT_ARAP_ZONE_ACCESS:
-               return rd_match_strval(value, diameter_arap_zone_access_vals);
-               break;
-       case DIAMETER_ATT_ACCT_AUTHENTIC:
-               return rd_match_strval(value, diameter_acct_authentic_vals);
-               break;
-       case DIAMETER_ATT_FRAMED_PROTOCOL:
-               return rd_match_strval(value, diameter_framed_protocol_vals);
-               break;
-       case DIAMETER_ATT_FRAMED_COMPRESSION:
-               return rd_match_strval(value, diameter_framed_compression_vals);
-               break;
-       case DIAMETER_ATT_AUTHENTICATION_TYPE:
-               return rd_match_strval(value, diameter_authentication_type_vals);
-               break;
-       case DIAMETER_ATT_ACCT_TERMINATE_CAUSE:
-               return rd_match_strval(value, diameter_acct_terminate_cause_vals);
-               break;
-       case DIAMETER_ATT_PROTOCOL:
-               return rd_match_strval(value, diameter_protocol_vals);
-               break;
-       case DIAMETER_ATT_DESTINATION_PORT:
-               return rd_match_strval(value, diameter_destination_port_vals);
+       size_t offset = 0;
+       guint32 plen;
+       guint32 available_bytes;
+/*     guint32 noffset; */
+
+       /* Loop through the packet, dissecting multiple diameter messages */
+       do {
+               available_bytes = tvb_length_remaining(tvb, offset);
+               if (available_bytes < 4) {
+                       g_warning("Diameter:  Bailing because only %d bytes of packet are available",
+                                         available_bytes);
+                       return; /* Bail.  We can't even get our length */
+               }
+
+               /* get our packet length */
+               plen = tvb_get_ntohl(tvb, offset);
+               plen &= 0x00ffffff; /* get rid of the flags */
+
+               /*Desegmentation */
+               if (gbl_diameter_desegment) {
+                       if (pinfo->can_desegment
+                               && plen > available_bytes) {
+                               pinfo->desegment_offset = offset;
+                               pinfo->desegment_len = plen - available_bytes;
+/*                             g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
+/*                                               plen, available_bytes); */
+                               return;
+                       }
+               }
+
+               /* Otherwise, dissect our packet */
+               offset = dissect_diameter_common(tvb, offset, pinfo, tree);
+
+/*             g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
+/*                               offset, noffset, tvb_length(tvb), available_bytes, plen); */
+/*             offset=noffset; */
+       } while (offset < tvb_reported_length(tvb));
+
+} /* 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;
+  gchar avpTypeString[64];
+  gchar avpNameString[64];
+  gchar *valstr;
+  guint32 vendorId=0;
+  gchar    vendorName[64];
+  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[1024];
+  int BadPacket = FALSE;
+  guint32 avpLength;
+  guint8 flags;
+  proto_item      *tf;
+  proto_tree      *flags_tree;
+
+  gint32 packetLength;
+  size_t avpDataLength;
+  int avpType;
+  gchar flagstr[64] = "<None>";
+  gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
+  gint        i;
+  guint      bpos;
+
+  packetLength = tvb_length(tvb);
+
+  /* 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;
+  }
+
+  /* Spin around until we run out of packet */
+  while (packetLength > 0 ) {
+
+       /* Check for short packet */
+       if (packetLength < (long)MIN_AVP_SIZE) {
+         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);
+
+       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) {
+         flagstr[0]=0;
+         for (i = 0; i < 8; i++) {
+               bpos = 1 << i;
+               if (flags & bpos) {
+                 if (flagstr[0]) {
+                       strcat(flagstr, ", ");
+                 }
+                 strcat(flagstr, fstr[i]);
+               }
+         }
+         if (strlen(flagstr) == 0) {
+               strcpy(flagstr,"<None>");
+         }
+       }
+
+       /* 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) {
+         strcpy(vendorName,
+                        diameter_vendor_to_str(vendorId, TRUE));
+       } else {
+         vendorName[0]='\0';
+       }
+
+       /* Check for bad length */
+       if (avpLength < MIN_AVP_SIZE ||
+               ((long)avpLength > packetLength)) {
+         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) {
+         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) {
+         g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
+                               packetLength);
+         BadPacket = TRUE;
+       }
+
+       /* Make avp Name & type */
+       strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
+                                                                        TypeValues,
+                                                                        "Unknown-Type: 0x%08x"));
+       strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
+
+       avptf = proto_tree_add_text(avp_tree, 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_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
+                                                                tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
+         offset += 4;
+
+         tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
+                                                                         offset , 1, flags, "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(avpi_tree, hf_diameter_avp_vendor_id,
+                                                                  tvb, offset, 4, vendorId, vendorName);
+               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:
+               sprintf(buffer, "%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_ATT_TERMINATION_ACTION:
-               return rd_match_strval(value, diameter_termination_action_vals);
+
+         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_ATT_EXTENSION_ID:
-               return rd_match_strval(value, diameter_extension_id_vals);
+         case DIAMETER_UTF8STRING:
+               {
+                 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,
+                                              "UTF8String: %*.*s",
+                                              (int)avpDataLength,
+                                              (int)avpDataLength, data);
+               }
                break;
-       case DIAMETER_ATT_MERIT_LAS_CODE:
-               return rd_match_strval(value, diameter_merit_las_code_vals);
+         case DIAMETER_IP_ADDRESS:
+               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 {
+                 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");
+               }
                break;
-       case DIAMETER_ATT_LOGIN_SERVICE:
-               return rd_match_strval(value, diameter_login_service_vals);
+
+         case DIAMETER_INTEGER32:
+               if (avpDataLength == 4) {
+                 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int32,
+                                     tvb, offset, avpDataLength, FALSE);
+               } else {
+                 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");
+               }
                break;
-       case DIAMETER_ATT_RSVP_SERVICE_TYPE:
-               return rd_match_strval(value, diameter_rsvp_service_type_vals);
+
+         case DIAMETER_UNSIGNED32:
+               if (avpDataLength == 4) {
+                 guint32 data;
+
+                 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 {
+                 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");
+               }
                break;
-       case DIAMETER_ATT_ACCT_STATUS_TYPE:
-               return rd_match_strval(value, diameter_acct_status_type_vals);
+
+         case DIAMETER_INTEGER64:
+               if (avpDataLength == 8) {
+                 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64,
+                                     tvb, offset, 8, FALSE);
+               } else {
+                 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");
+               }
                break;
-       }
 
-       return NULL;
-}
+         case DIAMETER_UNSIGNED64:
+               if (avpDataLength == 8) {
+                 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64,
+                                     tvb, offset, 8, FALSE);
+               } else {
+                 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");
+               }
+               break;
 
-static gchar *rd_value_to_str(e_avphdr *avph, const u_char *input, int length)
-{
-       int print_type;
-       guint32 intval;
-       char *valstr;
-       static char buffer[1024];
+         case DIAMETER_TIME:
+               if (avpDataLength == 4) {
+                 nstime_t data;
+                 gchar buffer[64];
+                 struct tm *ltp;
 
-/* prints the values of the attribute value pairs into a text buffer */
-       
-       print_type=match_numval(avph->avp_code,diameter_printinfo);
+                 data.secs = tvb_get_ntohl(tvb, offset);
+                 data.secs -= NTP_TIME_DIFF;
+                 data.nsecs = 0;
 
-       /* Set the Default */
-       strcpy(buffer, "Unknown Value");
+                 ltp = localtime(&data.secs);
+                 strftime(buffer, 64,
+                          "%a, %d %b %Y %H:%M:%S %z", ltp);
 
-       /* Default begin */
-       switch(print_type)
-               {
-               case DIAMETER_INTEGER32:
-                       /* Check for custom values */
-                       intval=pntohl(input);
-                       valstr=customValCheck(avph->avp_code, intval);
-                       if (valstr) {
-                               sprintf(buffer,"%s (%u)", valstr, intval);
-                       } else {
-                               sprintf(buffer,"%d", intval);
-                       }
-                       break;
-               case DIAMETER_UNSIGNED32:
-                       /* Check for custom values */
-                       intval=pntohl(input);
-                       valstr=customValCheck(avph->avp_code, intval);
-                       if (valstr) {
-                               sprintf(buffer,"%s (%u)", valstr, intval);
-                       } else {
-                               sprintf(buffer,"%u", intval);
-                       }
-                       break;
-               case DIAMETER_INTEGER64:
-               {
-                       long long llval;
-                       llval = *((long long *)input);
-                       sprintf(buffer,"%lld (Unsupported Conversion.  Byte ordering probably incorrect)",
-                           llval);
+                 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!  Bad Time Length");
                }
-               case DIAMETER_UNSIGNED64:
-               {
-                       long long llval;
-                       llval = *((long long *)input);
-                       sprintf(buffer,"%llu (Unsupported Conversion.  Byte ordering probably incorrect)",
-                           llval);
+               break;
+
+         case DIAMETER_ENUMERATED:
+               if (avpDataLength == 4) {
+                 guint32 data;
+
+                 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 {
+                 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");
                }
-                       break;
-               case DIAMETER_TIME:
-               {
-                       struct tm lt;
-                       intval=pntohl(input);
-                       intval -= NTP_TIME_DIFF;
-                       lt=*localtime((time_t *)&intval);
-                       strftime(buffer, 1024, 
-                           "%a, %d %b %Y %H:%M:%S %z",&lt);
+               break;
+         case DIAMETER_VENDOR_ID:
+               if (avpDataLength == 4) {
+                 guint32 data;
+
+                 data = tvb_get_ntohl(tvb, offset);
+                 valstr = diameter_vendor_to_str(data, TRUE);
+                 proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_data_uint32,
+                                            tvb, offset, avpDataLength, data,
+                                            "Vendor ID: %s (0x%08x)", valstr,
+                                            data);
+               } else {
+                 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");
                }
-               default:
-                       /* Do nothing */
-               
+               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 (0x%08x)",
+                                            valstr, data);
+               } else {
+                 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");
                }
-       return buffer;
-} /* rd value to str */
+               break;
+         case DIAMETER_MIP_REG_REQ:
+               safe_dissect_mip(tvb, pinfo, avpi_tree, offset, avpDataLength);
+               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 */
+
 
 
 void
 proto_reg_handoff_diameter(void)
 {
-       static int Initialized=FALSE;
-       static int TcpPort=0;
-#ifdef SCTP_DISSECTORS_ENABLED
-       static int SctpPort=0;
-#endif
-       if (Initialized) {
-               dissector_delete("tcp.port", TcpPort, dissect_diameter);
-#ifdef SCTP_DISSECTORS_ENABLED
-               dissector_delete("sctp.srcport", SctpPort, dissect_diameter);
-               dissector_delete("sctp.destport", SctpPort, dissect_diameter);
-#endif
-       } else {
-               Initialized=TRUE;
-       }
-
-       /* set port for future deletes */
-       TcpPort=gbl_diameterTcpPort;
-#ifdef SCTP_DISSECTORS_ENABLED
-       SctpPort=gbl_diameterSctpPort;
-#endif
+  static int Initialized=FALSE;
+  static int TcpPort=0;
+  static int SctpPort=0;
+  static dissector_handle_t diameter_tcp_handle;
+  static dissector_handle_t diameter_sctp_handle;
+
+  if (!Initialized) {
+       diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
+           proto_diameter);
+       diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
+           proto_diameter);
+       Initialized=TRUE;
+  } else {
+       dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
+       dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
+  }
 
-       strcpy(gbl_diameterString, "Diameter Protocol");
+  /* 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, dissect_diameter,
-           proto_diameter);
-#ifdef SCTP_DISSECTORS_ENABLED
-       dissector_add("sctp.srcport", gbl_diameterSctpPort,
-           dissect_diameter, proto_diameter);
-       dissector_add("sctp.destport", gbl_diameterSctpPort,
-           dissect_diameter, proto_diameter);
-#endif
+  /* 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_sctp_handle);
 }
 
 /* registration with the filtering engine */
 void
 proto_register_diameter(void)
 {
-
        static hf_register_info hf[] = {
-               { &hf_diameter_reserved,
-                 { "Reserved", "diameter.reserved", FT_UINT8, BASE_HEX, NULL, 0x0,
-                   "Should be zero" }},
-               { &hf_diameter_flags,
-                 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0xf8,
-                   "" }},
                { &hf_diameter_version,
-                 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x07,
-                   "" }},
+                 { "Version", "diameter.version", FT_UINT8, BASE_HEX, NULL, 0x00,
+                   "", HFILL }},
                { &hf_diameter_length,
-                 { "Length","diameter.length", FT_UINT16, BASE_DEC, NULL, 0x0,
-                   "" }},
-               { &hf_diameter_id,
-                 { "Identifier", "diameter.id", FT_UINT32, BASE_HEX, NULL, 0x0,
-                   "" }},
+                 { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
+                   "", HFILL }},
+
+               { &hf_diameter_flags,
+                 { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
+                   "", HFILL }},
+               { &hf_diameter_flags_request,
+                 { "Request", "diameter.flags.request", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_R,
+                       "", HFILL }},
+               { &hf_diameter_flags_proxyable,
+                 { "Proxyable", "diameter.flags.proxyable", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_P,
+                       "", HFILL }},
+               { &hf_diameter_flags_error,
+                 { "Error","diameter.flags.error", FT_BOOLEAN, 8, TFS(&flags_set_truth), DIAM_FLAGS_E,
+                       "", HFILL }},
+               { &hf_diameter_flags_reserved3,
+                 { "Reserved","diameter.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
+                       DIAM_FLAGS_RESERVED3, "", HFILL }},
+               { &hf_diameter_flags_reserved4,
+                 { "Reserved","diameter.flags.reserved4", FT_BOOLEAN, 8, TFS(&reserved_set),
+                       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,
+                 { "Reserved","diameter.flags.reserved6", FT_BOOLEAN, 8, TFS(&reserved_set),
+                       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_UINT32, BASE_DEC,
-                   VALS(diameter_command_code_vals), 0x0, "" }},
+                 { "Command Code","diameter.code", FT_UINT24, BASE_DEC,
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_vendor_id,
-                 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL, 0x0,
-                   "" }},
+                 { "VendorId", "diameter.vendorId", FT_UINT32, BASE_DEC, NULL,
+                       0x0,"", HFILL }},
+               { &hf_diameter_hopbyhopid,
+                 { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
+                   BASE_HEX, NULL, 0x0, "", HFILL }},
+               { &hf_diameter_endtoendid,
+                 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32,
+                   BASE_HEX, NULL, 0x0, "", HFILL }},
 
                { &hf_diameter_avp_code,
                  { "AVP Code","diameter.avp.code", FT_UINT32, BASE_DEC,
-                   VALS(diameter_attrib_type_vals), 0x0, "" }},
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_length,
-                 { "AVP length","diameter.avp.length", FT_UINT16, BASE_DEC,
-                   NULL, 0x0, "" }},
-               { &hf_diameter_avp_reserved,
-                 { "AVP Reserved","diameter.avp.reserved", FT_UINT8, BASE_HEX,
-                   NULL, 0x0, "Should be Zero" }},
+                 { "AVP Length","diameter.avp.length", FT_UINT24, BASE_DEC,
+                   NULL, 0x0, "", HFILL }},
+
+
                { &hf_diameter_avp_flags,
                  { "AVP Flags","diameter.avp.flags", FT_UINT8, BASE_HEX,
-                   NULL, 0x1f, "" }},
+                   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,
+                 { "Mandatory", "diameter.flags.mandatory", FT_BOOLEAN, 8, TFS(&flags_set_truth), AVP_FLAGS_M,
+                       "", 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,
+                 { "Reserved","diameter.avp.flags.reserved3", FT_BOOLEAN, 8, TFS(&reserved_set),
+                       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,
+                 { "Reserved","diameter.avp.flags.reserved5", FT_BOOLEAN, 8, TFS(&reserved_set),
+                       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,
+                 { "Reserved","diameter.avp.flags.reserved7", FT_BOOLEAN, 8, TFS(&reserved_set),
+                       AVP_FLAGS_RESERVED7,    "", HFILL }},
                { &hf_diameter_avp_vendor_id,
                  { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
-                   NULL, 0x0, "" }},
-               { &hf_diameter_avp_data_uint32,
-                 { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
-                   NULL, 0x0, "" }},
-#if 0
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_uint64,
-                 { "AVP Data","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
-                   NULL, 0x0, "" }},
-#endif
-               { &hf_diameter_avp_data_int32,
-                 { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC,
-                   NULL, 0x0, "" }},
-#if 0
+                 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_int64,
-                 { "AVP Data","diameter.avp.data.int64", FT_INT_64, BASE_DEC,
-                   NULL, 0x0, "" }},
-#endif
+                 { "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,
-                 { "AVP Data","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
-                   NULL, 0x0, "" }},
-
+                 { "Value","diameter.avp.data.bytes", FT_BYTES, BASE_NONE,
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_string,
-                 { "AVP Data","diameter.avp.data.string", FT_STRING, BASE_NONE,
-                   NULL, 0x0, "" }},
+                 { "Value","diameter.avp.data.string", FT_STRING, BASE_NONE,
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_v4addr,
-                 { "AVP Data","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
-                   NULL, 0x0, "" }},
+                 { "IPv4 Address","diameter.avp.data.v4addr", FT_IPv4, BASE_NONE,
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_v6addr,
-                 { "AVP Data","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
-                   NULL, 0x0, "" }},
+                 { "IPv6 Address","diameter.avp.data.v6addr", FT_IPv6, BASE_NONE,
+                   NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_time,
-                 { "AVP Data","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
-                   NULL, 0x0, "" }},
+                 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
+                   NULL, 0x0, "", HFILL }},
 
        };
        static gint *ett[] = {
                &ett_diameter,
+               &ett_diameter_flags,
                &ett_diameter_avp,
+               &ett_diameter_avp_flags,
                &ett_diameter_avpinfo
        };
        module_t *diameter_module;
+       gchar *default_diameterDictionary;
 
-       proto_diameter = proto_register_protocol (gbl_diameterString,
-           "DIAMETER", "diameter");
+       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));
 
        /* Register a configuration option for port */
        diameter_module = prefs_register_protocol(proto_diameter,
-           proto_reg_handoff_diameter);
+                                                                                         proto_reg_handoff_diameter);
        prefs_register_uint_preference(diameter_module, "tcp.port",
-                                      "DIAMETER TCP Port",
-                                      "Set the TCP port for DIAMETER messages",
-                                      10,
-                                      &gbl_diameterTcpPort);
-#ifdef SCTP_DISSECTORS_ENABLED
+                                                                  "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);
-#endif
-}
+                                                                  "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);
+
+       /* Desegmentation */
+       prefs_register_bool_preference(diameter_module, "desegment",
+                                                                  "Desegment all Diameter messages spanning multiple TCP segments",
+                                                                  "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
+                                                                  &gbl_diameter_desegment);
+
+       /* 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");
+} /* proto_register_diameter */