- some radcom files seem to have a different magic key than the one we
[obnox/wireshark/wip.git] / wiretap / radcom.c
1 /* radcom.c
2  *
3  * $Id: radcom.c,v 1.40 2002/12/17 21:53:57 oabad Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include "wtap-int.h"
31 #include "file_wrappers.h"
32 #include "buffer.h"
33 #include "radcom.h"
34
35 struct frame_date {
36         guint16 year;
37         guint8  month;
38         guint8  day;
39         guint32 sec;            /* seconds since midnight */
40         guint32 usec;
41 };
42
43 struct unaligned_frame_date {
44         char    year[2];
45         char    month;
46         char    day;
47         char    sec[4];         /* seconds since midnight */
48         char    usec[4];
49 };
50
51 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
52  * different in some captures */
53 static guint8 radcom_magic[8] = {
54         0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
55 };
56
57 static guint8 encap_magic[4] = {
58     0x00, 0x42, 0x43, 0x09
59 };
60
61 static guint8 active_time_magic[11] = {
62         0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65
63 };
64
65 /* RADCOM record header - followed by frame data (perhaps including FCS).
66    The first two bytes of "xxz" appear to equal "length", as do the
67    second two bytes; if a RADCOM box can be told not to save all of
68    the captured packet, might one or the other of those be the
69    captured length of the packet? */
70 struct radcomrec_hdr {
71         char    xxx[4];         /* unknown */
72         char    length[2];      /* packet length */
73         char    xxy[5];         /* unknown */
74         struct unaligned_frame_date date; /* date/time stamp of packet */
75         char    xxz[6];         /* unknown */
76         char    dce;            /* DCE/DTE flag (and other flags?) */
77         char    xxw[9];         /* unknown */
78 };
79
80 static gboolean radcom_read(wtap *wth, int *err, long *data_offset);
81 static gboolean radcom_seek_read(wtap *wth, long seek_off,
82         union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
83         int *err);
84 static int radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr,
85         int *err);
86 static gboolean radcom_read_rec_data(FILE_T fh, guchar *pd, int length,
87         int *err);
88
89 int radcom_open(wtap *wth, int *err)
90 {
91         int bytes_read;
92         guint8 r_magic[8], t_magic[11], search_encap[7];
93         struct frame_date start_date;
94         guint32 sec;
95         struct tm tm;
96
97         /* Read in the string that should be at the start of a RADCOM file */
98         errno = WTAP_ERR_CANT_READ;
99         bytes_read = file_read(r_magic, 1, 8, wth->fh);
100         if (bytes_read != 8) {
101                 *err = file_error(wth->fh);
102                 if (*err != 0)
103                         return -1;
104                 return 0;
105         }
106
107         /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
108          * captures. We force them to our standard value so that the test
109          * succeeds (until we find if they have a special meaning, perhaps a
110          * version number ?) */
111         r_magic[1] = 0xD2;
112         r_magic[2] = 0x00;
113         if (memcmp(r_magic, radcom_magic, 8) != 0) {
114                 return 0;
115         }
116
117         /* Look for the "Active Time" string. The "frame_date" structure should
118          * be located 32 bytes before the beginning of this string */
119         wth->data_offset = 8;
120         errno = WTAP_ERR_CANT_READ;
121         bytes_read = file_read(t_magic, 1, 11, wth->fh);
122         if (bytes_read != 11) {
123                 *err = file_error(wth->fh);
124                 if (*err != 0)
125                         return -1;
126                 return 0;
127         }
128         while (memcmp(t_magic, active_time_magic, 11) != 0)
129         {
130             if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
131                 return -1;
132             wth->data_offset += 1;
133             errno = WTAP_ERR_CANT_READ;
134             bytes_read = file_read(t_magic, 1, 11, wth->fh);
135             if (bytes_read != 11) {
136                 *err = file_error(wth->fh);
137                 if (*err != 0)
138                     return -1;
139                 return 0;
140             }
141         }
142         if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
143         wth->data_offset -= 32;
144
145         /* Get capture start time */
146         errno = WTAP_ERR_CANT_READ;
147         bytes_read = file_read(&start_date, 1, sizeof(struct frame_date),
148                                wth->fh);
149         if (bytes_read != sizeof(struct frame_date)) {
150                 *err = file_error(wth->fh);
151                 if (*err != 0)
152                         return -1;
153                 return 0;
154         }
155         wth->data_offset += sizeof(struct frame_date);
156
157         /* This is a radcom file */
158         wth->file_type = WTAP_FILE_RADCOM;
159         wth->subtype_read = radcom_read;
160         wth->subtype_seek_read = radcom_seek_read;
161         wth->snapshot_length = 0; /* not available in header, only in frame */
162
163         tm.tm_year = pletohs(&start_date.year)-1900;
164         tm.tm_mon = start_date.month-1;
165         tm.tm_mday = start_date.day;
166         sec = pletohl(&start_date.sec);
167         tm.tm_hour = sec/3600;
168         tm.tm_min = (sec%3600)/60;
169         tm.tm_sec = sec%60;
170         tm.tm_isdst = -1;
171
172         if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
173                 return -1;
174         wth->data_offset += sizeof(struct frame_date);
175
176         errno = WTAP_ERR_CANT_READ;
177         bytes_read = file_read(search_encap, 1, 4, wth->fh);
178         if (bytes_read != 4) {
179                 goto read_error;
180         }
181         wth->data_offset += 4;
182         while (memcmp(encap_magic, search_encap, 4)) {
183                 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
184                         return -1;
185                 wth->data_offset -= 3;
186                 errno = WTAP_ERR_CANT_READ;
187                 bytes_read = file_read(search_encap, 1, 4, wth->fh);
188                 if (bytes_read != 4) {
189                         goto read_error;
190                 }
191                 wth->data_offset += 4;
192         }
193         if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
194                 return -1;
195         wth->data_offset += 12;
196         errno = WTAP_ERR_CANT_READ;
197         bytes_read = file_read(search_encap, 1, 4, wth->fh);
198         if (bytes_read != 4) {
199                 goto read_error;
200         }
201         wth->data_offset += 4;
202         if (!memcmp(search_encap, "LAPB", 4))
203                 wth->file_encap = WTAP_ENCAP_LAPB;
204         else if (!memcmp(search_encap, "Ethe", 4))
205                 wth->file_encap = WTAP_ENCAP_ETHERNET;
206         else {
207                 g_message("pcap: network type \"%.4s\" unknown", search_encap);
208                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
209                 return -1;
210         }
211
212         /*bytes_read = file_read(&next_date, 1, sizeof(struct frame_date), wth->fh);
213         errno = WTAP_ERR_CANT_READ;
214         if (bytes_read != sizeof(struct frame_date)) {
215                 goto read_error;
216         }
217
218         while (memcmp(&start_date, &next_date, 4)) {
219                 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
220                         return -1;
221                 errno = WTAP_ERR_CANT_READ;
222                 bytes_read = file_read(&next_date, 1, sizeof(struct frame_date),
223                                    wth->fh);
224                 if (bytes_read != sizeof(struct frame_date)) {
225                         goto read_error;
226                 }
227         }*/
228
229         if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
230                 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
231                         return -1;
232                 wth->data_offset += 294;
233         } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
234                 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
235                         return -1;
236                 wth->data_offset += 297;
237         }
238
239         return 1;
240
241 read_error:
242         *err = file_error(wth->fh);
243         if (*err != 0)
244                 return -1;
245         return 0;
246 }
247
248 /* Read the next packet */
249 static gboolean radcom_read(wtap *wth, int *err, long *data_offset)
250 {
251         int     ret;
252         struct radcomrec_hdr hdr;
253         guint16 length;
254         guint32 sec;
255         int     bytes_read;
256         struct tm tm;
257         char    fcs[2];
258
259         /* Read record header. */
260         *data_offset = wth->data_offset;
261         ret = radcom_read_rec_header(wth->fh, &hdr, err);
262         if (ret <= 0) {
263                 /* Read error or EOF */
264                 return FALSE;
265         }
266         wth->data_offset += sizeof hdr;
267         length = pletohs(&hdr.length);
268         if (length == 0) return FALSE;
269
270         if (wth->file_encap == WTAP_ENCAP_LAPB)
271                 length -= 2; /* FCS */
272
273         wth->phdr.len = length;
274         wth->phdr.caplen = length;
275
276         tm.tm_year = pletohs(&hdr.date.year)-1900;
277         tm.tm_mon = hdr.date.month-1;
278         tm.tm_mday = hdr.date.day;
279         sec = pletohl(&hdr.date.sec);
280         tm.tm_hour = sec/3600;
281         tm.tm_min = (sec%3600)/60;
282         tm.tm_sec = sec%60;
283         tm.tm_isdst = -1;
284         wth->phdr.ts.tv_sec = mktime(&tm);
285         wth->phdr.ts.tv_usec = pletohl(&hdr.date.usec);
286         wth->pseudo_header.x25.flags = (hdr.dce & 0x1) ? 0x00 : FROM_DCE;
287
288         /*
289          * Read the packet data.
290          */
291         buffer_assure_space(wth->frame_buffer, length);
292         if (!radcom_read_rec_data(wth->fh,
293             buffer_start_ptr(wth->frame_buffer), length, err))
294                 return FALSE;   /* Read error */
295         wth->data_offset += length;
296
297         wth->phdr.pkt_encap = wth->file_encap;
298
299         if (wth->file_encap == WTAP_ENCAP_LAPB) {
300                 /* Read the FCS.
301                    XXX - should we put it in the pseudo-header? */
302                 errno = WTAP_ERR_CANT_READ;
303                 bytes_read = file_read(&fcs, 1, sizeof fcs, wth->fh);
304                 if (bytes_read != sizeof fcs) {
305                         *err = file_error(wth->fh);
306                         if (*err == 0)
307                                 *err = WTAP_ERR_SHORT_READ;
308                         return FALSE;
309                 }
310                 wth->data_offset += sizeof fcs;
311         }
312
313         return TRUE;
314 }
315
316 static gboolean
317 radcom_seek_read(wtap *wth, long seek_off,
318     union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err)
319 {
320         int     ret;
321         struct radcomrec_hdr hdr;
322
323         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
324                 return FALSE;
325
326         /* Read record header. */
327         ret = radcom_read_rec_header(wth->random_fh, &hdr, err);
328         if (ret <= 0) {
329                 /* Read error or EOF */
330                 if (ret == 0) {
331                         /* EOF means "short read" in random-access mode */
332                         *err = WTAP_ERR_SHORT_READ;
333                 }
334                 return FALSE;
335         }
336
337         pseudo_header->x25.flags = (hdr.dce & 0x1) ? 0x00 : FROM_DCE;
338
339         /*
340          * Read the packet data.
341          */
342         return radcom_read_rec_data(wth->random_fh, pd, length, err);
343 }
344
345 static int
346 radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr, int *err)
347 {
348         int     bytes_read;
349
350         errno = WTAP_ERR_CANT_READ;
351         bytes_read = file_read(hdr, 1, sizeof *hdr, fh);
352         if (bytes_read != sizeof *hdr) {
353                 *err = file_error(fh);
354                 if (*err != 0)
355                         return -1;
356                 if (bytes_read != 0) {
357                         *err = WTAP_ERR_SHORT_READ;
358                         return -1;
359                 }
360                 return 0;
361         }
362         return 1;
363 }
364
365 static gboolean
366 radcom_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
367 {
368         int     bytes_read;
369
370         errno = WTAP_ERR_CANT_READ;
371         bytes_read = file_read(pd, 1, length, fh);
372
373         if (bytes_read != length) {
374                 *err = file_error(fh);
375                 if (*err == 0)
376                         *err = WTAP_ERR_SHORT_READ;
377                 return FALSE;
378         }
379         return TRUE;
380 }