2 * Routines for opening .dcf capture files created by Daintree's
3 * Sensor Network Analyzer for 802.15.4 radios
4 * Copyright 2009, Exegin Technologies Limited <fff@exegin.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Started with packetlogger.c as a template, but little packetlogger code
11 * remains. Borrowed many snippets from dbs-etherwatch.c, the
12 * daintree_sna_process_hex_data function having the largest chunk.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
30 /* This module reads capture files saved by Daintree's Sensor Network Analyzer.
31 * Daintree captures are plain text files with a two line header,
32 * followed by packet records, one per line, with whitespace separated fields
33 * consisting of: packet number, time, bytes of capture data, capture data,
34 * unknown, unknown, signal strength?, unknown, etc, and terminated with CRLF.
37 /* Example capture file:
40 # SNA v2.2.0.4 SUS:20090709 ACT:819705
41 1 1233783799.326400 10 030809ffffffff07ffff 42 1 -69 25 2 0 1 32767
42 2 1233783799.477440 5 02000bffff 110 1 -44 25 6 0 1 32767
43 3 1233783799.809920 5 020013ffff 107 1 -45 25 43 0 1 3276
58 #include <wsutil/buffer.h>
59 #include "file_wrappers.h"
60 #include "daintree-sna.h"
62 typedef struct daintree_sna_header {
65 } daintree_sna_header_t;
67 #define DAINTREE_SNA_HEADER_SIZE 2
70 static const char daintree_magic_text[] =
71 { '#', 'F', 'o', 'r', 'm', 'a', 't', '=' };
73 #define DAINTREE_MAGIC_TEXT_SIZE (sizeof daintree_magic_text)
74 #define DAINTREE_MAX_LINE_SIZE 512
75 #define READDATA_BUF_SIZE (DAINTREE_MAX_LINE_SIZE/2)
76 #define READDATA_MAX_FIELD_SIZE "255" /* DAINTREE_MAX_LINE_SIZE/2 -1 */
78 #define COMMENT_LINE daintree_magic_text[0]
80 static gboolean daintree_sna_read(wtap *wth, int *err, gchar **err_info,
83 static gboolean daintree_sna_seek_read(wtap *wth, gint64 seek_off,
84 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
86 static gboolean daintree_sna_scan_header(struct wtap_pkthdr *phdr,
87 char *readLine, char *readData, int *err, gchar **err_info);
89 static gboolean daintree_sna_process_hex_data(struct wtap_pkthdr *phdr,
90 Buffer *buf, char *readData, int *err, gchar **err_info);
92 /* Open a file and determine if it's a Daintree file */
93 int daintree_sna_open(wtap *wth, int *err, gchar **err_info)
95 char readLine[DAINTREE_MAX_LINE_SIZE];
98 /* get first line of file header */
99 if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) {
100 *err = file_error(wth->fh, err_info);
101 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
106 /* check magic text */
108 while (i < DAINTREE_MAGIC_TEXT_SIZE) {
109 if (readLine[i] != daintree_magic_text[i]) return 0; /* not daintree format */
113 /* read second header line */
114 if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) {
115 *err = file_error(wth->fh, err_info);
116 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
120 if (readLine[0] != COMMENT_LINE) return 0; /* daintree files have a two line header */
122 /* set up the pointers to the handlers for this file type */
123 wth->subtype_read = daintree_sna_read;
124 wth->subtype_seek_read = daintree_sna_seek_read;
126 /* set up for file type */
127 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_DAINTREE_SNA;
128 wth->file_encap = WTAP_ENCAP_IEEE802_15_4_NOFCS;
129 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
130 wth->snapshot_length = 0; /* not available in header */
132 return 1; /* it's a Daintree file */
135 /* Read the capture file sequentially
136 * Wireshark scans the file with sequential reads during preview and initial display. */
138 daintree_sna_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
140 char readLine[DAINTREE_MAX_LINE_SIZE];
141 char readData[READDATA_BUF_SIZE];
143 *data_offset = file_tell(wth->fh);
145 /* we've only seen file header lines starting with '#', but
146 * if others appear in the file, they are tossed */
148 if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh) == NULL) {
149 *err = file_error(wth->fh, err_info);
150 return FALSE; /* all done */
152 } while (readLine[0] == COMMENT_LINE);
154 /* parse one line of capture data */
155 if (!daintree_sna_scan_header(&wth->phdr, readLine, readData,
159 /* process packet data */
160 return daintree_sna_process_hex_data(&wth->phdr, wth->frame_buffer,
161 readData, err, err_info);
164 /* Read the capture file randomly
165 * Wireshark opens the capture file for random access when displaying user-selected packets */
167 daintree_sna_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
168 Buffer *buf, int *err, gchar **err_info)
170 char readLine[DAINTREE_MAX_LINE_SIZE];
171 char readData[READDATA_BUF_SIZE];
173 if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
176 /* It appears only file header lines start with '#', but
177 * if we find any others, we toss them */
179 if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->random_fh) == NULL) {
180 *err = file_error(wth->random_fh, err_info);
181 return FALSE; /* all done */
183 } while (readLine[0] == COMMENT_LINE);
185 /* parse one line of capture data */
186 if (!daintree_sna_scan_header(phdr, readLine, readData, err, err_info))
189 /* process packet data */
190 return daintree_sna_process_hex_data(phdr, buf, readData, err,
194 /* Scan a header line and fill in a struct wtap_pkthdr */
196 daintree_sna_scan_header(struct wtap_pkthdr *phdr, char *readLine,
197 char *readData, int *err, gchar **err_info)
202 phdr->rec_type = REC_TYPE_PACKET;
203 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
205 if (sscanf(readLine, "%*s %18" G_GINT64_MODIFIER "u.%9d %9u %" READDATA_MAX_FIELD_SIZE "s",
206 &seconds, &useconds, &phdr->len, readData) != 4) {
207 *err = WTAP_ERR_BAD_FILE;
208 *err_info = g_strdup("daintree_sna: invalid read record");
212 /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
213 if (phdr->len <= FCS_LENGTH) {
214 *err = WTAP_ERR_BAD_FILE;
215 *err_info = g_strdup_printf("daintree_sna: packet length <= %u bytes, no frame data present",
219 phdr->len -= FCS_LENGTH;
221 phdr->ts.secs = (time_t) seconds;
222 phdr->ts.nsecs = useconds * 1000; /* convert mS to nS */
227 /* Convert packet data from ASCII hex string to binary in place,
228 * sanity-check its length against what we assume is the packet length field,
229 * and copy it into a Buffer */
231 daintree_sna_process_hex_data(struct wtap_pkthdr *phdr, Buffer *buf,
232 char *readData, int *err, gchar **err_info)
234 guchar *str = (guchar *)readData;
238 p = str; /* overlay source buffer */
240 /* convert hex string to guint8 */
242 /* most significant nibble */
243 if (!isxdigit((guchar)*str)) {
244 *err = WTAP_ERR_BAD_FILE;
245 *err_info = g_strdup("daintree_sna: non-hex digit in hex data");
248 if(isdigit((guchar)*str)) {
249 *p = (*str - '0') << 4;
251 *p = ((tolower(*str) - 'a') + 10) << 4;
255 /* least significant nibble */
256 if (!isxdigit((guchar)*str)) {
257 *err = WTAP_ERR_BAD_FILE;
258 *err_info = g_strdup("daintree_sna: non-hex digit in hex data");
261 if(isdigit((guchar)*str)) {
264 *p += (tolower(*str) - 'a') + 10;
268 /* next byte in buffer */
273 /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
274 if (bytes <= FCS_LENGTH) {
275 *err = WTAP_ERR_BAD_FILE;
276 *err_info = g_strdup_printf("daintree_sna: Only %u bytes of packet data",
281 if (bytes > phdr->len) {
282 *err = WTAP_ERR_BAD_FILE;
283 *err_info = g_strdup_printf("daintree_sna: capture length (%u) > packet length (%u)",
288 phdr->caplen = bytes;
290 ws_buffer_assure_space(buf, bytes);
291 memcpy(ws_buffer_start_ptr(buf), readData, bytes);