Remove write capabilities from wtap_optionblocks.
[metze/wireshark/wip.git] / wiretap / daintree-sna.c
1 /* daintree_sna.c
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>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
13  *
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.
18  *
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.
23  *
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,
27  * USA.
28  */
29
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.
35  */
36
37 /* Example capture file:
38
39 #Format=4
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
44
45 */
46
47 #include "config.h"
48
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <string.h>
52
53 #include "wtap-int.h"
54 #include "file_wrappers.h"
55 #include "daintree-sna.h"
56
57 typedef struct daintree_sna_header {
58         guint32 len;
59         guint64 ts;
60 } daintree_sna_header_t;
61
62 #define DAINTREE_SNA_HEADER_SIZE 2
63 #define FCS_LENGTH 2
64
65 static const char daintree_magic_text[] =
66 { '#', 'F', 'o', 'r', 'm', 'a', 't', '=' };
67
68 #define DAINTREE_MAGIC_TEXT_SIZE (sizeof daintree_magic_text)
69 #define DAINTREE_MAX_LINE_SIZE 512
70 #define READDATA_BUF_SIZE (DAINTREE_MAX_LINE_SIZE/2)
71 #define READDATA_MAX_FIELD_SIZE "255"  /* DAINTREE_MAX_LINE_SIZE/2 -1 */
72
73 #define COMMENT_LINE daintree_magic_text[0]
74
75 static gboolean daintree_sna_read(wtap *wth, int *err, gchar **err_info,
76         gint64 *data_offset);
77
78 static gboolean daintree_sna_seek_read(wtap *wth, gint64 seek_off,
79         struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
80
81 static gboolean daintree_sna_read_packet(FILE_T fh, struct wtap_pkthdr *phdr,
82         Buffer *buf, int *err, gchar **err_info);
83
84 /* Open a file and determine if it's a Daintree file */
85 wtap_open_return_val daintree_sna_open(wtap *wth, int *err, gchar **err_info)
86 {
87         char readLine[DAINTREE_MAX_LINE_SIZE];
88
89         /* get first line of file header */
90         if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, wth->fh)==NULL) {
91                 *err = file_error(wth->fh, err_info);
92                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
93                         return WTAP_OPEN_ERROR;
94                 return WTAP_OPEN_NOT_MINE;
95         }
96
97         /* check magic text */
98         if (memcmp(readLine, daintree_magic_text, DAINTREE_MAGIC_TEXT_SIZE) != 0)
99                 return WTAP_OPEN_NOT_MINE; /* not daintree format */
100
101         /* read second header line */
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)
105                         return WTAP_OPEN_ERROR;
106                 return WTAP_OPEN_NOT_MINE;
107         }
108         if (readLine[0] != COMMENT_LINE)
109                 return WTAP_OPEN_NOT_MINE; /* daintree files have a two line header */
110
111         /* set up the pointers to the handlers for this file type */
112         wth->subtype_read = daintree_sna_read;
113         wth->subtype_seek_read = daintree_sna_seek_read;
114
115         /* set up for file type */
116         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_DAINTREE_SNA;
117         wth->file_encap = WTAP_ENCAP_IEEE802_15_4_NOFCS;
118         wth->file_tsprec = WTAP_TSPREC_USEC;
119         wth->snapshot_length = 0; /* not available in header */
120
121         return WTAP_OPEN_MINE; /* it's a Daintree file */
122 }
123
124 /* Read the capture file sequentially
125  * Wireshark scans the file with sequential reads during preview and initial display. */
126 static gboolean
127 daintree_sna_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
128 {
129         *data_offset = file_tell(wth->fh);
130
131         /* parse that line and the following packet data */
132         return daintree_sna_read_packet(wth->fh, &wth->phdr,
133             wth->frame_buffer, err, err_info);
134 }
135
136 /* Read the capture file randomly
137  * Wireshark opens the capture file for random access when displaying user-selected packets */
138 static gboolean
139 daintree_sna_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
140         Buffer *buf, int *err, gchar **err_info)
141 {
142         if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
143                 return FALSE;
144
145         /* parse that line and the following packet data */
146         return daintree_sna_read_packet(wth->random_fh, phdr, buf, err,
147             err_info);
148 }
149
150 /* Read a header line, scan it, and fill in a struct wtap_pkthdr.
151  * Then convert packet data from ASCII hex string to binary in place,
152  * sanity-check its length against what we assume is the packet length field,
153  * and copy it into a Buffer. */
154 static gboolean
155 daintree_sna_read_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
156     int *err, gchar **err_info)
157 {
158         guint64 seconds;
159         int useconds;
160         char readLine[DAINTREE_MAX_LINE_SIZE];
161         char readData[READDATA_BUF_SIZE];
162         guchar *str = (guchar *)readData;
163         guint bytes;
164         guint8 *p;
165
166         /* we've only seen file header lines starting with '#', but
167          * if others appear in the file, they are tossed */
168         do {
169                 if (file_gets(readLine, DAINTREE_MAX_LINE_SIZE, fh) == NULL) {
170                         *err = file_error(fh, err_info);
171                         return FALSE; /* all done */
172                 }
173         } while (readLine[0] == COMMENT_LINE);
174
175         phdr->rec_type = REC_TYPE_PACKET;
176         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
177
178         if (sscanf(readLine, "%*s %18" G_GINT64_MODIFIER "u.%9d %9u %" READDATA_MAX_FIELD_SIZE "s",
179             &seconds, &useconds, &phdr->len, readData) != 4) {
180                 *err = WTAP_ERR_BAD_FILE;
181                 *err_info = g_strdup("daintree_sna: invalid read record");
182                 return FALSE;
183         }
184
185         /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
186         if (phdr->len <= FCS_LENGTH) {
187                 *err = WTAP_ERR_BAD_FILE;
188                 *err_info = g_strdup_printf("daintree_sna: packet length <= %u bytes, no frame data present",
189                     FCS_LENGTH);
190                 return FALSE;
191         }
192         phdr->len -= FCS_LENGTH;
193
194         phdr->ts.secs = (time_t) seconds;
195         phdr->ts.nsecs = useconds * 1000; /* convert mS to nS */
196
197         /*
198          * READDATA_BUF_SIZE is < WTAP_MAX_PACKET_SIZE, and is the maximum
199          * number of bytes of packet data we can generate, so we don't
200          * need to check the packet length.
201          */
202         p = str; /* overlay source buffer */
203         bytes = 0;
204         /* convert hex string to guint8 */
205         while(*str) {
206                 /* most significant nibble */
207                 if (!g_ascii_isxdigit(*str)) {
208                         *err = WTAP_ERR_BAD_FILE;
209                         *err_info = g_strdup("daintree_sna: non-hex digit in hex data");
210                         return FALSE;
211                 }
212                 if(g_ascii_isdigit(*str)) {
213                         *p = (*str - '0') << 4;
214                 } else {
215                         *p = ((g_ascii_tolower(*str) - 'a') + 10) << 4;
216                 }
217                 str++;
218
219                 /* least significant nibble */
220                 if (!g_ascii_isxdigit(*str)) {
221                         *err = WTAP_ERR_BAD_FILE;
222                         *err_info = g_strdup("daintree_sna: non-hex digit in hex data");
223                         return FALSE;
224                 }
225                 if(g_ascii_isdigit(*str)) {
226                         *p += *str - '0';
227                 } else {
228                         *p += (g_ascii_tolower(*str) - 'a') + 10;
229                 }
230                 str++;
231
232                 /* next byte in buffer */
233                 p++;
234                 bytes++;
235         }
236
237         /* Daintree doesn't store the FCS, but pads end of packet with 0xffff, which we toss */
238         if (bytes <= FCS_LENGTH) {
239                 *err = WTAP_ERR_BAD_FILE;
240                 *err_info = g_strdup_printf("daintree_sna: Only %u bytes of packet data",
241                     bytes);
242                 return FALSE;
243         }
244         bytes -= FCS_LENGTH;
245         if (bytes > phdr->len) {
246                 *err = WTAP_ERR_BAD_FILE;
247                 *err_info = g_strdup_printf("daintree_sna: capture length (%u) > packet length (%u)",
248                     bytes, phdr->len);
249                 return FALSE;
250         }
251
252         phdr->caplen = bytes;
253
254         ws_buffer_assure_space(buf, bytes);
255         memcpy(ws_buffer_start_ptr(buf), readData, bytes);
256         return TRUE;
257 }
258
259 /*
260  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
261  *
262  * Local variables:
263  * c-basic-offset: 8
264  * tab-width: 8
265  * indent-tabs-mode: t
266  * End:
267  *
268  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
269  * :indentSize=8:tabSize=8:noTabs=false:
270  */