* Sensor Network Analyzer for 802.15.4 radios
* Copyright 2009, Exegin Technologies Limited <fff@exegin.com>
*
- * $Id$
- *
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
- * Started with packetlogger.c as a template, but little packetlogger code
- * remains. Borrowed many snippets from dbs-etherwatch.c, the
- * daintree_sna_hex_char function having the largest chunk.
- *
+ * Started with packetlogger.c as a template, but little packetlogger code
+ * remains. Borrowed many snippets from dbs-etherwatch.c, the
+ * daintree_sna_process_hex_data function having the largest chunk.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* USA.
*/
-/* This module reads capture files saved by Daintree's Sensor Network Analyzer.
+/* This module reads capture files saved by Daintree's Sensor Network Analyzer.
* Daintree captures are plain text files with a two line header,
* followed by packet records, one per line, with whitespace separated fields
* consisting of: packet number, time, bytes of capture data, capture data,
*/
/* Example capture file:
-
+
#Format=4
# SNA v2.2.0.4 SUS:20090709 ACT:819705
1 1233783799.326400 10 030809ffffffff07ffff 42 1 -69 25 2 0 1 32767
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#include <glib.h>
-#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <ctype.h>
-#include "wtap.h"
#include "wtap-int.h"
-#include "buffer.h"
#include "file_wrappers.h"
#include "daintree-sna.h"
#define DAINTREE_MAGIC_TEXT_SIZE (sizeof daintree_magic_text)
#define DAINTREE_MAX_LINE_SIZE 512
#define READDATA_BUF_SIZE (DAINTREE_MAX_LINE_SIZE/2)
-#define SEEKDATA_BUF_SIZE (DAINTREE_MAX_LINE_SIZE/2)
#define READDATA_MAX_FIELD_SIZE "255" /* DAINTREE_MAX_LINE_SIZE/2 -1 */
-#define SEEKDATA_MAX_FIELD_SIZE "255" /* DAINTREE_MAX_LINE_SIZE/2 -1 */
#define COMMENT_LINE daintree_magic_text[0]
-static char readLine[DAINTREE_MAX_LINE_SIZE];
-static char seekLine[DAINTREE_MAX_LINE_SIZE];
-
-static char readData[READDATA_BUF_SIZE];
-static char seekData[SEEKDATA_BUF_SIZE];
-
-static gboolean daintree_sna_read(wtap *wth, int *err, gchar **err_info _U_,
+static gboolean daintree_sna_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset);
static gboolean daintree_sna_seek_read(wtap *wth, gint64 seek_off,
- union wtap_pseudo_header *pseudo_header _U_,
- guchar *pd, int len, int *err,
- gchar **err_info _U_);
+ struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
-static guint daintree_sna_hex_char(guchar *str, int *err);
+static gboolean daintree_sna_read_packet(FILE_T fh, struct wtap_pkthdr *phdr,
+ Buffer *buf, int *err, gchar **err_info);
/* Open a file and determine if it's a Daintree file */
-int daintree_sna_open(wtap *wth, int *err _U_, gchar **err_info _U_)
+wtap_open_return_val daintree_sna_open(wtap *wth, int *err, gchar **err_info)
{
- guint i;
+ char readLine[DAINTREE_MAX_LINE_SIZE];
/* get first line of file header */
- if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) return 0;
- wth->data_offset += strlen(readLine);
+ if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) {
+ *err = file_error(wth->fh, err_info);
+ if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
+ }
/* check magic text */
- i = 0;
- while (i < DAINTREE_MAGIC_TEXT_SIZE) {
- if (readLine[i] != daintree_magic_text[i]) return 0; /* not daintree format */
- i++;
- }
+ if (memcmp(readLine, daintree_magic_text, DAINTREE_MAGIC_TEXT_SIZE) != 0)
+ return WTAP_OPEN_NOT_MINE; /* not daintree format */
/* read second header line */
- if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) return 0;
- wth->data_offset += strlen(readLine);
- if (readLine[0] != COMMENT_LINE) return 0; /* daintree files have a two line header */
+ if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) {
+ *err = file_error(wth->fh, err_info);
+ if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
+ }
+ if (readLine[0] != COMMENT_LINE)
+ return WTAP_OPEN_NOT_MINE; /* daintree files have a two line header */
/* set up the pointers to the handlers for this file type */
wth->subtype_read = daintree_sna_read;
wth->subtype_seek_read = daintree_sna_seek_read;
/* set up for file type */
- wth->file_type = WTAP_FILE_DAINTREE_SNA;
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_DAINTREE_SNA;
wth->file_encap = WTAP_ENCAP_IEEE802_15_4_NOFCS;
- wth->tsprecision = WTAP_FILE_TSPREC_USEC;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
wth->snapshot_length = 0; /* not available in header */
- return 1; /* it's a Daintree file */
+ return WTAP_OPEN_MINE; /* it's a Daintree file */
}
/* Read the capture file sequentially
* Wireshark scans the file with sequential reads during preview and initial display. */
static gboolean
-daintree_sna_read(wtap *wth, int *err, gchar **err_info _U_, gint64 *data_offset)
+daintree_sna_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
{
- guint64 seconds;
+ *data_offset = file_tell(wth->fh);
- *data_offset = wth->data_offset;
-
- /* we've only seen file header lines starting with '#', but
- * if others appear in the file, they are tossed */
- do {
- if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh) == NULL) {
- *err = file_error(wth->fh);
- return FALSE; /* all done */
- }
- wth->data_offset += strlen(readLine);
- } while (readLine[0] == COMMENT_LINE);
-
- /* parse one line of capture data */
- if (sscanf(readLine, "%*s %" G_GINT64_MODIFIER "u.%d %u %" READDATA_MAX_FIELD_SIZE "s",
- &seconds, &wth->phdr.ts.nsecs, &wth->phdr.len, readData) != 4) {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup("daintree_sna: invalid read record");
- return FALSE;
- }
-
- /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
- if (wth->phdr.len <= FCS_LENGTH) {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup_printf("daintree_sna: packet length <= %u bytes, no frame data present",
- FCS_LENGTH);
- return FALSE;
- }
- wth->phdr.len -= FCS_LENGTH;
-
- wth->phdr.ts.secs = (time_t) seconds;
- wth->phdr.ts.nsecs *= 1000; /* convert mS to nS */
-
- /* convert packet data from ASCII string to hex, sanity-check its length against what we assume is the
- * packet length field, write data to frame buffer */
- if ((wth->phdr.caplen = daintree_sna_hex_char(readData, err)) > FCS_LENGTH) {
- if (wth->phdr.caplen <= wth->phdr.len) {
- buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
- memcpy(buffer_start_ptr(wth->frame_buffer), readData, wth->phdr.caplen);
- } else {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup_printf("daintree_sna: capture length (%u) > packet length (%u)",
- wth->phdr.caplen, wth->phdr.len);
- return FALSE;
- }
- } else {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup("daintree_sna: invalid packet data");
- return FALSE;
- }
-
- return TRUE;
+ /* parse that line and the following packet data */
+ return daintree_sna_read_packet(wth->fh, &wth->phdr,
+ wth->frame_buffer, err, err_info);
}
-/* Read the capture file randomly
+/* Read the capture file randomly
* Wireshark opens the capture file for random access when displaying user-selected packets */
static gboolean
-daintree_sna_seek_read(wtap *wth, gint64 seek_off, union wtap_pseudo_header
- *pseudo_header _U_, guchar *pd, int len, int *err,
- gchar **err_info _U_)
+daintree_sna_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
+ Buffer *buf, int *err, gchar **err_info)
{
- guint pkt_len;
-
if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
- /* It appears only file header lines start with '#', but
- * if we find any others, we toss them */
+ /* parse that line and the following packet data */
+ return daintree_sna_read_packet(wth->random_fh, phdr, buf, err,
+ err_info);
+}
+
+/* Read a header line, scan it, and fill in a struct wtap_pkthdr.
+ * Then convert packet data from ASCII hex string to binary in place,
+ * sanity-check its length against what we assume is the packet length field,
+ * and copy it into a Buffer. */
+static gboolean
+daintree_sna_read_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
+ int *err, gchar **err_info)
+{
+ guint64 seconds;
+ int useconds;
+ char readLine[DAINTREE_MAX_LINE_SIZE];
+ char readData[READDATA_BUF_SIZE];
+ guchar *str = (guchar *)readData;
+ guint bytes;
+ guint8 *p;
+
+ /* we've only seen file header lines starting with '#', but
+ * if others appear in the file, they are tossed */
do {
- if (file_gets(seekLine, DAINTREE_MAX_LINE_SIZE, wth->random_fh) == NULL) {
- *err = file_error(wth->random_fh);
+ if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, fh) == NULL) {
+ *err = file_error(fh, err_info);
return FALSE; /* all done */
}
- } while (seekLine[0] == COMMENT_LINE);
+ } while (readLine[0] == COMMENT_LINE);
- /* ignore all but packet data, since the sequential read pass stored everything else */
- if (sscanf(seekLine, "%*s %*u.%*u %*u %" SEEKDATA_MAX_FIELD_SIZE "s", seekData) != 1) {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup("daintree_sna: corrupted seek record");
- return FALSE;
- }
+ phdr->rec_type = REC_TYPE_PACKET;
+ phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
- /* convert packet data from ASCII hex string to guchar */
- if ((pkt_len = daintree_sna_hex_char(seekData, err)) <= FCS_LENGTH) {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup("daintree_sna: corrupted packet data");
+ if (sscanf(readLine, "%*s %18" G_GINT64_MODIFIER "u.%9d %9u %" READDATA_MAX_FIELD_SIZE "s",
+ &seconds, &useconds, &phdr->len, readData) != 4) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("daintree_sna: invalid read record");
return FALSE;
}
- pkt_len -= FCS_LENGTH; /* remove padded bytes that Daintree stores instead of FCS */
-
- if (pkt_len == (guint) len) {
- /* move to frame buffer for dissection */
- memcpy(pd, seekData, pkt_len);
- } else {
- *err = WTAP_ERR_BAD_RECORD;
- *err_info = g_strdup("daintree-sna: corrupted frame");
+ /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
+ if (phdr->len <= FCS_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("daintree_sna: packet length <= %u bytes, no frame data present",
+ FCS_LENGTH);
return FALSE;
- }
-
- return TRUE;
-}
+ }
+ phdr->len -= FCS_LENGTH;
-/* Convert an ASCII hex string to guchar */
-static guint
-daintree_sna_hex_char(guchar *str, int *err _U_) {
- guint bytes;
- guchar *p;
+ phdr->ts.secs = (time_t) seconds;
+ phdr->ts.nsecs = useconds * 1000; /* convert mS to nS */
+ /*
+ * READDATA_BUF_SIZE is < WTAP_MAX_PACKET_SIZE, and is the maximum
+ * number of bytes of packet data we can generate, so we don't
+ * need to check the packet length.
+ */
p = str; /* overlay source buffer */
bytes = 0;
- /* convert hex string to guchar */
+ /* convert hex string to guint8 */
while(*str) {
- if (!isxdigit((guchar)*str)) return 0;
/* most significant nibble */
- if(isdigit((guchar)*str)) {
+ if (!g_ascii_isxdigit(*str)) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("daintree_sna: non-hex digit in hex data");
+ return FALSE;
+ }
+ if(g_ascii_isdigit(*str)) {
*p = (*str - '0') << 4;
} else {
- *p = ((tolower(*str) - 'a') + 10) << 4;
+ *p = ((g_ascii_tolower(*str) - 'a') + 10) << 4;
}
str++;
- if (!isxdigit((guchar)*str)) return 0;
/* least significant nibble */
- if(isdigit((guchar)*str)) {
+ if (!g_ascii_isxdigit(*str)) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup("daintree_sna: non-hex digit in hex data");
+ return FALSE;
+ }
+ if(g_ascii_isdigit(*str)) {
*p += *str - '0';
} else {
- *p += (tolower(*str) - 'a') + 10;
+ *p += (g_ascii_tolower(*str) - 'a') + 10;
}
str++;
bytes++;
}
- return bytes;
+ /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
+ if (bytes <= FCS_LENGTH) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("daintree_sna: Only %u bytes of packet data",
+ bytes);
+ return FALSE;
+ }
+ bytes -= FCS_LENGTH;
+ if (bytes > phdr->len) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("daintree_sna: capture length (%u) > packet length (%u)",
+ bytes, phdr->len);
+ return FALSE;
+ }
+
+ phdr->caplen = bytes;
+
+ ws_buffer_assure_space(buf, bytes);
+ memcpy(ws_buffer_start_ptr(buf), readData, bytes);
+ return TRUE;
}
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */