/* ascendtext.c
- *
- * $Id$
*
* Wiretap Library
* Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
*
* 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.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include "wtap-int.h"
-#include "buffer.h"
#include "ascendtext.h"
#include "ascend-int.h"
#include "file_wrappers.h"
-#include <wsutil/file_util.h>
#include <errno.h>
#include <unistd.h>
#endif
-#include <ctype.h>
#include <string.h>
/* Last updated: Feb 03 2005: Josh Bailey (joshbailey@lucent.com).
This module reads the text hex dump output of various TAOS
(Lucent/Ascend Max, Max TNT, APX, etc) debug commands, including:
- * pridisplay traces primary rate ISDN
- * ether-display traces Ethernet packets (dangerous! CPU intensive)
+ * pridisplay traces primary rate ISDN
+ * ether-display traces Ethernet packets (dangerous! CPU intensive)
* wanopening, wandisplay, wannext, wandsess
- traces PPP or other WAN connections
+ traces PPP or other WAN connections
Please see ascend.y for examples.
typedef struct _ascend_magic_string {
guint type;
- const gchar *strptr;
+ const gchar *strptr;
+ size_t strlength;
} ascend_magic_string;
-#define ASCEND_MAGIC_STRINGS 11
-#define ASCEND_DATE "Date:"
-
/* these magic strings signify the headers of a supported debug commands */
+#define ASCEND_MAGIC_ENTRY(type, string) \
+ { type, string, sizeof string - 1 } /* strlen of a constant string */
static const ascend_magic_string ascend_magic[] = {
- { ASCEND_PFX_ISDN_X, "PRI-XMIT-" },
- { ASCEND_PFX_ISDN_R, "PRI-RCV-" },
- { ASCEND_PFX_WDS_X, "XMIT-" },
- { ASCEND_PFX_WDS_R, "RECV-" },
- { ASCEND_PFX_WDS_X, "XMIT:" },
- { ASCEND_PFX_WDS_R, "RECV:" },
- { ASCEND_PFX_WDS_X, "PPP-OUT" },
- { ASCEND_PFX_WDS_R, "PPP-IN" },
- { ASCEND_PFX_WDD, ASCEND_DATE },
- { ASCEND_PFX_WDD, "WD_DIALOUT_DISP:" },
- { ASCEND_PFX_ETHER, "ETHER" },
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_ISDN_X, "PRI-XMIT-"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_ISDN_R, "PRI-RCV-"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "XMIT-"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "RECV-"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "XMIT:"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "RECV:"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_X, "PPP-OUT"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDS_R, "PPP-IN"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_WDD, "WD_DIALOUT_DISP:"),
+ ASCEND_MAGIC_ENTRY(ASCEND_PFX_ETHER, "ETHER"),
};
-typedef struct {
- time_t inittime;
- int adjusted;
- gint64 next_packet_seek_start;
-} ascend_t;
+#define ASCEND_MAGIC_STRINGS G_N_ELEMENTS(ascend_magic)
+
+#define ASCEND_DATE "Date:"
static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
- gint64 *data_offset);
+ gint64 *data_offset);
static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
- union wtap_pseudo_header *pseudo_head, guint8 *pd, int len,
- int *err, gchar **err_info);
+ struct wtap_pkthdr *phdr, Buffer *buf,
+ int *err, gchar **err_info);
/* Seeks to the beginning of the next packet, and returns the
byte offset at which the header for that packet begins.
gint64 date_off = -1, cur_off, packet_off;
size_t string_level[ASCEND_MAGIC_STRINGS];
guint string_i = 0, type = 0;
+ static const gchar ascend_date[] = ASCEND_DATE;
+ size_t ascend_date_len = sizeof ascend_date - 1; /* strlen of a constant string */
+ size_t ascend_date_string_level;
guint excessive_read_count = 262144;
memset(&string_level, 0, sizeof(string_level));
+ ascend_date_string_level = 0;
while (((byte = file_getc(wth->fh)) != EOF)) {
excessive_read_count--;
return -1;
}
+ /*
+ * See whether this is the string_level[string_i]th character of
+ * Ascend magic string string_i.
+ */
for (string_i = 0; string_i < ASCEND_MAGIC_STRINGS; string_i++) {
const gchar *strptr = ascend_magic[string_i].strptr;
- size_t len = strlen(strptr);
+ size_t len = ascend_magic[string_i].strlength;
if (byte == *(strptr + string_level[string_i])) {
+ /*
+ * Yes, it is, so we need to check for the next character of
+ * that string.
+ */
string_level[string_i]++;
+
+ /*
+ * Have we matched the entire string?
+ */
if (string_level[string_i] >= len) {
+ /*
+ * Yes.
+ */
cur_off = file_tell(wth->fh);
if (cur_off == -1) {
/* Error. */
return -1;
}
- /* Date: header is a special case. Remember the offset,
- but keep looking for other headers. */
- if (strcmp(strptr, ASCEND_DATE) == 0) {
- date_off = cur_off - len;
+ /* We matched some other type of header. */
+ if (date_off == -1) {
+ /* We haven't yet seen a date header, so this packet
+ doesn't have one.
+ Back up over the header we just read; that's where a read
+ of this packet should start. */
+ packet_off = cur_off - len;
} else {
- if (date_off == -1) {
- /* Back up over the header we just read; that's where a read
- of this packet should start. */
- packet_off = cur_off - len;
- } else {
- /* This packet has a date/time header; a read of it should
- start at the beginning of *that* header. */
- packet_off = date_off;
- }
-
- type = ascend_magic[string_i].type;
- goto found;
+ /* This packet has a date/time header; a read of it should
+ start at the beginning of *that* header. */
+ packet_off = date_off;
}
+
+ type = ascend_magic[string_i].type;
+ goto found;
}
} else {
+ /*
+ * Not a match for this string, so reset the match process.
+ */
string_level[string_i] = 0;
}
}
- }
- if (byte != EOF || file_eof(wth->fh)) {
- /* Either we didn't find the offset, or 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, err_info);
+ /*
+ * See whether this is the date_string_level'th character of
+ * ASCEND_DATE.
+ */
+ if (byte == *(ascend_date + ascend_date_string_level)) {
+ /*
+ * Yes, it is, so we need to check for the next character of
+ * that string.
+ */
+ ascend_date_string_level++;
+
+ /*
+ * Have we matched the entire string?
+ */
+ if (ascend_date_string_level >= ascend_date_len) {
+ /* We matched a Date: header. It's a special case;
+ remember the offset, but keep looking for other
+ headers.
+
+ Reset the amount of Date: header that we've matched,
+ so that we start the process of matching a Date:
+ header all over again.
+
+ XXX - what if we match multiple Date: headers before
+ matching some other header? */
+ cur_off = file_tell(wth->fh);
+ if (cur_off == -1) {
+ /* Error. */
+ *err = file_error(wth->fh, err_info);
+ return -1;
+ }
+
+ date_off = cur_off - ascend_date_len;
+ ascend_date_string_level = 0;
+ }
+ } else {
+ /*
+ * Not a match for the Date: string, so reset the match process.
+ */
+ ascend_date_string_level = 0;
+ }
}
+
+ *err = file_error(wth->fh, err_info);
return -1;
found:
if (file_seek(wth->fh, packet_off, SEEK_SET, err) == -1)
return -1;
- wth->pseudo_header.ascend.type = type;
+ wth->phdr.pseudo_header.ascend.type = type;
return packet_off;
}
-int ascend_open(wtap *wth, int *err, gchar **err_info)
+wtap_open_return_val ascend_open(wtap *wth, int *err, gchar **err_info)
{
gint64 offset;
- ws_statb64 statbuf;
guint8 buf[ASCEND_MAX_PKT_LEN];
- ascend_pkthdr header;
- gint64 dummy_seek_start;
+ ascend_state_t parser_state;
+ ws_statb64 statbuf;
ascend_t *ascend;
/* We haven't yet allocated a data structure for our private stuff;
offset = ascend_seek(wth, err, err_info);
if (offset == -1) {
- if (*err == 0)
- return 0;
- else
- return -1;
+ if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
}
/* Do a trial parse of the first packet just found to see if we might really have an Ascend file */
- init_parse_ascend();
- if (parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header,
- &dummy_seek_start) != PARSED_RECORD) {
- return 0;
+ if (run_ascend_parser(wth->fh, &wth->phdr, buf, &parser_state, err, err_info) != 0) {
+ if (*err != 0) {
+ /* An I/O error. */
+ return WTAP_OPEN_ERROR;
+ }
+ }
+
+ /* if we got at least some data, and didn't get an I/O error, return
+ success even if the parser reported an error. This is because the
+ debug header gives the number of bytes on the wire, not actually
+ how many bytes are in the trace. We won't know where the data ends
+ until we run into the next packet. */
+ if (parser_state.caplen == 0) {
+ return WTAP_OPEN_NOT_MINE;
}
- wth->data_offset = offset;
- wth->file_type = WTAP_FILE_ASCEND;
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ASCEND;
- switch(wth->pseudo_header.ascend.type) {
+ switch(wth->phdr.pseudo_header.ascend.type) {
case ASCEND_PFX_ISDN_X:
case ASCEND_PFX_ISDN_R:
wth->file_encap = WTAP_ENCAP_ISDN;
offset that we can apply to each packet.
*/
if (wtap_fstat(wth, &statbuf, err) == -1) {
- g_free(ascend);
- return -1;
+ return WTAP_OPEN_ERROR;
}
ascend->inittime = statbuf.st_ctime;
- ascend->adjusted = 0;
- wth->tsprecision = WTAP_FILE_TSPREC_USEC;
-
- init_parse_ascend();
+ ascend->adjusted = FALSE;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
- return 1;
+ return WTAP_OPEN_MINE;
}
-static void config_pseudo_header(union wtap_pseudo_header *pseudo_head)
+typedef enum {
+ PARSED_RECORD,
+ PARSED_NONRECORD,
+ PARSE_FAILED
+} parse_t;
+
+/* Parse the capture file.
+ Returns:
+ PARSED_RECORD if we got a packet
+ PARSED_NONRECORD if the parser succeeded but didn't see a packet
+ PARSE_FAILED if the parser failed. */
+static parse_t
+parse_ascend(ascend_t *ascend, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
+ guint length, int *err, gchar **err_info)
{
- switch(pseudo_head->ascend.type) {
- case ASCEND_PFX_ISDN_X:
- pseudo_head->isdn.uton = TRUE;
- pseudo_head->isdn.channel = 0;
- break;
-
- case ASCEND_PFX_ISDN_R:
- pseudo_head->isdn.uton = FALSE;
- pseudo_head->isdn.channel = 0;
- break;
+ ascend_state_t parser_state;
+ int retval;
+
+ ws_buffer_assure_space(buf, length);
+ retval = run_ascend_parser(fh, phdr, ws_buffer_start_ptr(buf), &parser_state,
+ err, err_info);
+
+ /* did we see any data (hex bytes)? if so, tip off ascend_seek()
+ as to where to look for the next packet, if any. If we didn't,
+ maybe this record was broken. Advance so we don't get into
+ an infinite loop reading a broken trace. */
+ if (parser_state.first_hexbyte) {
+ ascend->next_packet_seek_start = parser_state.first_hexbyte;
+ } else {
+ /* Sometimes, a header will be printed but the data will be omitted, or
+ worse -- two headers will be printed, followed by the data for each.
+ Because of this, we need to be fairly tolerant of what we accept
+ here. If we didn't find any hex bytes, skip over what we've read so
+ far so we can try reading a new packet. */
+ ascend->next_packet_seek_start = file_tell(fh);
+ retval = 0;
+ }
- case ASCEND_PFX_ETHER:
- pseudo_head->eth.fcs_len = 0;
- break;
+ /* if we got at least some data, return success even if the parser
+ reported an error. This is because the debug header gives the number
+ of bytes on the wire, not actually how many bytes are in the trace.
+ We won't know where the data ends until we run into the next packet. */
+ if (parser_state.caplen) {
+ if (! ascend->adjusted) {
+ ascend->adjusted = TRUE;
+ if (parser_state.saw_timestamp) {
+ /*
+ * Capture file contained a date and time.
+ * We do this only if this is the very first packet we've seen -
+ * i.e., if "ascend->adjusted" is false - because
+ * if we get a date and time after the first packet, we can't
+ * go back and adjust the time stamps of the packets we've already
+ * processed, and basing the time stamps of this and following
+ * packets on the time stamp from the file text rather than the
+ * ctime of the capture file means times before this and after
+ * this can't be compared.
+ */
+ ascend->inittime = parser_state.timestamp;
+ }
+ if (ascend->inittime > parser_state.secs)
+ ascend->inittime -= parser_state.secs;
+ }
+ phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
+ phdr->ts.secs = parser_state.secs + ascend->inittime;
+ phdr->ts.nsecs = parser_state.usecs * 1000;
+ phdr->caplen = parser_state.caplen;
+ phdr->len = parser_state.wirelen;
+
+ /*
+ * For these types, the encapsulation we use is not WTAP_ENCAP_ASCEND,
+ * so set the pseudo-headers appropriately for the type (WTAP_ENCAP_ISDN
+ * or WTAP_ENCAP_ETHERNET).
+ */
+ switch(phdr->pseudo_header.ascend.type) {
+ case ASCEND_PFX_ISDN_X:
+ phdr->pseudo_header.isdn.uton = TRUE;
+ phdr->pseudo_header.isdn.channel = 0;
+ break;
+
+ case ASCEND_PFX_ISDN_R:
+ phdr->pseudo_header.isdn.uton = FALSE;
+ phdr->pseudo_header.isdn.channel = 0;
+ break;
+
+ case ASCEND_PFX_ETHER:
+ phdr->pseudo_header.eth.fcs_len = 0;
+ break;
+ }
+ return PARSED_RECORD;
}
+
+ /* Didn't see any data. Still, perhaps the parser was happy. */
+ if (retval) {
+ if (*err == 0) {
+ /* Not a bad record, so a parse error. Return WTAP_ERR_BAD_FILE,
+ with the parse error as the error string. */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup((parser_state.ascend_parse_error != NULL) ? parser_state.ascend_parse_error : "parse error");
+ }
+ return PARSE_FAILED;
+ } else
+ return PARSED_NONRECORD;
}
/* Read the next packet; called from wtap_read(). */
static gboolean ascend_read(wtap *wth, int *err, gchar **err_info,
- gint64 *data_offset)
+ gint64 *data_offset)
{
ascend_t *ascend = (ascend_t *)wth->priv;
gint64 offset;
- guint8 *buf = buffer_start_ptr(wth->frame_buffer);
- ascend_pkthdr header;
/* parse_ascend() will advance the point at which to look for the next
packet's header, to just after the last packet's header (ie. at the
SEEK_SET, err) == -1)
return FALSE;
- offset = ascend_seek(wth, err, err_info);
- if (offset == -1)
- return FALSE;
- if (parse_ascend(wth->fh, buf, &wth->pseudo_header.ascend, &header,
- &(ascend->next_packet_seek_start)) != PARSED_RECORD) {
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
+ offset = ascend_seek(wth, err, err_info);
+ if (offset == -1)
+ return FALSE;
+ if (parse_ascend(ascend, wth->fh, &wth->phdr, wth->frame_buffer,
+ wth->snapshot_length, err, err_info) != PARSED_RECORD)
return FALSE;
- }
-
- buffer_assure_space(wth->frame_buffer, wth->snapshot_length);
-
- config_pseudo_header(&wth->pseudo_header);
-
- if (! ascend->adjusted) {
- ascend->adjusted = 1;
- if (header.start_time != 0) {
- /*
- * Capture file contained a date and time.
- * We do this only if this is the very first packet we've seen -
- * i.e., if "ascend->adjusted" is false - because
- * if we get a date and time after the first packet, we can't
- * go back and adjust the time stamps of the packets we've already
- * processed, and basing the time stamps of this and following
- * packets on the time stamp from the file text rather than the
- * ctime of the capture file means times before this and after
- * this can't be compared.
- */
- ascend->inittime = header.start_time;
- }
- if (ascend->inittime > header.secs)
- ascend->inittime -= header.secs;
- }
- wth->phdr.ts.secs = header.secs + ascend->inittime;
- wth->phdr.ts.nsecs = header.usecs * 1000;
- wth->phdr.caplen = header.caplen;
- wth->phdr.len = header.len;
- wth->data_offset = offset;
*data_offset = offset;
return TRUE;
}
static gboolean ascend_seek_read(wtap *wth, gint64 seek_off,
- union wtap_pseudo_header *pseudo_head, guint8 *pd, int len _U_,
- int *err, gchar **err_info)
+ struct wtap_pkthdr *phdr, Buffer *buf,
+ int *err, gchar **err_info)
{
ascend_t *ascend = (ascend_t *)wth->priv;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
- if (parse_ascend(wth->random_fh, pd, &pseudo_head->ascend, NULL,
- &(ascend->next_packet_seek_start)) != PARSED_RECORD) {
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup((ascend_parse_error != NULL) ? ascend_parse_error : "parse error");
+ if (parse_ascend(ascend, wth->random_fh, phdr, buf,
+ wth->snapshot_length, err, err_info) != PARSED_RECORD)
return FALSE;
- }
- config_pseudo_header(pseudo_head);
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:
+ */