summaryrefslogtreecommitdiffstats
path: root/wiretap/dbs-etherwatch.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /wiretap/dbs-etherwatch.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'wiretap/dbs-etherwatch.c')
-rw-r--r--wiretap/dbs-etherwatch.c670
1 files changed, 670 insertions, 0 deletions
diff --git a/wiretap/dbs-etherwatch.c b/wiretap/dbs-etherwatch.c
new file mode 100644
index 00000000..4147b039
--- /dev/null
+++ b/wiretap/dbs-etherwatch.c
@@ -0,0 +1,670 @@
+/* dbs-etherwatch.c
+ *
+ * Wiretap Library
+ * Copyright (c) 2001 by Marc Milgram <ethereal@mmilgram.NOSPAMmail.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+#include "wtap-int.h"
+#include "dbs-etherwatch.h"
+#include "file_wrappers.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* This module reads the text output of the 'DBS-ETHERTRACE' command in VMS
+ * It was initially based on vms.c.
+ */
+
+/*
+ Example 'ETHERWATCH' output data (with "printable" characters in the
+ "printable characters" section of the output replaced by "." if they have
+ the 8th bit set, so as not to upset compilers that are expecting text
+ in comments to be in a particular character encoding that can't handle
+ those values):
+ETHERWATCH X5-008
+42 names and addresses were loaded
+Reading recorded data from PERSISTENCE
+------------------------------------------------------------------------------
+From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
+Protocol 08-00 00 00-00-00-00-00, 60 byte buffer at 10-OCT-2001 10:20:45.16
+ [E..<8...........]- 0-[45 00 00 3C 38 93 00 00 1D 06 D2 12 80 93 11 1A]
+ [.........(......]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 90 00 00 00 00]
+ [................]- 32-[A0 02 FF FF 95 BD 00 00 02 04 05 B4 03 03 04 01]
+ [............ ]- 48-[01 01 08 0A 90 90 E5 14 00 00 00 00]
+------------------------------------------------------------------------------
+From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
+Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17
+ [E..(8......%....]- 0-[45 00 00 28 38 94 00 00 1D 06 D2 25 80 93 11 1A]
+ [.........(..Z.4w]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 91 5A 1C 34 77]
+ [P.#(.s..........]- 32-[50 10 23 28 C1 73 00 00 02 04 05 B4 03 03 00 00]
+ [.. ]- 48-[02 04]
+
+
+Alternative HEX only output, slightly more efficient and all wireshark needs:
+------------------------------------------------------------------------------
+From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
+Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17
+ 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6]
+ 20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00]
+ 40-[03 30 30 30 30 30 00 00 03 30]
+ */
+
+/* Magic text to check for DBS-ETHERWATCH-ness of file */
+static const char dbs_etherwatch_hdr_magic[] =
+{ 'E', 'T', 'H', 'E', 'R', 'W', 'A', 'T', 'C', 'H', ' '};
+#define DBS_ETHERWATCH_HDR_MAGIC_SIZE \
+ (sizeof dbs_etherwatch_hdr_magic / sizeof dbs_etherwatch_hdr_magic[0])
+
+/* Magic text for start of packet */
+static const char dbs_etherwatch_rec_magic[] =
+{'F', 'r', 'o', 'm', ' '};
+#define DBS_ETHERWATCH_REC_MAGIC_SIZE \
+ (sizeof dbs_etherwatch_rec_magic / sizeof dbs_etherwatch_rec_magic[0])
+
+/*
+ * Default packet size - maximum normal Ethernet packet size, without an
+ * FCS.
+ */
+#define DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN 1514
+
+static gboolean dbs_etherwatch_read(wtap *wth, wtap_rec *rec,
+ Buffer *buf, int *err, gchar **err_info, gint64 *data_offset);
+static gboolean dbs_etherwatch_seek_read(wtap *wth, gint64 seek_off,
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
+static gboolean parse_dbs_etherwatch_packet(FILE_T fh, wtap_rec *rec,
+ Buffer* buf, int *err, gchar **err_info);
+static guint parse_single_hex_dump_line(char* rec, guint8 *buf,
+ int byte_offset);
+static guint parse_hex_dump(char* dump, guint8 *buf, char separator, char end);
+
+static int dbs_etherwatch_file_type_subtype = -1;
+
+void register_dbs_etherwatch(void);
+
+/* Seeks to the beginning of the next packet, and returns the
+ byte offset. Returns -1 on failure, and sets "*err" to the error
+ and "*err_info" to null or an additional error string. */
+static gint64 dbs_etherwatch_seek_next_packet(wtap *wth, int *err,
+ gchar **err_info)
+{
+ int byte;
+ unsigned int level = 0;
+ gint64 cur_off;
+
+ while ((byte = file_getc(wth->fh)) != EOF) {
+ if (byte == dbs_etherwatch_rec_magic[level]) {
+ level++;
+ if (level >= DBS_ETHERWATCH_REC_MAGIC_SIZE) {
+ /* note: we're leaving file pointer right after the magic characters */
+ cur_off = file_tell(wth->fh);
+ if (cur_off == -1) {
+ /* Error. */
+ *err = file_error(wth->fh, err_info);
+ return -1;
+ }
+ return cur_off + 1;
+ }
+ } else {
+ level = 0;
+ }
+ }
+ /* EOF or error. */
+ *err = file_error(wth->fh, err_info);
+ return -1;
+}
+
+#define DBS_ETHERWATCH_HEADER_LINES_TO_CHECK 200
+#define DBS_ETHERWATCH_LINE_LENGTH 240
+
+/* Look through the first part of a file to see if this is
+ * a DBS Ethertrace text trace file.
+ *
+ * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
+ * if we get an I/O error, "*err" will be set to a non-zero value and
+ * "*err_info" will be set to null or an error string.
+ */
+static gboolean dbs_etherwatch_check_file_type(wtap *wth, int *err,
+ gchar **err_info)
+{
+ char buf[DBS_ETHERWATCH_LINE_LENGTH];
+ int line, byte;
+ gsize reclen;
+ unsigned int i, level;
+
+ buf[DBS_ETHERWATCH_LINE_LENGTH-1] = 0;
+
+ for (line = 0; line < DBS_ETHERWATCH_HEADER_LINES_TO_CHECK; line++) {
+ if (file_gets(buf, DBS_ETHERWATCH_LINE_LENGTH, wth->fh) == NULL) {
+ /* EOF or error. */
+ *err = file_error(wth->fh, err_info);
+ return FALSE;
+ }
+
+ reclen = strlen(buf);
+ if (reclen < DBS_ETHERWATCH_HDR_MAGIC_SIZE)
+ continue;
+
+ level = 0;
+ for (i = 0; i < reclen; i++) {
+ byte = buf[i];
+ if (byte == dbs_etherwatch_hdr_magic[level]) {
+ level++;
+ if (level >=
+ DBS_ETHERWATCH_HDR_MAGIC_SIZE) {
+ return TRUE;
+ }
+ }
+ else
+ level = 0;
+ }
+ }
+ *err = 0;
+ return FALSE;
+}
+
+
+wtap_open_return_val dbs_etherwatch_open(wtap *wth, int *err, gchar **err_info)
+{
+ /* Look for DBS ETHERWATCH header */
+ if (!dbs_etherwatch_check_file_type(wth, err, err_info)) {
+ if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ wth->file_encap = WTAP_ENCAP_ETHERNET;
+ wth->file_type_subtype = dbs_etherwatch_file_type_subtype;
+ wth->snapshot_length = 0; /* not known */
+ wth->subtype_read = dbs_etherwatch_read;
+ wth->subtype_seek_read = dbs_etherwatch_seek_read;
+ wth->file_tsprec = WTAP_TSPREC_10_MSEC;
+
+ /*
+ * Add an IDB; we don't know how many interfaces were
+ * involved, so we just say one interface, about which
+ * we only know the link-layer type, snapshot length,
+ * and time stamp resolution.
+ */
+ wtap_add_generated_idb(wth);
+
+ return WTAP_OPEN_MINE;
+}
+
+/* Find the next packet and parse it; called from wtap_read(). */
+static gboolean dbs_etherwatch_read(wtap *wth, wtap_rec *rec,
+ Buffer *buf, int *err, gchar **err_info, gint64 *data_offset)
+{
+ gint64 offset;
+
+ /* Find the next packet */
+ offset = dbs_etherwatch_seek_next_packet(wth, err, err_info);
+ if (offset < 1)
+ return FALSE;
+ *data_offset = offset;
+
+ /* Parse the packet */
+ return parse_dbs_etherwatch_packet(wth->fh, rec, buf, err, err_info);
+}
+
+/* Used to read packets in random-access fashion */
+static gboolean
+dbs_etherwatch_seek_read(wtap *wth, gint64 seek_off,
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
+{
+ if (file_seek(wth->random_fh, seek_off - 1, SEEK_SET, err) == -1)
+ return FALSE;
+
+ return parse_dbs_etherwatch_packet(wth->random_fh, rec, buf, err,
+ err_info);
+}
+
+/* Parse a packet */
+/*
+Packet header:
+ 1 2 3 4
+0123456789012345678901234567890123456789012345
+From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB]
+Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17
+*/
+#define MAC_ADDR_LENGTH 6 /* Length MAC address */
+#define DEST_MAC_PREFIX "] to " /* Prefix to the dest. MAC address */
+#define PROTOCOL_LENGTH 2 /* Length protocol */
+#define PROTOCOL_POS 9 /* Position protocol */
+#define SAP_LENGTH 2 /* Length DSAP+SSAP */
+#define SAP_POS 9 /* Position DSAP+SSAP */
+#define CTL_UNNUMB_LENGTH 1 /* Length unnumbered control field */
+#define CTL_NUMB_LENGTH 2 /* Length numbered control field */
+#define CTL_POS 15 /* Position control field */
+#define PID_LENGTH 5 /* Length PID */
+#define PID_POS 18 /* Position PID */
+#define LENGTH_POS 33 /* Position length */
+#define HEX_HDR_SPR '-' /* Separator char header hex values */
+#define HEX_HDR_END ' ' /* End char hdr. hex val. except PID */
+#define HEX_PID_END ',' /* End char PID hex value */
+#define IEEE802_LEN_LEN 2 /* Length of the IEEE 802 len. field */
+/*
+To check whether it is Ethernet II or IEEE 802 we check the values of the
+control field and PID, when they are all 0's we assume it is Ethernet II
+else IEEE 802. In IEEE 802 the DSAP and SSAP are behind protocol, the
+length in the IEEE data we have to construct.
+*/
+#define ETH_II_CHECK_POS 15
+#define ETH_II_CHECK_STR "00 00-00-00-00-00,"
+/*
+To check whether it IEEE 802.3 with SNAP we check that both the DSAP & SSAP
+values are 0xAA and the control field 0x03.
+*/
+#define SNAP_CHECK_POS 9
+#define SNAP_CHECK_STR "AA-AA 03"
+/*
+To check whether the control field is 1 or two octets we check if it is
+unnumbered. Unnumbered has length 1, numbered 2.
+*/
+#define CTL_UNNUMB_MASK 0x03
+#define CTL_UNNUMB_VALUE 0x03
+static gboolean
+parse_dbs_etherwatch_packet(FILE_T fh, wtap_rec *rec, Buffer* buf,
+ int *err, gchar **err_info)
+{
+ guint8 *pd;
+ char line[DBS_ETHERWATCH_LINE_LENGTH];
+ int num_items_scanned;
+ int eth_hdr_len, pkt_len, csec;
+ int length_pos, length_from, length;
+ struct tm tm;
+ char mon[4] = "xxx";
+ gchar *p;
+ static const gchar months[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
+ int count, line_count;
+
+ /* Make sure we have enough room for a regular Ethernet packet */
+ ws_buffer_assure_space(buf, DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN);
+ pd = ws_buffer_start_ptr(buf);
+
+ eth_hdr_len = 0;
+ memset(&tm, 0, sizeof(tm));
+ /* Our file pointer should be on the first line containing the
+ * summary information for a packet. Read in that line and
+ * extract the useful information
+ */
+ if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) {
+ *err = file_error(fh, err_info);
+ if (*err == 0) {
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ return FALSE;
+ }
+
+ /* Get the destination address */
+ p = strstr(line, DEST_MAC_PREFIX);
+ if(!p) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: destination address not found");
+ return FALSE;
+ }
+ p += strlen(DEST_MAC_PREFIX);
+ if(parse_hex_dump(p, &pd[eth_hdr_len], HEX_HDR_SPR, HEX_HDR_END)
+ != MAC_ADDR_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: destination address not valid");
+ return FALSE;
+ }
+ eth_hdr_len += MAC_ADDR_LENGTH;
+
+ /* Get the source address */
+ /*
+ * Since the first part of the line is already skipped in order to find
+ * the start of the record we cannot index, just look for the first
+ * 'HEX' character
+ */
+ p = line;
+ while(!g_ascii_isxdigit(*p)) {
+ p++;
+ }
+ if(parse_hex_dump(p, &pd[eth_hdr_len], HEX_HDR_SPR,
+ HEX_HDR_END) != MAC_ADDR_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: source address not valid");
+ return FALSE;
+ }
+ eth_hdr_len += MAC_ADDR_LENGTH;
+
+ /* Read the next line of the record header */
+ if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) {
+ *err = file_error(fh, err_info);
+ if (*err == 0) {
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ return FALSE;
+ }
+
+ /* Check the lines is as least as long as the length position */
+ if(strlen(line) < LENGTH_POS) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: line too short");
+ return FALSE;
+ }
+
+ num_items_scanned = sscanf(line + LENGTH_POS,
+ "%9d byte buffer at %2d-%3s-%4d %2d:%2d:%2d.%9d",
+ &pkt_len,
+ &tm.tm_mday, mon,
+ &tm.tm_year, &tm.tm_hour, &tm.tm_min,
+ &tm.tm_sec, &csec);
+
+ if (num_items_scanned != 8) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: header line not valid");
+ return FALSE;
+ }
+
+ if (pkt_len < 0) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: packet header has a negative packet length");
+ return FALSE;
+ }
+
+ /* Determine whether it is Ethernet II or IEEE 802 */
+ if(strncmp(&line[ETH_II_CHECK_POS], ETH_II_CHECK_STR,
+ strlen(ETH_II_CHECK_STR)) == 0) {
+ /* Ethernet II */
+ /* Get the Protocol */
+ if(parse_hex_dump(&line[PROTOCOL_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
+ HEX_HDR_END) != PROTOCOL_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: Ethernet II protocol value not valid");
+ return FALSE;
+ }
+ eth_hdr_len += PROTOCOL_LENGTH;
+ } else {
+ /* IEEE 802 */
+ /* Remember where to put the length in the header */
+ length_pos = eth_hdr_len;
+ /* Leave room in the header for the length */
+ eth_hdr_len += IEEE802_LEN_LEN;
+ /* Remember how much of the header should not be added to the length */
+ length_from = eth_hdr_len;
+ /* Get the DSAP + SSAP */
+ if(parse_hex_dump(&line[SAP_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
+ HEX_HDR_END) != SAP_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: 802.2 DSAP+SSAP value not valid");
+ return FALSE;
+ }
+ eth_hdr_len += SAP_LENGTH;
+ /* Get the (first part of the) control field */
+ if(parse_hex_dump(&line[CTL_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
+ HEX_HDR_END) != CTL_UNNUMB_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: 802.2 control field first part not valid");
+ return FALSE;
+ }
+ /* Determine whether the control is numbered, and thus longer */
+ if((pd[eth_hdr_len] & CTL_UNNUMB_MASK) != CTL_UNNUMB_VALUE) {
+ /* Get the rest of the control field, the first octet in the PID */
+ if(parse_hex_dump(&line[PID_POS],
+ &pd[eth_hdr_len + CTL_UNNUMB_LENGTH], HEX_HDR_END,
+ HEX_HDR_SPR) != CTL_NUMB_LENGTH - CTL_UNNUMB_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: 802.2 control field second part value not valid");
+ return FALSE;
+ }
+ eth_hdr_len += CTL_NUMB_LENGTH;
+ } else {
+ eth_hdr_len += CTL_UNNUMB_LENGTH;
+ }
+ /* Determine whether it is SNAP */
+ if(strncmp(&line[SNAP_CHECK_POS], SNAP_CHECK_STR,
+ strlen(SNAP_CHECK_STR)) == 0) {
+ /* Get the PID */
+ if(parse_hex_dump(&line[PID_POS], &pd[eth_hdr_len], HEX_HDR_SPR,
+ HEX_PID_END) != PID_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: 802.2 PID value not valid");
+ return FALSE;
+ }
+ eth_hdr_len += PID_LENGTH;
+ }
+ /* Write the length in the header */
+ length = eth_hdr_len - length_from + pkt_len;
+ pd[length_pos] = (length) >> 8;
+ pd[length_pos+1] = (length) & 0xFF;
+ }
+
+ rec->rec_type = REC_TYPE_PACKET;
+ rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
+ rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
+
+ p = strstr(months, mon);
+ if (p)
+ tm.tm_mon = (int)(p - months) / 3;
+ tm.tm_year -= 1900;
+
+ tm.tm_isdst = -1;
+ rec->ts.secs = mktime(&tm);
+ rec->ts.nsecs = csec * 10000000;
+ rec->rec_header.packet_header.caplen = eth_hdr_len + pkt_len;
+ rec->rec_header.packet_header.len = eth_hdr_len + pkt_len;
+
+ if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
+ /*
+ * Probably a corrupt capture file; return an error,
+ * so that our caller doesn't blow up trying to allocate
+ * space for an immensely-large packet.
+ */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = ws_strdup_printf("dbs_etherwatch: File has %u-byte packet, bigger than maximum of %u",
+ rec->rec_header.packet_header.caplen, WTAP_MAX_PACKET_SIZE_STANDARD);
+ return FALSE;
+ }
+
+ /* Make sure we have enough room, even for an oversized Ethernet packet */
+ ws_buffer_assure_space(buf, rec->rec_header.packet_header.caplen);
+ pd = ws_buffer_start_ptr(buf);
+
+ /*
+ * We don't have an FCS in this frame.
+ */
+ rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0;
+
+ /* Parse the hex dump */
+ count = 0;
+ while (count < pkt_len) {
+ if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) {
+ *err = file_error(fh, err_info);
+ if (*err == 0) {
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ return FALSE;
+ }
+ if (!(line_count = parse_single_hex_dump_line(line,
+ &pd[eth_hdr_len + count], count))) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: packet data value not valid");
+ return FALSE;
+ }
+ count += line_count;
+ if (count > pkt_len) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("dbs_etherwatch: packet data value has too many bytes");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/* Parse a hex dump line */
+/*
+/DISPLAY=BOTH output:
+
+ 1 2 3 4
+0123456789012345678901234567890123456789012345
+ [E..(8...........]- 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A]
+ [.........(..Z.4y]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 BF 5A 1C 34 79]
+ [P.#(.C...00000..]- 32-[50 10 23 28 C1 43 00 00 03 30 30 30 30 30 00 00]
+ [.0 ]- 48-[03 30]
+
+/DISPLAY=HEXADECIMAL output:
+
+ 1 2 3 4
+0123456789012345678901234567890123456789012345
+ 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6]
+ 20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00]
+ 40-[03 30 30 30 30 30 00 00 03 30]
+
+*/
+
+#define TYPE_CHECK_POS 2 /* Position to check the type of hex dump */
+#define TYPE_CHECK_BOTH '[' /* Value at pos. that indicates BOTH type */
+#define COUNT_POS_BOTH 21 /* Count position BOTH type */
+#define COUNT_POS_HEX 1 /* Count position HEX type */
+#define COUNT_SIZE 5 /* Length counter */
+#define HEX_DUMP_START '[' /* Start char */
+#define HEX_DUMP_SPR ' ' /* Separator char */
+#define HEX_DUMP_END ']' /* End char */
+
+/* Take a string representing one line from a hex dump and converts the
+ * text to binary data. We check the printed offset with the offset
+ * we are passed to validate the record. We place the bytes in the buffer
+ * at the specified offset.
+ *
+ * Returns length parsed if a good hex dump, 0 if bad.
+ */
+static guint
+parse_single_hex_dump_line(char* rec, guint8 *buf, int byte_offset) {
+
+ int pos, i;
+ int value;
+
+
+ /* Check that the record is as least as long as the check offset */
+ for(i = 0; i < TYPE_CHECK_POS; i++)
+ {
+ if(rec[i] == '\0') {
+ return 0;
+ }
+ }
+ /* determine the format and thus the counter offset and hex dump length */
+ if(rec[TYPE_CHECK_POS] == TYPE_CHECK_BOTH)
+ {
+ pos = COUNT_POS_BOTH;
+ }
+ else
+ {
+ pos = COUNT_POS_HEX;
+ }
+
+ /* Check that the record is as least as long as the start position */
+ while(i < pos)
+ {
+ if(rec[i] == '\0') {
+ return 0;
+ }
+ i++;
+ }
+
+ /* Get the byte_offset directly from the record */
+ value = 0;
+ for(i = 0; i < COUNT_SIZE; i++) {
+ if(!g_ascii_isspace(rec[pos])) {
+ if(g_ascii_isdigit(rec[pos])) {
+ value *= 10;
+ value += rec[pos] - '0';
+ } else {
+ return 0;
+ }
+ }
+ pos++;
+ }
+
+ if (value != byte_offset) {
+ return 0;
+ }
+
+ /* find the start of the hex dump */
+ while(rec[pos] != HEX_DUMP_START) {
+ if(rec[pos] == '\0') {
+ return 0;
+ }
+ pos++;
+ }
+ pos++;
+ return parse_hex_dump(&rec[pos], buf, HEX_DUMP_SPR, HEX_DUMP_END);
+}
+
+/* Parse a hex dump */
+static guint
+parse_hex_dump(char* dump, guint8 *buf, char separator, char end) {
+ int pos, count;
+
+ /* Parse the hex dump */
+ pos = 0;
+ count = 0;
+ while(dump[pos] != end) {
+ /* Check the hex value */
+ if(!(g_ascii_isxdigit(dump[pos]) &&
+ g_ascii_isxdigit(dump[pos + 1]))) {
+ return 0;
+ }
+ /* Get the hex value */
+ if(g_ascii_isdigit(dump[pos])) {
+ buf[count] = (dump[pos] - '0') << 4;
+ } else {
+ buf[count] = (g_ascii_toupper(dump[pos]) - 'A' + 10) << 4;
+ }
+ pos++;
+ if(g_ascii_isdigit(dump[pos])) {
+ buf[count] += dump[pos] - '0';
+ } else {
+ buf[count] += g_ascii_toupper(dump[pos]) - 'A' + 10;
+ }
+ pos++;
+ count++;
+ /* Skip the separator characters */
+ while(dump[pos] == separator) {
+ pos++;
+ }
+ }
+ return count;
+}
+
+static const struct supported_block_type dbs_etherwatch_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info dbs_etherwatch_info = {
+ "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL,
+ FALSE, BLOCKS_SUPPORTED(dbs_etherwatch_blocks_supported),
+ NULL, NULL, NULL
+};
+
+void register_dbs_etherwatch(void)
+{
+ dbs_etherwatch_file_type_subtype = wtap_register_file_type_subtype(&dbs_etherwatch_info);
+
+ /*
+ * Register name for backwards compatibility with the
+ * wtap_filetypes table in Lua.
+ */
+ wtap_register_backwards_compatibility_lua_name("DBS_ETHERWATCH",
+ dbs_etherwatch_file_type_subtype);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */