Enable IPX network name resolution by providing for an /etc/ipxnets
authorgram <gram@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 21 Nov 1999 16:32:23 +0000 (16:32 +0000)
committergram <gram@f5534014-38df-0310-8fa8-9805f1628bb7>
Sun, 21 Nov 1999 16:32:23 +0000 (16:32 +0000)
and a $HOME/.ethereal/ipxnets file. get_ipxnet_name() and other functions,
similar to get_ether_name() and friends, have been added.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@1085 f5534014-38df-0310-8fa8-9805f1628bb7

doc/ethereal.pod.template
packet-ipx.c
proto.c
resolv.c
resolv.h

index 515a0c65495576077d66b96b7c699c627a05ef56..4b4f76b442511da50d9221e5ffe6275d11b7c412 100644 (file)
@@ -617,8 +617,29 @@ the display filter. The type of the field is also given.
 =head1 FILES
 
 B</etc/ethers> is consulted to correlate 6-byte hardware addresses to names. If an address is not
-found in B</etc/ethers>, the
-B<$HOME/.ethereal/ethers> file is consulted next.
+found in B</etc/ethers>, the B<$HOME/.ethereal/ethers> file is consulted next. Each line
+contains one hardware address and name, separated by whitespace.
+The digits of the hardware address are separated by either a colon (:), a dash (-), or
+a period (.). The following three lines are valid lines of an ethers file:
+
+  ff:ff:ff:ff:ff:ff          Broadcast
+  c0-00-ff-ff-ff-ff          TR_broadcast
+  00.00.00.00.00.00          Zero_broadcast
+
+B</usr/local/etc/manuf> matches the 3-byte vendor portion of a 6-byte hardware address with
+the manufacturer's name. The format of the file is the same as the B</etc/ethers> file,
+except that each address is three bytes instead of six.
+
+B</etc/ipxnets> and B<$HOME/.ethereal/ipxnets> correlate 4-byte IPX network numbers to names.
+The format is the same as the B</etc/ethers> file, except that each address if four bytes
+instead of six. Additionally, the address can be represented a single hexadecimal number,
+as is more common in the IPX world, rather than four hex octets. For example, these four
+lines are valid lines of an ipxnets file.
+
+  C0.A8.2C.00              HR
+  c0-a8-1c-00              CEO
+  00:00:BE:EF              IT_Server1
+  110f                     FileServer3
 
 =head1 SEE ALSO
 
index 0f9af48a206c673bf19aea7f6e4c62227ea86e14..70065cc7346ec64ad856930513132c829fad9a9e 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for NetWare's IPX
  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
  *
- * $Id: packet-ipx.c,v 1.34 1999/11/20 05:35:13 gram Exp $
+ * $Id: packet-ipx.c,v 1.35 1999/11/21 16:32:14 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@unicom.net>
@@ -268,10 +268,10 @@ ipx_addr_to_str(guint32 net, const guint8 *ad)
        name = get_ether_name_if_known(ad);
 
        if (name) {
-               sprintf(cur, "%X.%s", net, name);
+               sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
        }
        else {
-               sprintf(cur, "%X.%s", net, ether_to_str_punct(ad, '\0'));
+               sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
        }
        return cur;
 }
@@ -286,7 +286,6 @@ dissect_ipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
        int             len;
        guint8          *ipx_snode, *ipx_dnode, *ipx_snet, *ipx_dnet;
 
-       gchar           *str_dnet, *str_snet;
        guint16         ipx_dsocket, ipx_ssocket;
        dissect_func_t  *dissect;
        guint32         ipx_dnet_val, ipx_snet_val;
@@ -294,8 +293,6 @@ dissect_ipx(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
        /* Calculate here for use in pinfo and in tree */
        ipx_dnet = (guint8*)&pd[offset+6];
        ipx_snet = (guint8*)&pd[offset+18];
-       str_dnet = ipxnet_to_string(ipx_dnet);
-       str_snet = ipxnet_to_string(ipx_snet);
        ipx_dnet_val = pntohl(ipx_dnet);
        ipx_snet_val = pntohl(ipx_snet);
        ipx_dsocket = pntohs(&pd[offset+16]);
diff --git a/proto.c b/proto.c
index feeb458dcd126cc788bcf24d14227211c019931a..6aedb1bada3dea55ba62890a9b9f6bd61e9bdc04 100644 (file)
--- a/proto.c
+++ b/proto.c
@@ -1,7 +1,7 @@
 /* proto.c
  * Routines for protocol tree
  *
- * $Id: proto.c,v 1.49 1999/11/16 11:43:06 guy Exp $
+ * $Id: proto.c,v 1.50 1999/11/21 16:32:15 gram Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -610,7 +610,8 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
 
                case FT_IPXNET:
                        snprintf(label_str, ITEM_LABEL_LENGTH,
-                               "%s: 0x%08X", fi->hfinfo->name, fi->value.numeric);
+                               "%s: 0x%08X (%s)", fi->hfinfo->name,
+                               fi->value.numeric, get_ipxnet_name(fi->value.numeric));
                        break;
 
                case FT_ETHER:
index 82f0595bf2a0ff721691aee8e70cfafc5de4567b..c5d0be1c53b07d422fd37a3d81085902abf7b60a 100644 (file)
--- a/resolv.c
+++ b/resolv.c
@@ -1,7 +1,7 @@
 /* resolv.c
  * Routines for network object lookup
  *
- * $Id: resolv.c,v 1.19 1999/11/20 06:05:56 gram Exp $
+ * $Id: resolv.c,v 1.20 1999/11/21 16:32:16 gram Exp $
  *
  * Laurent Deniel <deniel@worldnet.fr>
  *
 
 #include "packet.h"
 #include "packet-ipv6.h"
+#include "packet-ipx.h"
 #include "globals.h"
 #include "resolv.h"
 
 #define MAXMANUFLEN    9       /* max vendor name length with ending '\0' */
 #define HASHETHSIZE    1024
 #define HASHHOSTSIZE   1024
+#define HASHIPXNETSIZE 256
 #define HASHMANUFSIZE   256
 #define HASHPORTSIZE   256
 
@@ -90,6 +92,10 @@ typedef struct hashname {
   struct hashname      *next;
 } hashname_t;
 
+/* hash table used for IPX network lookup */
+
+typedef struct hashname hashipxnet_t;
+
 /* hash tables used for ethernet and manufacturer lookup */
 
 typedef struct hashmanuf {
@@ -113,13 +119,23 @@ typedef struct _ether
   char                         name[MAXNAMELEN];
 } ether_t;
 
+/* internal ipxnet type */
+
+typedef struct _ipxnet
+{
+  u_int                        addr;
+  char                         name[MAXNAMELEN];
+} ipxnet_t;
+
 static hashname_t      *host_table[HASHHOSTSIZE];
 static hashname_t      *udp_port_table[HASHPORTSIZE];
 static hashname_t      *tcp_port_table[HASHPORTSIZE];
 static hashether_t     *eth_table[HASHETHSIZE];
 static hashmanuf_t     *manuf_table[HASHMANUFSIZE];
+static hashipxnet_t    *ipxnet_table[HASHIPXNETSIZE];
 
 static int             eth_resolution_initialized = 0;
+static int             ipxnet_resolution_initialized = 0;
 
 /*
  *  Global variables (can be changed in GUI sections)
@@ -129,6 +145,8 @@ int g_resolving_actif = 1;          /* routines are active by default */
 
 gchar *g_ethers_path  = EPATH_ETHERS;
 gchar *g_pethers_path = NULL;          /* "$HOME"/EPATH_PERSONAL_ETHERS    */
+gchar *g_ipxnets_path  = EPATH_IPXNETS;
+gchar *g_pipxnets_path = NULL;         /* "$HOME"/EPATH_PERSONAL_IPXNETS   */
 gchar *g_manuf_path   = EPATH_MANUF;   /* may only be changed before the   */
                                        /* first resolving call             */
 
@@ -373,7 +391,8 @@ static int parse_ether_line(char *line, ether_t *eth, int six_bytes)
   /*
    *  See man ethers(4) for /etc/ethers file format
    *  (not available on all systems).
-   *  We allow both ethernet address separators (':' and '-').
+   *  We allow both ethernet address separators (':' and '-'),
+   *  as well as Ethereal's '.' separator.
    */
 
   gchar *cp;
@@ -679,75 +698,278 @@ static u_char *eth_name_lookup(const u_char *addr)
 
 } /* eth_name_lookup */
 
-/* Look for an ether name in the hash, and return it if found.
- * If it's not found, simply return NULL. We DO NOT make a new
- * hash entry for it with the hex digits turned into a string.
- */
-u_char *get_ether_name_if_known(const u_char *addr)
+static u_char *eth_addr_lookup(u_char *name)
 {
+  ether_t *eth;
   hashether_t *tp;
   hashether_t **table = eth_table;
-  int i,j;
+  int i;
 
-  /* Initialize ether structs if we're the first
-   * ether-related function called */
-  if (!g_resolving_actif)
+  /* to be optimized (hash table from name to addr) */
+  for (i = 0; i < HASHETHSIZE; i++) {
+    tp = table[i];
+    while (tp) {
+      if (strcmp(tp->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;
+
+} /* eth_addr_lookup */
+
+
+/* IPXNETS */
+static int parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
+{
+  /*
+   *  We allow three address separators (':', '-', and '.'),
+   *  as well as no separators
+   */
+
+  gchar                *cp;
+  guint32      a, a0, a1, a2, a3;
+  gboolean     found_single_number = FALSE;
+    
+  if ((cp = strchr(line, '#')))
+    *cp = '\0';
   
-  if (!eth_resolution_initialized) {
-    initialize_ethers();
-    eth_resolution_initialized = 1;
+  if ((cp = strtok(line, " \t\n")) == NULL)
+    return -1;
+
+  /* Either fill a0,a1,a2,a3 and found_single_number is FALSE,
+   * fill a and found_single_number is TRUE,
+   * or return -1
+   */
+  if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
+    if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
+      if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
+        if (sscanf(cp, "%x", &a) == 1) {
+         found_single_number = TRUE;
+       }
+       else {
+         return -1;
+       }
+      }
+    }
   }
 
-  j = (addr[2] << 8) | addr[3];
-  i = (addr[4] << 8) | addr[5];
+  if ((cp = strtok(NULL, " \t\n")) == NULL)
+    return -1;
 
-  tp = table[ (i ^ j) & (HASHETHSIZE - 1)];
+  if (found_single_number) {
+       ipxnet->addr = a;
+  }
+  else {
+       ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
+  }
+
+  strncpy(ipxnet->name, cp, MAXNAMELEN);
+  ipxnet->name[MAXNAMELEN-1] = '\0';
+
+  return 0;
+
+} /* parse_ipxnets_line */
+
+static FILE *ipxnet_p = NULL;
+
+static void set_ipxnetent(char *path)
+{
+  if (ipxnet_p)
+    rewind(ipxnet_p);
+  else
+    ipxnet_p = fopen(path, "r");
+}
+
+static void end_ipxnetent(void)
+{
+  if (ipxnet_p) {
+    fclose(ipxnet_p);
+    ipxnet_p = NULL;
+  }
+}
+
+static ipxnet_t *get_ipxnetent(void)
+{
+  static ipxnet_t ipxnet;
+  static int     size = 0;
+  static char   *buf = NULL;
+  
+  if (ipxnet_p == NULL) 
+    return NULL;
+
+  while (fgetline(&buf, &size, ipxnet_p) >= 0) {
+    if (parse_ipxnets_line(buf, &ipxnet) == 0) {
+      return &ipxnet;
+    }
+  }
+    
+  return NULL;
+
+} /* get_ipxnetent */
+
+static ipxnet_t *get_ipxnetbyname(u_char *name)
+{
+  ipxnet_t *ipxnet;
+  
+  set_ipxnetent(g_ipxnets_path);
+
+  while ((ipxnet = get_ipxnetent()) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
+    ;
+
+  if (ipxnet == NULL) {
+    end_ipxnetent();
+    
+    set_ipxnetent(g_pipxnets_path);
+
+    while ((ipxnet = get_ipxnetent()) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
+      ;
+
+    end_ipxnetent();
+  }
+
+  return ipxnet;
+
+} /* get_ipxnetbyname */
+
+static ipxnet_t *get_ipxnetbyaddr(guint32 addr)
+{
+
+  ipxnet_t *ipxnet;
+  
+  set_ipxnetent(g_ipxnets_path);
+
+  while ((ipxnet = get_ipxnetent()) && (addr != ipxnet->addr) ) ;
+
+  if (ipxnet == NULL) {
+    end_ipxnetent();
+    
+    set_ipxnetent(g_pipxnets_path);
+    
+    while ((ipxnet = get_ipxnetent()) && (addr != ipxnet->addr) )
+      ;
+    
+    end_ipxnetent();
+  }
+
+  return ipxnet;
+
+} /* get_ipxnetbyaddr */
+
+static void initialize_ipxnets(void)
+{
+
+#ifdef DEBUG_RESOLV
+  signal(SIGSEGV, SIG_IGN);
+#endif
+
+  /* Set g_pipxnets_path here, but don't actually do anything
+   * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr()
+   */
+  if (g_pipxnets_path == NULL) {
+    g_pipxnets_path = g_malloc(strlen(getenv("HOME")) + 
+                             strlen(EPATH_PERSONAL_IPXNETS) + 2);
+    sprintf(g_pipxnets_path, "%s/%s", 
+           (char *)getenv("HOME"), EPATH_PERSONAL_IPXNETS);
+  }
+
+} /* initialize_ipxnets */
+
+static hashipxnet_t *add_ipxnet_name(u_int addr, u_char *name)
+{
+  hashipxnet_t *tp;
+  hashipxnet_t **table = ipxnet_table;
+
+  /* XXX - check goodness of hash function */
+
+  tp = table[ addr & (HASHIPXNETSIZE - 1)];
 
   if( tp == NULL ) {
-         /* Hash key not found in table.
-          * Force a lookup (and a hash entry) for addr, then call
-          * myself. I plan on not getting into an infinite loop because
-          * eth_name_lookup() is guaranteed to make a hashtable entry,
-          * so when I call myself again, I can never get into this
-          * block of code again. Knock on wood...
-          */
-         (void) eth_name_lookup(addr);
-         return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
+    tp = table[ addr & (HASHIPXNETSIZE - 1)] = 
+      (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
+  } else {  
+    while(1) {
+      if (tp->next == NULL) {
+       tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
+       tp = tp->next;
+       break;
+      }
+      tp = tp->next;
+    }
   }
-  else { 
+  
+  tp->addr = addr;
+  strncpy(tp->name, name, MAXNAMELEN);
+  tp->name[MAXNAMELEN-1] = '\0';
+  tp->next = NULL;
+
+  return tp;
+
+} /* add_ipxnet_name */
+
+static u_char *ipxnet_name_lookup(const u_int addr)
+{
+  hashipxnet_t *tp;
+  hashipxnet_t **table = ipxnet_table;
+  ipxnet_t *ipxnet;
+
+  tp = table[ addr & (HASHIPXNETSIZE - 1)];
+
+  if( tp == NULL ) {
+    tp = table[ addr & (HASHIPXNETSIZE - 1)] = 
+      (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
+  } else {  
     while(1) {
-      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
-             if (tp->is_name_from_file) {
-               /* A name was found, and its origin is an ethers file */
-               return tp->name;
-             }
-             else {
-               /* A name was found, but it was created, not found in a file */
-               return NULL;
-             }
+      if (tp->addr == addr) {
+       return tp->name;
       }
       if (tp->next == NULL) {
-         /* Read my reason above for why I'm sure I can't get into an infinite loop */
-         (void) eth_name_lookup(addr);
-         return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
+       tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
+       tp = tp->next;
+       break;
       }
       tp = tp->next;
     }
   }
-  g_assert_not_reached();
-  return NULL;
-}
+  
+  /* fill in a new entry */
 
-static u_char *eth_addr_lookup(u_char *name)
+  tp->addr = addr;
+  tp->next = NULL;
+
+  if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
+    /* unknown name */
+      sprintf(tp->name, "%X", addr);
+
+  } else {
+    strncpy(tp->name, ipxnet->name, MAXNAMELEN);
+    tp->name[MAXNAMELEN-1] = '\0';
+  }
+
+  return (tp->name);
+
+} /* ipxnet_name_lookup */
+
+static u_int ipxnet_addr_lookup(u_char *name, gboolean *success)
 {
-  ether_t *eth;
-  hashether_t *tp;
-  hashether_t **table = eth_table;
+  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 < HASHETHSIZE; i++) {
+  for (i = 0; i < HASHIPXNETSIZE; i++) {
     tp = table[i];
     while (tp) {
       if (strcmp(tp->name, name) == 0)
@@ -758,16 +980,19 @@ static u_char *eth_addr_lookup(u_char *name)
 
   /* not in hash table : performs a file lookup */
 
-  if ((eth = get_ethbyname(name)) == NULL)
-    return NULL;
+  if ((ipxnet = get_ipxnetbyname(name)) == NULL) {
+         *success = FALSE;
+         return 0;
+  }
 
   /* add new entry in hash table */
 
-  tp = add_eth_name(eth->addr, name);
+  tp = add_ipxnet_name(ipxnet->addr, name);
 
+  *success = TRUE;
   return tp->addr;
 
-} /* eth_addr_lookup */
+} /* ipxnet_addr_lookup */
 
 
 /* 
@@ -878,6 +1103,67 @@ extern u_char *get_ether_name(const u_char *addr)
 
 } /* get_ether_name */
 
+/* Look for an ether name in the hash, and return it if found.
+ * If it's not found, simply return NULL. We DO NOT make a new
+ * hash entry for it with the hex digits turned into a string.
+ */
+u_char *get_ether_name_if_known(const u_char *addr)
+{
+  hashether_t *tp;
+  hashether_t **table = eth_table;
+  int i,j;
+
+  /* Initialize ether structs if we're the first
+   * ether-related function called */
+  if (!g_resolving_actif)
+    return NULL;
+  
+  if (!eth_resolution_initialized) {
+    initialize_ethers();
+    eth_resolution_initialized = 1;
+  }
+
+  j = (addr[2] << 8) | addr[3];
+  i = (addr[4] << 8) | addr[5];
+
+  tp = table[ (i ^ j) & (HASHETHSIZE - 1)];
+
+  if( tp == NULL ) {
+         /* Hash key not found in table.
+          * Force a lookup (and a hash entry) for addr, then call
+          * myself. I plan on not getting into an infinite loop because
+          * eth_name_lookup() is guaranteed to make a hashtable entry,
+          * so when I call myself again, I can never get into this
+          * block of code again. Knock on wood...
+          */
+         (void) eth_name_lookup(addr);
+         return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
+  }
+  else { 
+    while(1) {
+      if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
+             if (tp->is_name_from_file) {
+               /* A name was found, and its origin is an ethers file */
+               return tp->name;
+             }
+             else {
+               /* A name was found, but it was created, not found in a file */
+               return NULL;
+             }
+      }
+      if (tp->next == NULL) {
+         /* Read my reason above for why I'm sure I can't get into an infinite loop */
+         (void) eth_name_lookup(addr);
+         return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
+      }
+      tp = tp->next;
+    }
+  }
+  g_assert_not_reached();
+  return NULL;
+}
+
+
 extern u_char *get_ether_addr(u_char *name)
 {
 
@@ -892,6 +1178,40 @@ extern u_char *get_ether_addr(u_char *name)
 
 } /* get_ether_addr */
 
+
+extern u_char *get_ipxnet_name(const guint32 addr)
+{
+  if (!g_resolving_actif)
+    return ipxnet_to_string((guint8 *)&addr);
+
+  if (!ipxnet_resolution_initialized) {
+    initialize_ipxnets();
+    ipxnet_resolution_initialized = 1;
+  }
+
+  return ipxnet_name_lookup(addr);
+
+} /* get_ipxnet_name */
+
+extern guint32 get_ipxnet_addr(u_char *name, gboolean *known)
+{
+       guint32 addr;
+       gboolean success;
+
+  /* force resolution (do not check g_resolving_actif) */
+
+  if (!ipxnet_resolution_initialized) {
+    initialize_ipxnets();
+    ipxnet_resolution_initialized = 1;
+  }
+
+  addr =  ipxnet_addr_lookup(name, &success);
+
+  *known = success;
+  return addr;
+
+} /* get_ipxnet_addr */
+
 extern u_char *get_manuf_name(u_char *addr) 
 {
   static gchar  str[3][MAXMANUFLEN];
index c2406ab250d627b3abcb15fc1daa2bc66e487984..2a7723e90db316519a55f5f8c78f6e57336fa073 100644 (file)
--- a/resolv.h
+++ b/resolv.h
@@ -1,7 +1,7 @@
 /* resolv.h
  * Definitions for network object lookup
  *
- * $Id: resolv.h,v 1.10 1999/11/20 05:35:15 gram Exp $
+ * $Id: resolv.h,v 1.11 1999/11/21 16:32:16 gram Exp $
  *
  * Laurent Deniel <deniel@worldnet.fr>
  *
 #endif
 
 #define EPATH_ETHERS           "/etc/ethers"
+#define EPATH_IPXNETS          "/etc/ipxnets"
 #define EPATH_MANUF            DATAFILE_DIR "/manuf"
-#define EPATH_PERSONAL_ETHERS  ".ethereal/ethers" /* with "$HOME/" prefix */
+#define EPATH_PERSONAL_ETHERS  ".ethereal/ethers"  /* with "$HOME/" prefix */
+#define EPATH_PERSONAL_IPXNETS         ".ethereal/ipxnets" /* with "$HOME/" prefix */
 
 #ifndef MAXNAMELEN
 #define MAXNAMELEN     64      /* max name length (hostname and port name) */
 /* global variables */
 
 extern gchar *g_ethers_path;
+extern gchar *g_ipxnets_path;
 extern gchar *g_manuf_path;
 extern gchar *g_pethers_path;
+extern gchar *g_pipxnets_path;
 
 /* Functions in resolv.c */
 
@@ -72,9 +76,17 @@ extern u_char *get_ether_name_if_known(const u_char *addr);
 /* get_manuf_name returns the vendor name or "%02x:%02x:%02x" if not known */
 extern u_char *get_manuf_name(u_char *addr);
 
+/* get_ipxnet_name returns the logical name if found in an ipxnets file,
+ * or a string formatted with "%X" if not */
+extern u_char *get_ipxnet_name(const guint32 addr);
+
 /* returns the ethernet address corresponding to name or NULL if not known */
 extern u_char *get_ether_addr(u_char *name);
 
+/* returns the ipx network corresponding to name. If name is unknown,
+ * 0 is returned and 'known' is set to TRUE. */
+guint32 get_ipxnet_addr(u_char *name, gboolean *known);
+
 /* adds a hostname/IP in the hash table */
 extern void add_host_name(u_int addr, u_char *name);