When initializing a capture filter, assign a pointer to an empty string
[obnox/wireshark/wip.git] / packet.c
index de5d9a81d1b9dc8e58b85ab9b5ca3dfff935f625..0a6dcdf405244ca50a3224b5ed3c21fa109ea108 100644 (file)
--- a/packet.c
+++ b/packet.c
@@ -1,7 +1,7 @@
 /* packet.c
  * Routines for packet disassembly
  *
- * $Id: packet.c,v 1.38 1999/08/20 06:55:05 guy Exp $
+ * $Id: packet.c,v 1.62 1999/12/29 07:37:12 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 # include <netinet/in.h>
 #endif
 
+#include <arpa/inet.h>
+
+#ifdef NEED_INET_V6DEFS_H
+# include "inet_v6defs.h"
+#endif
+
 #include "packet.h"
+#include "print.h"
+#include "timestamp.h"
 #include "file.h"
 
+#include "packet-atalk.h"
+
+#include "packet-ipv6.h"
+
+#include "packet-sna.h"
+
+#include "packet-vines.h"
+
+#ifndef __RESOLV_H__
+#include "resolv.h"
+#endif
+
 extern capture_file  cf;
 
-int proto_frame = -1;
-int hf_frame_arrival_time = -1;
-int hf_frame_packet_len = -1;
-int hf_frame_capture_len = -1;
+static int proto_frame = -1;
+static int hf_frame_arrival_time = -1;
+static int hf_frame_time_delta = -1;
+static int hf_frame_number = -1;
+static int hf_frame_packet_len = -1;
+static int hf_frame_capture_len = -1;
+
+static gint ett_frame = -1;
+
+/* 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.
+ * If punct is '\0', no punctuation is applied (and thus
+ * the resulting string is 5 bytes shorter)
+ */
 gchar *
-ether_to_str(const guint8 *ad) {
+ether_to_str_punct(const guint8 *ad, char punct) {
   static gchar  str[3][18];
   static gchar *cur;
   gchar        *p;
@@ -91,7 +128,8 @@ ether_to_str(const guint8 *ad) {
     *--p = hex_digits[octet&0xF];
     if (i == 0)
       break;
-    *--p = ':';
+    if (punct)
+      *--p = punct;
     i--;
   }
   return p;
@@ -134,6 +172,18 @@ ip_to_str(const guint8 *ad) {
   return p;
 }
 
+gchar *
+ip6_to_str(struct e_in6_addr *ad) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif
+  static gchar buf[INET6_ADDRSTRLEN];
+
+  inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf));
+  return buf;
+}
+
+
 #define        PLURALIZE(n)    (((n) > 1) ? "s" : "")
 #define        COMMA(do_it)    ((do_it) ? ", " : "")
 
@@ -153,6 +203,11 @@ time_secs_to_str(guint32 time)
     cur = &str[0][0];
   }
 
+  if (time == 0) {
+    sprintf(cur, "0 time");
+    return cur;
+  }
+
   secs = time % 60;
   time /= 60;
   mins = time % 60;
@@ -185,25 +240,24 @@ time_secs_to_str(guint32 time)
 }
 
 /* Max string length for displaying byte string.  */
-#define        MAX_BYTE_STR_LEN        16
+#define        MAX_BYTE_STR_LEN        20
 
 /* Turn an array of bytes into a string showing the bytes in hex. */
+#define        N_BYTES_TO_STR_STRINGS  6
 gchar *
 bytes_to_str(const guint8 *bd, int bd_len) {
-  static gchar  str[3][MAX_BYTE_STR_LEN+3+1];
-  static gchar *cur;
+  static gchar  str[N_BYTES_TO_STR_STRINGS][MAX_BYTE_STR_LEN+3+1];
+  static int    cur_idx;
+  gchar        *cur;
   gchar        *p;
   int           len;
   static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
                                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
-  if (cur == &str[0][0]) {
-    cur = &str[1][0];
-  } else if (cur == &str[1][0]) {  
-    cur = &str[2][0];
-  } else {  
-    cur = &str[0][0];
-  }
+  cur_idx++;
+  if (cur_idx >= N_BYTES_TO_STR_STRINGS)
+    cur_idx = 0;
+  cur = &str[cur_idx][0];
   p = cur;
   len = MAX_BYTE_STR_LEN;
   while (bd_len > 0 && len > 0) {
@@ -266,6 +320,25 @@ abs_time_to_str(struct timeval *abs_time)
         return cur;
 }
 
+gchar *
+rel_time_to_str(struct timeval *rel_time)
+{
+        static gchar *cur;
+        static char str[3][10+1+6+1];
+
+        if (cur == &str[0][0]) {
+                cur = &str[1][0];
+        } else if (cur == &str[1][0]) {
+                cur = &str[2][0];
+        } else {
+                cur = &str[0][0];
+        }
+
+       sprintf(cur, "%ld.%06ld", (long)rel_time->tv_sec,
+               (long)rel_time->tv_usec);
+
+        return cur;
+}
 
 /*
  * Given a pointer into a data buffer, and to the end of the buffer,
@@ -383,6 +456,7 @@ format_text(const u_char *string, int len)
        * Put "..." and quit.
        */
       strcpy(fmtbufp, " ...");
+      fmtbufp += 4;
       break;
     }
     c = *string++;
@@ -493,7 +567,7 @@ match_strval(guint32 val, const value_string *vs) {
 
 /* Generate, into "buf", a string showing the bits of a bitfield.
    Return a pointer to the character after that string. */
-static char *
+char *
 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
 {
   int i;
@@ -595,27 +669,388 @@ check_col(frame_data *fd, gint el) {
 /* Adds a vararg list to a packet info string. */
 void
 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
-  va_list    ap;
-  int        i;
+  va_list ap;
+  int     i;
+  size_t  max_len;
   
   va_start(ap, format);
   for (i = 0; i < fd->cinfo->num_cols; i++) {
-    if (fd->cinfo->fmt_matx[i][el])
-      vsnprintf(fd->cinfo->col_data[i], COL_MAX_LEN, format, ap);
+    if (fd->cinfo->fmt_matx[i][el]) {
+      if (el == COL_INFO)
+       max_len = COL_MAX_INFO_LEN;
+      else
+       max_len = COL_MAX_LEN;
+      vsnprintf(fd->cinfo->col_data[i], max_len, format, ap);
+    }
   }
 }
 
 void
 col_add_str(frame_data *fd, gint el, const gchar* str) {
-  int i;
+  int    i;
+  size_t max_len;
+
+  for (i = 0; i < fd->cinfo->num_cols; i++) {
+    if (fd->cinfo->fmt_matx[i][el]) {
+      if (el == COL_INFO)
+       max_len = COL_MAX_INFO_LEN;
+      else
+       max_len = COL_MAX_LEN;
+      strncpy(fd->cinfo->col_data[i], str, max_len);
+      fd->cinfo->col_data[i][max_len - 1] = 0;
+    }
+  }
+}
+
+/* Appends a vararg list to a packet info string. */
+void
+col_append_fstr(frame_data *fd, gint el, gchar *format, ...) {
+  va_list ap;
+  int     i;
+  size_t  len, max_len;
   
+  va_start(ap, format);
+  for (i = 0; i < fd->cinfo->num_cols; i++) {
+    if (fd->cinfo->fmt_matx[i][el]) {
+      len = strlen(fd->cinfo->col_data[i]);
+      if (el == COL_INFO)
+       max_len = COL_MAX_INFO_LEN;
+      else
+       max_len = COL_MAX_LEN;
+      vsnprintf(&fd->cinfo->col_data[i][len], max_len - len, format, ap);
+    }
+  }
+}
+
+void
+col_append_str(frame_data *fd, gint el, gchar* str) {
+  int    i;
+  size_t len, max_len;
+
   for (i = 0; i < fd->cinfo->num_cols; i++) {
     if (fd->cinfo->fmt_matx[i][el]) {
-      strncpy(fd->cinfo->col_data[i], str, COL_MAX_LEN);
-      fd->cinfo->col_data[i][COL_MAX_LEN - 1] = 0;
+      len = strlen(fd->cinfo->col_data[i]);
+      if (el == COL_INFO)
+       max_len = COL_MAX_LEN;
+      else
+       max_len = COL_MAX_INFO_LEN;
+      strncat(fd->cinfo->col_data[i], str, max_len - len);
+      fd->cinfo->col_data[i][max_len - 1] = 0;
+    }
+  }
+}
+
+/* To do: Add check_col checks to the col_add* routines */
+
+static void
+col_set_abs_time(frame_data *fd, int col)
+{
+  struct tm *tmp;
+  time_t then;
+
+  then = fd->abs_secs;
+  tmp = localtime(&then);
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
+    tmp->tm_hour,
+    tmp->tm_min,
+    tmp->tm_sec,
+    (long)fd->abs_usecs/100);
+}
+
+static void
+col_set_rel_time(frame_data *fd, int col)
+{
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
+    fd->rel_usecs);
+}
+
+static void
+col_set_delta_time(frame_data *fd, int col)
+{
+  snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
+    fd->del_usecs);
+}
+
+/* Add "command-line-specified" time.
+   XXX - this is called from "file.c" when the user changes the time
+   format they want for "command-line-specified" time; it's a bit ugly
+   that we have to export it, but if we go to a CList-like widget that
+   invokes callbacks to get the text for the columns rather than
+   requiring us to stuff the text into the widget from outside, we
+   might be able to clean this up. */
+void
+col_set_cls_time(frame_data *fd, int col)
+{
+  switch (timestamp_type) {
+    case ABSOLUTE:
+      col_set_abs_time(fd, col);
+      break;
+
+    case RELATIVE:
+      col_set_rel_time(fd, col);
+      break;
+
+    case DELTA:
+      col_set_delta_time(fd, col);
+      break;
+  }
+}
+
+static void
+col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
+{
+  u_int ipv4_addr;
+  struct e_in6_addr ipv6_addr;
+  struct atalk_ddp_addr ddp_addr;
+  struct sna_fid_type_4_addr sna_fid_type_4_addr;
+
+  switch (addr->type) {
+
+  case AT_ETHER:
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
+    else
+      strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
+    break;
+
+  case AT_IPv4:
+    memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
+    else
+      strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
+    break;
+
+  case AT_IPv6:
+    memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
+    else
+      strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+    break;
+
+  case AT_IPX:
+    strncpy(fd->cinfo->col_data[col],
+      ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
+    break;
+
+  case AT_SNA:
+    switch (addr->len) {
+
+    case 1:
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]);
+      break;
+
+    case 2:
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X",
+        pntohs(&addr->data[0]));
+      break;
+
+    case SNA_FID_TYPE_4_ADDR_LEN:
+      memcpy(&sna_fid_type_4_addr, addr->data, SNA_FID_TYPE_4_ADDR_LEN);
+      strncpy(fd->cinfo->col_data[col],
+        sna_fid_type_4_addr_to_str(&sna_fid_type_4_addr), COL_MAX_LEN);
+      break;
+    }
+    break;
+
+  case AT_ATALK:
+    memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
+    strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr),
+      COL_MAX_LEN);
+    break;
+
+  case AT_VINES:
+    strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]),
+      COL_MAX_LEN);
+    break;
+
+  default:
+    break;
+  }
+  fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
+
+static void
+col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
+               gboolean is_res)
+{
+  switch (ptype) {
+
+  case PT_TCP:
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN);
+    else
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+    break;
+
+  case PT_UDP:
+    if (is_res)
+      strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN);
+    else
+      snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+    break;
+
+  default:
+    break;
+  }
+  fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
+
+void
+fill_in_columns(frame_data *fd)
+{
+  int i;
+
+  for (i = 0; i < fd->cinfo->num_cols; i++) {
+    switch (fd->cinfo->col_fmt[i]) {
+
+    case COL_NUMBER:
+      snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
+      break;
+
+    case COL_CLS_TIME:
+      col_set_cls_time(fd, i);
+      break;
+
+    case COL_ABS_TIME:
+      col_set_abs_time(fd, i);
+      break;
+
+    case COL_REL_TIME:
+      col_set_rel_time(fd, i);
+      break;
+
+    case COL_DELTA_TIME:
+      col_set_delta_time(fd, i);
+      break;
+
+    case COL_DEF_SRC:
+    case COL_RES_SRC:  /* COL_DEF_SRC is currently just like COL_RES_SRC */
+      col_set_addr(fd, i, &pi.src, TRUE);
+      break;
+
+    case COL_UNRES_SRC:
+      col_set_addr(fd, i, &pi.src, FALSE);
+      break;
+
+    case COL_DEF_DL_SRC:
+    case COL_RES_DL_SRC:
+      col_set_addr(fd, i, &pi.dl_src, TRUE);
+      break;
+
+    case COL_UNRES_DL_SRC:
+      col_set_addr(fd, i, &pi.dl_src, FALSE);
+      break;
+
+    case COL_DEF_NET_SRC:
+    case COL_RES_NET_SRC:
+      col_set_addr(fd, i, &pi.net_src, TRUE);
+      break;
+
+    case COL_UNRES_NET_SRC:
+      col_set_addr(fd, i, &pi.net_src, FALSE);
+      break;
+
+    case COL_DEF_DST:
+    case COL_RES_DST:  /* COL_DEF_DST is currently just like COL_RES_DST */
+      col_set_addr(fd, i, &pi.dst, TRUE);
+      break;
+
+    case COL_UNRES_DST:
+      col_set_addr(fd, i, &pi.dst, FALSE);
+      break;
+
+    case COL_DEF_DL_DST:
+    case COL_RES_DL_DST:
+      col_set_addr(fd, i, &pi.dl_dst, TRUE);
+      break;
+
+    case COL_UNRES_DL_DST:
+      col_set_addr(fd, i, &pi.dl_dst, FALSE);
+      break;
+
+    case COL_DEF_NET_DST:
+    case COL_RES_NET_DST:
+      col_set_addr(fd, i, &pi.net_dst, TRUE);
+      break;
+
+    case COL_UNRES_NET_DST:
+      col_set_addr(fd, i, &pi.net_dst, FALSE);
+      break;
+
+    case COL_DEF_SRC_PORT:
+    case COL_RES_SRC_PORT:     /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
+      col_set_port(fd, i, pi.ptype, pi.srcport, TRUE);
+      break;
+
+    case COL_UNRES_SRC_PORT:
+      col_set_port(fd, i, pi.ptype, pi.srcport, FALSE);
+      break;
+
+    case COL_DEF_DST_PORT:
+    case COL_RES_DST_PORT:     /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
+      col_set_port(fd, i, pi.ptype, pi.destport, TRUE);
+      break;
+
+    case COL_UNRES_DST_PORT:
+      col_set_port(fd, i, pi.ptype, pi.destport, FALSE);
+      break;
+
+    case COL_PROTOCOL: /* currently done by dissectors */
+    case COL_INFO:     /* currently done by dissectors */
+      break;
+
+    case COL_PACKET_LENGTH:
+      snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
+      break;
+
+    case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
+      break;
     }
   }
 }
+       
+void blank_packetinfo(void)
+{
+  pi.dl_src.type = AT_NONE;
+  pi.dl_dst.type = AT_NONE;
+  pi.net_src.type = AT_NONE;
+  pi.net_dst.type = AT_NONE;
+  pi.src.type = AT_NONE;
+  pi.dst.type = AT_NONE;
+  pi.ipproto  = 0;
+  pi.ptype = PT_NONE;
+  pi.srcport  = 0;
+  pi.destport = 0;
+}
+
+/* Allow protocols to register "init" routines, which are called before
+   we make a pass through a capture file and dissect all its packets
+   (e.g., when we read in a new capture file, or run a "filter packets"
+   or "colorize packets" pass over the current capture file). */
+static GSList *init_routines;
+
+void
+register_init_routine(void (*func)(void))
+{
+       init_routines = g_slist_append(init_routines, func);
+}
+
+/* Call all the registered "init" routines. */
+static void
+call_init_routine(gpointer routine, gpointer dummy)
+{
+       void (*func)(void) = routine;
+
+       (*func)();
+}
+
+void
+init_all_protocols(void)
+{
+       g_slist_foreach(init_routines, &call_init_routine, NULL);
+}
 
 /* this routine checks the frame type from the cf structure */
 void
@@ -628,9 +1063,10 @@ dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
        /* Put in frame header information. */
        if (tree) {
          ti = proto_tree_add_item_format(tree, proto_frame, 0, fd->cap_len,
-           NULL, "Frame (%d on wire, %d captured)", fd->pkt_len, fd->cap_len);
+           NULL, "Frame %u (%u on wire, %u captured)", fd->num,
+           fd->pkt_len, fd->cap_len);
 
-         fh_tree = proto_item_add_subtree(ti, ETT_FRAME);
+         fh_tree = proto_item_add_subtree(ti, ett_frame);
 
          tv.tv_sec = fd->abs_secs;
          tv.tv_usec = fd->abs_usecs;
@@ -638,6 +1074,15 @@ dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
          proto_tree_add_item(fh_tree, hf_frame_arrival_time,
                0, 0, &tv);
 
+         tv.tv_sec = fd->del_secs;
+         tv.tv_usec = fd->del_usecs;
+
+         proto_tree_add_item(fh_tree, hf_frame_time_delta,
+               0, 0, &tv);
+
+         proto_tree_add_item(fh_tree, hf_frame_number,
+               0, 0, fd->num);
+
          proto_tree_add_item_format(fh_tree, hf_frame_packet_len,
                0, 0, fd->pkt_len, "Packet Length: %d byte%s", fd->pkt_len,
                plurality(fd->pkt_len, "", "s"));
@@ -647,6 +1092,8 @@ dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
                plurality(fd->cap_len, "", "s"));
        }
 
+       blank_packetinfo();
+
        /* Set the initial payload to the packet length, and the initial
           captured payload to the capture length (other protocols may
           reduce them if their headers say they're less). */
@@ -658,12 +1105,15 @@ dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
                        dissect_eth(pd, 0, fd, tree);
                        break;
                case WTAP_ENCAP_FDDI :
-                       dissect_fddi(pd, fd, tree);
+                       dissect_fddi(pd, fd, tree, FALSE);
+                       break;
+               case WTAP_ENCAP_FDDI_BITSWAPPED :
+                       dissect_fddi(pd, fd, tree, TRUE);
                        break;
                case WTAP_ENCAP_TR :
                        dissect_tr(pd, 0, fd, tree);
                        break;
-               case WTAP_ENCAP_NONE :
+               case WTAP_ENCAP_NULL :
                        dissect_null(pd, fd, tree);
                        break;
                case WTAP_ENCAP_PPP :
@@ -681,6 +1131,15 @@ dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
                case WTAP_ENCAP_ATM_SNIFFER :
                        dissect_atm(pd, fd, tree);
                        break;
+               case WTAP_ENCAP_ASCEND :
+                       dissect_ascend(pd, fd, tree);
+                       break;
+               case WTAP_ENCAP_LAPD :
+                       dissect_lapd(pd, fd, tree);
+                       break;
+               case WTAP_ENCAP_V120 :
+                       dissect_v120(pd, fd, tree);
+                       break;
        }
 }
 
@@ -689,15 +1148,31 @@ proto_register_frame(void)
 {
        static hf_register_info hf[] = {
                { &hf_frame_arrival_time,
-               { "Arrival Time",               "frame.time", FT_ABSOLUTE_TIME, NULL }},
+               { "Arrival Time",               "frame.time", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0,
+                       ""}},
+
+               { &hf_frame_time_delta,
+               { "Time delta from previous packet",    "frame.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL,
+                       0x0,
+                       "" }},
+
+               { &hf_frame_number,
+               { "Frame Number",               "frame.number", FT_UINT32, BASE_DEC, NULL, 0x0,
+                       "" }},
 
                { &hf_frame_packet_len,
-               { "Total Frame Length",         "frame.pkt_len", FT_UINT32, NULL }},
+               { "Total Frame Length",         "frame.pkt_len", FT_UINT32, BASE_DEC, NULL, 0x0,
+                       "" }},
 
                { &hf_frame_capture_len,
-               { "Capture Frame Length",       "frame.cap_len", FT_UINT32, NULL }}
+               { "Capture Frame Length",       "frame.cap_len", FT_UINT32, BASE_DEC, NULL, 0x0,
+                       "" }},
+       };
+       static gint *ett[] = {
+               &ett_frame,
        };
 
        proto_frame = proto_register_protocol("Frame", "frame");
        proto_register_field_array(proto_frame, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));
 }