Get rid of the fd member of a wth structure; the FILE_T's in that
[obnox/wireshark/wip.git] / wiretap / iseries.c
index 3c0ed2414e142fa9e92b9decbb4522b4df732f96..c48dae95e5eae2be14e76133f0d96bdc1a551c81 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 
+#include <wsutil/str_util.h>
+
 #define ISERIES_HDR_MAGIC_STR  " COMMUNICATIONS TRACE"
 #define ISERIES_HDR_MAGIC_LEN   21
 #define ISERIES_PKT_MAGIC_STR   "ETHV2"
 #define ISERIES_FORMAT_ASCII    1
 #define ISERIES_FORMAT_UNICODE  2
 
+typedef struct {
+  gboolean have_date;     /* TRUE if we found a capture start date */
+  int year, month, day;   /* The start date */
+  gboolean tcp_formatted; /* TCP/IP data formated Y/N */
+  int format;             /* Trace format type        */
+} iseries_t;
+
 static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
                              gint64 *data_offset);
 static gboolean iseries_seek_read (wtap * wth, gint64 seek_off,
                                   union wtap_pseudo_header *pseudo_header,
                                   guint8 * pd, int len, int *err,
                                   gchar ** err_info);
-static gboolean iseries_check_file_type (wtap * wth, int *err, int format);
-static gint64 iseries_seek_next_packet (wtap * wth, int *err);
+static gboolean iseries_check_file_type (wtap * wth, int *err, gchar **err_info,
+                                        int format);
+static gint64 iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info);
 static int iseries_parse_packet (wtap * wth, FILE_T fh,
                                 union wtap_pseudo_header *pseudo_header,
                                 guint8 * pd, int *err, gchar ** err_info);
 static int iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes);
-static gboolean iseries_parse_hex_string (guint8 * ascii, guint8 * buf,
+static gboolean iseries_parse_hex_string (const char * ascii, guint8 * buf,
                                          int len);
 
 int
-iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
+iseries_open (wtap * wth, int *err, gchar ** err_info)
 {
   int bytes_read;
   char magic[ISERIES_HDR_MAGIC_LEN];
@@ -167,10 +177,10 @@ iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
    * Check that file starts with a valid iSeries COMMS TRACE header
    */
   errno = WTAP_ERR_CANT_READ;
-  bytes_read = file_read (&magic, 1, sizeof magic, wth->fh);
+  bytes_read = file_read (&magic, sizeof magic, wth->fh);
   if (bytes_read != sizeof magic)
     {
-      *err = file_error (wth->fh);
+      *err = file_error (wth->fh, err_info);
       if (*err != 0)
        return -1;
       return 0;
@@ -187,7 +197,7 @@ iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
        * Do some basic sanity checking to ensure we can handle the
        * contents of this trace
        */
-      if (!iseries_check_file_type (wth, err, ISERIES_FORMAT_ASCII))
+      if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII))
        {
          if (*err == 0)
            return 0;
@@ -195,7 +205,7 @@ iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
            return -1;
        }
       wth->data_offset = 0;
-      wth->file_encap = WTAP_ENCAP_PER_PACKET;
+      wth->file_encap = WTAP_ENCAP_ETHERNET;
       wth->file_type = WTAP_FILE_ISERIES;
       wth->snapshot_length = 0;
       wth->subtype_read = iseries_read;
@@ -219,7 +229,7 @@ iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
        * Do some basic sanity checking to ensure we can handle the
        * contents of this trace
        */
-      if (!iseries_check_file_type (wth, err, ISERIES_FORMAT_UNICODE))
+      if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE))
        {
          if (*err == 0)
            return 0;
@@ -227,7 +237,7 @@ iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
            return -1;
        }
       wth->data_offset = 0;
-      wth->file_encap = WTAP_ENCAP_PER_PACKET;
+      wth->file_encap = WTAP_ENCAP_ETHERNET;
       wth->file_type = WTAP_FILE_ISERIES_UNICODE;
       wth->snapshot_length = 0;
       wth->subtype_read = iseries_read;
@@ -250,19 +260,19 @@ iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
  * requisit requirements and additional information.
  */
 static gboolean
-iseries_check_file_type (wtap * wth, int *err, int format)
+iseries_check_file_type (wtap * wth, int *err, gchar **err_info, int format)
 {
   guint line;
   int num_items_scanned;
-  char buf[ISERIES_LINE_LENGTH], protocol[9], tcpformat[2];
-  guint8 *sdate;
+  char buf[ISERIES_LINE_LENGTH], protocol[9], tcpformat[2] = "";
+  iseries_t *iseries;
 
   /* Save trace format for passing between packets */
-  sdate = g_malloc (10);
-  wth->capture.iseries = g_malloc (sizeof (iseries_t));
-  wth->capture.iseries->sdate = NULL;
-  wth->capture.iseries->format = format;
-  wth->capture.iseries->tcp_formatted = FALSE;
+  iseries = (iseries_t *) g_malloc (sizeof (iseries_t));
+  wth->priv = (void *)iseries;
+  iseries->have_date = FALSE;
+  iseries->format = format;
+  iseries->tcp_formatted = FALSE;
 
   for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
     {
@@ -271,11 +281,11 @@ iseries_check_file_type (wtap * wth, int *err, int format)
          /*
           * Check that we are dealing with an ETHERNET trace
           */
-         if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
+         if (iseries->format == ISERIES_FORMAT_UNICODE)
            {
-             iseries_UNICODE_to_ASCII (buf, ISERIES_LINE_LENGTH);
+             iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
            }
-         g_strup(buf);
+         ascii_strup_inplace(buf);
          num_items_scanned = sscanf (buf,
                                      "   OBJECT PROTOCOL  . . . . . . :  %8s",
                                      protocol);
@@ -295,11 +305,11 @@ iseries_check_file_type (wtap * wth, int *err, int format)
            {
              if (strncmp (tcpformat, "Y", 1) == 0)
                {
-                 wth->capture.iseries->tcp_formatted = TRUE;
+                 iseries->tcp_formatted = TRUE;
                }
              else
                {
-                 wth->capture.iseries->tcp_formatted = FALSE;
+                 iseries->tcp_formatted = FALSE;
                }
            }
 
@@ -308,11 +318,12 @@ iseries_check_file_type (wtap * wth, int *err, int format)
           * extract it here and store for all packets to access
           */
          num_items_scanned = sscanf (buf,
-                                     "   START DATE/TIME  . . . . . . :  %8s",
-                                     sdate);
-         if (num_items_scanned == 1)
+                                     "   START DATE/TIME  . . . . . . :  %2d/%2d/%4d",
+                                     &iseries->month, &iseries->day,
+                                     &iseries->year);
+         if (num_items_scanned == 3)
            {
-             wth->capture.iseries->sdate = sdate;
+             iseries->have_date = TRUE;
            }
 
        }
@@ -322,7 +333,7 @@ iseries_check_file_type (wtap * wth, int *err, int format)
          if (file_eof (wth->fh))
            *err = 0;
          else
-           *err = file_error (wth->fh);
+           *err = file_error (wth->fh, err_info);
          return FALSE;
        }
     }
@@ -342,7 +353,7 @@ iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
   /*
    * Locate the next packet
    */
-  offset = iseries_seek_next_packet (wth, err);
+  offset = iseries_seek_next_packet (wth, err, err_info);
   if (offset < 1)
     return FALSE;
 
@@ -362,11 +373,13 @@ iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
 
 /*
  * Seeks to the beginning of the next packet, and returns the
- * byte offset.  Returns -1 on failure, and sets "*err" to the error.
+ * byte offset.  Returns -1 on failure, and sets "*err" to the error
+ * and "*err_info" to null or an additional error string.
  */
 static gint64
-iseries_seek_next_packet (wtap * wth, int *err)
+iseries_seek_next_packet (wtap * wth, int *err, gchar **err_info)
 {
+  iseries_t *iseries = (iseries_t *)wth->priv;
   char buf[ISERIES_LINE_LENGTH];
   int line;
   gint64 cur_off;
@@ -374,7 +387,8 @@ iseries_seek_next_packet (wtap * wth, int *err)
 
   /*
    * Seeks to the beginning of the next packet, and returns the
-   * byte offset.  Returns -1 on failure, and sets "*err" to the error.
+   * byte offset.  Returns -1 on failure, and sets "*err" to the error
+   * and "*err_info" to null or an additional error string.
    */
   for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
     {
@@ -383,15 +397,15 @@ iseries_seek_next_packet (wtap * wth, int *err)
 
          /* Convert UNICODE to ASCII if required and determine    */
          /* the number of bytes to rewind to beginning of record. */
-         if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
+         if (iseries->format == ISERIES_FORMAT_UNICODE)
            {
              /* buflen is #bytes to 1st 0x0A */
-             buflen = iseries_UNICODE_to_ASCII (buf, ISERIES_LINE_LENGTH);
+             buflen = iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
            }
          else
            {
              /* Else buflen is just length of the ASCII string */
-             buflen = strlen (buf);
+             buflen = (long) strlen (buf);
            }
          /* If packet header found return the offset */
          if (strncmp (buf + 80, ISERIES_PKT_MAGIC_STR, ISERIES_PKT_MAGIC_LEN)
@@ -401,7 +415,7 @@ iseries_seek_next_packet (wtap * wth, int *err)
              cur_off = file_tell (wth->fh);
              if (cur_off == -1)
                {
-                 *err = file_error (wth->fh);
+                 *err = file_error (wth->fh, err_info);
                  return -1;
                }
              if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
@@ -416,13 +430,13 @@ iseries_seek_next_packet (wtap * wth, int *err)
        {
          if (file_eof (wth->fh))
            {
+             /* We got an EOF. */
              *err = 0;
            }
          else
            {
-             /* We (presumably) got an error (there's no equivalent to "ferror()"
-                in zlib, alas, so we don't have a wrapper to check for an error). */
-             *err = file_error (wth->fh);
+             /* We got an error. */
+             *err = file_error (wth->fh, err_info);
            }
          return -1;
        }
@@ -472,16 +486,18 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
                      union wtap_pseudo_header *pseudo_header, guint8 * pd,
                      int *err, gchar ** err_info)
 {
+  iseries_t *iseries = (iseries_t *)wth->priv;
   gint64 cur_off;
   gboolean isValid, isCurrentPacket, IPread, TCPread, isDATA;
   int num_items_scanned, line, pktline, buflen, i;
   guint32 pkt_len;
-  int cap_len, pktnum, month, day, year, hr, min, sec, csec;
+  int cap_len, pktnum, hr, min, sec, csec;
   char direction[2], destmac[13], srcmac[13], type[5], ipheader[41],
     tcpheader[81];
   char hex1[17], hex2[17], hex3[17], hex4[17];
   char data[ISERIES_LINE_LENGTH * 2];
-  guint8 *buf, *asciibuf, *tcpdatabuf, *workbuf;
+  guint8 *buf;
+  char   *tcpdatabuf, *workbuf, *asciibuf;
   struct tm tm;
 
   /*
@@ -495,7 +511,7 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
       cur_off = file_tell (fh);
       if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
        {
-         *err = file_error (fh);
+         *err = file_error (fh, err_info);
          if (*err == 0)
            {
              *err = WTAP_ERR_SHORT_READ;
@@ -503,18 +519,18 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
          return -1;
        }
       /* Convert UNICODE data to ASCII */
-      if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
+      if (iseries->format == ISERIES_FORMAT_UNICODE)
        {
-         iseries_UNICODE_to_ASCII (data, ISERIES_LINE_LENGTH);
+         iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
        }
       /* look for packet header */
-      for (i=0; i<8; i++) {      
-       if (strncmp(data+i,"*",1) == 0)
-         strncpy(data+i," ",1);
+      for (i=0; i<8; i++) {
+                 if (strncmp(data+i,"*",1) == 0)
+                         g_strlcpy(data+i," ",(ISERIES_LINE_LENGTH * 2));
       }
       num_items_scanned =
        sscanf (data,
-               "%6d   %1s   %6d  %d:%d:%d.%d               %12s  %12s  ETHV2   Type: %s",
+               "%6d   %1s   %6d  %2d:%2d:%2d.%9d               %12s  %12s  ETHV2   Type: %4s",
                &pktnum, direction, &cap_len, &hr, &min, &sec, &csec, destmac,
                srcmac, type);
       if (num_items_scanned == 10)
@@ -543,17 +559,15 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
   /*
    * If we have Wiretap Header then populate it here
    *
-   * XXX - Timer resolution on the iSeries is hardware dependant, the value for csec may be
+   * XXX - Timer resolution on the iSeries is hardware dependant; the value for csec may be
    * different on other platforms though all the traces I've seen seem to show resolution
    * to Milliseconds (i.e HH:MM:SS.nnnnn) or Nanoseconds (i.e HH:MM:SS.nnnnnn)
    */
-  if (wth->capture.iseries->sdate)
+  if (iseries->have_date)
     {
-      num_items_scanned =
-       sscanf (wth->capture.iseries->sdate, "%d/%d/%d", &month, &day, &year);
-      tm.tm_year = 100 + year;
-      tm.tm_mon = month - 1;
-      tm.tm_mday = day;
+      tm.tm_year = 100 + iseries->year;
+      tm.tm_mon = iseries->month - 1;
+      tm.tm_mday = iseries->day;
       tm.tm_hour = hr;
       tm.tm_min = min;
       tm.tm_sec = sec;
@@ -569,11 +583,12 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
        {
          wth->phdr.ts.nsecs = csec * 10000;
        }
-      wth->phdr.caplen = cap_len;
-      wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
-      pseudo_header->eth.fcs_len = -1;
     }
 
+    wth->phdr.caplen = cap_len;
+    wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
+    pseudo_header->eth.fcs_len = -1;
+
   /*
    * Start Reading packet contents
    */
@@ -602,7 +617,7 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
            }
          else
            {
-             *err = file_error (fh);
+             *err = file_error (fh, err_info);
              if (*err == 0)
                {
                  *err = WTAP_ERR_SHORT_READ;
@@ -612,14 +627,14 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
        }
 
       /* Convert UNICODE data to ASCII and determine line length */
-      if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
+      if (iseries->format == ISERIES_FORMAT_UNICODE)
        {
-         buflen = iseries_UNICODE_to_ASCII (data, ISERIES_LINE_LENGTH);
+         buflen = iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
        }
       else
        {
          /* Else bytes to rewind is just length of ASCII string */
-         buflen = strlen (data);
+         buflen = (int) strlen (data);
        }
 
       /* If this is a IP header hex string then set flag */
@@ -686,7 +701,7 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
          if (cur_off == -1)
            {
              /* Error. */
-             *err = file_error (fh);
+             *err = file_error (fh, err_info);
              return -1;
            }
          if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
@@ -700,7 +715,7 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
    * For a formated trace ensure we have read at least the IP and TCP headers otherwise
    * exit and pass error message to user.
    */
-  if (wth->capture.iseries->tcp_formatted)
+  if (iseries->tcp_formatted)
     {
       if (!IPread)
        {
@@ -724,7 +739,7 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
   if (isDATA)
     {
       /* packet contained data */
-      if (wth->capture.iseries->tcp_formatted)
+      if (iseries->tcp_formatted)
        {
          /* build string for formatted fields */
          g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s%s",
@@ -764,19 +779,19 @@ iseries_parse_packet (wtap * wth, FILE_T fh,
       buffer_assure_space (wth->frame_buffer, ISERIES_MAX_PACKET_LEN);
       buf = buffer_start_ptr (wth->frame_buffer);
       /* Convert ascii data to binary and return in the frame buffer */
-      iseries_parse_hex_string (asciibuf, buf, strlen (asciibuf));
+      iseries_parse_hex_string (asciibuf, buf, (int) strlen (asciibuf));
     }
   else
     {
       /* Convert ascii data to binary and return in the frame buffer */
-      iseries_parse_hex_string (asciibuf, pd, strlen (asciibuf));
+      iseries_parse_hex_string (asciibuf, pd, (int) strlen (asciibuf));
     }
 
   /* free buffers allocs and return */
   *err = 0;
-  free (asciibuf);
-  free (tcpdatabuf);
-  free (workbuf);
+  g_free (asciibuf);
+  g_free (tcpdatabuf);
+  g_free (workbuf);
   return wth->phdr.len;
 }
 
@@ -815,18 +830,31 @@ iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
  * Requires ASCII hex data and buffer to populate with binary data
  */
 static gboolean
-iseries_parse_hex_string (guint8 * ascii, guint8 * buf, int len)
+iseries_parse_hex_string (const char * ascii, guint8 * buf, int len)
 {
   int i, byte;
-  char hexvalue[3] = { 0, 0, 0 };
+  gint hexvalue;
+  guint8 bytevalue;
 
   byte = 0;
-  for (i = 0; i < len; i++)
+  i = 0;
+  for (;;)
     {
-      hexvalue[0] = ascii[i];
+      if (i >= len)
+        break;
+      hexvalue = g_ascii_xdigit_value(ascii[i]);
+      i++;
+      if (hexvalue == -1)
+        return FALSE;  /* not a valid hex digit */
+      bytevalue = (guint8)(hexvalue << 4);
+      if (i >= len)
+        return FALSE;  /* only one hex digit of the byte is present */
+      hexvalue = g_ascii_xdigit_value(ascii[i]);
       i++;
-      hexvalue[1] = ascii[i];
-      buf[byte] = (guint8) strtoul (hexvalue, NULL, 16);
+      if (hexvalue == -1)
+        return FALSE;  /* not a valid hex digit */
+      bytevalue |= (guint8) hexvalue;
+      buf[byte] = bytevalue;
       byte++;
     }
   return TRUE;