#include <errno.h>
#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_PACKET_LEN 16384
#define ISERIES_MAX_TRACE_LEN 99999999
-#define ISERIES_PKT_ALLOC_SIZE (pkt_len*2)+1
#define ISERIES_FORMAT_ASCII 1
#define ISERIES_FORMAT_UNICODE 2
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 gboolean
iseries_parse_packet (wtap * wth, FILE_T fh, struct wtap_pkthdr *phdr,
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], csec[9+1];
+ char direction[2], destmac[13], srcmac[13], type[5];
+ guint32 csec;
char data[ISERIES_LINE_LENGTH * 2];
int offset;
char *ascii_buf;
ascii_strup_inplace (data);
num_items_scanned =
sscanf (data,
- "%*[ \n\t]%6d%*[ *\n\t]%1s%*[ \n\t]%6d%*[ \n\t]%2d:%2d:%2d.%9[0-9]%*[ \n\t]"
+ "%*[ \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,
+ &pktnum, direction, &pkt_len, &hr, &min, &sec, &csec, destmac,
srcmac, type);
if (num_items_scanned == 10)
{
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;
}
tm.tm_sec = sec;
tm.tm_isdst = -1;
phdr->ts.secs = mktime (&tm);
- csec[sizeof(csec) - 1] = '\0';
- switch (strlen(csec))
- {
- case 0:
- phdr->ts.nsecs = 0;
- break;
- case 1:
- phdr->ts.nsecs = atoi(csec) * 100000000;
- break;
- case 2:
- phdr->ts.nsecs = atoi(csec) * 10000000;
- break;
- case 3:
- phdr->ts.nsecs = atoi(csec) * 1000000;
- break;
- case 4:
- phdr->ts.nsecs = atoi(csec) * 100000;
- break;
- case 5:
- phdr->ts.nsecs = atoi(csec) * 10000;
- break;
- case 6:
- phdr->ts.nsecs = atoi(csec) * 1000;
- break;
- case 7:
- phdr->ts.nsecs = atoi(csec) * 100;
- break;
- case 8:
- phdr->ts.nsecs = atoi(csec) * 10;
- break;
- case 9:
- phdr->ts.nsecs = atoi(csec);
- break;
- }
+ phdr->ts.nsecs = csec * csec_multiplier(csec);
}
phdr->len = pkt_len;
phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
phdr->pseudo_header.eth.fcs_len = -1;
- ascii_buf = (char *)g_malloc (ISERIES_PKT_ALLOC_SIZE);
- g_snprintf(ascii_buf, ISERIES_PKT_ALLOC_SIZE, "%s%s%s", destmac, srcmac, type);
- ascii_offset = 14*2; /* 14-byte Ethernet header, 2 characters per byte */
+ /*
+ * 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.)
+ */
+ 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;
/*
* Start reading packet contents
strncmp(data + 22, "Option Hdr: ", 14) == 0)
{
ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
- ISERIES_PKT_ALLOC_SIZE - 1,
+ pkt_len*2,
data + 22 + 14, err,
err_info);
if (ascii_offset == -1)
if (strncmp(data + 9, "Data . . . . . : ", 18) == 0)
{
ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
- ISERIES_PKT_ALLOC_SIZE - 1,
+ pkt_len*2,
data + 9 + 18, err,
err_info);
if (ascii_offset == -1)
if (offset == 36 || offset == 27)
{
ascii_offset = append_hex_digits(ascii_buf, ascii_offset,
- ISERIES_PKT_ALLOC_SIZE - 1,
+ pkt_len*2,
data + offset, err,
err_info);
if (ascii_offset == -1)
}
}
}
- ascii_buf[ascii_offset] = '\0';
/*
* Make the captured length be the amount of bytes we've read (which
* XXX - this can happen for IPv6 packets if the next header isn't the
* last header.
*/
- phdr->caplen = ((guint32) strlen (ascii_buf))/2;
+ phdr->caplen = ((guint32) ascii_offset)/2;
/* Make sure we have enough room for the packet. */
- ws_buffer_assure_space (buf, ISERIES_MAX_PACKET_LEN);
+ 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), strlen (ascii_buf));
+ iseries_parse_hex_string (ascii_buf, ws_buffer_start_ptr (buf), ascii_offset);
/* free buffer allocs and return */
*err = 0;