Add support for DLT_APPLE_IP_OVER_IEEE_1394.
[obnox/wireshark/wip.git] / epan / to_str.c
index 6ea8d125b0e31433901eff63d5aa73a1d5e7c97f..1d09a6f2560c96a5d9a5ee75be388b5899be30fa 100644 (file)
@@ -1,22 +1,22 @@
 /* to_str.c
  * Routines for utilities to convert various other types to strings.
  *
- * $Id: to_str.c,v 1.14 2002/06/23 10:32:32 guy Exp $
+ * $Id: to_str.c,v 1.43 2004/03/23 01:02:40 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- * 
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <string.h>
 
 #ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_WINSOCK2_H
-# include <winsock2.h>   /* for "u_char" */
+# include <sys/types.h>                /* needed for <netinet/in.h> */
 #endif
 
 #ifdef NEED_SNPRINTF_H
@@ -42,7 +38,7 @@
 #endif
 
 #ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
+# include <netinet/in.h>       /* needed for <arpa/inet.h> on some platforms */
 #endif
 
 #ifdef HAVE_ARPA_INET_H
 #endif
 
 #ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
+#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 NEED_INET_V6DEFS_H
 #include "to_str.h"
 #include "resolv.h"
 #include "pint.h"
+#include "atalk-utils.h"
+#include "sna-utils.h"
+#include "osi-utils.h"
+#include "packet-mtp3.h"
 #include <stdio.h>
 #include <time.h>
 
+#define MAX_BYTESTRING_LEN     6
 
-/* Wrapper for the most common case of asking
- * for a string using a colon as the hex-digit separator.
- */
-
-gchar *
-ether_to_str(const guint8 *ad)
-{
-       return ether_to_str_punct(ad, ':');
-}
-
-/* Places char punct in the string as the hex-digit separator.
+/* Routine to convert a sequence of bytes to a hex string, one byte/two hex
+ * digits at at a time, with a specified punctuation character between
+ * the bytes.  The sequence of bytes must be no longer than
+ * MAX_BYTESTRING_LEN.
+ *
  * If punct is '\0', no punctuation is applied (and thus
- * the resulting string is 5 bytes shorter)
+ * the resulting string is (len-1) bytes shorter)
  */
-gchar *
-ether_to_str_punct(const guint8 *ad, char punct) {
-  static gchar  str[3][18];
+static gchar *
+bytestring_to_str(const guint8 *ad, guint32 len, char punct) {
+  static gchar  str[3][MAX_BYTESTRING_LEN*3];
   static gchar *cur;
   gchar        *p;
   int          i;
   guint32      octet;
-  static const gchar hex_digits[16] = "0123456789abcdef";
+  /* At least one version of Apple's C compiler/linker is buggy, causing
+     a complaint from the linker about the "literal C string section"
+     not ending with '\0' if we initialize a 16-element "char" array with
+     a 16-character string, the fact that initializing such an array with
+     such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
+     '\0' byte in the string nonwithstanding. */
+  static const gchar hex_digits[16] =
+      { '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+  g_assert(len > 0 && len <= MAX_BYTESTRING_LEN);
+  len--;
 
   if (cur == &str[0][0]) {
     cur = &str[1][0];
-  } else if (cur == &str[1][0]) {  
+  } else if (cur == &str[1][0]) {
     cur = &str[2][0];
-  } else {  
+  } else {
     cur = &str[0][0];
   }
   p = &cur[18];
   *--p = '\0';
-  i = 5;
+  i = len;
   for (;;) {
     octet = ad[i];
     *--p = hex_digits[octet&0xF];
@@ -111,66 +121,138 @@ ether_to_str_punct(const guint8 *ad, char punct) {
   return p;
 }
 
+/* Wrapper for the most common case of asking
+ * for a string using a colon as the hex-digit separator.
+ */
+/* XXX FIXME   
+remove this one later when every call has been converted to address_to_str() 
+*/
+gchar *
+ether_to_str(const guint8 *ad)
+{
+       return bytestring_to_str(ad, 6, ':');
+}
+
+/* 
+ This function is very fast and this function is called a lot.
+ XXX update the address_to_str stuff to use this function.
+*/
 gchar *
 ip_to_str(const guint8 *ad) {
   static gchar  str[4][16];
-  static gchar *cur;
+  static int   cur_idx=0;
+  gchar *cur;
 
-  if (cur == &str[0][0]) {
-    cur = &str[1][0];
-  } else if (cur == &str[1][0]) {
-    cur = &str[2][0];
-  } else if (cur == &str[2][0]) {
-    cur = &str[3][0];
-  } else {  
-    cur = &str[0][0];
+  cur_idx++;
+  if(cur_idx>3){ 
+     cur_idx=0;
   }
+  cur=&str[cur_idx][0];
+
   ip_to_str_buf(ad, cur);
   return cur;
 }
 
+/* 
+ This function is very fast and this function is called a lot.
+ XXX update the address_to_str stuff to use this function.
+*/
+static const char * const fast_strings[] = {
+"0", "1", "2", "3", "4", "5", "6", "7", 
+"8", "9", "10", "11", "12", "13", "14", "15", 
+"16", "17", "18", "19", "20", "21", "22", "23", 
+"24", "25", "26", "27", "28", "29", "30", "31", 
+"32", "33", "34", "35", "36", "37", "38", "39", 
+"40", "41", "42", "43", "44", "45", "46", "47", 
+"48", "49", "50", "51", "52", "53", "54", "55", 
+"56", "57", "58", "59", "60", "61", "62", "63", 
+"64", "65", "66", "67", "68", "69", "70", "71", 
+"72", "73", "74", "75", "76", "77", "78", "79", 
+"80", "81", "82", "83", "84", "85", "86", "87", 
+"88", "89", "90", "91", "92", "93", "94", "95", 
+"96", "97", "98", "99", "100", "101", "102", "103", 
+"104", "105", "106", "107", "108", "109", "110", "111", 
+"112", "113", "114", "115", "116", "117", "118", "119", 
+"120", "121", "122", "123", "124", "125", "126", "127", 
+"128", "129", "130", "131", "132", "133", "134", "135", 
+"136", "137", "138", "139", "140", "141", "142", "143", 
+"144", "145", "146", "147", "148", "149", "150", "151", 
+"152", "153", "154", "155", "156", "157", "158", "159", 
+"160", "161", "162", "163", "164", "165", "166", "167", 
+"168", "169", "170", "171", "172", "173", "174", "175", 
+"176", "177", "178", "179", "180", "181", "182", "183", 
+"184", "185", "186", "187", "188", "189", "190", "191", 
+"192", "193", "194", "195", "196", "197", "198", "199", 
+"200", "201", "202", "203", "204", "205", "206", "207", 
+"208", "209", "210", "211", "212", "213", "214", "215", 
+"216", "217", "218", "219", "220", "221", "222", "223", 
+"224", "225", "226", "227", "228", "229", "230", "231", 
+"232", "233", "234", "235", "236", "237", "238", "239", 
+"240", "241", "242", "243", "244", "245", "246", "247", 
+"248", "249", "250", "251", "252", "253", "254", "255"
+};
 void
 ip_to_str_buf(const guint8 *ad, gchar *buf)
 {
-  gchar        *p;
-  int           i;
-  guint32       octet;
-  guint32       digit;
-  gboolean      saw_nonzero;
+       register gchar const *p;
+       register gchar *b=buf;
+       register gchar c;
+
+       p=fast_strings[*ad++];
+       while((c=*p)){
+               *b++=c;
+               p++;
+       }
+       *b++='.';
 
-  p = buf;
-  i = 0;
-  for (;;) {
-    saw_nonzero = FALSE;
-    octet = ad[i];
-    digit = octet/100;
-    if (digit != 0) {
-      *p++ = digit + '0';
-      saw_nonzero = TRUE;
-    }
-    octet %= 100;
-    digit = octet/10;
-    if (saw_nonzero || digit != 0)
-      *p++ = digit + '0';
-    digit = octet%10;
-    *p++ = digit + '0';
-    if (i == 3)
-      break;
-    *p++ = '.';
-    i++;
-  }
-  *p = '\0';
+       p=fast_strings[*ad++];
+       while((c=*p)){
+               *b++=c;
+               p++;
+       }
+       *b++='.';
+
+       p=fast_strings[*ad++];
+       while((c=*p)){
+               *b++=c;
+               p++;
+       }
+       *b++='.';
+
+       p=fast_strings[*ad++];
+       while((c=*p)){
+               *b++=c;
+               p++;
+       }
+       *b=0;
 }
 
+
+/* XXX FIXME   
+remove this one later when every call has been converted to address_to_str() 
+*/
 gchar *
-ip6_to_str(struct e_in6_addr *ad) {
+ip6_to_str(const struct e_in6_addr *ad) {
 #ifndef INET6_ADDRSTRLEN
 #define INET6_ADDRSTRLEN 46
 #endif
-  static gchar buf[INET6_ADDRSTRLEN];
+  static int i=0;
+  static gchar *strp, str[4][INET6_ADDRSTRLEN];
 
-  inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf));
-  return buf;
+  i++;
+  if(i>=4){
+    i=0;
+  }
+  strp=str[i];
+
+  ip6_to_str_buf(ad, strp);
+  return strp;
+}
+
+void
+ip6_to_str_buf(const struct e_in6_addr *ad, gchar *buf)
+{
+  inet_ntop(AF_INET6, (const guchar*)ad, buf, INET6_ADDRSTRLEN);
 }
 
 gchar*
@@ -194,7 +276,8 @@ ipx_addr_to_str(guint32 net, const guint8 *ad)
                sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
        }
        else {
-               sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
+               sprintf(cur, "%s.%s", get_ipxnet_name(net),
+                   bytestring_to_str(ad, 6, '\0'));
        }
        return cur;
 }
@@ -214,15 +297,23 @@ ipxnet_to_str_punct(const guint32 ad, char punct)
   gchar        *p;
   int          i;
   guint32      octet;
-  static const gchar hex_digits[16] = "0123456789ABCDEF";
+  /* At least one version of Apple's C compiler/linker is buggy, causing
+     a complaint from the linker about the "literal C string section"
+     not ending with '\0' if we initialize a 16-element "char" array with
+     a 16-character string, the fact that initializing such an array with
+     such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
+     '\0' byte in the string nonwithstanding. */
+  static const gchar hex_digits[16] =
+      { '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
   static const guint32  octet_mask[4] =
          { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
 
   if (cur == &str[0][0]) {
     cur = &str[1][0];
-  } else if (cur == &str[1][0]) {  
+  } else if (cur == &str[1][0]) {
     cur = &str[2][0];
-  } else {  
+  } else {
     cur = &str[0][0];
   }
   p = &cur[12];
@@ -255,11 +346,16 @@ vines_addr_to_str(const guint8 *addrp)
   } else {
     cur = &str[0][0];
   }
-
-  sprintf(cur, "%08x.%04x", pntohl(&addrp[0]), pntohs(&addrp[4]));
+  vines_addr_to_str_buf(addrp, cur);
   return cur;
 }
 
+void
+vines_addr_to_str_buf(const guint8 *addrp, gchar *buf)
+{
+  sprintf(buf, "%08x.%04x", pntohl(&addrp[0]), pntohs(&addrp[4]));
+}
+
 #define        PLURALIZE(n)    (((n) > 1) ? "s" : "")
 #define        COMMA(do_it)    ((do_it) ? ", " : "")
 
@@ -329,9 +425,9 @@ time_secs_to_str(guint32 time)
 
   if (cur == &str[0][0]) {
     cur = &str[1][0];
-  } else if (cur == &str[1][0]) {  
+  } else if (cur == &str[1][0]) {
     cur = &str[2][0];
-  } else {  
+  } else {
     cur = &str[0][0];
   }
 
@@ -353,9 +449,9 @@ time_msecs_to_str(guint32 time)
 
   if (cur == &str[0][0]) {
     cur = &str[1][0];
-  } else if (cur == &str[1][0]) {  
+  } else if (cur == &str[1][0]) {
     cur = &str[2][0];
-  } else {  
+  } else {
     cur = &str[0][0];
   }
 
@@ -391,7 +487,7 @@ abs_time_to_str(nstime_t *abs_time)
 {
         struct tm *tmp;
         static gchar *cur;
-        static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+6+1 + 5 /* extra */];
+        static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+9+1];
 
         if (cur == &str[0][0]) {
                 cur = &str[1][0];
@@ -403,17 +499,45 @@ abs_time_to_str(nstime_t *abs_time)
 
         tmp = localtime(&abs_time->secs);
         if (tmp) {
-          sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%09ld",
-                  mon_names[tmp->tm_mon],
-                  tmp->tm_mday,
-                  tmp->tm_year + 1900,
-                  tmp->tm_hour,
-                  tmp->tm_min,
-                  tmp->tm_sec,
-                  (long)abs_time->nsecs);
+               sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%09ld",
+                   mon_names[tmp->tm_mon],
+                   tmp->tm_mday,
+                   tmp->tm_year + 1900,
+                   tmp->tm_hour,
+                   tmp->tm_min,
+                   tmp->tm_sec,
+                   (long)abs_time->nsecs);
+        } else
+               strncpy(cur, "Not representable", sizeof(str[0]));
+        return cur;
+}
+
+gchar *
+abs_time_secs_to_str(time_t abs_time)
+{
+        struct tm *tmp;
+        static gchar *cur;
+        static char str[3][3+1+2+2+4+1+2+1+2+1+2+1];
+
+        if (cur == &str[0][0]) {
+                cur = &str[1][0];
+        } else if (cur == &str[1][0]) {
+                cur = &str[2][0];
         } else {
-          strncpy(cur, "Not representable", sizeof(str[0]));
+                cur = &str[0][0];
         }
+
+        tmp = localtime(&abs_time);
+        if (tmp) {
+               sprintf(cur, "%s %2d, %d %02d:%02d:%02d",
+                   mon_names[tmp->tm_mon],
+                   tmp->tm_mday,
+                   tmp->tm_year + 1900,
+                   tmp->tm_hour,
+                   tmp->tm_min,
+                   tmp->tm_sec);
+        } else
+               strncpy(cur, "Not representable", sizeof(str[0]));
         return cur;
 }
 
@@ -522,10 +646,74 @@ rel_time_to_secs_str(nstime_t *rel_time)
         return cur;
 }
 
+
+/* XXX FIXME   
+remove this one later when every call has been converted to address_to_str() 
+*/
+gchar *
+fc_to_str(const guint8 *ad)
+{
+    return bytestring_to_str (ad, 3, '.');
+}
+
+/* FC Network Header Network Address Authority Identifiers */
+
+#define FC_NH_NAA_IEEE         1       /* IEEE 802.1a */
+#define FC_NH_NAA_IEEE_E       2       /* IEEE Exteneded */
+#define FC_NH_NAA_LOCAL                3
+#define FC_NH_NAA_IP           4       /* 32-bit IP address */
+#define FC_NH_NAA_IEEE_R       5       /* IEEE Registered */
+#define FC_NH_NAA_IEEE_R_E     6       /* IEEE Registered Exteneded */
+/* according to FC-PH 3 draft these are now reclaimed and reserved */
+#define FC_NH_NAA_CCITT_INDV   12      /* CCITT 60 bit individual address */
+#define FC_NH_NAA_CCITT_GRP    14      /* CCITT 60 bit group address */
+
+gchar *
+fcwwn_to_str (const guint8 *ad)
+{
+    int fmt;
+    guint8 oui[6];
+    static gchar ethstr[512];
+    
+    if (ad == NULL) return NULL;
+    
+    fmt = (ad[0] & 0xF0) >> 4;
+
+    switch (fmt) {
+
+    case FC_NH_NAA_IEEE:
+    case FC_NH_NAA_IEEE_E:
+        memcpy (oui, &ad[2], 6);
+        sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0], 
+                 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
+                 get_manuf_name (oui));
+        break;
+
+    case FC_NH_NAA_IEEE_R:
+        oui[0] = ((ad[0] & 0x0F) << 4) | ((ad[1] & 0xF0) >> 4);
+        oui[1] = ((ad[1] & 0x0F) << 4) | ((ad[2] & 0xF0) >> 4);
+        oui[2] = ((ad[2] & 0x0F) << 4) | ((ad[3] & 0xF0) >> 4);
+        oui[3] = ((ad[3] & 0x0F) << 4) | ((ad[4] & 0xF0) >> 4);
+        oui[4] = ((ad[4] & 0x0F) << 4) | ((ad[5] & 0xF0) >> 4);
+        oui[5] = ((ad[5] & 0x0F) << 4) | ((ad[6] & 0xF0) >> 4);
+
+        sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
+                 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
+                 get_manuf_name (oui));
+        break;
+
+    default:
+        sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ad[0],
+                 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7]);
+        break;
+    }
+    return (ethstr);
+}
+
 /* Generate, into "buf", a string showing the bits of a bitfield.
    Return a pointer to the character after that string. */
 char *
-decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
+other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
 {
   int i;
   guint32 bit;
@@ -552,6 +740,16 @@ decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
     if (i % 4 == 0)
       *p++ = ' ';
   }
+  *p = '\0';
+  return p;
+}
+
+char *
+decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
+{
+  char *p;
+
+  p = other_decode_bitfield_value(buf, val, mask, width);
   strcpy(p, " = ");
   p += 3;
   return p;
@@ -595,4 +793,83 @@ decode_numeric_bitfield(guint32 val, guint32 mask, int width,
 }
 
 
+/*XXX FIXME the code below may be called very very frequently in the future.
+  optimize it for speed and get rid of the slow sprintfs */
+/* XXX - perhaps we should have individual address types register
+   a table of routines to do operations such as address-to-name translation,
+   address-to-string translation, and the like, and have this call them,
+   and also have an address-to-string-with-a-name routine */
+/* XXX - use this, and that future address-to-string-with-a-name routine,
+   in "col_set_addr()"; it might also be useful to have address types
+   export the names of the source and destination address fields, so
+   that "col_set_addr()" need know nothing whatsoever about particular
+   address types */
+/* convert an address struct into a printable string */
+gchar* 
+address_to_str(address *addr)
+{
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+  static int i=0;
+  static gchar *strp, str[16][INET6_ADDRSTRLEN];/* IPv6 is the largest one */
 
+  i++;
+  if(i>=16){
+    i=0;
+  }
+  strp=str[i];
+
+  address_to_str_buf(addr, strp);
+  return strp;
+}
+
+void
+address_to_str_buf(address *addr, gchar *buf)
+{
+  struct atalk_ddp_addr ddp_addr;
+
+  switch(addr->type){
+  case AT_ETHER:
+    sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", addr->data[0], addr->data[1], addr->data[2], addr->data[3], addr->data[4], addr->data[5]);
+    break;
+  case AT_IPv4:
+    ip_to_str_buf(addr->data, buf);
+    break;
+  case AT_IPv6:
+    inet_ntop(AF_INET6, addr->data, buf, INET6_ADDRSTRLEN);
+    break;
+  case AT_IPX:
+    sprintf(buf, "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x", addr->data[0], addr->data[1], addr->data[2], addr->data[3], addr->data[4], addr->data[5], addr->data[6], addr->data[7], addr->data[8], addr->data[9]);
+    break;
+  case AT_SNA:
+    sna_fid_to_str_buf(addr, buf);
+    break;
+  case AT_ATALK:
+    memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
+    atalk_addr_to_str_buf(&ddp_addr, buf);
+    break;
+  case AT_VINES:
+    vines_addr_to_str_buf(addr->data, buf);
+    break;
+  case AT_OSI:
+    print_nsap_net_buf(addr->data, addr->len, buf);
+    break;
+  case AT_ARCNET:
+    sprintf(buf, "0x%02X", addr->data[0]);
+    break;
+  case AT_FC:
+    sprintf(buf, "%02x.%02x.%02x", addr->data[0], addr->data[1], addr->data[2]);
+    break;
+  case AT_SS7PC:
+    mtp3_addr_to_str_buf(addr->data, buf);
+    break;
+  case AT_EUI64:
+    sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+            addr->data[0], addr->data[1], addr->data[2], addr->data[3],
+            addr->data[4], addr->data[5], addr->data[6], addr->data[7]);
+    break;
+  default:
+    g_assert_not_reached();
+  }
+}