summaryrefslogtreecommitdiff
path: root/wiretap/daintree-sna.c
diff options
context:
space:
mode:
authorStig Bjørlykke <stig@bjorlykke.org>2009-05-24 22:49:36 +0000
committerStig Bjørlykke <stig@bjorlykke.org>2009-05-24 22:49:36 +0000
commit5fa6b90f6b3a2e0a4f81bc43a0848682008a8925 (patch)
tree9cad1eec3eb3ab527e0ec72d9b0d8443aada5ad5 /wiretap/daintree-sna.c
parent905b8d0b2db72e8f1dc37c86fa2f0840761a0e2e (diff)
downloadwireshark-5fa6b90f6b3a2e0a4f81bc43a0848682008a8925.tar.gz
From Fred Fierling (bug 3486):
Added support for Daintree's Sensor Network Analyzer capture files. svn path=/trunk/; revision=28463
Diffstat (limited to 'wiretap/daintree-sna.c')
-rw-r--r--wiretap/daintree-sna.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/wiretap/daintree-sna.c b/wiretap/daintree-sna.c
new file mode 100644
index 0000000000..73884e4e4d
--- /dev/null
+++ b/wiretap/daintree-sna.c
@@ -0,0 +1,266 @@
+/* daintree_sna.c
+ * Routines for opening .dcf capture files created by Daintree's
+ * 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.
+ *
+ * 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+/* 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,
+ * unknown, unknown, signal strength?, unknown, etc, and terminated with CRLF.
+ */
+
+/* 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
+2 1233783799.477440 5 02000bffff 110 1 -44 25 6 0 1 32767
+3 1233783799.809920 5 020013ffff 107 1 -45 25 43 0 1 3276
+
+*/
+
+#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"
+
+typedef struct daintree_sna_header {
+ guint32 len;
+ guint64 ts;
+} daintree_sna_header_t;
+
+#define DAINTREE_SNA_HEADER_SIZE 2
+#define FCS_LENGTH 2
+
+static const char daintree_magic_text[] =
+{ '#', 'F', 'o', 'r', 'm', 'a', 't', '=' };
+
+#define DAINTREE_MAGIC_TEXT_SIZE (sizeof daintree_magic_text)
+#define DAINTREE_MAX_LINE_SIZE 512
+#define COMMENT_LINE daintree_magic_text[0]
+
+static char readLine[DAINTREE_MAX_LINE_SIZE];
+static char seekLine[DAINTREE_MAX_LINE_SIZE];
+static char readData[DAINTREE_MAX_LINE_SIZE/2];
+static char seekData[DAINTREE_MAX_LINE_SIZE/2];
+
+static gboolean daintree_sna_read(wtap *wth, int *err, gchar **err_info _U_,
+ 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_);
+
+static guint daintree_sna_hex_char(guchar *str, int *err);
+
+/* Open a file and determine if it's a Daintree file */
+int daintree_sna_open(wtap *wth, int *err _U_, gchar **err_info _U_)
+{
+ guint i;
+
+ /* get first line of file header */
+ if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) return 0;
+ wth->data_offset += strlen(readLine);
+
+ /* check magic text */
+ i = 0;
+ while (i < DAINTREE_MAGIC_TEXT_SIZE) {
+ if (readLine[i] != daintree_magic_text[i]) return 0; /* not daintree format */
+ i++;
+ }
+
+ /* 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 */
+
+ /* 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_encap = WTAP_ENCAP_IEEE802_15_4;
+ wth->tsprecision = WTAP_FILE_TSPREC_USEC;
+
+ return 1; /* 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)
+{
+ guint64 seconds;
+
+ *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.%u %u %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;
+ }
+
+ 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) {
+ /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
+ wth->phdr.caplen -= FCS_LENGTH;
+ 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 (%d) > packet length (%d)",
+ 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;
+}
+
+/* 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_)
+{
+ 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 */
+ do {
+ if (file_gets(seekLine, DAINTREE_MAX_LINE_SIZE, wth->random_fh) == NULL) {
+ *err = file_error(wth->random_fh);
+ return FALSE; /* all done */
+ }
+ } while (seekLine[0] == COMMENT_LINE);
+
+ /* ignore all but packet data, since the sequential read pass stored everything else */
+ if (sscanf(seekLine, "%*s %*u.%*u %*u %s", seekData) != 1) {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup("daintree_sna: corrupted seek record");
+ return FALSE;
+ }
+
+ /* 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");
+ 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");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Convert an ASCII hex string to guchar */
+static guint
+daintree_sna_hex_char(guchar *str, int *err _U_) {
+ guint bytes;
+ guchar *p;
+
+ p = str; /* overlay source buffer */
+ bytes = 0;
+ /* convert hex string to guchar */
+ while(*str) {
+ if (!isxdigit((guchar)*str)) return 0;
+ /* most significant nibble */
+ if(isdigit((guchar)*str)) {
+ *p = (*str - '0') << 4;
+ } else {
+ *p = ((tolower(*str) - 'a') + 10) << 4;
+ }
+ str++;
+
+ if (!isxdigit((guchar)*str)) return 0;
+ /* least significant nibble */
+ if(isdigit((guchar)*str)) {
+ *p += *str - '0';
+ } else {
+ *p += (tolower(*str) - 'a') + 10;
+ }
+ str++;
+
+ /* next byte in buffer */
+ p++;
+ bytes++;
+ }
+
+ return bytes;
+}