dcerpc: remove use-after-free (found by clang).
[metze/wireshark/wip.git] / epan / addr_resolv.c
index 13b2ebb74c0d0f4cba4e9b37310a3dea531d0c22..bc14ec5ff94897d0ad1bfdfb7cc470098ae7b701 100644 (file)
@@ -39,7 +39,7 @@
  * are most likely to take a long time, given the way address-to-name
  * lookups are done over NBNS).
  *
- * Mac OS X does have SIGALRM, but if you longjmp() out of a name resolution
+ * macOS does have SIGALRM, but if you longjmp() out of a name resolution
  * call in a signal handler, you might crash, because the state of the
  * resolution code that sends messages to lookupd might be inconsistent
  * if you jump out of it in middle of a call.
 #include <sys/socket.h>     /* needed to define AF_ values on UNIX */
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>       /* needed to define AF_ values on Windows */
-#endif
-
 #ifdef _WIN32
-# include <ws2tcpip.h>
+#include <winsock2.h>       /* needed to define AF_ values on Windows */
+#include <ws2tcpip.h>
 #endif
 
 #ifdef HAVE_C_ARES
 #include "addr_resolv.h"
 #include "wsutil/filesystem.h"
 
-#include <wsutil/report_err.h>
+#include <wsutil/report_message.h>
 #include <wsutil/file_util.h>
 #include <wsutil/pint.h>
-#include "wsutil/inet_aton.h"
 #include <wsutil/inet_addr.h>
 
 #include <epan/strutil.h>
 #define ENAME_ETHERS    "ethers"
 #define ENAME_IPXNETS   "ipxnets"
 #define ENAME_MANUF     "manuf"
+#define ENAME_WKA       "wka"
 #define ENAME_SERVICES  "services"
 #define ENAME_VLANS     "vlans"
+#define ENAME_SS7PCS    "ss7pcs"
+#define ENAME_ENTERPRISES "enterprises.tsv"
 
 #define HASHETHSIZE      2048
 #define HASHHOSTSIZE     2048
 
 typedef struct sub_net_hashipv4 {
     guint             addr;
+    /* XXX: No longer needed?*/
     guint8            flags;          /* B0 dummy_entry, B1 resolve, B2 If the address is used in the trace */
     struct sub_net_hashipv4   *next;
     gchar             name[MAXNAMELEN];
@@ -161,6 +161,12 @@ typedef struct hashvlan {
     gchar               name[MAXVLANNAMELEN];
 } hashvlan_t;
 
+typedef struct ss7pc {
+    guint32             id; /* 1st byte NI, 3 following bytes: Point Code */
+    gchar               pc_addr[MAXNAMELEN];
+    gchar               name[MAXNAMELEN];
+} hashss7pc_t;
+
 /* hash tables used for ethernet and manufacturer lookup */
 #define HASHETHER_STATUS_UNRESOLVED     1
 #define HASHETHER_STATUS_RESOLVED_DUMMY 2
@@ -178,6 +184,7 @@ struct hashmanuf {
     guint8            addr[3];
     char              hexaddr[3*3];
     char              resolved_name[MAXNAMELEN];
+    char              resolved_longname[MAXNAMELEN];
 };
 
 /* internal ethernet type */
@@ -185,6 +192,7 @@ typedef struct _ether
 {
     guint8            addr[6];
     char              name[MAXNAMELEN];
+    char              longname[MAXNAMELEN];
 } ether_t;
 
 /* internal ipxnet type */
@@ -205,6 +213,7 @@ static wmem_map_t *ipxnet_hash_table = NULL;
 static wmem_map_t *ipv4_hash_table = NULL;
 static wmem_map_t *ipv6_hash_table = NULL;
 static wmem_map_t *vlan_hash_table = NULL;
+static wmem_map_t *ss7pc_hash_table = NULL;
 
 static wmem_list_t *manually_resolved_ipv4_list = NULL;
 static wmem_list_t *manually_resolved_ipv6_list = NULL;
@@ -217,20 +226,22 @@ typedef struct _resolved_ipv4
 
 typedef struct _resolved_ipv6
 {
-    struct e_in6_addr  ip6_addr;
+    ws_in6_addr  ip6_addr;
     char               name[MAXNAMELEN];
 } resolved_ipv6_t;
 
 static addrinfo_lists_t addrinfo_lists = { NULL, NULL};
 
-static gchar        *cb_service;
-static port_type    cb_proto = PT_NONE;
-
+struct cb_serv_data {
+    gchar       *service;
+    port_type    proto;
+};
 
 static wmem_map_t *manuf_hashtable = NULL;
 static wmem_map_t *wka_hashtable = NULL;
 static wmem_map_t *eth_hashtable = NULL;
 static wmem_map_t *serv_port_hashtable = NULL;
+static GHashTable *enterprises_hashtable = NULL;
 
 static subnet_length_entry_t subnet_length_entries[SUBNETLENGTHSIZE]; /* Ordered array of entries */
 static gboolean have_subnet_entry = FALSE;
@@ -240,7 +251,7 @@ static gboolean new_resolved_objects = FALSE;
 static GPtrArray* extra_hosts_files = NULL;
 
 static hashether_t *add_eth_name(const guint8 *addr, const gchar *name);
-static void add_serv_port_cb(const guint32 port);
+static void add_serv_port_cb(const guint32 port, gpointer ptr);
 
 
 /* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing
@@ -271,7 +282,7 @@ static gboolean
 ipv6_equal(gconstpointer v1, gconstpointer v2)
 {
 
-    if (memcmp(v1, v2, sizeof (struct e_in6_addr)) == 0) {
+    if (memcmp(v1, v2, sizeof (ws_in6_addr)) == 0) {
         return TRUE;
     }
 
@@ -288,7 +299,8 @@ e_addr_resolve gbl_resolv_flags = {
     TRUE,   /* dns_pkt_addr_resolution */
     TRUE,   /* use_external_net_name_resolver */
     FALSE,  /* load_hosts_file_from_profile_only */
-    FALSE   /* vlan_name */
+    FALSE,  /* vlan_name */
+    FALSE   /* ss7 point code names */
 };
 #ifdef HAVE_C_ARES
 static guint name_resolve_concurrency = 500;
@@ -302,11 +314,16 @@ static guint name_resolve_concurrency = 500;
 
 gchar *g_ethers_path    = NULL;     /* global ethers file     */
 gchar *g_pethers_path   = NULL;     /* personal ethers file   */
+gchar *g_wka_path       = NULL;     /* global well-known-addresses file */
+gchar *g_manuf_path     = NULL;     /* global manuf file      */
 gchar *g_ipxnets_path   = NULL;     /* global ipxnets file    */
 gchar *g_pipxnets_path  = NULL;     /* personal ipxnets file  */
 gchar *g_services_path  = NULL;     /* global services file   */
 gchar *g_pservices_path = NULL;     /* personal services file */
 gchar *g_pvlan_path     = NULL;     /* personal vlans file    */
+gchar *g_ss7pcs_path    = NULL;     /* personal ss7pcs file   */
+gchar *g_enterprises_path = NULL;   /* global enterprises file   */
+gchar *g_penterprises_path = NULL;  /* personal enterprises file */
                                     /* first resolving call   */
 
 /* c-ares */
@@ -322,7 +339,7 @@ typedef struct _async_dns_queue_msg
 {
     union {
         guint32           ip4;
-        struct e_in6_addr ip6;
+        ws_in6_addr ip6;
     } addr;
     int                 family;
 } async_dns_queue_msg_t;
@@ -333,13 +350,6 @@ typedef struct _async_hostent {
     void *addrp;
 } async_hostent_t;
 
-#if ( ( ARES_VERSION_MAJOR < 1 )                                     \
-        || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
-static void c_ares_ghba_cb(void *arg, int status, struct hostent *hostent);
-#else
-static void c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *hostent);
-#endif
-
 ares_channel ghba_chan; /* ares_gethostbyaddr -- Usually non-interactive, no timeout */
 ares_channel ghbn_chan; /* ares_gethostbyname -- Usually interactive, timeout */
 
@@ -464,18 +474,12 @@ add_service_name(port_type proto, const guint port, const char *service_name)
 static void
 parse_service_line (char *line)
 {
-    /*
-     *  See the services(4) or services(5) man page for services file format
-     *  (not available on all systems).
-     */
-
     gchar *cp;
     gchar *service;
     gchar *port;
     port_type proto;
-
+    struct cb_serv_data cb_data;
     range_t *port_rng = NULL;
-    guint32 max_port = MAX_UDP_PORT;
 
     if ((cp = strchr(line, '#')))
         *cp = '\0';
@@ -493,52 +497,48 @@ parse_service_line (char *line)
     if (strtok(cp, "/") == NULL)
         return;
 
-    if ((cp = strtok(NULL, "/")) == NULL)
-        return;
-
-    /* seems we got all interesting things from the file */
-    if (strcmp(cp, "tcp") == 0) {
-        max_port = MAX_TCP_PORT;
-        proto = PT_TCP;
-    }
-    else if (strcmp(cp, "udp") == 0) {
-        max_port = MAX_UDP_PORT;
-        proto = PT_UDP;
-    }
-    else if (strcmp(cp, "sctp") == 0) {
-        max_port = MAX_SCTP_PORT;
-        proto = PT_SCTP;
-    }
-    else if (strcmp(cp, "dccp") == 0) {
-        max_port = MAX_DCCP_PORT;
-        proto = PT_DCCP;
-    } else {
+    if (range_convert_str(NULL, &port_rng, port, G_MAXUINT16) != CVT_NO_ERROR) {
+        wmem_free (NULL, port_rng);
         return;
     }
 
-    if (CVT_NO_ERROR != range_convert_str(&port_rng, port, max_port)) {
-        /* some assertion here? */
-        return;
+    while ((cp = strtok(NULL, "/")) != NULL) {
+        if (strcmp(cp, "tcp") == 0) {
+            proto = PT_TCP;
+        }
+        else if (strcmp(cp, "udp") == 0) {
+            proto = PT_UDP;
+        }
+        else if (strcmp(cp, "sctp") == 0) {
+            proto = PT_SCTP;
+        }
+        else if (strcmp(cp, "dccp") == 0) {
+            proto = PT_DCCP;
+        }
+        else {
+            break;
+        }
+        cb_data.service = service;
+        cb_data.proto = proto;
+        range_foreach(port_rng, add_serv_port_cb, &cb_data);
     }
 
-    cb_service = service;
-    cb_proto = proto;
-    range_foreach(port_rng, add_serv_port_cb);
-    g_free (port_rng);
-    cb_proto = PT_NONE;
+    wmem_free (NULL, port_rng);
 } /* parse_service_line */
 
 
 static void
-add_serv_port_cb(const guint32 port)
+add_serv_port_cb(const guint32 port, gpointer ptr)
 {
+    struct cb_serv_data *cb_data = (struct cb_serv_data *)ptr;
+
     if ( port ) {
-        add_service_name(cb_proto, port, cb_service);
+        add_service_name(cb_data->proto, port, cb_data->service);
     }
 }
 
 
-static void
+static gboolean
 parse_services_file(const char * path)
 {
     FILE *serv_p;
@@ -549,13 +549,14 @@ parse_services_file(const char * path)
     serv_p = ws_fopen(path, "r");
 
     if (serv_p == NULL)
-        return;
+        return FALSE;
 
     while (fgetline(&buf, &size, serv_p) >= 0) {
         parse_service_line(buf);
     }
 
     fclose(serv_p);
+    return TRUE;
 }
 
 /* -----------------
@@ -632,6 +633,7 @@ serv_name_lookup(port_type proto, guint port)
 static void
 initialize_services(void)
 {
+    gboolean parse_file = TRUE;
     g_assert(serv_port_hashtable == NULL);
     serv_port_hashtable = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
 
@@ -643,15 +645,130 @@ initialize_services(void)
 
     /* Compute the pathname of the personal services file */
     if (g_pservices_path == NULL) {
-        g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
+        /* Check profile directory before personal configuration */
+        g_pservices_path = get_persconffile_path(ENAME_SERVICES, TRUE);
+        if (!parse_services_file(g_pservices_path)) {
+            g_free(g_pservices_path);
+            g_pservices_path = get_persconffile_path(ENAME_SERVICES, FALSE);
+        } else {
+            parse_file = FALSE;
+        }
+    }
+    if (parse_file) {
+        parse_services_file(g_pservices_path);
     }
-    parse_services_file(g_pservices_path);
 }
 
 static void
 service_name_lookup_cleanup(void)
 {
     serv_port_hashtable = NULL;
+    g_free(g_services_path);
+    g_services_path = NULL;
+    g_free(g_pservices_path);
+    g_pservices_path = NULL;
+}
+
+static void
+parse_enterprises_line (char *line)
+{
+    char *tok, *dec_str, *org_str;
+    guint32 dec;
+
+    if ((tok = strchr(line, '#')))
+        *tok = '\0';
+    dec_str = strtok(line, " \t");
+    if (!dec_str)
+        return;
+    org_str = strtok(NULL, ""); /* everything else */
+    if (org_str)
+        org_str = g_strstrip(org_str);
+    if (!org_str)
+        return;
+    if (!ws_strtou32(dec_str, NULL, &dec))
+        return;
+    g_hash_table_replace(enterprises_hashtable, GUINT_TO_POINTER(dec), g_strdup(org_str));
+}
+
+
+static gboolean
+parse_enterprises_file(const char * path)
+{
+    FILE *fp;
+    static int size = 0;
+    static char *buf = NULL;
+
+    fp = ws_fopen(path, "r");
+    if (fp == NULL)
+        return FALSE;
+
+    while (fgetline(&buf, &size, fp) >= 0) {
+        parse_enterprises_line(buf);
+    }
+
+    fclose(fp);
+    return TRUE;
+}
+
+static void
+initialize_enterprises(void)
+{
+    g_assert(enterprises_hashtable == NULL);
+    enterprises_hashtable = g_hash_table_new_full(NULL, NULL, NULL, g_free);
+
+    if (g_enterprises_path == NULL) {
+        g_enterprises_path = get_datafile_path(ENAME_ENTERPRISES);
+    }
+    parse_enterprises_file(g_enterprises_path);
+
+    if (g_penterprises_path == NULL) {
+        g_penterprises_path = get_persconffile_path(ENAME_ENTERPRISES, FALSE);
+    }
+    parse_enterprises_file(g_penterprises_path);
+}
+
+const gchar *
+try_enterprises_lookup(guint32 value)
+{
+    return (const gchar *)g_hash_table_lookup(enterprises_hashtable, GUINT_TO_POINTER(value));
+}
+
+const gchar *
+enterprises_lookup(guint32 value, const char *unknown_str)
+{
+    const gchar *s;
+
+    s = try_enterprises_lookup(value);
+    if (s != NULL)
+        return s;
+    if (unknown_str != NULL)
+        return unknown_str;
+    return "<Unknown>";
+}
+
+void
+enterprises_base_custom(char *buf, guint32 value)
+{
+    const gchar *s;
+
+    if ((s = try_enterprises_lookup(value)) == NULL)
+        s = ITEM_LABEL_UNKNOWN_STR;
+    g_snprintf(buf, ITEM_LABEL_LENGTH, "%s (%u)", s, value);
+}
+
+static void
+enterprises_cleanup(void)
+{
+    g_assert(enterprises_hashtable);
+    g_hash_table_destroy(enterprises_hashtable);
+    enterprises_hashtable = NULL;
+    g_assert(g_enterprises_path);
+    g_free(g_enterprises_path);
+    g_enterprises_path = NULL;
+    if (g_pservices_path) {
+        g_free(g_pservices_path);
+        g_pservices_path = NULL;
+    }
 }
 
 /* Fill in an IP4 structure with info from subnets file or just with the
@@ -662,22 +779,19 @@ fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
 {
     subnet_entry_t subnet_entry;
 
-    if (tp->flags & DUMMY_ADDRESS_ENTRY)
-        return; /* already done */
-
-    tp->flags |= DUMMY_ADDRESS_ENTRY; /* Overwrite if we get async DNS reply */
+    /* Overwrite if we get async DNS reply */
 
     /* Do we have a subnet for this address? */
     subnet_entry = subnet_lookup(addr);
     if (0 != subnet_entry.mask) {
         /* Print name, then '.' then IP address after subnet mask */
         guint32 host_addr;
-        gchar buffer[MAX_IP_STR_LEN];
+        gchar buffer[WS_INET_ADDRSTRLEN];
         gchar* paddr;
         gsize i;
 
         host_addr = addr & (~(guint32)subnet_entry.mask);
-        ip_to_str_buf((guint8 *)&host_addr, buffer, MAX_IP_STR_LEN);
+        ip_to_str_buf((guint8 *)&host_addr, buffer, WS_INET_ADDRSTRLEN);
         paddr = buffer;
 
         /* Skip to first octet that is not totally masked
@@ -697,6 +811,7 @@ fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
          */
         g_snprintf(tp->name, MAXNAMELEN, "%s%s", subnet_entry.name, paddr);
     } else {
+        /* XXX: This means we end up printing "1.2.3.4 (1.2.3.4)" in many cases */
         ip_to_str_buf((const guint8 *)&addr, tp->name, MAXNAMELEN);
     }
 }
@@ -707,28 +822,14 @@ fill_dummy_ip4(const guint addr, hashipv4_t* volatile tp)
 static void
 fill_dummy_ip6(hashipv6_t* volatile tp)
 {
-    if (tp->flags & DUMMY_ADDRESS_ENTRY)
-        return; /* already done */
-
-    tp->flags |= DUMMY_ADDRESS_ENTRY; /* Overwrite if we get async DNS reply */
+    /* Overwrite if we get async DNS reply */
     g_strlcpy(tp->name, tp->ip6, MAXNAMELEN);
 }
 
 #ifdef HAVE_C_ARES
 
 static void
-c_ares_ghba_cb(
-        void *arg,
-        int status,
-#if ( ( ARES_VERSION_MAJOR < 1 )                                     \
-        || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
-        struct hostent *he
-#else
-        int timeouts _U_,
-        struct hostent *he
-#endif
-        ) {
-
+c_ares_ghba_cb(void *arg, int status, int timeouts _U_, struct hostent *he) {
     async_dns_queue_msg_t *caqm = (async_dns_queue_msg_t *)arg;
     char **p;
 
@@ -779,8 +880,9 @@ host_lookup(const guint addr)
          * and then try to resolve it.
          */
         tp = new_ipv4(addr);
+        fill_dummy_ip4(addr, tp);
         wmem_map_insert(ipv4_hash_table, GUINT_TO_POINTER(addr), tp);
-    } else if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) != DUMMY_ADDRESS_ENTRY) {
+    } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
         return tp;
     }
 
@@ -789,7 +891,6 @@ host_lookup(const guint addr)
      * resolve it already.
      */
 
-    fill_dummy_ip4(addr, tp);
     if (!gbl_resolv_flags.network_name)
         return tp;
 
@@ -809,7 +910,7 @@ host_lookup(const guint addr)
 
 /* --------------- */
 static hashipv6_t *
-new_ipv6(const struct e_in6_addr *addr)
+new_ipv6(const ws_in6_addr *addr)
 {
     hashipv6_t *tp = wmem_new(wmem_epan_scope(), hashipv6_t);
     memcpy(tp->addr, addr->bytes, sizeof tp->addr);
@@ -821,7 +922,7 @@ new_ipv6(const struct e_in6_addr *addr)
 
 /* ------------------------------------ */
 static hashipv6_t *
-host_lookup6(const struct e_in6_addr *addr)
+host_lookup6(const ws_in6_addr *addr)
 {
     hashipv6_t * volatile tp;
 #ifdef HAVE_C_ARES
@@ -834,13 +935,14 @@ host_lookup6(const struct e_in6_addr *addr)
          * We don't already have an entry for this host name; create one,
          * and then try to resolve it.
          */
-        struct e_in6_addr *addr_key;
+        ws_in6_addr *addr_key;
 
-        addr_key = wmem_new(wmem_epan_scope(), struct e_in6_addr);
+        addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
         tp = new_ipv6(addr);
         memcpy(addr_key, addr, 16);
+        fill_dummy_ip6(tp);
         wmem_map_insert(ipv6_hash_table, addr_key, tp);
-    } else if ((tp->flags & DUMMY_AND_RESOLVE_FLGS) != DUMMY_ADDRESS_ENTRY) {
+    } else if (tp->flags & TRIED_OR_RESOLVED_MASK) {
         return tp;
     }
 
@@ -849,7 +951,6 @@ host_lookup6(const struct e_in6_addr *addr)
      * resolve it already.
      */
 
-    fill_dummy_ip6(tp);
     if (!gbl_resolv_flags.network_name)
         return tp;
 
@@ -895,13 +996,13 @@ host_lookup6(const struct e_in6_addr *addr)
 
 
 /*
- * If "manuf_file" is FALSE, parse a 6-byte MAC address.
- * If "manuf_file" is TRUE, parse an up-to-6-byte sequence with an optional
+ * If "accept_mask" is FALSE,  either 3 or 6 bytes are valid, but no other number of bytes is.
+ * If "accept_mask" is TRUE, parse an up-to-6-byte sequence with an optional
  * mask.
  */
 static gboolean
 parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
-        const gboolean manuf_file)
+        const gboolean accept_mask)
 {
     int i;
     unsigned long num;
@@ -923,8 +1024,8 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
         /* OK, what character terminated the octet? */
         if (*cp == '/') {
             /* "/" - this has a mask. */
-            if (!manuf_file) {
-                /* Entries with masks are allowed only in the "manuf" files. */
+            if (!accept_mask) {
+                /* Entries with masks are not allowed in this file. */
                 return FALSE;
             }
             cp++; /* skip past the '/' to get to the mask */
@@ -954,9 +1055,8 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
             /* We're at the end of the address, and there's no mask. */
             if (i == 2) {
                 /* We got 3 bytes, so this is a manufacturer ID. */
-                if (!manuf_file) {
-                    /* Manufacturer IDs are only allowed in the "manuf"
-                       files. */
+                if (!accept_mask) {
+                    /* Manufacturer IDs are not allowed in this file */
                     return FALSE;
                 }
                 /* Indicate that this is a manufacturer ID (0 is not allowed
@@ -966,10 +1066,8 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
             }
 
             if (i == 5) {
-                /* We got 6 bytes, so this is a MAC address.
-                   If we're reading one of the "manuf" files, indicate that
-                   this is a MAC address (48 is not allowed as a mask). */
-                if (manuf_file)
+                /* We got 6 bytes, so this is a MAC address (48 is not allowed as a mask). */
+                if (accept_mask)
                     *mask = 48;
                 return TRUE;
             }
@@ -998,7 +1096,7 @@ parse_ether_address(const char *cp, ether_t *eth, unsigned int *mask,
 
 static int
 parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
-        const gboolean manuf_file)
+        const gboolean accept_mask)
 {
     /*
      *  See the ethers(4) or ethers(5) man page for ethers file format
@@ -1009,13 +1107,22 @@ parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
 
     gchar *cp;
 
-    if ((cp = strchr(line, '#')))
+    line = g_strstrip(line);
+    if (line[0] == '\0' || line[0] == '#')
+        return -1;
+
+    if ((cp = strchr(line, '#'))) {
+        cp--;
+        while (g_ascii_isspace(*cp)) {
+            cp--;
+        }
         *cp = '\0';
+    }
 
     if ((cp = strtok(line, " \t")) == NULL)
         return -1;
 
-    if (!parse_ether_address(cp, eth, mask, manuf_file))
+    if (!parse_ether_address(cp, eth, mask, accept_mask))
         return -1;
 
     if ((cp = strtok(NULL, " \t")) == NULL)
@@ -1023,6 +1130,14 @@ parse_ether_line(char *line, ether_t *eth, unsigned int *mask,
 
     g_strlcpy(eth->name, cp, MAXNAMELEN);
 
+    if ((cp = strtok(NULL, "")) != NULL)
+    {
+        g_strlcpy(eth->longname, cp, MAXNAMELEN);
+    } else {
+        /* Make the long name the short name */
+        g_strlcpy(eth->longname, eth->name, MAXNAMELEN);
+    }
+
     return 0;
 
 } /* parse_ether_line */
@@ -1048,7 +1163,7 @@ end_ethent(void)
 }
 
 static ether_t *
-get_ethent(unsigned int *mask, const gboolean manuf_file)
+get_ethent(unsigned int *mask, const gboolean accept_mask)
 {
 
     static ether_t eth;
@@ -1059,7 +1174,7 @@ get_ethent(unsigned int *mask, const gboolean manuf_file)
         return NULL;
 
     while (fgetline(&buf, &size, eth_p) >= 0) {
-        if (parse_ether_line(buf, &eth, mask, manuf_file) == 0) {
+        if (parse_ether_line(buf, &eth, mask, accept_mask) == 0) {
             return &eth;
         }
     }
@@ -1068,33 +1183,6 @@ get_ethent(unsigned int *mask, const gboolean manuf_file)
 
 } /* get_ethent */
 
-#if 0
-static ether_t *
-get_ethbyname(const gchar *name)
-{
-    ether_t *eth;
-
-    set_ethent(g_pethers_path);
-
-    while (((eth = get_ethent(NULL, FALSE)) != NULL) && strncmp(name, eth->name, MAXNAMELEN) != 0)
-        ;
-
-    if (eth == NULL) {
-        end_ethent();
-
-        set_ethent(g_ethers_path);
-
-        while (((eth = get_ethent(NULL, FALSE)) != NULL) && strncmp(name, eth->name, MAXNAMELEN) != 0)
-            ;
-
-        end_ethent();
-    }
-
-    return eth;
-
-} /* get_ethbyname */
-#endif
-
 static ether_t *
 get_ethbyaddr(const guint8 *addr)
 {
@@ -1121,7 +1209,8 @@ get_ethbyaddr(const guint8 *addr)
 
 } /* get_ethbyaddr */
 
-static hashmanuf_t *manuf_hash_new_entry(const guint8 *addr, char* name)
+static hashmanuf_t *
+manuf_hash_new_entry(const guint8 *addr, char* name, char* longname)
 {
     int    *manuf_key;
     hashmanuf_t *manuf_value;
@@ -1133,14 +1222,20 @@ static hashmanuf_t *manuf_hash_new_entry(const guint8 *addr, char* name)
     manuf_value = wmem_new(wmem_epan_scope(), hashmanuf_t);
 
     memcpy(manuf_value->addr, addr, 3);
-    manuf_value->status = (name != NULL) ? HASHETHER_STATUS_RESOLVED_NAME : HASHETHER_STATUS_UNRESOLVED;
     if (name != NULL) {
         g_strlcpy(manuf_value->resolved_name, name, MAXNAMELEN);
         manuf_value->status = HASHETHER_STATUS_RESOLVED_NAME;
+        if (longname != NULL) {
+            g_strlcpy(manuf_value->resolved_longname, longname, MAXNAMELEN);
+        }
+        else {
+            g_strlcpy(manuf_value->resolved_longname, name, MAXNAMELEN);
+        }
     }
     else {
         manuf_value->status = HASHETHER_STATUS_UNRESOLVED;
         manuf_value->resolved_name[0] = '\0';
+        manuf_value->resolved_longname[0] = '\0';
     }
     /* Values returned by bytes_to_hexstr_punct() are *not* null-terminated */
     endp = bytes_to_hexstr_punct(manuf_value->hexaddr, addr, sizeof(manuf_value->addr), ':');
@@ -1151,37 +1246,36 @@ static hashmanuf_t *manuf_hash_new_entry(const guint8 *addr, char* name)
 }
 
 static void
-add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name)
+wka_hash_new_entry(const guint8 *addr, char* name)
 {
     guint8 *wka_key;
 
-    /*
-     * XXX - can we use Standard Annotation Language annotations to
-     * note that mask, as returned by parse_ethe)r_address() (and thus
-     * by the routines that call it, and thus passed to us) cannot be > 48,
-     * or is SAL too weak to express that?
-     */
-    if (mask >= 48) {
-        /* This is a well-known MAC address; just add this to the Ethernet
-           hash table */
-        add_eth_name(addr, name);
-        return;
-    }
-
-    if (mask == 0) {
-        /* This is a manufacturer ID; add it to the manufacturer ID hash table */
-        manuf_hash_new_entry(addr, name);
-        return;
-    } /* mask == 0 */
-
-    /* This is a range of well-known addresses; add it to the appropriate
-       well-known-address table, creating that table if necessary. */
-
     wka_key = (guint8 *)wmem_alloc(wmem_epan_scope(), 6);
     memcpy(wka_key, addr, 6);
 
     wmem_map_insert(wka_hashtable, wka_key, wmem_strdup(wmem_epan_scope(), name));
+}
+
+static void
+add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name, gchar *longname)
+{
+    switch (mask)
+    {
+    case 0:
+        /* This is a manufacturer ID; add it to the manufacturer ID hash table */
+        manuf_hash_new_entry(addr, name, longname);
+        break;
 
+    case 48:
+        /* This is a well-known MAC address; add it to the Ethernet hash table */
+        add_eth_name(addr, name);
+        break;
+
+    default:
+        /* This is a range of well-known addresses; add it to the well-known-address table */
+        wka_hash_new_entry(addr, name);
+        break;
+    }
 } /* add_manuf_name */
 
 static hashmanuf_t *
@@ -1221,7 +1315,7 @@ manuf_name_lookup(const guint8 *addr)
     }
 
     /* Add the address as a hex string */
-    return manuf_hash_new_entry(addr, NULL);
+    return manuf_hash_new_entry(addr, NULL, NULL);
 
 } /* manuf_name_lookup */
 
@@ -1284,7 +1378,6 @@ static void
 initialize_ethers(void)
 {
     ether_t *eth;
-    char    *manuf_path;
     guint    mask = 0;
 
     /* hash table initialization */
@@ -1294,32 +1387,52 @@ initialize_ethers(void)
 
     /* Compute the pathname of the ethers file. */
     if (g_ethers_path == NULL) {
-        g_ethers_path = wmem_strdup_printf(wmem_epan_scope(), "%s" G_DIR_SEPARATOR_S "%s",
-                get_systemfile_dir(), ENAME_ETHERS);
+        g_ethers_path = g_build_filename(get_systemfile_dir(), ENAME_ETHERS, NULL);
     }
 
     /* Set g_pethers_path here, but don't actually do anything
-     * with it. It's used in get_ethbyname() and get_ethbyaddr()
+     * with it. It's used in get_ethbyaddr().
      */
     if (g_pethers_path == NULL)
         g_pethers_path = get_persconffile_path(ENAME_ETHERS, FALSE);
 
     /* Compute the pathname of the manuf file */
-    manuf_path = get_datafile_path(ENAME_MANUF);
+    if (g_manuf_path == NULL)
+        g_manuf_path = get_datafile_path(ENAME_MANUF);
 
     /* Read it and initialize the hash table */
-    set_ethent(manuf_path);
-
+    set_ethent(g_manuf_path);
     while ((eth = get_ethent(&mask, TRUE))) {
-        add_manuf_name(eth->addr, mask, eth->name);
+        add_manuf_name(eth->addr, mask, eth->name, eth->longname);
     }
-
     end_ethent();
 
-    g_free(manuf_path);
+    /* Compute the pathname of the wka file */
+    if (g_wka_path == NULL)
+        g_wka_path = get_datafile_path(ENAME_WKA);
+
+    /* Read it and initialize the hash table */
+    set_ethent(g_wka_path);
+    while ((eth = get_ethent(&mask, TRUE))) {
+        add_manuf_name(eth->addr, mask, eth->name, eth->longname);
+    }
+    end_ethent();
 
 } /* initialize_ethers */
 
+static void
+ethers_cleanup(void)
+{
+    g_free(g_ethers_path);
+    g_ethers_path = NULL;
+    g_free(g_pethers_path);
+    g_pethers_path = NULL;
+    g_free(g_manuf_path);
+    g_manuf_path = NULL;
+    g_free(g_wka_path);
+    g_wka_path = NULL;
+}
+
 /* Resolve ethernet address */
 static hashether_t *
 eth_addr_resolve(hashether_t *tp) {
@@ -1339,7 +1452,7 @@ eth_addr_resolve(hashether_t *tp) {
         /* Unknown name.  Try looking for it in the well-known-address
            tables for well-known address ranges smaller than 2^24. */
         mask = 7;
-        for (;;) {
+        do {
             /* Only the topmost 5 bytes participate fully */
             if ((name = wka_name_lookup(addr, mask+40)) != NULL) {
                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x",
@@ -1347,13 +1460,10 @@ eth_addr_resolve(hashether_t *tp) {
                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
                 return tp;
             }
-            if (mask == 0)
-                break;
-            mask--;
-        }
+        } while (mask--);
 
         mask = 7;
-        for (;;) {
+        do {
             /* Only the topmost 4 bytes participate fully */
             if ((name = wka_name_lookup(addr, mask+32)) != NULL) {
                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x",
@@ -1361,13 +1471,10 @@ eth_addr_resolve(hashether_t *tp) {
                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
                 return tp;
             }
-            if (mask == 0)
-                break;
-            mask--;
-        }
+        } while (mask--);
 
         mask = 7;
-        for (;;) {
+        do {
             /* Only the topmost 3 bytes participate fully */
             if ((name = wka_name_lookup(addr, mask+24)) != NULL) {
                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x",
@@ -1375,10 +1482,7 @@ eth_addr_resolve(hashether_t *tp) {
                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
                 return tp;
             }
-            if (mask == 0)
-                break;
-            mask--;
-        }
+        } while (mask--);
 
         /* Now try looking in the manufacturer table. */
         manuf_value = manuf_name_lookup(addr);
@@ -1392,7 +1496,7 @@ eth_addr_resolve(hashether_t *tp) {
         /* Now try looking for it in the well-known-address
            tables for well-known address ranges larger than 2^24. */
         mask = 7;
-        for (;;) {
+        do {
             /* Only the topmost 2 bytes participate fully */
             if ((name = wka_name_lookup(addr, mask+16)) != NULL) {
                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x",
@@ -1401,13 +1505,10 @@ eth_addr_resolve(hashether_t *tp) {
                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
                 return tp;
             }
-            if (mask == 0)
-                break;
-            mask--;
-        }
+        } while (mask--);
 
         mask = 7;
-        for (;;) {
+        do {
             /* Only the topmost byte participates fully */
             if ((name = wka_name_lookup(addr, mask+8)) != NULL) {
                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x",
@@ -1416,12 +1517,10 @@ eth_addr_resolve(hashether_t *tp) {
                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
                 return tp;
             }
-            if (mask == 0)
-                break;
-            mask--;
-        }
+        } while (mask--);
 
-        for (mask = 7; mask > 0; mask--) {
+        mask = 7;
+        do {
             /* Not even the topmost byte participates fully */
             if ((name = wka_name_lookup(addr, mask)) != NULL) {
                 g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x:%02x:%02x:%02x",
@@ -1430,7 +1529,7 @@ eth_addr_resolve(hashether_t *tp) {
                 tp->status = HASHETHER_STATUS_RESOLVED_DUMMY;
                 return tp;
             }
-        }
+        } while (--mask); /* Work down to the last bit */
 
         /* No match whatsoever. */
         set_address(&ether_addr, AT_ETHER, 6, addr);
@@ -1489,6 +1588,7 @@ eth_name_lookup(const guint8 *addr, const gboolean resolve)
     hashether_t  *tp;
 
     tp = (hashether_t *)wmem_map_lookup(eth_hashtable, addr);
+
     if (tp == NULL) {
         tp = eth_hash_new_entry(addr, resolve);
     } else {
@@ -1501,41 +1601,6 @@ eth_name_lookup(const guint8 *addr, const gboolean resolve)
 
 } /* eth_name_lookup */
 
-static guint8 *
-eth_addr_lookup(const gchar *name _U_)
-{
-#if 0
-    /* XXX Do we need reverse lookup??? */
-    ether_t      *eth;
-    hashether_t  *tp;
-    hashether_t **table = eth_table;
-    gint          i;
-
-    /* to be optimized (hash table from name to addr) */
-    for (i = 0; i < HASHETHSIZE; i++) {
-        tp = table[i];
-        while (tp) {
-            if (strcmp(tp->resolved_name, name) == 0)
-                return tp->addr;
-            tp = tp->next;
-        }
-    }
-
-    /* not in hash table : performs a file lookup */
-
-    if ((eth = get_ethbyname(name)) == NULL)
-        return NULL;
-
-    /* add new entry in hash table */
-
-    tp = add_eth_name(eth->addr, name);
-
-    return tp->addr;
-#endif
-    return NULL;
-
-} /* eth_addr_lookup */
-
 
 /* IPXNETS */
 static int
@@ -1630,34 +1695,6 @@ get_ipxnetent(void)
 
 } /* get_ipxnetent */
 
-/* Unused ??? */
-#if 0
-static ipxnet_t *
-get_ipxnetbyname(const gchar *name)
-{
-    ipxnet_t *ipxnet;
-
-    set_ipxnetent(g_ipxnets_path);
-
-    while (((ipxnet = get_ipxnetent()) != NULL) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
-        ;
-
-    if (ipxnet == NULL) {
-        end_ipxnetent();
-
-        set_ipxnetent(g_pipxnets_path);
-
-        while (((ipxnet = get_ipxnetent()) != NULL) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
-            ;
-
-        end_ipxnetent();
-    }
-
-    return ipxnet;
-
-} /* get_ipxnetbyname */
-#endif
-
 static ipxnet_t *
 get_ipxnetbyaddr(guint32 addr)
 {
@@ -1698,7 +1735,7 @@ initialize_ipxnets(void)
     }
 
     /* Set g_pipxnets_path here, but don't actually do anything
-     * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr()
+     * with it. It's used in get_ipxnetbyaddr().
      */
     if (g_pipxnets_path == NULL)
         g_pipxnets_path = get_persconffile_path(ENAME_IPXNETS, FALSE);
@@ -1709,37 +1746,10 @@ static void
 ipx_name_lookup_cleanup(void)
 {
     ipxnet_hash_table = NULL;
+    g_free(g_pipxnets_path);
+    g_pipxnets_path = NULL;
 }
 
-#if 0
-static hashipxnet_t *
-add_ipxnet_name(guint addr, const gchar *name)
-{
-    hashipxnet_t *tp;
-
-    tp = (hashipxnet_t   *)g_hash_table_lookup(ipxnet_hash_table, &addr);
-    if (tp) {
-        g_strlcpy(tp->name, name, MAXNAMELEN);
-    } else {
-        int *key;
-
-        key = (int *)g_new(int, 1);
-        *key = addr;
-        tp = g_new(hashipxnet_t,1);
-        g_strlcpy(tp->name, name, MAXNAMELEN);
-        g_hash_table_insert(ipxnet_hash_table, key, tp);
-    }
-
-    tp->addr = addr;
-    g_strlcpy(tp->name, name, MAXNAMELEN);
-    tp->next = NULL;
-    new_resolved_objects = TRUE;
-
-    return tp;
-
-} /* add_ipxnet_name */
-#endif
-
 static gchar *
 ipxnet_name_lookup(wmem_allocator_t *allocator, const guint addr)
 {
@@ -1774,46 +1784,6 @@ ipxnet_name_lookup(wmem_allocator_t *allocator, const guint addr)
 
 } /* ipxnet_name_lookup */
 
-static guint
-ipxnet_addr_lookup(const gchar *name _U_, gboolean *success)
-{
-    *success = FALSE;
-    return 0;
-#if 0
-    /* XXX Do we need reverse lookup??? */
-    ipxnet_t *ipxnet;
-    hashipxnet_t *tp;
-    hashipxnet_t **table = ipxnet_table;
-    int i;
-
-    /* to be optimized (hash table from name to addr) */
-    for (i = 0; i < HASHIPXNETSIZE; i++) {
-        tp = table[i];
-        while (tp) {
-            if (strcmp(tp->name, name) == 0) {
-                *success = TRUE;
-                return tp->addr;
-            }
-            tp = tp->next;
-        }
-    }
-
-    /* not in hash table : performs a file lookup */
-
-    if ((ipxnet = get_ipxnetbyname(name)) == NULL) {
-        *success = FALSE;
-        return 0;
-    }
-
-    /* add new entry in hash table */
-
-    tp = add_ipxnet_name(ipxnet->addr, name);
-
-    *success = TRUE;
-    return tp->addr;
-#endif
-} /* ipxnet_addr_lookup */
-
 /* VLANS */
 static int
 parse_vlan_line(char *line, vlan_t *vlan)
@@ -1908,8 +1878,8 @@ initialize_vlans(void)
     g_assert(vlan_hash_table == NULL);
     vlan_hash_table = wmem_map_new(wmem_epan_scope(), g_int_hash, g_int_equal);
 
-    /* Set g_pipxnets_path here, but don't actually do anything
-     * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr()
+    /* Set g_pvlan_path here, but don't actually do anything
+     * with it. It's used in get_vlannamebyid()
      */
     if (g_pvlan_path == NULL)
         g_pvlan_path = get_persconffile_path(ENAME_VLANS, FALSE);
@@ -1920,6 +1890,8 @@ static void
 vlan_name_lookup_cleanup(void)
 {
     vlan_hash_table = NULL;
+    g_free(g_pvlan_path);
+    g_pvlan_path = NULL;
 }
 
 static const gchar *
@@ -1966,7 +1938,7 @@ read_hosts_file (const char *hostspath, gboolean store_entries)
     gchar *cp;
     union {
         guint32 ip4_addr;
-        struct e_in6_addr ip6_addr;
+        ws_in6_addr ip6_addr;
     } host_addr;
     gboolean is_ipv6, entry_found = FALSE;
 
@@ -2041,7 +2013,7 @@ add_ip_name_from_string (const char *addr, const char *name)
 {
     union {
         guint32 ip4_addr;
-        struct e_in6_addr ip6_addr;
+        ws_in6_addr ip6_addr;
     } host_addr;
     gboolean is_ipv6;
     resolved_ipv4_t *resolved_ipv4_entry;
@@ -2079,7 +2051,7 @@ ipv4_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user
     addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
     hashipv4_t *ipv4_hash_table_entry = (hashipv4_t *)value;
 
-    if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == RESOLVED_ADDRESS_USED) {
+    if ((ipv4_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
         lists->ipv4_addr_list = g_list_prepend(lists->ipv4_addr_list, ipv4_hash_table_entry);
     }
 
@@ -2095,7 +2067,7 @@ ipv6_hash_table_resolved_to_list(gpointer key _U_, gpointer value, gpointer user
     addrinfo_lists_t *lists = (addrinfo_lists_t*)user_data;
     hashipv6_t *ipv6_hash_table_entry = (hashipv6_t *)value;
 
-    if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == RESOLVED_ADDRESS_USED) {
+    if ((ipv6_hash_table_entry->flags & USED_AND_RESOLVED_MASK) == USED_AND_RESOLVED_MASK) {
         lists->ipv6_addr_list = g_list_prepend (lists->ipv6_addr_list, ipv6_hash_table_entry);
     }
 
@@ -2270,8 +2242,6 @@ subnet_entry_set(guint32 subnet_addr, const guint8 mask_length, const gchar* nam
 
     tp->next = NULL;
     tp->addr = subnet_addr;
-    /* Clear DUMMY_ADDRESS_ENTRY */
-    tp->flags &= ~DUMMY_ADDRESS_ENTRY; /*Never used again...*/
     g_strlcpy(tp->name, name, MAXNAMELEN); /* This is longer than subnet names can actually be */
     have_subnet_entry = TRUE;
 }
@@ -2290,9 +2260,18 @@ subnet_name_lookup_init(void)
         subnet_length_entries[i].mask = g_htonl(ip_get_subnet_mask(length));
     }
 
-    subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE);
-    if (!read_subnets_file(subnetspath) && errno != ENOENT) {
-        report_open_failure(subnetspath, errno, FALSE);
+    /* Check profile directory before personal configuration */
+    subnetspath = get_persconffile_path(ENAME_SUBNETS, TRUE);
+    if (!read_subnets_file(subnetspath)) {
+        if (errno != ENOENT) {
+            report_open_failure(subnetspath, errno, FALSE);
+        }
+
+        g_free(subnetspath);
+        subnetspath = get_persconffile_path(ENAME_SUBNETS, FALSE);
+        if (!read_subnets_file(subnetspath) && errno != ENOENT) {
+            report_open_failure(subnetspath, errno, FALSE);
+        }
     }
     g_free(subnetspath);
 
@@ -2306,6 +2285,151 @@ subnet_name_lookup_init(void)
     g_free(subnetspath);
 }
 
+/* SS7 PC Name Resolution Portion */
+static hashss7pc_t *
+new_ss7pc(const guint8 ni, const guint32 pc)
+{
+    hashss7pc_t *tp = wmem_new(wmem_epan_scope(), hashss7pc_t);
+    tp->id = (ni<<24) + (pc&0xffffff);
+    tp->pc_addr[0] = '\0';
+    tp->name[0] = '\0';
+
+    return tp;
+}
+
+static hashss7pc_t *
+host_lookup_ss7pc(const guint8 ni, const guint32 pc)
+{
+    hashss7pc_t * volatile tp;
+    guint32 id;
+
+    id = (ni<<24) + (pc&0xffffff);
+
+    tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
+    if (tp == NULL) {
+        tp = new_ss7pc(ni, pc);
+        wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
+    }
+
+    return tp;
+}
+
+void fill_unresolved_ss7pc(const gchar * pc_addr, const guint8 ni, const guint32 pc)
+{
+    hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
+
+    g_strlcpy(tp->pc_addr, pc_addr, MAXNAMELEN);
+}
+
+const gchar *
+get_hostname_ss7pc(const guint8 ni, const guint32 pc)
+{
+    hashss7pc_t *tp = host_lookup_ss7pc(ni, pc);
+
+    /* never resolved yet*/
+    if (tp->pc_addr[0] == '\0')
+        return tp->pc_addr;
+
+    /* Don't have name in file */
+    if (tp->name[0] == '\0')
+        return tp->pc_addr;
+
+    if (!gbl_resolv_flags.ss7pc_name)
+        return tp->pc_addr;
+
+    return tp->name;
+}
+
+static void
+add_ss7pc_name(const guint8 ni, guint32 pc, const gchar *name)
+{
+    hashss7pc_t *tp;
+    guint32 id;
+
+    if (!name || name[0] == '\0')
+        return;
+
+    id = (ni<<24) + (pc&0xffffff);
+    tp = (hashss7pc_t *)wmem_map_lookup(ss7pc_hash_table, GUINT_TO_POINTER(id));
+    if (!tp) {
+        tp = new_ss7pc(ni, pc);
+        wmem_map_insert(ss7pc_hash_table, GUINT_TO_POINTER(id), tp);
+    }
+
+    if (g_ascii_strcasecmp(tp->name, name)) {
+        g_strlcpy(tp->name, name, MAXNAMELEN);
+    }
+}
+
+static gboolean
+read_ss7pcs_file(const char *ss7pcspath)
+{
+    FILE *hf;
+    char *line = NULL;
+    int size = 0;
+    gchar *cp;
+    guint8 ni;
+    guint32 pc;
+    gboolean entry_found = FALSE;
+
+    /*
+    *  File format is Network Indicator (decimal)<dash>Point Code (Decimal)<tab/space>Hostname
+    */
+    if ((hf = ws_fopen(ss7pcspath, "r")) == NULL)
+        return FALSE;
+
+    while (fgetline(&line, &size, hf) >= 0) {
+        if ((cp = strchr(line, '#')))
+            *cp = '\0';
+
+        if ((cp = strtok(line, "-")) == NULL)
+            continue; /*no ni-pc separator*/
+        if (!ws_strtou8(cp, NULL, &ni))
+            continue;
+        if (ni > 3)
+             continue;
+
+        if ((cp = strtok(NULL, " \t")) == NULL)
+            continue; /* no tokens for pc and name */
+        if (!ws_strtou32(cp, NULL, &pc))
+            continue;
+        if (pc >> 24 > 0)
+            continue;
+
+        if ((cp = strtok(NULL, " \t")) == NULL)
+            continue; /* no host name */
+
+        entry_found = TRUE;
+        add_ss7pc_name(ni, pc, cp);
+    }
+    wmem_free(wmem_epan_scope(), line);
+
+    fclose(hf);
+    return entry_found ? TRUE : FALSE;
+}
+
+static void
+ss7pc_name_lookup_init(void)
+{
+    char *ss7pcspath;
+
+    g_assert(ss7pc_hash_table == NULL);
+
+    ss7pc_hash_table = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal);
+
+    /*
+     * Load the user's ss7pcs file
+     */
+    ss7pcspath = get_persconffile_path(ENAME_SS7PCS, TRUE);
+    if (!read_ss7pcs_file(ss7pcspath) && errno != ENOENT) {
+        report_open_failure(ss7pcspath, errno, FALSE);
+    }
+    g_free(ss7pcspath);
+}
+
+/* SS7PC Name Resolution End*/
+
+
 /*
  *  External Functions
  */
@@ -2315,7 +2439,8 @@ addr_resolve_pref_init(module_t *nameres)
 {
     prefs_register_bool_preference(nameres, "mac_name",
             "Resolve MAC addresses",
-            "Resolve Ethernet MAC address to manufacturer names",
+            "Resolve Ethernet MAC addresses to host names from the preferences"
+            " or system's Ethers file, or to a manufacturer based name.",
             &gbl_resolv_flags.mac_name);
 
     prefs_register_bool_preference(nameres, "transport_name",
@@ -2370,13 +2495,18 @@ addr_resolve_pref_init(module_t *nameres)
 
     prefs_register_bool_preference(nameres, "vlan_name",
             "Resolve VLAN IDs",
-            "Resolve VLAN IDs to describing names."
-            " To do so you need a file called vlans in your"
-            " user preference directory. Format of the file is:"
-            "  \"ID<Tab>Name\""
-            " One line per VLAN.",
+            "Resolve VLAN IDs to network names from the preferences \"vlans\" file."
+            " Format of the file is: \"ID<Tab>Name\"."
+            " One line per VLAN, e.g.: 1 Management",
             &gbl_resolv_flags.vlan_name);
 
+    prefs_register_bool_preference(nameres, "ss7_pc_name",
+            "Resolve SS7 PCs",
+            "Resolve SS7 Point Codes to node names from the profiles \"ss7pcs\" file."
+            " Format of the file is: \"Network_Indicator<Dash>PC_Decimal<Tab>Name\"."
+            " One line per Point Code, e.g.: 2-1234 MyPointCode1",
+            &gbl_resolv_flags.ss7pc_name);
+
 }
 
 void
@@ -2387,6 +2517,7 @@ disable_name_resolution(void) {
     gbl_resolv_flags.dns_pkt_addr_resolution            = FALSE;
     gbl_resolv_flags.use_external_net_name_resolver     = FALSE;
     gbl_resolv_flags.vlan_name                          = FALSE;
+    gbl_resolv_flags.ss7pc_name                         = FALSE;
 }
 
 #ifdef HAVE_C_ARES
@@ -2415,7 +2546,7 @@ host_name_lookup_process(void) {
                     c_ares_ghba_cb, caqm);
             async_dns_in_flight++;
         } else if (caqm->family == AF_INET6) {
-            ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(struct e_in6_addr),
+            ares_gethostbyaddr(ghba_chan, &caqm->addr.ip6, sizeof(ws_in6_addr),
                     AF_INET6, c_ares_ghba_cb, caqm);
             async_dns_in_flight++;
         }
@@ -2488,7 +2619,7 @@ get_hostname(const guint addr)
 /* -------------------------- */
 
 const gchar *
-get_hostname6(const struct e_in6_addr *addr)
+get_hostname6(const ws_in6_addr *addr)
 {
     /* XXX why do we call this if we're not resolving? To create hash entries?
      * Why?
@@ -2531,7 +2662,7 @@ add_ipv4_name(const guint addr, const gchar *name)
 
 /* -------------------------- */
 void
-add_ipv6_name(const struct e_in6_addr *addrp, const gchar *name)
+add_ipv6_name(const ws_in6_addr *addrp, const gchar *name)
 {
     hashipv6_t *tp;
 
@@ -2544,9 +2675,9 @@ add_ipv6_name(const struct e_in6_addr *addrp, const gchar *name)
 
     tp = (hashipv6_t *)wmem_map_lookup(ipv6_hash_table, addrp);
     if (!tp) {
-        struct e_in6_addr *addr_key;
+        ws_in6_addr *addr_key;
 
-        addr_key = wmem_new(wmem_epan_scope(), struct e_in6_addr);
+        addr_key = wmem_new(wmem_epan_scope(), ws_in6_addr);
         tp = new_ipv6(addrp);
         memcpy(addr_key, addrp, 16);
         wmem_map_insert(ipv6_hash_table, addr_key, tp);
@@ -2653,6 +2784,8 @@ host_name_lookup_init(void)
     subnet_name_lookup_init();
 
     add_manually_resolved();
+
+    ss7pc_name_lookup_init();
 }
 
 void
@@ -2666,6 +2799,7 @@ host_name_lookup_cleanup(void)
     ipxnet_hash_table = NULL;
     ipv4_hash_table = NULL;
     ipv6_hash_table = NULL;
+    ss7pc_hash_table = NULL;
 
     for(i = 0; i < SUBNETLENGTHSIZE; ++i) {
         if (subnet_length_entries[i].subnet_addresses != NULL) {
@@ -2806,7 +2940,7 @@ get_ether_name_if_known(const guint8 *addr)
     g_assert(tp != NULL);
 
     if (tp->status == HASHETHER_STATUS_RESOLVED_NAME) {
-        /* Name is from an ethers file (or is a "well-known" MAC address name from the manuf file) */
+        /* Name is from an ethers file */
         return tp->resolved_name;
     }
     else {
@@ -2815,15 +2949,6 @@ get_ether_name_if_known(const guint8 *addr)
     }
 }
 
-guint8 *
-get_ether_addr(const gchar *name)
-{
-
-    /* force resolution (do not check gbl_resolv_flags) */
-    return eth_addr_lookup(name);
-
-} /* get_ether_addr */
-
 void
 add_ether_byip(const guint ip, const guint8 *eth)
 {
@@ -2869,20 +2994,6 @@ get_ipxnet_name(wmem_allocator_t *allocator, const guint32 addr)
 
 } /* get_ipxnet_name */
 
-guint32
-get_ipxnet_addr(const gchar *name, gboolean *known)
-{
-    guint32 addr;
-    gboolean success;
-
-    /* force resolution (do not check gbl_resolv_flags) */
-    addr =  ipxnet_addr_lookup(name, &success);
-
-    *known = success;
-    return addr;
-
-} /* get_ipxnet_addr */
-
 gchar *
 get_vlan_name(wmem_allocator_t *allocator, const guint16 id)
 {
@@ -2908,17 +3019,6 @@ get_manuf_name(const guint8 *addr)
 
 } /* get_manuf_name */
 
-const gchar *
-uint_get_manuf_name(const guint oid)
-{
-    guint8 addr[3];
-
-    addr[0] = (oid >> 16) & 0xFF;
-    addr[1] = (oid >> 8) & 0xFF;
-    addr[2] = (oid >> 0) & 0xFF;
-    return get_manuf_name(addr);
-}
-
 const gchar *
 tvb_get_manuf_name(tvbuff_t *tvb, gint offset)
 {
@@ -2942,11 +3042,11 @@ get_manuf_name_if_known(const guint8 *addr)
     manuf_key = manuf_key | oct;
 
     manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, &manuf_key);
-    if ((manuf_value == NULL) || (manuf_value->status != HASHETHER_STATUS_UNRESOLVED)) {
+    if ((manuf_value == NULL) || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
         return NULL;
     }
 
-    return manuf_value->resolved_name;
+    return manuf_value->resolved_longname;
 
 } /* get_manuf_name_if_known */
 
@@ -2956,11 +3056,11 @@ uint_get_manuf_name_if_known(const guint manuf_key)
     hashmanuf_t *manuf_value;
 
     manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, &manuf_key);
-    if ((manuf_value == NULL) || (manuf_value->status != HASHETHER_STATUS_UNRESOLVED)) {
+    if ((manuf_value == NULL) || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) {
         return NULL;
     }
 
-    return manuf_value->resolved_name;
+    return manuf_value->resolved_longname;
 }
 
 const gchar *
@@ -2971,7 +3071,7 @@ tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset)
 
 char* get_hash_manuf_resolved_name(hashmanuf_t* manuf)
 {
-    return manuf->resolved_name;
+    return manuf->resolved_longname;
 }
 
 gchar *
@@ -2998,18 +3098,7 @@ eui64_to_display(wmem_allocator_t *allocator, const guint64 addr_eui64)
 #ifdef HAVE_C_ARES
 #define GHI_TIMEOUT (250 * 1000)
 static void
-c_ares_ghi_cb(
-        void *arg,
-        int status,
-#if ( ( ARES_VERSION_MAJOR < 1 )                                     \
-    || ( 1 == ARES_VERSION_MAJOR && ARES_VERSION_MINOR < 5 ) )
-        struct hostent *hp
-#else
-        int timeouts _U_,
-        struct hostent *hp
-#endif
-        ) {
-
+c_ares_ghi_cb(void *arg, int status, int timeouts _U_, struct hostent *hp) {
     /*
      * XXX - If we wanted to be really fancy we could cache results here and
      * look them up in get_host_ipaddr* below.
@@ -3022,14 +3111,12 @@ c_ares_ghi_cb(
 }
 #endif /* HAVE_C_ARES */
 
-/* Translate a string, assumed either to be a dotted-quad IP address or
- * a host name, to a numeric IP address.  Return TRUE if we succeed and
- * set "*addrp" to that numeric IP address; return FALSE if we fail.
- * Used more in the dfilter parser rather than in packet dissectors */
+/* Translate a string, assumed either to be a dotted-quad IPv4 address or
+ * a host name, to a numeric IPv4 address.  Return TRUE if we succeed and
+ * set "*addrp" to that numeric IPv4 address; return FALSE if we fail. */
 gboolean
 get_host_ipaddr(const char *host, guint32 *addrp)
 {
-    struct in_addr      ipaddr;
 #ifdef HAVE_C_ARES
     struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
     int nfds;
@@ -3038,11 +3125,11 @@ get_host_ipaddr(const char *host, guint32 *addrp)
 #endif
 
     /*
-     * don't change it to inet_pton(AF_INET), they are not 100% compatible.
-     * inet_pton(AF_INET) does not support hexadecimal notation nor
-     * less-than-4 octet notation.
+     * XXX - are there places where this is used to translate something
+     * that's *only* supposed to be an IPv4 address, and where it
+     * *shouldn't* translate host names?
      */
-    if (!inet_aton(host, &ipaddr)) {
+    if (!ws_inet_pton4(host, addrp)) {
 
         /* It's not a valid dotted-quad IP address; is it a valid
          * host name?
@@ -3081,28 +3168,18 @@ get_host_ipaddr(const char *host, guint32 *addrp)
         }
         return FALSE;
 #endif
-    } else {
-        /* Does the string really contain dotted-quad IP?
-         * Check against inet_atons that accept strings such as
-         * "130.230" as valid addresses and try to convert them
-         * to some form of a classful (host.net) notation.
-         */
-        unsigned int a0, a1, a2, a3;
-        if (sscanf(host, "%u.%u.%u.%u", &a0, &a1, &a2, &a3) != 4)
-            return FALSE;
     }
 
-    *addrp = ipaddr.s_addr;
     return TRUE;
 }
 
 /*
- * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address.
- * Return TRUE if we succeed and set "*addrp" to that numeric IP address;
+ * Translate IPv6 numeric address or FQDN hostname into binary IPv6 address.
+ * Return TRUE if we succeed and set "*addrp" to that numeric IPv6 address;
  * return FALSE if we fail.
  */
 gboolean
-get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
+get_host_ipaddr6(const char *host, ws_in6_addr *addrp)
 {
 #ifdef HAVE_C_ARES
     struct timeval tv = { 0, GHI_TIMEOUT }, *tvp;
@@ -3116,6 +3193,10 @@ get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
 
     /* It's not a valid dotted-quad IP address; is it a valid
      * host name?
+     *
+     * XXX - are there places where this is used to translate something
+     * that's *only* supposed to be an IPv6 address, and where it
+     * *shouldn't* translate host names?
      */
 
     /* If we're not allowed to do name resolution, don't do name
@@ -3131,7 +3212,7 @@ get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
     if (!async_dns_initialized || name_resolve_concurrency < 1) {
         return FALSE;
     }
-    ahe.addr_size = (int) sizeof (struct e_in6_addr);
+    ahe.addr_size = (int) sizeof (ws_in6_addr);
     ahe.copied = 0;
     ahe.addrp = addrp;
     ares_gethostbyname(ghbn_chan, host, AF_INET6, c_ares_ghi_cb, &ahe);
@@ -3210,6 +3291,7 @@ addr_resolv_init(void)
     initialize_ethers();
     initialize_ipxnets();
     initialize_vlans();
+    initialize_enterprises();
     /* host name initialization is done on a per-capture-file basis */
     /*host_name_lookup_init();*/
 }
@@ -3220,7 +3302,9 @@ addr_resolv_cleanup(void)
 {
     vlan_name_lookup_cleanup();
     service_name_lookup_cleanup();
+    ethers_cleanup();
     ipx_name_lookup_cleanup();
+    enterprises_cleanup();
     /* host name initialization is done on a per-capture-file basis */
     /*host_name_lookup_cleanup();*/
 }
@@ -3234,7 +3318,7 @@ str_to_ip(const char *str, void *dst)
 gboolean
 str_to_ip6(const char *str, void *dst)
 {
-    return ws_inet_pton6(str, (struct e_in6_addr *)dst);
+    return ws_inet_pton6(str, (ws_in6_addr *)dst);
 }
 
 /*