From Harald Welte:
[obnox/wireshark/wip.git] / epan / address_to_str.c
index 7f4691a66af2171978aca904f5c910a51a408d90..b0c421811b95721ab5acdad545e8be252d70902b 100644 (file)
@@ -66,6 +66,7 @@
 
 /* private to_str.c API, don't export to .h! */
 char *word_to_hex(char *out, guint16 word);
+char *word_to_hex_npad(char *out, guint16 word);
 char *dword_to_hex_punct(char *out, guint32 dword, char punct);
 char *dword_to_hex(char *out, guint32 dword);
 char *bytes_to_hexstr(char *out, const guint8 *ad, guint32 len);
@@ -91,6 +92,12 @@ ether_to_str(const guint8 *ad)
        return bytestring_to_str(ad, 6, ':');
 }
 
+gchar *
+tvb_ether_to_str(tvbuff_t *tvb, const gint offset)
+{
+       return bytestring_to_str(tvb_get_ptr(tvb, offset, 6), 6, ':');
+}
+
 /*
  This function is very fast and this function is called a lot.
  XXX update the ep_address_to_str stuff to use this function.
@@ -120,13 +127,9 @@ remove this one later when every call has been converted to ep_address_to_str()
 */
 gchar *
 ip6_to_str(const struct e_in6_addr *ad) {
-#ifndef INET6_ADDRSTRLEN
-#define INET6_ADDRSTRLEN 46
-#endif
   gchar *str;
 
-  str=ep_alloc(INET6_ADDRSTRLEN+1);
-
+  str=ep_alloc(MAX_IP6_STR_LEN);
   ip6_to_str_buf(ad, str);
   return str;
 }
@@ -137,15 +140,126 @@ tvb_ip6_to_str(tvbuff_t *tvb, const gint offset)
 {
   gchar *buf;
 
-  buf=ep_alloc(INET6_ADDRSTRLEN+1);
+  buf=ep_alloc(MAX_IP6_STR_LEN);
   ip6_to_str_buf((const struct e_in6_addr *)tvb_get_ptr(tvb, offset, IPV6_LENGTH), buf);
   return buf;
 }
 
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static void
+ip6_to_str_buf_len(const guchar* src, char *buf, size_t buf_len)
+{
+       struct { int base, len; } best, cur;
+       guint words[8];
+       int i;
+
+       if (buf_len < MAX_IP6_STR_LEN) {        /* buf_len < 40 */
+               g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);     /* Let the unexpected value alert user */
+               return;
+       }
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       for (i = 0; i < 16; i += 2) {
+               words[i / 2] = (src[i+1] << 0);
+               words[i / 2] |= (src[i] << 8);
+       }
+       best.base = -1; best.len = 0;
+       cur.base = -1;  cur.len = 0;
+       for (i = 0; i < 8; i++) {
+               if (words[i] == 0) {
+                       if (cur.base == -1) {
+                               cur.base = i;
+                               cur.len = 1;
+                       } else
+                               cur.len++;
+               } else {
+                       if (cur.base != -1) {
+                               if (best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if (cur.base != -1) {
+               if (best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if (best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /* Is this address an encapsulated IPv4? */
+       /* XXX, 
+        * Orginal code dated 1996 uses ::/96 as a valid IPv4-compatible addresses
+        * but since Feb 2006 ::/96 is deprecated one.
+        * Quoting wikipedia [0]:
+        * > The 96-bit zero-value prefix ::/96, originally known as IPv4-compatible 
+        * > addresses, was mentioned in 1995[35] but first described in 1998.[41] 
+        * > This class of addresses was used to represent IPv4 addresses within 
+        * > an IPv6 transition technology. Such an IPv6 address has its first 
+        * > (most significant) 96 bits set to zero, while its last 32 bits are the 
+        * > IPv4 address that is represented. 
+        * > In February 2006 the Internet Engineering Task Force (IETF) has deprecated 
+        * > the use of IPv4-compatible addresses.[1] The only remaining use of this address 
+        * > format is to represent an IPv4 address in a table or database with fixed size 
+        * > members that must also be able to store an IPv6 address.
+        *
+        * If needed it can be fixed by changing next line:
+        *   if (best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
+        * to:
+        *   if (best.base == 0 && best.len == 5 && words[5] == 0xffff)
+        *
+        * [0] http://en.wikipedia.org/wiki/IPv6_address#Historical_notes
+        */
+
+       if (best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
+       {
+               /* best.len == 6 -> ::IPv4; 5 -> ::ffff:IPv4 */
+               buf = g_stpcpy(buf, "::");
+               if (best.len == 5)
+               buf = g_stpcpy(buf, "ffff:");
+               ip_to_str_buf(src + 12, buf, MAX_IP_STR_LEN);
+               /* max: 2 + 5 + 16 == 23 bytes */
+               return;
+       }
+
+       /*
+        * Format the result.
+        */
+       for (i = 0; i < 8; i++) {
+               /* Are we inside the best run of 0x00's? */
+               if (i == best.base) {
+                       *buf++ = ':';
+                       i += best.len;
+
+                       /* Was it a trailing run of 0x00's? */
+                       if (i == 8) {
+                               *buf++ = ':';
+                               break;
+                       }
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0)
+                       *buf++ = ':';
+
+               buf = word_to_hex_npad(buf, words[i]); /* max: 4B */
+               /* max: 8 * 4 + 7 == 39 bytes */
+       }
+       *buf = '\0';    /* 40 byte */
+}
+
 void
 ip6_to_str_buf(const struct e_in6_addr *ad, gchar *buf)
 {
-  inet_ntop(AF_INET6, (const guchar*)ad, buf, INET6_ADDRSTRLEN);
+  ip6_to_str_buf_len((const guchar*)ad, buf, MAX_IP6_STR_LEN);
 }
 
 gchar*
@@ -197,15 +311,46 @@ vines_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len)
 }
 
 gchar *
-vines_addr_to_str(const guint8 *addrp)
+tvb_vines_addr_to_str(tvbuff_t *tvb, const gint offset)
 {
   gchar        *buf;
 
   buf=ep_alloc(214); /* XXX, 14 here? */
 
-  vines_addr_to_str_buf(addrp, buf, 214);
+  vines_addr_to_str_buf(tvb_get_ptr(tvb, offset, VINES_ADDR_LEN), buf, 214);
+  return buf;
+}
+
+/*
+ This function is very fast and this function is called a lot.
+ XXX update the ep_address_to_str stuff to use this function.
+*/
+gchar *
+eui64_to_str(const guint64 ad) {
+  gchar *buf;
+  guint8 *p_eui64;
+
+  p_eui64 = ep_alloc(8);
+  buf=ep_alloc(EUI64_STR_LEN);
+
+  /* Copy and convert the address to network byte order. */
+  *(guint64 *)(void *)(p_eui64) = pntoh64(&(ad));
+
+  g_snprintf(buf, EUI64_STR_LEN, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 
+  p_eui64[0], p_eui64[1], p_eui64[2], p_eui64[3],
+  p_eui64[4], p_eui64[5], p_eui64[6], p_eui64[7] );
   return buf;
 }
+gchar *
+tvb_eui64_to_str(tvbuff_t *tvb, const gint offset, const guint encoding)
+{
+  if(encoding)
+  {
+    return eui64_to_str(tvb_get_letoh64(tvb, offset));
+  }else {
+    return eui64_to_str(tvb_get_ntoh64(tvb, offset));
+  }
+}
 
 static void
 usb_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len)
@@ -245,11 +390,14 @@ ib_addr_to_str_buf( const address *addr, gchar *buf, int buf_len){
        if (addr->len >= 16) {  /* GID is 128bits */
                #define PREAMBLE_STR_LEN                (sizeof("GID: ") - 1)
                g_snprintf(buf,buf_len,"GID: ");
-               if (    inet_ntop(AF_INET6, addr->data, buf + PREAMBLE_STR_LEN,
-                                                 buf_len + PREAMBLE_STR_LEN) == NULL ) /* Returns NULL if no space and does not touch buf */
+               if (buf_len < (int)PREAMBLE_STR_LEN ||
+                               inet_ntop(AF_INET6, addr->data, buf + PREAMBLE_STR_LEN, 
+                                                 buf_len - PREAMBLE_STR_LEN) == NULL ) /* Returns NULL if no space and does not touch buf */
                        g_snprintf ( buf, buf_len, BUF_TOO_SMALL_ERR ); /* Let the unexpected value alert user */
        } else {        /* this is a LID (16 bits) */
-               guint16 lid_number = *((guint16*) addr->data);
+               guint16 lid_number;
+               
+               memcpy((void *)&lid_number, addr->data, sizeof lid_number);
                g_snprintf(buf,buf_len,"LID: %u",lid_number);
        }
 }
@@ -263,6 +411,12 @@ fc_to_str(const guint8 *ad)
     return bytestring_to_str (ad, 3, '.');
 }
 
+gchar *
+tvb_fc_to_str(tvbuff_t *tvb, const gint offset)
+{
+    return bytestring_to_str (tvb_get_ptr(tvb, offset, 3), 3, '.');
+}
+
 /* FC Network Header Network Address Authority Identifiers */
 
 #define FC_NH_NAA_IEEE         1       /* IEEE 802.1a */
@@ -317,6 +471,12 @@ fcwwn_to_str (const guint8 *ad)
     return (ethstr);
 }
 
+gchar *
+tvb_fcwwn_to_str(tvbuff_t *tvb, const gint offset)
+{
+       return fcwwn_to_str (tvb_get_ptr(tvb, offset, 8));
+}
+
 /*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
@@ -374,8 +534,7 @@ address_to_str_buf(const address *addr, gchar *buf, int buf_len)
     ip_to_str_buf(addr->data, buf, buf_len);
     break;
   case AT_IPv6:
-    if ( inet_ntop(AF_INET6, addr->data, buf, buf_len) == NULL ) /* Returns NULL if no space and does not touch buf */
-       g_snprintf ( buf, buf_len, BUF_TOO_SMALL_ERR );                 /* Let the unexpected value alert user */
+    ip6_to_str_buf_len(addr->data, buf, buf_len);
     break;
   case AT_IPX:                                         /* 22 bytes */
     addrdata = addr->data;