/* iseries.c
- *
- * $Id$
*
* Wiretap Library
- * Copyright (c) 2005 by Martin Warnes <Martin_Warnes@Stercomm.com>
+ * Copyright (c) 2011 by Martin Warnes <Martin_Warnes@uk.ibm.com>
*
* Based on toshiba.c and vms.c
*
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* This module will read the contents of the iSeries (OS/400) Communication trace
- * Both ASCII & Unicode formatted traces are supported.
+ * Both ASCII & Unicode (little-endian UCS-2) formatted traces are supported.
*
* iSeries Comms traces consist of a header page and a subsequent number of packet records
*
* currently the following options are a requirement for this module:
*
* 1. Object protocol = ETHERNET (Default)
- * 2. ASCII or UNICODE file formats.
+ * 2. ASCII or Unicode file formats.
*
* The above can be acheived by passing option ASCII(*YES) with the trace command
*
Format Broadcast data . . . : Y Y=Yes, N=No
*/
-/* iSeries formatted packet records consist of a header line identifying the packet number,direction,size,
- * timestamp,source/destination MAC addresses and packet type.
+/* iSeries IPv4 formatted packet records consist of a packet header line
+ * identifying the packet number, direction, size, timestamp,
+ * source/destination MAC addresses and packet type.
+ *
+ * Thereafter there will be a formated display of the headers above
+ * the link layer, such as ARP, IP, TCP, UDP, and ICMP (all but
+ * ICMP have either been seen in captures or on pages such as the ones
+ * at
+ *
+ * http://www-912.ibm.com/s_dir/SLKBase.nsf/1ac66549a21402188625680b0002037e/e05fb0515bc3449686256ce600512c37?OpenDocument
+ *
+ * and
+ *
+ * http://publib.boulder.ibm.com/infocenter/javasdk/v5r0/index.jsp?topic=%2Fcom.ibm.java.doc.diagnostics.50%2Fdiag%2Fproblem_determination%2Fi5os_perf_io_commstrace.html
*
- * Thereafter there will be a formated display of the IP and TCP headers as well as a hex string dump
- * of the headers themselves displayed in the the "IP Header" and "TCP header" fields.
+ * so we cannot assume that "IP Header" or "TCP Header" will appear). The
+ * formatted display includes lines that show the contents of some of the
+ * fields in the header, as well as hex strings dumps of the headers
+ * themselves, with tags such as "IP Header :", "ARP Header :",
+ * "TCP Header :", "UDP Header :", and (presumably) "ICMP Header:".
*
- * If the packet contains data this is displayed as 4 groups of 16 hex digits followed by an ASCII
- * representaion of the data line.
+ * If the packet contains data this is displayed as 4 groups of 16 hex digits
+ * followed by an ASCII representaion of the data line.
*
- * Information from the header line, IP header, TCP header and if available data lines are extracted
- * by the module for displaying.
+ * Information from the packet header line, higher-level headers and, if
+ * available, data lines are extracted by the module for displaying.
*
*
Record Data Record Controller Destination Source Frame
FC276228786B3EB0 EF34F5F1D27EF8DF 20926820E7B322AA 739F1FB20D **'B(XK>**4***.** *H **"*S*.*. *
*/
-/* iSeries unformatted packet record consist of the same header record as the formatted trace but all
- * other records are simply unformatted data containing IP, TCP and packet data combined.
+/* iSeries IPv6 formatted traces are similar to the IPv4 version above,
+ * except that the higher-level headers have "IPv6 Header:" and
+ * "ICMPv6 Hdr:", and data data is no longer output in groups of 16 hex
+ * digits.
+ *
+
+Record Data Record Destination Source Frame
+Number S/R Length Timer MAC Address MAC Address Format
+------ --- ------ ------------ ------------ ------------ ------
+ 218 S 1488 15:01:14.389 0011BC358680 00096B6BD918 ETHV2 Type: 86DD
+ IPv6 Data: Ver: 06 Traffic Class: 00 Flow Label: 000000
+ Payload Length: 1448 Next Header: 06,TCP Hop Limit: 64
+ Src Addr: fd00:0:0:20f2::122
+ Dest Addr: fd00:0:0:20a0::155
+ IPv6 Header: 6000000005A80640FD000000000020F20000000000000122FD000000000020A0
+ 0000000000000155
+ TCP . . . : Src Port: 21246,Unassigned Dest Port: 13601,Unassigned
+ SEQ Number: 2282300877 ('880925CD'X) ACK Number: 3259003715 ('C2407343'X)
+ Code Bits: ACK Window: 65535 TCP Option: NO OP
+ TCP Header : 52FE3521880925CDC24073438010FFFFCFBB00000101080A0E15127000237A08
+ Data . . . . . : 54435032000200140000061880000000ECBEB867F0000000004CE640E6C1D9D5 *TCP2........*...***g*....L*@*****
+ C9D5C740E3C8C9E240C9E240E3C8C540E6C1D9D5C9D5C740C6C9C5D3C4404040 ****@****@**@***@*******@*****@@@*
+ 4040404040404040404040404040404040404040404040404040404040404040 *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
+*/
+
+/* iSeries unformatted packet record consist of the same header record as
+ * the formatted trace but all other records are simply unformatted data
+ * containing higher-level headers and packet data combined.
*
Record Data Record Controller Destination Source Frame Number Number Poll/
Number S/R Length Timer Name MAC Address MAC Address Format Command Sent Received Final DSAP SSAP
A00216D06A200000 020405B40402080A 1104B6C000000000 010303000B443BF1 **..*J .....*......**.........D;**
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include "wtap-int.h"
-#include "buffer.h"
#include "iseries.h"
#include "file_wrappers.h"
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <errno.h>
-#define ISERIES_HDR_MAGIC_STR " COMMUNICATIONS TRACE"
-#define ISERIES_HDR_MAGIC_LEN 21
-#define ISERIES_PKT_MAGIC_STR "ETHV2"
-#define ISERIES_PKT_MAGIC_LEN 5
-#define ISERIES_LINE_LENGTH 270
-#define ISERIES_HDR_LINES_TO_CHECK 50
-#define ISERIES_PKT_LINES_TO_CHECK 4
-#define ISERIES_MAX_PACKET_LEN 16384
-#define ISERIES_MAX_TRACE_LEN 99999999
-#define ISERIES_PKT_ALLOC_SIZE (cap_len*2)+1
-#define ISERIES_FORMAT_ASCII 1
-#define ISERIES_FORMAT_UNICODE 2
+#include <wsutil/str_util.h>
+#include <wsutil/strtoi.h>
+
+#define ISERIES_LINE_LENGTH 270
+#define ISERIES_HDR_LINES_TO_CHECK 100
+#define ISERIES_PKT_LINES_TO_CHECK 4
+#define ISERIES_MAX_TRACE_LEN 99999999
+#define ISERIES_FORMAT_ASCII 1
+#define ISERIES_FORMAT_UNICODE 2
+
+/*
+ * Magic strings - "COMMUNICATIONS TRACE", in ASCII and little-endian UCS-2.
+ */
+static const char iseries_hdr_magic_ascii[] = {
+ 'C', 'O', 'M', 'M',
+ 'U', 'N', 'I', 'C',
+ 'A', 'T', 'I', 'O',
+ 'N', 'S', ' ', 'T',
+ 'R', 'A', 'C', 'E'
+};
+static const char iseries_hdr_magic_le_ucs_2[] = {
+ 'C', 0x0, 'O', 0x0, 'M', 0x0, 'M', 0x0,
+ 'U', 0x0, 'N', 0x0, 'I', 0x0, 'C', 0x0,
+ 'A', 0x0, 'T', 0x0, 'I', 0x0, 'O', 0x0,
+ 'N', 0x0, 'S', 0x0, ' ', 0x0, 'T', 0x0,
+ 'R', 0x0, 'A', 0x0, 'C', 0x0, 'E', 0x0
+};
+
+typedef struct {
+ gboolean have_date; /* TRUE if we found a capture start date */
+ int year, month, day; /* The start date */
+ int format; /* Trace format type */
+} iseries_t;
static gboolean iseries_read (wtap * wth, int *err, gchar ** err_info,
- gint64 *data_offset);
+ 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 int iseries_parse_packet (wtap * wth, FILE_T fh,
- union wtap_pseudo_header *pseudo_header,
- guint8 * pd, int *err, gchar ** err_info);
+ struct wtap_pkthdr *phdr,
+ Buffer * buf, int *err, gchar ** err_info);
+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 gboolean iseries_parse_packet (wtap * wth, FILE_T fh,
+ struct wtap_pkthdr *phdr,
+ Buffer * buf, 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,
- int len);
+static gboolean iseries_parse_hex_string (const char * ascii, guint8 * buf,
+ size_t len);
-int
-iseries_open (wtap * wth, int *err, gchar ** err_info _U_)
+/*
+ * XXX - it would probably be cleaner to use a UCS-2 flavor of file_gets(),
+ * rather than file_gets(), if we're reading a UCS-2 file.
+ */
+wtap_open_return_val
+iseries_open (wtap * wth, int *err, gchar ** err_info)
{
- int bytes_read;
- char magic[ISERIES_HDR_MAGIC_LEN];
- /* UNICODE identification */
- char unicodemagic[ISERIES_HDR_MAGIC_LEN] =
- { '\xFF', '\xFE', '\x20', '\x00', '\x43', '\x00', '\x4F', '\x00', '\x4D',
- '\x00', '\x4D', '\x00', '\x55', '\x00', '\x4E', '\x00', '\x49', '\x00',
- '\x43', '\x00', '\x41'
- };
+ gint offset;
+ char magic[ISERIES_LINE_LENGTH];
/*
* Check that file starts with a valid iSeries COMMS TRACE header
+ * by scanning for it in the first line
*/
- errno = WTAP_ERR_CANT_READ;
- bytes_read = file_read (&magic, 1, sizeof magic, wth->fh);
- if (bytes_read != sizeof magic)
+ if (!wtap_read_bytes (wth->fh, &magic, sizeof magic, err, err_info))
{
- *err = file_error (wth->fh);
- if (*err != 0)
- return -1;
- return 0;
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
}
- /* Check if this is an ASCII formatted file */
- if (memcmp (magic, ISERIES_HDR_MAGIC_STR, ISERIES_HDR_MAGIC_LEN) == 0)
+ /*
+ * Check if this is a little-endian UCS-2 Unicode formatted file by scanning
+ * for the magic string
+ */
+ offset=0;
+ while ((unsigned int)offset < (ISERIES_LINE_LENGTH - (sizeof iseries_hdr_magic_le_ucs_2)))
{
- if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
- {
- return 0;
- }
- /*
- * 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 (*err == 0)
- return 0;
- else
- return -1;
- }
- wth->data_offset = 0;
- wth->file_encap = WTAP_ENCAP_PER_PACKET;
- wth->file_type = WTAP_FILE_ISERIES;
- wth->snapshot_length = 0;
- wth->subtype_read = iseries_read;
- wth->subtype_seek_read = iseries_seek_read;
- wth->tsprecision = WTAP_FILE_TSPREC_USEC;
- if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
- {
- return 0;
- }
- return 1;
- }
+ if (memcmp (magic + offset, iseries_hdr_magic_le_ucs_2, sizeof iseries_hdr_magic_le_ucs_2) == 0) {
+ if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
+ {
+ return WTAP_OPEN_ERROR;
+ }
+ /*
+ * Do some basic sanity checking to ensure we can handle the
+ * contents of this trace
+ */
+ if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_UNICODE))
+ {
+ if (*err == 0)
+ return WTAP_OPEN_NOT_MINE;
+ else
+ return WTAP_OPEN_ERROR;
+ }
- /* Check if this is a UNICODE formatted file */
- if (memcmp (magic, unicodemagic, ISERIES_HDR_MAGIC_LEN) == 0)
- {
- if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
- {
- return 0;
- }
- /*
- * 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 (*err == 0)
- return 0;
- else
- return -1;
- }
- wth->data_offset = 0;
- wth->file_encap = WTAP_ENCAP_PER_PACKET;
- wth->file_type = WTAP_FILE_ISERIES_UNICODE;
- wth->snapshot_length = 0;
- wth->subtype_read = iseries_read;
- wth->subtype_seek_read = iseries_seek_read;
- wth->tsprecision = WTAP_FILE_TSPREC_USEC;
- if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
- {
- return 0;
- }
- return 1;
+ wth->file_encap = WTAP_ENCAP_ETHERNET;
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
+ wth->snapshot_length = 0;
+ wth->subtype_read = iseries_read;
+ wth->subtype_seek_read = iseries_seek_read;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+
+ if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
+ {
+ return WTAP_OPEN_ERROR;
+ }
+ return WTAP_OPEN_MINE;
+ }
+ offset += 1;
}
- /* Neither ASCII or UNICODE so not supported */
- return 0;
-}
+ /*
+ * Check if this is a ASCII formatted file by scanning for the magic string
+ */
+ offset=0;
+ while ((unsigned int)offset < (ISERIES_LINE_LENGTH - sizeof iseries_hdr_magic_ascii))
+ {
+ if (memcmp (magic + offset, iseries_hdr_magic_ascii, sizeof iseries_hdr_magic_ascii) == 0)
+ {
+ if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
+ {
+ return WTAP_OPEN_ERROR;
+ }
+ /*
+ * Do some basic sanity checking to ensure we can handle the
+ * contents of this trace
+ */
+ if (!iseries_check_file_type (wth, err, err_info, ISERIES_FORMAT_ASCII))
+ {
+ if (*err == 0)
+ return WTAP_OPEN_NOT_MINE;
+ else
+ return WTAP_OPEN_ERROR;
+ }
+
+ wth->file_encap = WTAP_ENCAP_ETHERNET;
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ISERIES;
+ wth->snapshot_length = 0;
+ wth->subtype_read = iseries_read;
+ wth->subtype_seek_read = iseries_seek_read;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+
+ if (file_seek (wth->fh, 0, SEEK_SET, err) == -1)
+ {
+ return WTAP_OPEN_ERROR;
+ }
+ return WTAP_OPEN_MINE;
+ }
+ offset += 1;
+ }
+
+ /* Neither ASCII or UNICODE so not supported */
+ return WTAP_OPEN_NOT_MINE;
+ }
/*
* Do some basic sanity checking to ensure we can handle the
* 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;
+ gboolean is_iseries = FALSE;
+ guint line;
+ int num_items_scanned;
+ char buf[ISERIES_LINE_LENGTH], protocol[9];
+ 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));
+ iseries->have_date = FALSE;
+ iseries->format = format;
for (line = 0; line < ISERIES_HDR_LINES_TO_CHECK; line++)
{
- if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) != NULL)
- {
- /*
- * Check that we are dealing with an ETHERNET trace
- */
- if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
- {
- iseries_UNICODE_to_ASCII (buf, ISERIES_LINE_LENGTH);
- }
- g_strup(buf);
- num_items_scanned = sscanf (buf,
- " OBJECT PROTOCOL . . . . . . : %8s",
- protocol);
- if (num_items_scanned == 1)
- {
- if (memcmp (protocol, "ETHERNET", 8) != 0)
- return FALSE;
- }
-
- /*
- * Determine if the data has been formatted or not
- */
- num_items_scanned = sscanf (buf,
- " FORMAT TCP/IP DATA ONLY . . : %1s",
- tcpformat);
- if (num_items_scanned == 1)
- {
- if (strncmp (tcpformat, "Y", 1) == 0)
- {
- wth->capture.iseries->tcp_formatted = TRUE;
- }
- else
- {
- wth->capture.iseries->tcp_formatted = FALSE;
- }
- }
-
- /*
- * The header is the only place where the date part of the timestamp is held, so
- * 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)
- {
- wth->capture.iseries->sdate = sdate;
- }
-
- }
- else
- {
- /* EOF or error. */
- if (file_eof (wth->fh))
- *err = 0;
- else
- *err = file_error (wth->fh);
- return FALSE;
- }
+ memset(buf, 0x0, sizeof(buf));
+ if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
+ {
+ /* EOF or error. */
+ *err = file_error (wth->fh, err_info);
+ if (*err == WTAP_ERR_SHORT_READ)
+ *err = 0;
+ break;
+ }
+
+ /*
+ * Check that we are dealing with an ETHERNET trace
+ */
+ if (iseries->format == ISERIES_FORMAT_UNICODE)
+ {
+ iseries_UNICODE_to_ASCII ((guint8 *)buf, ISERIES_LINE_LENGTH);
+ }
+ ascii_strup_inplace (buf);
+ num_items_scanned = sscanf (buf,
+ "%*[ \n\t]OBJECT PROTOCOL%*[ .:\n\t]%8s",
+ protocol);
+ if (num_items_scanned == 1)
+ {
+ if (memcmp (protocol, "ETHERNET", 8) == 0)
+ {
+ *err = 0;
+ is_iseries = TRUE;
+ }
+ }
+
+ /*
+ * The header is the only place where the date part of the timestamp is held, so
+ * extract it here and store for all packets to access
+ */
+ num_items_scanned = sscanf (buf,
+ "%*[ \n\t]START DATE/TIME%*[ .:\n\t]%2d/%2d/%2d",
+ &iseries->month, &iseries->day,
+ &iseries->year);
+ if (num_items_scanned == 3)
+ {
+ iseries->have_date = TRUE;
+ }
}
- *err = 0;
- return TRUE;
+
+ if (is_iseries)
+ wth->priv = (void *) iseries;
+ else
+ g_free(iseries);
+
+ return is_iseries;
}
/*
iseries_read (wtap * wth, int *err, gchar ** err_info, gint64 *data_offset)
{
gint64 offset;
- int pkt_len;
/*
* Locate the next packet
*/
- offset = iseries_seek_next_packet (wth, err);
- if (offset < 1)
+ offset = iseries_seek_next_packet (wth, err, err_info);
+ if (offset < 0)
return FALSE;
+ *data_offset = offset;
/*
* Parse the packet and extract the various fields
*/
- pkt_len =
- iseries_parse_packet (wth, wth->fh, &wth->pseudo_header, NULL, err,
- err_info);
- if (pkt_len == -1)
- return FALSE;
-
- wth->data_offset = offset;
- *data_offset = offset;
- return TRUE;
+ return iseries_parse_packet (wth, wth->fh, &wth->phdr, wth->frame_buffer,
+ err, err_info);
}
/*
* 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 or EOF; on EOF, sets
+ * *err to 0, and, on failure, 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)
{
- char buf[ISERIES_LINE_LENGTH];
- int line;
- gint64 cur_off;
- long buflen;
+ iseries_t *iseries = (iseries_t *)wth->priv;
+ char buf[ISERIES_LINE_LENGTH],type[5];
+ int line, num_items_scanned;
+ gint64 cur_off;
+ long buflen;
- /*
- * Seeks to the beginning of the next packet, and returns the
- * byte offset. Returns -1 on failure, and sets "*err" to the error.
- */
for (line = 0; line < ISERIES_MAX_TRACE_LEN; line++)
{
- if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) != NULL)
- {
-
- /* 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)
- {
- /* buflen is #bytes to 1st 0x0A */
- buflen = iseries_UNICODE_to_ASCII (buf, ISERIES_LINE_LENGTH);
- }
- else
- {
- /* Else buflen is just length of the ASCII string */
- buflen = strlen (buf);
- }
- /* If packet header found return the offset */
- if (strncmp (buf + 80, ISERIES_PKT_MAGIC_STR, ISERIES_PKT_MAGIC_LEN)
- == 0)
- {
- /* Rewind to beginning of line */
- cur_off = file_tell (wth->fh);
- if (cur_off == -1)
- {
- *err = file_error (wth->fh);
- return -1;
- }
- if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
- {
- return -1;
- }
- return cur_off - buflen;
- }
- }
- /* Otherwise we got an error or reached EOF */
- else
- {
- if (file_eof (wth->fh))
- {
- *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);
- }
- return -1;
- }
+ if (file_gets (buf, ISERIES_LINE_LENGTH, wth->fh) == NULL)
+ {
+ /* EOF or error. */
+ *err = file_error (wth->fh, err_info);
+ return -1;
+ }
+ /* Convert UNICODE to ASCII if required and determine */
+ /* the number of bytes to rewind to beginning of record. */
+ if (iseries->format == ISERIES_FORMAT_UNICODE)
+ {
+ /* buflen is #bytes to 1st 0x0A */
+ buflen = iseries_UNICODE_to_ASCII ((guint8 *) buf, ISERIES_LINE_LENGTH);
+ }
+ else
+ {
+ /* Else buflen is just length of the ASCII string */
+ buflen = (long) strlen (buf);
+ }
+ ascii_strup_inplace (buf);
+ /* If packet header found return the offset */
+ num_items_scanned =
+ sscanf (buf+78,
+ "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
+ if (num_items_scanned == 1)
+ {
+ /* Rewind to beginning of line */
+ cur_off = file_tell (wth->fh);
+ if (cur_off == -1)
+ {
+ *err = file_error (wth->fh, err_info);
+ return -1;
+ }
+ if (file_seek (wth->fh, cur_off - buflen, SEEK_SET, err) == -1)
+ {
+ return -1;
+ }
+ return cur_off - buflen;
+ }
}
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info =
+ g_strdup_printf ("iseries: next packet header not found within %d lines",
+ ISERIES_MAX_TRACE_LEN);
return -1;
}
* Read packets in random-access fashion
*/
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)
+iseries_seek_read (wtap * wth, gint64 seek_off, struct wtap_pkthdr *phdr,
+ Buffer * buf, int *err, gchar ** err_info)
{
- int pkt_len;
/* seek to packet location */
if (file_seek (wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
/*
* Parse the packet and extract the various fields
*/
- pkt_len = iseries_parse_packet (wth, wth->random_fh, pseudo_header, pd,
- err, err_info);
+ return iseries_parse_packet (wth, wth->random_fh, phdr, buf,
+ err, err_info);
+}
+
+static int
+append_hex_digits(char *ascii_buf, int ascii_offset, int max_offset,
+ char *data, int *err, gchar **err_info)
+{
+ int in_offset, out_offset;
+ int c;
+ unsigned int i;
+ gboolean overflow = FALSE;
- if (pkt_len != len)
+ in_offset = 0;
+ out_offset = ascii_offset;
+ for (;;)
{
- if (pkt_len != -1)
- {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info =
- g_strdup_printf
- ("iseries: requested length %d doesn't match record length %d",
- len, pkt_len);
- }
- return FALSE;
+ /*
+ * Process a block of up to 16 hex digits.
+ * The block is terminated early by an end-of-line indication (NUL,
+ * CR, or LF), by a space (which terminates the last block of the
+ * data we're processing), or by a "*", which introduces the ASCII representation
+ * of the data.
+ * All characters in the block must be upper-case hex digits;
+ * there might or might not be a space *after* a block, but, if so,
+ * that will be skipped over after the block is processed.
+ */
+ for (i = 0; i < 16; i++, in_offset++)
+ {
+ /*
+ * If we see an end-of-line indication, or an early-end-of-block
+ * indication (space), we're done. (Only the last block ends
+ * early.)
+ */
+ c = data[in_offset] & 0xFF;
+ if (c == '\0' || c == ' ' || c == '*' || c == '\r' || c == '\n')
+ {
+ goto done;
+ }
+ if (!g_ascii_isxdigit(c) || g_ascii_islower(c))
+ {
+ /*
+ * Not a hex digit, or a lower-case hex digit.
+ * Treat this as an indication that the line isn't a data
+ * line, so we just ignore it.
+ *
+ * XXX - do so only for continuation lines; treat non-hex-digit
+ * characters as errors for other lines?
+ */
+ return ascii_offset; /* pretend we appended nothing */
+ }
+ if (out_offset >= max_offset)
+ overflow = TRUE;
+ else
+ {
+ ascii_buf[out_offset] = c;
+ out_offset++;
+ }
+ }
+ /*
+ * Skip blanks, if any.
+ */
+ for (; (data[in_offset] & 0xFF) == ' '; in_offset++)
+ ;
}
- return TRUE;
+done:
+ /*
+ * If we processed an *odd* number of hex digits, report an error.
+ */
+ if ((i % 2) != 0)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("iseries: odd number of hex digits in a line");
+ return -1;
+ }
+ if (overflow)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("iseries: more packet data than the packet length indicated");
+ return -1;
+ }
+ return out_offset;
+}
+
+/* return the multiplier for nanoseconds */
+static guint32
+csec_multiplier(guint32 csec)
+{
+ if (csec < 10) return 100000000;
+ if (csec < 100) return 10000000;
+ if (csec < 1000) return 1000000;
+ if (csec < 10000) return 100000;
+ if (csec < 100000) return 10000;
+ if (csec < 1000000) return 1000;
+ if (csec < 10000000) return 100;
+ if (csec < 100000000) return 10;
+ return 1;
}
/* Parses a packet. */
-static int
-iseries_parse_packet (wtap * wth, FILE_T fh,
- union wtap_pseudo_header *pseudo_header, guint8 * pd,
- int *err, gchar ** err_info)
+static gboolean
+iseries_parse_packet (wtap * wth, FILE_T fh, struct wtap_pkthdr *phdr,
+ Buffer *buf, int *err, gchar **err_info)
{
- gint64 cur_off;
- gboolean isValid, isCurrentPacket, IPread, TCPread, isDATA;
- int num_items_scanned, line, pktline, buflen;
- guint32 pkt_len;
- int cap_len, pktnum, month, day, year, 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;
- struct tm tm;
+ iseries_t *iseries = (iseries_t *)wth->priv;
+ gint64 cur_off;
+ gboolean isValid, isCurrentPacket;
+ int num_items_scanned, line, pktline, buflen;
+ int pkt_len, pktnum, hr, min, sec;
+ char direction[2], destmac[13], srcmac[13], type[5];
+ guint32 csec;
+ char data[ISERIES_LINE_LENGTH * 2];
+ int offset;
+ char *ascii_buf;
+ int ascii_offset;
+ struct tm tm;
/*
* Check for packet headers in first 3 lines this should handle page breaks
isValid = FALSE;
for (line = 1; line < ISERIES_PKT_LINES_TO_CHECK; line++)
{
- cur_off = file_tell (fh);
if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
- {
- *err = file_error (fh);
- if (*err == 0)
- {
- *err = WTAP_ERR_SHORT_READ;
- }
- return -1;
- }
+ {
+ *err = file_error (fh, err_info);
+ return FALSE;
+ }
/* Convert UNICODE data to ASCII */
- if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
- {
- iseries_UNICODE_to_ASCII (data, ISERIES_LINE_LENGTH);
- }
- /* look for packet header */
+ if (iseries->format == ISERIES_FORMAT_UNICODE)
+ {
+ iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
+ }
+ ascii_strup_inplace (data);
num_items_scanned =
- sscanf (data,
- "%6d %1s %6d %d:%d:%d.%d %12s %12s ETHV2 Type: %s",
- &pktnum, direction, &cap_len, &hr, &min, &sec, &csec, destmac,
- srcmac, type);
+ sscanf (data,
+ "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9u%*[ \n\t]"
+ "%12s%*[ \n\t]%12s%*[ \n\t]ETHV2%*[ \n\t]TYPE:%*[ \n\t]%4s",
+ &pktnum, direction, &pkt_len, &hr, &min, &sec, &csec, destmac,
+ srcmac, type);
if (num_items_scanned == 10)
- {
- /* OK! We found the packet header line */
- isValid = TRUE;
- /*
- * XXX - The Capture length returned by the iSeries trace doesn't seem to include the src/dest MAC
- * addresses or the packet type. So we add them here.
- */
- cap_len += 14;
- break;
- }
+ {
+ if (pktnum < 0)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a negative packet number");
+ return FALSE;
+ }
+
+ if (pkt_len < 0)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a negative packet length");
+ return FALSE;
+ }
+
+ if (hr < 0)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a negative hour in the time stamp");
+ return FALSE;
+ }
+
+ if (hr > 23)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a hour in the time stamp greater than 23");
+ return FALSE;
+ }
+
+ if (min < 0)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a negative minute in the time stamp");
+ return FALSE;
+ }
+
+ if (min > 59)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a minute in the time stamp greater than 59");
+ return FALSE;
+ }
+
+ if (sec < 0)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a negative second in the time stamp");
+ return FALSE;
+ }
+
+ /*
+ * Yes, 60, even though the time-conversion routines on most OSes
+ * might not handle leap seconds.
+ */
+ if (sec > 60)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a second in the time stamp greater than 60");
+ return FALSE;
+ }
+
+ if (strlen(destmac) != 12)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a destination MAC address shorter than 6 bytes");
+ return FALSE;
+ }
+
+ if (strlen(srcmac) != 12)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has a source MAC address shorter than 6 bytes");
+ return FALSE;
+ }
+
+ if (strlen(type) != 4)
+ {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup ("iseries: packet header has an Ethernet type/length field than 2 bytes");
+ return FALSE;
+ }
+
+ /* OK! We found the packet header line */
+ isValid = TRUE;
+ /*
+ * XXX - The Capture length returned by the iSeries trace doesn't
+ * seem to include the Ethernet header, so we add its length here.
+ *
+ * Check the length first, just in case it's *so* big that, after
+ * adding the Ethernet header length, it overflows.
+ */
+ if (pkt_len > WTAP_MAX_PACKET_SIZE - 14)
+ {
+ /*
+ * Probably a corrupt capture file; don't blow up trying
+ * to allocate space for an immensely-large packet, and
+ * don't think it's a really *small* packet because it
+ * overflowed. (Calculate the size as a 64-bit value in
+ * the error message, to avoid an overflow.)
+ */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("iseries: File has %" G_GUINT64_FORMAT "-byte packet, bigger than maximum of %u",
+ (guint64)pkt_len + 14,
+ WTAP_MAX_PACKET_SIZE);
+ return FALSE;
+ }
+ pkt_len += 14;
+ break;
+ }
}
/*
*/
if (!isValid)
{
- *err = WTAP_ERR_BAD_RECORD;
+ *err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup ("iseries: packet header isn't valid");
- return -1;
+ return FALSE;
}
+ phdr->rec_type = REC_TYPE_PACKET;
+ phdr->presence_flags = WTAP_HAS_CAP_LEN;
+
/*
* If we have Wiretap Header then populate it here
*
- * 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)
+ * Timer resolution on the iSeries is hardware dependent. We determine
+ * the resolution based on how many digits we see.
*/
- 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_hour = hr;
- tm.tm_min = min;
- tm.tm_sec = sec;
- tm.tm_isdst = -1;
- wth->phdr.ts.secs = mktime (&tm);
- /* Handle Millisecond precision for timer */
- if (csec > 99999)
- {
- wth->phdr.ts.nsecs = csec * 1000;
- }
- /* Handle Nanosecond precision for timer */
- else
- {
- wth->phdr.ts.nsecs = csec * 10000;
- }
- wth->phdr.caplen = cap_len;
- wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
- pseudo_header->eth.fcs_len = -1;
+ phdr->presence_flags |= WTAP_HAS_TS;
+ 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;
+ tm.tm_isdst = -1;
+ phdr->ts.secs = mktime (&tm);
+ phdr->ts.nsecs = csec * csec_multiplier(csec);
}
+ phdr->len = pkt_len;
+ phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
+ phdr->pseudo_header.eth.fcs_len = -1;
+
/*
- * Start Reading packet contents
+ * Allocate a buffer big enough to hold the claimed packet length
+ * worth of byte values; each byte will be two hex digits, so the
+ * buffer's size should be twice the packet length.
+ *
+ * (There is no need to null-terminate the buffer.)
*/
- isCurrentPacket = TRUE;
- IPread = FALSE;
- TCPread = FALSE;
- isDATA = FALSE;
+ ascii_buf = (char *)g_malloc (pkt_len*2);
+ ascii_offset = 0;
+
+ /*
+ * Copy in the Ethernet header.
+ *
+ * The three fields have already been checked to have the right length
+ * (6 bytes, hence 12 characters, of hex-dump destination and source
+ * addresses, and 2 bytes, hence 4 characters, of hex-dump type/length).
+ *
+ * pkt_len is guaranteed to be >= 14, so 2*pkt_len is guaranteed to be
+ * >= 28, so we don't need to do any bounds checking.
+ */
+ memcpy(&ascii_buf[0], destmac, 12);
+ ascii_offset += 12;
+ memcpy(&ascii_buf[12], srcmac, 12);
+ ascii_offset += 12;
+ memcpy(&ascii_buf[24], type, 4);
+ ascii_offset += 4;
+
/*
- * Allocate 2 work buffers to handle concatentation of the hex data block
+ * Start reading packet contents
*/
- tcpdatabuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
- g_snprintf (tcpdatabuf, 1, "%s", "");
- workbuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
- g_snprintf (workbuf, 1, "%s", "");
+ isCurrentPacket = TRUE;
+
/* loop through packet lines and breakout when the next packet header is read */
pktline = 0;
while (isCurrentPacket)
pktline++;
/* Read the next line */
if (file_gets (data, ISERIES_LINE_LENGTH, fh) == NULL)
- {
- if (file_eof (fh))
- {
- break;
- }
- else
- {
- *err = file_error (fh);
- if (*err == 0)
- {
- *err = WTAP_ERR_SHORT_READ;
- }
- return -1;
- }
- }
+ {
+ *err = file_error (fh, err_info);
+ if (*err == 0)
+ {
+ /* Hit the EOF without an error */
+ break;
+ }
+ goto errxit;
+ }
/* Convert UNICODE data to ASCII and determine line length */
- if (wth->capture.iseries->format == ISERIES_FORMAT_UNICODE)
- {
- buflen = iseries_UNICODE_to_ASCII (data, ISERIES_LINE_LENGTH);
- }
+ if (iseries->format == ISERIES_FORMAT_UNICODE)
+ {
+ buflen = iseries_UNICODE_to_ASCII ((guint8 *)data, ISERIES_LINE_LENGTH);
+ }
else
- {
- /* Else bytes to rewind is just length of ASCII string */
- buflen = strlen (data);
- }
+ {
+ /* Else bytes to rewind is just length of ASCII string */
+ buflen = (int) strlen (data);
+ }
- /* If this is a IP header hex string then set flag */
- num_items_scanned = sscanf (data + 22, "IP Header : %40s", ipheader);
- if (num_items_scanned == 1)
- {
- IPread = TRUE;
- }
+ /*
+ * Skip leading white space.
+ */
+ for (offset = 0; g_ascii_isspace(data[offset]); offset++)
+ ;
- /* If this is TCP header hex string then set flag */
- num_items_scanned = sscanf (data + 22, "TCP Header : %80s", tcpheader);
- if (num_items_scanned == 1)
- {
- TCPread = TRUE;
- }
+ /*
+ * The higher-level header information starts at an offset of
+ * 22 characters. The header tags are 14 characters long.
+ *
+ * XXX - for IPv6, if the next header isn't the last header,
+ * the intermediate headers do *NOT* appear to be shown in
+ * the dump file *at all*, so the packet *cannot* be
+ * reconstructed!
+ */
+ if (offset == 22)
+ {
+ if (strncmp(data + 22, "IP Header : ", 14) == 0 ||
+ strncmp(data + 22, "IPv6 Header: ", 14) == 0 ||
+ strncmp(data + 22, "ARP Header : ", 14) == 0 ||
+ strncmp(data + 22, "TCP Header : ", 14) == 0 ||
+ strncmp(data + 22, "UDP Header : ", 14) == 0 ||
+ strncmp(data + 22, "ICMP Header: ", 14) == 0 ||
+ strncmp(data + 22, "ICMPv6 Hdr: ", 14) == 0 ||
+ strncmp(data + 22, "Option Hdr: ", 14) == 0)
+ {
+ ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
+ pkt_len*2,
+ data + 22 + 14, err,
+ err_info);
+ if (ascii_offset == -1)
+ {
+ /* Bad line. */
+ return FALSE;
+ }
+ continue;
+ }
+ }
/*
- * If there is data in the packet handle it here.
+ * Is this a data line?
*
- * The data header line will have the "Data . . " identifier, subsequent lines don't
+ * The "Data" starts at an offset of 8.
*/
- num_items_scanned =
- sscanf (data + 27, "%16[A-Z0-9] %16[A-Z0-9] %16[A-Z0-9] %16[A-Z0-9]",
- hex1, hex2, hex3, hex4);
- if (num_items_scanned > 0)
- {
- isDATA = TRUE;
- /*
- * Scan the data line for data blocks, depending on the number of blocks scanned
- * add them along with current tcpdata buffer to the work buffer and then copy
- * work buffer to tcpdata buffer to continue building up tcpdata buffer to contain
- * a single hex string.
- */
- switch (num_items_scanned)
- {
- case 1:
- g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s", tcpdatabuf,
- hex1);
- break;
- case 2:
- g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s",
- tcpdatabuf, hex1, hex2);
- break;
- case 3:
- g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s",
- tcpdatabuf, hex1, hex2, hex3);
- break;
- default:
- g_snprintf (workbuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s",
- tcpdatabuf, hex1, hex2, hex3, hex4);
- }
- memcpy (tcpdatabuf, workbuf, ISERIES_PKT_ALLOC_SIZE);
- }
+ if (offset == 9)
+ {
+ if (strncmp(data + 9, "Data . . . . . : ", 18) == 0)
+ {
+ ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
+ pkt_len*2,
+ data + 9 + 18, err,
+ err_info);
+ if (ascii_offset == -1)
+ {
+ /* Bad line. */
+ return FALSE;
+ }
+ continue;
+ }
+ }
+
+ /*
+ * Is this a continuation of a previous header or data line?
+ * That's blanks followed by hex digits; first try the
+ * "no column separators" form.
+ *
+ * Continuations of header lines begin at an offset of 36;
+ * continuations of data lines begin at an offset of 27.
+ */
+ if (offset == 36 || offset == 27)
+ {
+ ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
+ pkt_len*2,
+ data + offset, err,
+ err_info);
+ if (ascii_offset == -1)
+ {
+ /* Bad line. */
+ return FALSE;
+ }
+ continue;
+ }
/*
* If we see the identifier for the next packet then rewind and set
* isCurrentPacket FALSE
*/
- if ((strncmp (data + 80, ISERIES_PKT_MAGIC_STR, ISERIES_PKT_MAGIC_LEN)
- == 0) && pktline > 1)
- {
- isCurrentPacket = FALSE;
- cur_off = file_tell (fh);
- if (cur_off == -1)
- {
- /* Error. */
- *err = file_error (fh);
- return -1;
- }
- if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
- {
- return -1;
- }
- }
- }
-
- /*
- * 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 (!IPread)
- {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup ("iseries: IP header isn't valid");
- return -1;
- }
- if (!TCPread)
- {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup ("iseries: TCP header isn't valid");
- return -1;
- }
- }
-
- /*
- * Create a buffer to hold all the ASCII Hex data and populate with all the
- * extracted data.
- */
- asciibuf = g_malloc (ISERIES_PKT_ALLOC_SIZE);
- if (isDATA)
- {
- /* packet contained data */
- if (wth->capture.iseries->tcp_formatted)
- {
- /* build string for formatted fields */
- g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s%s",
- destmac, srcmac, type, ipheader, tcpheader, tcpdatabuf);
- }
- else
- {
- /* build string for unformatted data fields */
- g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s", destmac,
- srcmac, type, tcpdatabuf);
- }
- }
- else
- {
- /* No data in the packet */
- g_snprintf (asciibuf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s%s%s", destmac,
- srcmac, type, ipheader, tcpheader);
+ ascii_strup_inplace (data);
+ /* If packet header found return the offset */
+ num_items_scanned =
+ sscanf (data+78,
+ "%*[ \n\t]ETHV2%*[ .:\n\t]TYPE%*[ .:\n\t]%4s",type);
+ if ((num_items_scanned == 1) && pktline > 1)
+ {
+ isCurrentPacket = FALSE;
+ cur_off = file_tell( fh);
+ if (cur_off == -1)
+ {
+ /* Error. */
+ *err = file_error (fh, err_info);
+ goto errxit;
+ }
+ if (file_seek (fh, cur_off - buflen, SEEK_SET, err) == -1)
+ {
+ /* XXX: need to set err_info ?? */
+ goto errxit;
+ }
+ }
}
/*
- * Extract the packet length from the actual IP header; this may
- * differ from the capture length reported by the formatted trace.
- * Note: if the entire Ethernet packet is present, but the IP
- * packet is less than 46 bytes long, there will be padding, and
- * the length in the IP header won't include the padding; if
- * the packet length is less than the captured length, set the
- * packet length to the captured length.
+ * Make the captured length be the amount of bytes we've read (which
+ * is half the number of characters of hex dump we have).
+ *
+ * XXX - this can happen for IPv6 packets if the next header isn't the
+ * last header.
*/
- num_items_scanned = sscanf (asciibuf + 32, "%4x", &pkt_len);
- wth->phdr.len = pkt_len + 14;
- if (wth->phdr.caplen > wth->phdr.len)
- wth->phdr.len = wth->phdr.caplen;
+ phdr->caplen = ((guint32) ascii_offset)/2;
- /* Make sure we have enough room for the packet, only create buffer if none supplied */
- if (pd == NULL)
- {
- 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));
- }
- else
- {
- /* Convert ascii data to binary and return in the frame buffer */
- iseries_parse_hex_string (asciibuf, pd, strlen (asciibuf));
- }
+ /* Make sure we have enough room for the packet. */
+ ws_buffer_assure_space (buf, phdr->caplen);
+ /* Convert ascii data to binary and return in the frame buffer */
+ iseries_parse_hex_string (ascii_buf, ws_buffer_start_ptr (buf), ascii_offset);
- /* free buffers allocs and return */
+ /* free buffer allocs and return */
*err = 0;
- free (asciibuf);
- free (tcpdatabuf);
- free (workbuf);
- return wth->phdr.len;
+ g_free (ascii_buf);
+ return TRUE;
+
+errxit:
+ g_free (ascii_buf);
+ return FALSE;
}
/*
static int
iseries_UNICODE_to_ASCII (guint8 * buf, guint bytes)
{
- guint i;
+ guint i;
guint8 *bufptr;
+
bufptr = buf;
for (i = 0; i < bytes; i++)
{
switch (buf[i])
- {
- case 0xFE:
- case 0xFF:
- case 0x00:
- break;
- default:
- *bufptr = buf[i];
- bufptr++;
- }
+ {
+ case 0xFE:
+ case 0xFF:
+ case 0x00:
+ break;
+ default:
+ *bufptr = buf[i];
+ bufptr++;
+ }
if (buf[i] == 0x0A)
- return i;
+ return i;
}
return i;
}
* 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, size_t len)
{
- int i, byte;
- char hexvalue[3] = { 0, 0, 0 };
+ size_t i;
+ int byte;
+ gint hexvalue;
+ guint8 bytevalue;
byte = 0;
for (i = 0; i < len; i++)
{
- hexvalue[0] = ascii[i];
+ 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 << 4);
+ if (i >= len)
+ return FALSE; /* only one hex digit of the byte is present */
+ hexvalue = g_ascii_xdigit_value(ascii[i]);
+ if (hexvalue == -1)
+ return FALSE; /* not a valid hex digit */
+ bytevalue |= (guint8) hexvalue;
+ buf[byte] = bytevalue;
byte++;
}
return TRUE;
}
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=2 tabstop=8 expandtab:
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */