From 5fa6b90f6b3a2e0a4f81bc43a0848682008a8925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig=20Bj=C3=B8rlykke?= Date: Sun, 24 May 2009 22:49:36 +0000 Subject: [PATCH] From Fred Fierling (bug 3486): Added support for Daintree's Sensor Network Analyzer capture files. svn path=/trunk/; revision=28463 --- AUTHORS | 4 + wiretap/Makefile.common | 1 + wiretap/daintree-sna.c | 266 ++++++++++++++++++++++++++++++++++++++++ wiretap/daintree-sna.h | 32 +++++ wiretap/file_access.c | 7 +- wiretap/wtap.h | 1 + 6 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 wiretap/daintree-sna.c create mode 100644 wiretap/daintree-sna.h diff --git a/AUTHORS b/AUTHORS index 6861826564..03345e308c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2855,6 +2855,10 @@ Benjamin Tse { Overlapped pipe I/O for dumpcap under Windows } +Fred Fierling { + Daintree's Sensor Network Analyzer file support +} + and by: Pavel Roskin diff --git a/wiretap/Makefile.common b/wiretap/Makefile.common index d52ab163cb..74c61a458a 100644 --- a/wiretap/Makefile.common +++ b/wiretap/Makefile.common @@ -40,6 +40,7 @@ NONGENERATED_C_FILES = \ commview.c \ cosine.c \ csids.c \ + daintree-sna.c \ dbs-etherwatch.c \ dct3trace.c \ erf.c \ 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 + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 +#include +#include +#include +#include +#include + +#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; +} diff --git a/wiretap/daintree-sna.h b/wiretap/daintree-sna.h new file mode 100644 index 0000000000..3a7b0f33c9 --- /dev/null +++ b/wiretap/daintree-sna.h @@ -0,0 +1,32 @@ +/* daintree-sna.h + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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. + * + */ + +#ifndef __DAINTREE_SNA_H__ +#define __DAINTREE_SNA_H__ + +int daintree_sna_open(wtap *wth, int *err, gchar **err_info _U_); + +#endif /* __DAINTREE_SNA_H__ */ + diff --git a/wiretap/file_access.c b/wiretap/file_access.c index 0669bc3abb..a389ffce3f 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -80,6 +80,7 @@ #include "tnef.h" #include "dct3trace.h" #include "packetlogger.h" +#include "daintree-sna.h" /* The open_file_* routines should return: @@ -128,6 +129,7 @@ static wtap_open_routine_t open_routines_base[] = { mpeg_open, tnef_open, dct3trace_open, + daintree_sna_open, /* Files that don't have magic bytes at a fixed location, * but that instead require a heuristic of some sort to * identify them. This includes the ASCII trace files that @@ -602,7 +604,10 @@ static const struct file_type_info dump_open_table_base[] = { { "Gammu DCT3 trace", "dct3trace", "*.xml", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_PACKETLOGGER */ - { "PacketLogger", "pklg", "*.pklg", NULL, FALSE, NULL, NULL } + { "PacketLogger", "pklg", "*.pklg", NULL, FALSE, NULL, NULL }, + + /* WTAP_FILE_DAINTREE_SNA */ + { "Daintree SNA", "dsna", "*.dcf", NULL, FALSE, NULL, NULL } }; gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info); diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 7dedc768d6..c3f82ebc7d 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -271,6 +271,7 @@ extern "C" { #define WTAP_FILE_TNEF 53 #define WTAP_FILE_DCT3TRACE 54 #define WTAP_FILE_PACKETLOGGER 55 +#define WTAP_FILE_DAINTREE_SNA 56 #define WTAP_NUM_FILE_TYPES wtap_get_num_file_types()