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>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * Started with packetlogger.c as a template, but little packetlogger code
13 * remains. Borrowed many snippets from dbs-etherwatch.c, the
14 * daintree_sna_process_hex_data function having the largest chunk.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
32 /* This module reads capture files saved by Daintree's Sensor Network Analyzer.
33 * Daintree captures are plain text files with a two line header,
34 * followed by packet records, one per line, with whitespace separated fields
35 * consisting of: packet number, time, bytes of capture data, capture data,
36 * unknown, unknown, signal strength?, unknown, etc, and terminated with CRLF.
39 /* Example capture file:
42 # SNA v2.2.0.4 SUS:20090709 ACT:819705
43 1 1233783799.326400 10 030809ffffffff07ffff 42 1 -69 25 2 0 1 32767
44 2 1233783799.477440 5 02000bffff 110 1 -44 25 6 0 1 32767
45 3 1233783799.809920 5 020013ffff 107 1 -45 25 43 0 1 3276
61 #include "file_wrappers.h"
62 #include "daintree-sna.h"
64 typedef struct daintree_sna_header
{
67 } daintree_sna_header_t
;
69 #define DAINTREE_SNA_HEADER_SIZE 2
72 static const char daintree_magic_text
[] =
73 { '#', 'F', 'o', 'r', 'm', 'a', 't', '=' };
75 #define DAINTREE_MAGIC_TEXT_SIZE (sizeof daintree_magic_text)
76 #define DAINTREE_MAX_LINE_SIZE 512
77 #define READDATA_BUF_SIZE (DAINTREE_MAX_LINE_SIZE/2)
78 #define READDATA_MAX_FIELD_SIZE "255" /* DAINTREE_MAX_LINE_SIZE/2 -1 */
80 #define COMMENT_LINE daintree_magic_text[0]
82 static gboolean
daintree_sna_read(wtap
*wth
, int *err
, gchar
**err_info
,
85 static gboolean
daintree_sna_seek_read(wtap
*wth
, gint64 seek_off
,
86 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int len
, int *err
,
89 static gboolean
daintree_sna_scan_header(struct wtap_pkthdr
*phdr
,
90 char *readLine
, char *readData
, int *err
, gchar
**err_info
);
92 static gboolean
daintree_sna_process_hex_data(struct wtap_pkthdr
*phdr
,
93 Buffer
*buf
, char *readData
, int *err
, gchar
**err_info
);
95 /* Open a file and determine if it's a Daintree file */
96 int daintree_sna_open(wtap
*wth
, int *err
, gchar
**err_info
)
98 char readLine
[DAINTREE_MAX_LINE_SIZE
];
101 /* get first line of file header */
102 if (file_gets(readLine
, DAINTREE_MAX_LINE_SIZE
, wth
->fh
)==NULL
) {
103 *err
= file_error(wth
->fh
, err_info
);
104 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
109 /* check magic text */
111 while (i
< DAINTREE_MAGIC_TEXT_SIZE
) {
112 if (readLine
[i
] != daintree_magic_text
[i
]) return 0; /* not daintree format */
116 /* read second header line */
117 if (file_gets(readLine
, DAINTREE_MAX_LINE_SIZE
, wth
->fh
)==NULL
) {
118 *err
= file_error(wth
->fh
, err_info
);
119 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
123 if (readLine
[0] != COMMENT_LINE
) return 0; /* daintree files have a two line header */
125 /* set up the pointers to the handlers for this file type */
126 wth
->subtype_read
= daintree_sna_read
;
127 wth
->subtype_seek_read
= daintree_sna_seek_read
;
129 /* set up for file type */
130 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_DAINTREE_SNA
;
131 wth
->file_encap
= WTAP_ENCAP_IEEE802_15_4_NOFCS
;
132 wth
->tsprecision
= WTAP_FILE_TSPREC_USEC
;
133 wth
->snapshot_length
= 0; /* not available in header */
135 return 1; /* it's a Daintree file */
138 /* Read the capture file sequentially
139 * Wireshark scans the file with sequential reads during preview and initial display. */
141 daintree_sna_read(wtap
*wth
, int *err
, gchar
**err_info
, gint64
*data_offset
)
143 char readLine
[DAINTREE_MAX_LINE_SIZE
];
144 char readData
[READDATA_BUF_SIZE
];
146 *data_offset
= file_tell(wth
->fh
);
148 /* we've only seen file header lines starting with '#', but
149 * if others appear in the file, they are tossed */
151 if (file_gets(readLine
, DAINTREE_MAX_LINE_SIZE
, wth
->fh
) == NULL
) {
152 *err
= file_error(wth
->fh
, err_info
);
153 return FALSE
; /* all done */
155 } while (readLine
[0] == COMMENT_LINE
);
157 /* parse one line of capture data */
158 if (!daintree_sna_scan_header(&wth
->phdr
, readLine
, readData
,
162 /* process packet data */
163 return daintree_sna_process_hex_data(&wth
->phdr
, wth
->frame_buffer
,
164 readData
, err
, err_info
);
167 /* Read the capture file randomly
168 * Wireshark opens the capture file for random access when displaying user-selected packets */
170 daintree_sna_seek_read(wtap
*wth
, gint64 seek_off
, struct wtap_pkthdr
*phdr
,
171 Buffer
*buf
, int len _U_
, int *err
, gchar
**err_info
)
173 char readLine
[DAINTREE_MAX_LINE_SIZE
];
174 char readData
[READDATA_BUF_SIZE
];
176 if(file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
179 /* It appears only file header lines start with '#', but
180 * if we find any others, we toss them */
182 if (file_gets(readLine
, DAINTREE_MAX_LINE_SIZE
, wth
->random_fh
) == NULL
) {
183 *err
= file_error(wth
->random_fh
, err_info
);
184 return FALSE
; /* all done */
186 } while (readLine
[0] == COMMENT_LINE
);
188 /* parse one line of capture data */
189 if (!daintree_sna_scan_header(phdr
, readLine
, readData
, err
, err_info
))
192 /* process packet data */
193 return daintree_sna_process_hex_data(phdr
, buf
, readData
, err
,
197 /* Scan a header line and fill in a struct wtap_pkthdr */
199 daintree_sna_scan_header(struct wtap_pkthdr
*phdr
, char *readLine
,
200 char *readData
, int *err
, gchar
**err_info
)
205 phdr
->presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
207 if (sscanf(readLine
, "%*s %18" G_GINT64_MODIFIER
"u.%9d %9u %" READDATA_MAX_FIELD_SIZE
"s",
208 &seconds
, &useconds
, &phdr
->len
, readData
) != 4) {
209 *err
= WTAP_ERR_BAD_FILE
;
210 *err_info
= g_strdup("daintree_sna: invalid read record");
214 /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
215 if (phdr
->len
<= FCS_LENGTH
) {
216 *err
= WTAP_ERR_BAD_FILE
;
217 *err_info
= g_strdup_printf("daintree_sna: packet length <= %u bytes, no frame data present",
221 phdr
->len
-= FCS_LENGTH
;
223 phdr
->ts
.secs
= (time_t) seconds
;
224 phdr
->ts
.nsecs
= useconds
* 1000; /* convert mS to nS */
229 /* Convert packet data from ASCII hex string to binary in place,
230 * sanity-check its length against what we assume is the packet length field,
231 * and copy it into a Buffer */
233 daintree_sna_process_hex_data(struct wtap_pkthdr
*phdr
, Buffer
*buf
,
234 char *readData
, int *err
, gchar
**err_info
)
236 guchar
*str
= (guchar
*)readData
;
240 p
= str
; /* overlay source buffer */
242 /* convert hex string to guint8 */
244 /* most significant nibble */
245 if (!isxdigit((guchar
)*str
)) {
246 *err
= WTAP_ERR_BAD_FILE
;
247 *err_info
= g_strdup("daintree_sna: non-hex digit in hex data");
250 if(isdigit((guchar
)*str
)) {
251 *p
= (*str
- '0') << 4;
253 *p
= ((tolower(*str
) - 'a') + 10) << 4;
257 /* least significant nibble */
258 if (!isxdigit((guchar
)*str
)) {
259 *err
= WTAP_ERR_BAD_FILE
;
260 *err_info
= g_strdup("daintree_sna: non-hex digit in hex data");
263 if(isdigit((guchar
)*str
)) {
266 *p
+= (tolower(*str
) - 'a') + 10;
270 /* next byte in buffer */
275 /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
276 if (bytes
<= FCS_LENGTH
) {
277 *err
= WTAP_ERR_BAD_FILE
;
278 *err_info
= g_strdup_printf("daintree_sna: Only %u bytes of packet data",
283 if (bytes
> phdr
->len
) {
284 *err
= WTAP_ERR_BAD_FILE
;
285 *err_info
= g_strdup_printf("daintree_sna: capture length (%u) > packet length (%u)",
290 phdr
->caplen
= bytes
;
292 buffer_assure_space(buf
, bytes
);
293 memcpy(buffer_start_ptr(buf
), readData
, bytes
);