various string related changes, mainly replace sprintf/snprintf by g_snprintf
[obnox/wireshark/wip.git] / packet-diameter.c
index 6fbad7677a5f2d113400962532431e2c96f3020e..4295a4dd67f24cb89960288b799c4a066362c3c2 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-diameter.c
  * Routines for Diameter packet disassembly
  *
- * $Id: packet-diameter.c,v 1.37 2001/12/10 00:25:27 guy Exp $
+ * $Id: packet-diameter.c,v 1.62 2004/03/05 22:25:23 obiot Exp $
  *
  * Copyright (c) 2001 by David Frascone <dave@frascone.com>
  *
 #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 <errno.h>
 #include <ctype.h>
 #include <time.h>
 #include <glib.h>
-#include <filesystem.h>
+#include <epan/filesystem.h>
 #include "xmlstub.h"
-#include "packet.h"
-#include "resolv.h"
+#include <epan/packet.h>
+#include <epan/resolv.h>
+#include "report_err.h"
 #include "prefs.h"
+#include "packet-tcp.h"
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
 
 /* This must be defined before we include packet-diameter-defs.h */
 
@@ -74,7 +73,7 @@ typedef enum {
   DIAMETER_MIP_REG_REQ,        /* OctetString */
   DIAMETER_VENDOR_ID,           /* Integer32  */
   DIAMETER_APPLICATION_ID
-  
+
 } diameterDataType;
 
 
@@ -126,7 +125,7 @@ typedef struct avp_info {
 typedef struct command_code {
   guint32              code;
   gchar               *name;
-  gchar               *vendorString;
+  gchar               *vendorName;
   struct command_code *next;
 } CommandCode;
 
@@ -156,11 +155,6 @@ static ApplicationId   *ApplicationIdHead=NULL;
 #define TCP_PORT_DIAMETER      1812
 #define SCTP_PORT_DIAMETER     1812
 
-static const true_false_string flags_set_truth = {
-  "Set",
-  "Not set"
-};
-
 static const true_false_string reserved_set = {
   "*** Error! Reserved Bit is Set",
   "Ok"
@@ -170,7 +164,6 @@ static int hf_diameter_length = -1;
 static int hf_diameter_code = -1;
 static int hf_diameter_hopbyhopid =-1;
 static int hf_diameter_endtoendid =-1;
-static int hf_diameter_reserved = -1;
 static int hf_diameter_version = -1;
 static int hf_diameter_vendor_id = -1;
 static int hf_diameter_flags = -1;
@@ -185,7 +178,6 @@ 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;
@@ -214,16 +206,17 @@ 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;
-static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
+static guint gbl_diameterTcpPort=TCP_PORT_DIAMETER;
+static guint gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
 
 /* desegmentation of Diameter over TCP */
 static gboolean gbl_diameter_desegment = TRUE;
 
-#define DIAMETER_DIR "diameter"
-#define DICT_FN "dictionary.xml"
-static gchar *gbl_diameterDictionary = NULL;
+/* Allow zero as a valid application ID */
+static gboolean allow_zero_as_app_id = FALSE;
+
+#define DICT_FN  "diameter/dictionary.xml"
+static gchar *gbl_diameterDictionary;
 
 typedef struct _e_diameterhdr {
   guint32  versionLength;
@@ -288,13 +281,13 @@ xmlParseFilePush( char *filename, int checkValid) {
   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);
+       report_open_failure(filename, errno, FALSE);
        return NULL;
   }
 
@@ -310,7 +303,7 @@ xmlParseFilePush( char *filename, int checkValid) {
        valid=ctxt->valid;
        XmlStub.xmlFreeParserCtxt(ctxt);
   }
-  fclose(f); 
+  fclose(f);
 
   /* Check valid */
   if (!valid) {
@@ -336,7 +329,7 @@ addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
   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;
@@ -360,7 +353,7 @@ addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
   avpListHead = entry;
 
   return (0);
-       
+
 } /* addStaticAVP */
 
 /*
@@ -369,7 +362,7 @@ addStaticAVP(int code, gchar *name, diameterDataType type, value_string *values)
  * add them too.
  */
 static int
-xmlParseAVP(xmlDocPtr doc, xmlNodePtr cur)
+xmlParseAVP(xmlNodePtr cur)
 {
   char *name=NULL, *description=NULL, *code=NULL, *mayEncrypt=NULL,
        *mandatory=NULL, *protected=NULL, *vendorBit=NULL, *vendorName = NULL,
@@ -394,28 +387,26 @@ xmlParseAVP(xmlDocPtr doc, xmlNodePtr cur)
   cur = cur->xmlChildrenNode;
 
   while (cur != NULL ) {
-       if (!strcasecmp((char *)cur->name, "type")) {
+       if (strcasecmp(cur->name, "type") == 0) {
          type = XmlStub.xmlGetProp(cur, "type-name");
-       }
-       if (!strcasecmp((char *)cur->name, "enum")) {
+       } 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;
-       }
-       if (!strcasecmp((char *)cur->name, "grouped")) {
+       } else if (strcasecmp(cur->name, "grouped") == 0) {
          /* WORK Recurse here for grouped AVPs */
          type = "grouped";
        }
@@ -444,13 +435,13 @@ xmlParseAVP(xmlDocPtr doc, xmlNodePtr cur)
   }
 
   /* WORK - Handle flags  -- for validation later */
-       
+
 
   /* And, create the entry */
   entry = (avpInfo *)g_malloc(sizeof(avpInfo));
   entry->name = g_strdup(name);
   entry->code = atol(code);
-  if (vendorName) 
+  if (vendorName)
        entry->vendorName = g_strdup(vendorName);
   else
        entry->vendorName = NULL;
@@ -491,9 +482,9 @@ addCommand(int code, char *name, char *vendorId)
   entry->name = g_strdup(name);
   entry->code = code;
   if (vendorId)
-       entry->vendorString = g_strdup(vendorId);
+       entry->vendorName = g_strdup(vendorId);
   else
-       entry->vendorString = NULL;
+       entry->vendorName = "None";
 
   /* Add the entry to the list */
   entry->next = commandListHead;
@@ -507,7 +498,7 @@ addCommand(int code, char *name, char *vendorId)
  * list of commands.
  */
 static int
-xmlParseCommand(xmlDocPtr doc, xmlNodePtr cur)
+xmlParseCommand(xmlNodePtr cur)
 {
   char *name, *code, *vendorIdString;
 
@@ -535,8 +526,8 @@ dictionaryAddApplication(char *name, int id)
 {
   ApplicationId *entry;
 
-  if (!name || (id <= 0)) {
-       g_warning( "Diameter Error: Inavlid application (name=%p, id=%d)",
+  if (!name || (id < 0) || (id == 0 && !allow_zero_as_app_id)) {
+       g_warning( "Diameter Error: Invalid application (name=%p, id=%d)",
                           name, id);
        return (-1);
   } /* Sanity Checks */
@@ -546,10 +537,10 @@ dictionaryAddApplication(char *name, int id)
        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;
@@ -584,7 +575,7 @@ addVendor(int id, gchar *name, gchar *longName)
  * This routine will pars in a XML vendor entry.
  */
 static int
-xmlParseVendor(xmlDocPtr doc, xmlNodePtr cur)
+xmlParseVendor(xmlNodePtr cur)
 {
   char *name=NULL, *code=NULL, *id=NULL;
 
@@ -605,23 +596,23 @@ xmlParseVendor(xmlDocPtr doc, xmlNodePtr cur)
  * This routine will either parse in the base protocol, or an application.
  */
 static int
-xmlDictionaryParseSegment(xmlDocPtr doc, xmlNodePtr cur, int base)
+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! */
@@ -629,25 +620,25 @@ xmlDictionaryParseSegment(xmlDocPtr doc, xmlNodePtr cur, int base)
        }
   }
 
-       
+
   /*
    * Get segment values
    */
   cur = cur->xmlChildrenNode;
   while (cur != NULL) {
-       if (!strcasecmp((char *)cur->name, "avp")) {
+       if (strcasecmp(cur->name, "avp") == 0) {
          /* we have an avp!!! */
-         xmlParseAVP(doc, cur);
-       } else if (!strcasecmp((char *)cur->name, "vendor")) {
+         xmlParseAVP(cur);
+       } else if (strcasecmp(cur->name, "vendor") == 0) {
          /* we have a vendor */
-         xmlParseVendor(doc, cur);
+         xmlParseVendor(cur);
          /* For now, ignore typedefn and text */
-       } else if (!strcasecmp((char *)cur->name, "command")) {
+       } else if (strcasecmp(cur->name, "command") == 0) {
          /* Found a command */
-         xmlParseCommand(doc,cur);
-       } else if (!strcasecmp((char *)cur->name, "text")) {
-       } else if (!strcasecmp((char *)cur->name, "comment")) {
-       } else if (!strcasecmp((char *)cur->name, "typedefn")) {
+         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 */
@@ -661,21 +652,23 @@ xmlDictionaryParseSegment(xmlDocPtr doc, xmlNodePtr cur, int base)
 } /* xmlDictionaryParseSegment */
 
 /*
- * The main xml parse routine.  This will walk through an XML 
+ * The main xml parse routine.  This will walk through an XML
  * dictionary that has been parsed by libxml.
  */
 static int
-xmlDictionaryParse(xmlDocPtr doc, xmlNodePtr cur)
+xmlDictionaryParse(xmlNodePtr cur)
 {
-  /* We should expect a base protocol, followed by multiple applicaitons */
+  /* We should expect a base protocol, followed by multiple applications */
   while (cur != NULL) {
-       if (!strcasecmp((char *)cur->name, "base")) {
+       if (strcasecmp(cur->name, "base") == 0) {
          /* Base protocol.  Descend and parse */
-         xmlDictionaryParseSegment(doc, cur, 1);
-       } else if (!strcasecmp((char *)cur->name, "application")) {
+         xmlDictionaryParseSegment(cur, 1);
+       } else if (strcasecmp(cur->name, "application") == 0) {
          /* Application.  Descend and parse */
-         xmlDictionaryParseSegment(doc, cur, 0);
-       } else if (!strcasecmp((char *)cur->name, "text")) {
+         xmlDictionaryParseSegment(cur, 0);
+       } else if (strcasecmp(cur->name, "text") == 0) {
+         /* Ignore text */
+       } else if (strcasecmp(cur->name, "comment") == 0) {
          /* Ignore text */
        } else {
          g_warning( "Diameter: XML Expecting a base or an application  (got \"%s\")",
@@ -693,7 +686,7 @@ xmlDictionaryParse(xmlDocPtr doc, xmlNodePtr cur)
  * This routine will call libxml to parse in the dictionary.
  */
 static int
-loadXMLDictionary()
+loadXMLDictionary(void)
 {
   xmlDocPtr doc;
   xmlNodePtr cur;
@@ -711,7 +704,7 @@ loadXMLDictionary()
                          gbl_diameterDictionary);
        return -1;
   }
-       
+
   /*
    * Check the document is of the right kind
    */
@@ -728,12 +721,12 @@ loadXMLDictionary()
        XmlStub.xmlFreeDoc(doc);
        return -1;
   }
-       
+
   /*
    * Ok, the dictionary has been parsed by libxml, and is valid.
    * All we have to do now is read in our information.
    */
-  if (xmlDictionaryParse(doc, cur->xmlChildrenNode) != 0) {
+  if (xmlDictionaryParse(cur->xmlChildrenNode) != 0) {
        /* Error has already been printed */
        return -1;
   }
@@ -751,7 +744,7 @@ loadXMLDictionary()
  * with the old static data from packet-diameter-defs.h
  */
 static void
-initializeDictionaryDefaults()
+initializeDictionaryDefaults(void)
 {
   int i;
 
@@ -777,16 +770,16 @@ initializeDictionaryDefaults()
 
 } /* initializeDictionaryDefaults */
 
-/* 
- * This routine will attempt to load the XML dictionary, and on 
+/*
+ * This routine will attempt to load the XML dictionary, and on
  * failure, will call initializeDictionaryDefaults to load in
  * our static dictionary.
  */
 static void
-initializeDictionary()
+initializeDictionary(void)
 {
   /*
-   * Using ugly ordering here.  If loadLibXML succeeds, then 
+   * 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.
    */
@@ -804,39 +797,64 @@ initializeDictionary()
  * These routines manipulate the diameter structures.
  */
 
-/* return command string, based on the code */
+/* return vendor string, based on the id */
 static gchar *
-diameter_command_to_str(guint32 commandCode)
-{
-  CommandCode *probe;
+diameter_vendor_to_str(guint32 vendorId, gboolean longName) {
+  VendorId *probe;
   static gchar buffer[64];
 
-  for (probe=commandListHead; probe; probe=probe->next) {
-       if (commandCode == probe->code) {
-         return probe->name;
+  for (probe=vendorListHead; probe; probe=probe->next) {
+       if (vendorId == probe->id) {
+         if (longName)
+               return probe->longName;
+         else
+               return probe->name;
        }
   }
 
   snprintf(buffer, sizeof(buffer),
-                  "Cmd-0x%08x", commandCode);
+                  "Vendor 0x%08x", vendorId);
   return buffer;
-}/*diameter_command_to_str */
-/* return vendor string, based on the id */
+} /*diameter_vendor_to_str */
+
+/* return command string, based on the code */
 static gchar *
-diameter_vendor_to_str(guint32 vendorId) {
-  VendorId *probe;
+diameter_command_to_str(guint32 commandCode, guint32 vendorId)
+{
+  CommandCode *probe;
   static gchar buffer[64];
+  gchar *vendorName=NULL;
 
-  for (probe=vendorListHead; probe; probe=probe->next) {
-       if (vendorId == probe->id) {
-         return probe->longName;
+  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;
+               }
+         }
        }
   }
 
+  g_warning("Diameter: Unable to find name for command code 0x%08x, Vendor \"%u\"!",
+                       commandCode, vendorId);
   snprintf(buffer, sizeof(buffer),
-                  "Vendor 0x%08x", vendorId);
+                  "Cmd-0x%08x", commandCode);
   return buffer;
-} /*diameter_vendor_to_str */
+}/*diameter_command_to_str */
+
 /* return application string, based on the id */
 static gchar *
 diameter_app_to_str(guint32 vendorId) {
@@ -855,56 +873,117 @@ diameter_app_to_str(guint32 vendorId) {
 } /*diameter_app_to_str */
 
 /* return an avp type, based on the code */
-diameterDataType
-diameter_avp_get_type(guint32 avpCode){
+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) {
-         /* We found it! */
-         return probe->type;
+
+         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 %d!", avpCode);
+  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)
+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) {
-         /* We found it! */
-         return probe->name;
+         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);
+
   /* 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 avpValue)
+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) {
-         ValueName *vprobe;
-         for(vprobe=probe->values; vprobe; vprobe=vprobe->next) {
-               if (avpValue == vprobe->value) {
-                 return vprobe->name;
+         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;
+                       }
+                 }
+                 sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
+                 return buffer;
                }
          }
-         sprintf(buffer, "Unknown Value: 0x%08x", avpValue);
-         return buffer;
        }
   }
   /* If we don't find the avp, build a value string */
@@ -912,29 +991,28 @@ diameter_avp_get_value(guint32 avpCode, guint32 avpValue)
   return buffer;
 } /* diameter_avp_get_value */
 
-static gchar *
-diameter_time_to_string(gchar *timeValue)
-{
-  static gchar buffer[64];
-  int intval;
-  struct tm lt;
-
-  intval=pntohl(*((guint32*)timeValue));
-  intval -= NTP_TIME_DIFF;
-  lt=*localtime((time_t *)&intval);
-  strftime(buffer, 1024, 
-                  "%a, %d %b %Y %H:%M:%S %z",&lt);
-  return buffer;
-} /* diameter_time_to_string */
-
 
 /* Code to actually dissect the packets */
 
+static gboolean
+check_diameter(tvbuff_t *tvb)
+{
+  if (!tvb_bytes_exist(tvb, 0, 1))
+       return FALSE;   /* not enough bytes to check the version */
+  if (tvb_get_guint8(tvb, 0) != 1)
+       return FALSE;   /* not version 1 */
+
+  /* XXX - fetch length and make sure it's at least MIN_DIAMETER_SIZE?
+     Fetch flags and check that none of the DIAM_FLAGS_RESERVED bits
+     are set? */
+  return TRUE;
+}
+
 /*
  * Main dissector
  */
-static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info *pinfo,
-                                                                          proto_tree *tree)
+static void
+dissect_diameter_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
 
   /* Set up structures needed to add the protocol subtree and manage it */
@@ -944,7 +1022,7 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
   tvbuff_t        *avp_tvb;
   proto_tree      *diameter_tree;
   e_diameterhdr    dh;
-  size_t           offset=0;
+  int              offset=0;
   size_t           avplength;
   proto_tree      *avp_tree;
   proto_item      *avptf;
@@ -953,14 +1031,11 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
   guint8           version, flags;
   gchar            flagstr[64] = "<None>";
   gchar           *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Error", "Proxyable", "Request" };
-  gchar            commandString[64], vendorString[64];
+  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.
@@ -970,28 +1045,28 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
          initializeDictionary();
          initialized=TRUE;
   }
-       
+
   /* Make entries in Protocol column and Info column on summary display */
-  if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
-       col_add_str(pinfo->cinfo, COL_PROTOCOL, "Diameter");
-  if (check_col(pinfo->cinfo, COL_INFO)) 
+  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 = ntohl(dh.versionLength);
-  dh.flagsCmdCode = ntohl(dh.flagsCmdCode);
-  dh.vendorId = ntohl(dh.vendorId);
-  dh.hopByHopId = ntohl(dh.hopByHopId);
-  dh.endToEndId = ntohl(dh.endToEndId);
+  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(vendorString, 
-                  diameter_vendor_to_str(dh.vendorId));
+       strcpy(vendorName,
+                  diameter_vendor_to_str(dh.vendorId, TRUE));
   } else {
-       strcpy(vendorString, "None");
+       strcpy(vendorName, "None");
   }
 
 
@@ -1002,7 +1077,7 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
   commandCode = DIAM_GET_COMMAND(dh);
 
   /* Set up our flags */
-  if (check_col(pinfo->cinfo, COL_INFO) || tree) {  
+  if (check_col(pinfo->cinfo, COL_INFO) || tree) {
        flagstr[0]=0;
        for (i = 0; i < 8; i++) {
          bpos = 1 << i;
@@ -1017,18 +1092,18 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
          strcpy(flagstr,"<None>");
        }
   }
-  
+
   /* Set up our commandString */
-  strcpy(commandString, diameter_command_to_str(commandCode));
-  if (flags & DIAM_FLAGS_R) 
+  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: %d bytes less than min size (%d bytes))",
-                         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;
   }
 
@@ -1042,20 +1117,20 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
 
   if (check_col(pinfo->cinfo, COL_INFO)) {
        col_add_fstr(pinfo->cinfo, COL_INFO,
-                                "%s%s%s%s%s vendor=%s (hop-id=%d) (end-id=%d) RPE=%d%d%d",
+                                "%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, vendorString,
+                                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. */
@@ -1103,7 +1178,7 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
 
        /* Vendor Id */
        proto_tree_add_uint_format(diameter_tree,hf_diameter_vendor_id,
-                                                          tvb, offset, 4,      dh.vendorId, "Vendor-Id: %s", vendorString);
+                                                          tvb, offset, 4,      dh.vendorId, "Vendor-Id: %s", vendorName);
        offset += 4;
 
        /* Hop-by-hop Identifier */
@@ -1118,7 +1193,7 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
 
        /* If we have a bad packet, don't bother trying to parse the AVPs */
        if (BadPacket) {
-         return (offset + MAX(pktLength,MIN_DIAMETER_SIZE));
+         return;
        }
 
        /* Start looking at the AVPS */
@@ -1126,70 +1201,46 @@ static guint32 dissect_diameter_common(tvbuff_t *tvb, size_t start, packet_info
 
        /* 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;
   }
-  return (offset + MAX(pktLength, MIN_DIAMETER_SIZE));
-
 } /* dissect_diameter_common */
 
-static void
-dissect_diameter_sctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+
+static guint
+get_diameter_pdu_len(tvbuff_t *tvb, int offset)
 {
-       dissect_diameter_common(tvb, 0, pinfo, tree);
+  /* Get the length of the Diameter packet. */
+  return tvb_get_ntoh24(tvb, offset + 1);
 }
 
-static void
-dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_diameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       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));
+  if (!check_diameter(tvb))
+       return 0;
+  dissect_diameter_common(tvb, pinfo, tree);
+  return tvb_length(tvb);
+}
 
+static int
+dissect_diameter_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+  if (!check_diameter(tvb))
+       return 0;
+  tcp_dissect_pdus(tvb, pinfo, tree, gbl_diameter_desegment, 4,
+       get_diameter_pdu_len, dissect_diameter_common);
+  return tvb_length(tvb);
 } /* dissect_diameter_tcp */
 
 /*
@@ -1219,7 +1270,7 @@ safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
   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);
@@ -1262,12 +1313,11 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
   gchar avpNameString[64];
   gchar *valstr;
   guint32 vendorId=0;
-  gchar    vendorString[64];
+  gchar    vendorName[64];
   int hdrLength;
   int fixAmt;
   proto_tree *avpi_tree;
-  size_t offset = 0 ;
-  char dataBuffer[4096];
+  size_t offset = 0;
   tvbuff_t        *group_tvb;
   proto_tree *group_tree;
   proto_item *grouptf;
@@ -1278,7 +1328,7 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
   guint8 flags;
   proto_item      *tf;
   proto_tree      *flags_tree;
-       
+
   gint32 packetLength;
   size_t avpDataLength;
   int avpType;
@@ -1301,25 +1351,25 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
 
        /* Check for short packet */
        if (packetLength < (long)MIN_AVP_SIZE) {
-         g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%d bytes))",
-                               packetLength, 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 = ntohl(avph.avp_code);
-       avph.avp_flagsLength = ntohl(avph.avp_flagsLength);
-       
+       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) {  
+       if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
          flagstr[0]=0;
          for (i = 0; i < 8; i++) {
                bpos = 1 << i;
@@ -1337,29 +1387,30 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
 
        /* Dissect our vendor id if it exists  and set hdr length */
        if (flags & AVP_FLAGS_V) {
-         vendorId = ntohl(avph.avp_vendorId);
+         vendorId = g_ntohl(avph.avp_vendorId);
          /* Vendor id */
          hdrLength = sizeof(e_avphdr);
        } else {
          /* No vendor */
-         hdrLength = sizeof(e_avphdr) - 
+         hdrLength = sizeof(e_avphdr) -
                sizeof(guint32);
          vendorId = 0;
        }
 
        if (vendorId) {
-         strcpy(vendorString, 
-                        diameter_vendor_to_str(vendorId));
+         strcpy(vendorName,
+                        diameter_vendor_to_str(vendorId, TRUE));
        } else {
-         vendorString[0]='\0';
+         vendorName[0]='\0';
        }
 
        /* Check for bad length */
-       if (avpLength < MIN_AVP_SIZE || 
+       if (avpLength < MIN_AVP_SIZE ||
                ((long)avpLength > packetLength)) {
-         g_warning("Diameter: AVP payload size invalid: avp_length: %d bytes,  "
-                               "min: %d bytes,    packetLen: %d",
-                               avpLength, MIN_AVP_SIZE, 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;
        }
 
@@ -1371,17 +1422,17 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
          /* 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) ",
@@ -1390,9 +1441,10 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
        }
 
        /* Make avp Name & type */
-       strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code), TypeValues, 
+       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));
+       strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
 
        avptf = proto_tree_add_text(avp_tree, tvb,
                                                                offset, avpLength + fixAmt,
@@ -1407,7 +1459,7 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
          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);
@@ -1428,7 +1480,7 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
 
          if (flags & AVP_FLAGS_V) {
                proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
-                                                                  tvb, offset, 4, vendorId, vendorString);
+                                                                  tvb, offset, 4, vendorId, vendorName);
                offset += 4;
          }
 
@@ -1441,15 +1493,14 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
          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)");
+                                       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);
-         tvb_memcpy(tvb, (guint8*) dataBuffer, offset, MIN(4095,avpDataLength));
-       
-         
+         avpType=diameter_avp_get_type(avph.avp_code,vendorId);
+
          switch(avpType) {
          case DIAMETER_GROUPED:
                sprintf(buffer, "%s Grouped AVPs", avpNameString);
@@ -1457,7 +1508,7 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
                grouptf = proto_tree_add_text(avpi_tree,
                                                                          tvb, offset, tvb_length(tvb),
                                                                          buffer);
-                               
+
                group_tree = proto_item_add_subtree(grouptf,
                                                                                        ett_diameter_avp);
 
@@ -1469,115 +1520,170 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
                break;
 
          case DIAMETER_IDENTITY:
-               proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
-                                                                        tvb, offset, avpDataLength, dataBuffer,
-                                                                        "Identity: %*.*s", (int)avpDataLength, (int)avpDataLength,
-                                                                        dataBuffer);
+               {
+                 const guint8 *data;
+
+                 data = tvb_get_ptr(tvb, offset, avpDataLength);
+                 proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
+                                              tvb, offset, avpDataLength, data,
+                                              "Identity: %*.*s",
+                                              (int)avpDataLength,
+                                              (int)avpDataLength, data);
+               }
                break;
          case DIAMETER_UTF8STRING:
-               proto_tree_add_string_format(avpi_tree, hf_diameter_avp_data_string,
-                                                                        tvb, offset, avpDataLength, dataBuffer,
-                                                                        "UTF8String: %*.*s", (int)avpDataLength, (int)avpDataLength,
-                                                                        dataBuffer);
+               {
+                 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_IP_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));
+                 proto_tree_add_item(avpi_tree, hf_diameter_avp_data_v4addr,
+                                     tvb, offset, avpDataLength, FALSE);
                } 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]));
+                 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, dataBuffer,
-                                                                         "Error!  Bad Address Length");
+                                             tvb, offset, avpDataLength,
+                                             tvb_get_ptr(tvb, offset, avpDataLength),
+                                             "Error!  Bad Address Length");
                }
                break;
 
          case DIAMETER_INTEGER32:
-               {
-                 gint32 data;
-                 memcpy(&data, dataBuffer, 4);
-                 data = ntohl(data);
-                 proto_tree_add_int_format(avpi_tree, hf_diameter_avp_data_int32,
-                                                                       tvb, offset, avpDataLength, data,
-                                                                       "Value: %d", data );
+               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_UNSIGNED32:
-               {
+               if (avpDataLength == 4) {
                  guint32 data;
 
-                 memcpy(&data, dataBuffer, 4);
-                 data=ntohl(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 );
+                                            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_INTEGER64:
-               proto_tree_add_item(avpi_tree, hf_diameter_avp_data_int64, tvb, offset, 8, FALSE);
+               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;
 
          case DIAMETER_UNSIGNED64:
-               proto_tree_add_item(avpi_tree, hf_diameter_avp_data_uint64, tvb, offset, 8, FALSE);
+               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;
 
          case DIAMETER_TIME:
-               valstr=diameter_time_to_string(dataBuffer);
+               if (avpDataLength == 4) {
+                 nstime_t data;
+                 gchar buffer[64];
+                 struct tm *ltp;
 
-               proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
-                                                                       tvb, offset, avpDataLength, dataBuffer, "Time: %s", valstr);
+                 data.secs = tvb_get_ntohl(tvb, offset);
+                 data.secs -= NTP_TIME_DIFF;
+                 data.nsecs = 0;
+
+                 ltp = localtime(&data.secs);
+                 strftime(buffer, 64,
+                          "%a, %d %b %Y %H:%M:%S %z", ltp);
+
+                 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");
+               }
                break;
 
          case DIAMETER_ENUMERATED:
-               {
+               if (avpDataLength == 4) {
                  guint32 data;
-                 
-                 memcpy(&data, dataBuffer, 4);
-                 data = ntohl(data);
-                 valstr = diameter_avp_get_value(avph.avp_code, 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);
+                                            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_VENDOR_ID:
-               {
+               if (avpDataLength == 4) {
                  guint32 data;
-                 
-                 memcpy(&data, dataBuffer, 4);
-                 data = ntohl(data);
-                 valstr = diameter_vendor_to_str(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,
-                                                                        "%s (0x%08x)", valstr, data);
+                                            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");
                }
                break;
          case DIAMETER_APPLICATION_ID:
-               {
+               if (avpDataLength == 4) {
                  guint32 data;
-                 
-                 memcpy(&data, dataBuffer, 4);
-                 data = ntohl(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,
-                                                                        "%s (0x%08x)", valstr, data);
+                                            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");
                }
                break;
          case DIAMETER_MIP_REG_REQ:
@@ -1587,10 +1693,11 @@ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree
          default:
          case DIAMETER_OCTET_STRING:
                proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
-                                                                       tvb, offset, avpDataLength, dataBuffer,
-                                                                       "Hex Data Highlighted Below");
+                                           tvb, offset, avpDataLength,
+                                           tvb_get_ptr(tvb, offset, avpDataLength),
+                                          "Hex Data Highlighted Below");
                break;
-                               
+
          } /* switch type */
        } /* avpi_tree != null */
        offset += (avpLength - hdrLength);
@@ -1607,29 +1714,27 @@ proto_reg_handoff_diameter(void)
   static int TcpPort=0;
   static int SctpPort=0;
   static dissector_handle_t diameter_tcp_handle;
-  static dissector_handle_t diameter_sctp_handle;
+  static dissector_handle_t diameter_handle;
 
   if (!Initialized) {
-       diameter_tcp_handle = create_dissector_handle(dissect_diameter_tcp,
+       diameter_tcp_handle = new_create_dissector_handle(dissect_diameter_tcp,
            proto_diameter);
-       diameter_sctp_handle = create_dissector_handle(dissect_diameter_sctp,
+       diameter_handle = new_create_dissector_handle(dissect_diameter,
            proto_diameter);
        Initialized=TRUE;
   } else {
        dissector_delete("tcp.port", TcpPort, diameter_tcp_handle);
-       dissector_delete("sctp.port", SctpPort, diameter_sctp_handle);
+       dissector_delete("sctp.port", SctpPort, diameter_handle);
   }
 
   /* set port for future deletes */
   TcpPort=gbl_diameterTcpPort;
   SctpPort=gbl_diameterSctpPort;
 
-  strcpy(gbl_diameterString, "Diameter Protocol");
-
   /* 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);
+  dissector_add("sctp.port", gbl_diameterSctpPort, diameter_handle);
 }
 
 /* registration with the filtering engine */
@@ -1643,7 +1748,7 @@ proto_register_diameter(void)
                { &hf_diameter_length,
                  { "Length","diameter.length", FT_UINT24, BASE_DEC, NULL, 0x0,
                    "", HFILL }},
-               
+
                { &hf_diameter_flags,
                  { "Flags", "diameter.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
                    "", HFILL }},
@@ -1682,9 +1787,9 @@ proto_register_diameter(void)
                  { "Hop-by-Hop Identifier", "diameter.hopbyhopid", FT_UINT32,
                    BASE_HEX, NULL, 0x0, "", HFILL }},
                { &hf_diameter_endtoendid,
-                 { "End-to-End Identifier", "diameter.endtoendid", FT_UINT32, 
+                 { "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,
                    NULL, 0x0, "", HFILL }},
@@ -1724,32 +1829,31 @@ proto_register_diameter(void)
                  { "AVP Vendor Id","diameter.avp.vendorId", FT_UINT32, BASE_DEC,
                    NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_uint64,
-                 { "AVP Data","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
+                 { "Value","diameter.avp.data.uint64", FT_UINT64, BASE_DEC,
                    NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_int64,
-                 { "AVP Data","diameter.avp.data.int64", FT_INT64, BASE_DEC,
+                 { "Value","diameter.avp.data.int64", FT_INT64, BASE_DEC,
                    NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_uint32,
-                 { "AVP Data","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
+                 { "Value","diameter.avp.data.uint32", FT_UINT32, BASE_DEC,
                    NULL, 0x0, "", HFILL }},
                { &hf_diameter_avp_data_int32,
-                 { "AVP Data","diameter.avp.data.int32", FT_INT32, BASE_DEC,
+                 { "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,
+                 { "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,
+                 { "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,
+                 { "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,
+                 { "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,
+                 { "Time","diameter.avp.data.time", FT_ABSOLUTE_TIME, BASE_NONE,
                    NULL, 0x0, "", HFILL }},
 
        };
@@ -1761,9 +1865,9 @@ proto_register_diameter(void)
                &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));
 
@@ -1783,24 +1887,36 @@ proto_register_diameter(void)
        /*
         * Build our default dictionary filename
         */
-       if (! gbl_diameterDictionary) {
-               gbl_diameterDictionary = (gchar *) g_malloc(strlen(get_datafile_dir()) +
-                                                                                                       1 + strlen(DICT_FN) + 1); /* slash + fn + null */
-               sprintf(gbl_diameterDictionary, "%s" G_DIR_SEPARATOR_S "%s",
-                               get_datafile_dir(), DICT_FN );
-       }
-       /* Now register its preferences so it can be changed. */
+       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, "diameter.desegment",
-                                                                  "Desegment all Diameter messages spanning multiple TCP segments",
+       prefs_register_bool_preference(diameter_module, "desegment",
+                                                                  "Desegment all Diameter messages\nspanning multiple TCP segments",
                                                                   "Whether the Diameter dissector should desegment all messages spanning multiple TCP segments",
                                                                   &gbl_diameter_desegment);
-
+       /* Allow zero as valid application ID */
+       prefs_register_bool_preference(diameter_module, "allow_zero_as_app_id",
+                       "Allow 0 as valid application ID",
+                       "If set, the value 0 (zero) can be used as a valid "
+                       "application ID. This is used in experimental cases.",
+                       &allow_zero_as_app_id);
        /* Register some preferences we no longer support, so we can report
           them as obsolete rather than just illegal. */
        prefs_register_obsolete_preference(diameter_module, "udp.port");