Do not call wtap_file_read_unknown_bytes() or
[metze/wireshark/wip.git] / wiretap / radcom.c
1 /* radcom.c
2  *
3  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #include <errno.h>
26 #include <string.h>
27 #include "wtap-int.h"
28 #include "file_wrappers.h"
29 #include "buffer.h"
30 #include "radcom.h"
31
32 struct frame_date {
33         guint16 year;
34         guint8  month;
35         guint8  day;
36         guint32 sec;            /* seconds since midnight */
37         guint32 usec;
38 };
39
40 struct unaligned_frame_date {
41         char    year[2];
42         char    month;
43         char    day;
44         char    sec[4];         /* seconds since midnight */
45         char    usec[4];
46 };
47
48 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
49  * different in some captures */
50 static const guint8 radcom_magic[8] = {
51         0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
52 };
53
54 static const guint8 encap_magic[4] = {
55         0x00, 0x42, 0x43, 0x09
56 };
57
58 static const guint8 active_time_magic[11] = {
59         0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65
60 };
61
62 /* RADCOM record header - followed by frame data (perhaps including FCS).
63
64    "data_length" appears to be the length of packet data following
65    the record header.  It's 0 in the last record.
66
67    "length" appears to be the amount of captured packet data, and
68    "real_length" might be the actual length of the frame on the wire -
69    in some captures, it's the same as "length", and, in others,
70    it's greater than "length".  In the last record, however, those
71    may have bogus values (or is that some kind of trailer record?).
72
73    "xxx" appears to be all-zero in all but the last record in one
74    capture; if so, perhaps this indicates that the last record is,
75    in fact, a trailer of some sort, and some field in the header
76    is a record type. */
77 struct radcomrec_hdr {
78         char    xxx[4];         /* unknown */
79         char    data_length[2]; /* packet length? */
80         char    xxy[5];         /* unknown */
81         struct unaligned_frame_date date; /* date/time stamp of packet */
82         char    real_length[2]; /* actual length of packet */
83         char    length[2];      /* captured length of packet */
84         char    xxz[2];         /* unknown */
85         char    dce;            /* DCE/DTE flag (and other flags?) */
86         char    xxw[9];         /* unknown */
87 };
88
89 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
90         gint64 *data_offset);
91 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
92         struct wtap_pkthdr *pkhdr, guint8 *pd, int length,
93         int *err, gchar **err_info);
94 static int radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr,
95         int *err, gchar **err_info);
96 static gboolean radcom_read_rec_data(FILE_T fh, guint8 *pd, int length,
97         int *err, gchar **err_info);
98
99 int radcom_open(wtap *wth, int *err, gchar **err_info)
100 {
101         int bytes_read;
102         guint8 r_magic[8], t_magic[11], search_encap[7];
103         struct frame_date start_date;
104 #if 0
105         guint32 sec;
106         struct tm tm;
107 #endif
108
109         /* Read in the string that should be at the start of a RADCOM file */
110         errno = WTAP_ERR_CANT_READ;
111         bytes_read = file_read(r_magic, 8, wth->fh);
112         if (bytes_read != 8) {
113                 *err = file_error(wth->fh, err_info);
114                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
115                         return -1;
116                 return 0;
117         }
118
119         /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
120          * captures. We force them to our standard value so that the test
121          * succeeds (until we find if they have a special meaning, perhaps a
122          * version number ?) */
123         r_magic[1] = 0xD2;
124         r_magic[2] = 0x00;
125         if (memcmp(r_magic, radcom_magic, 8) != 0) {
126                 return 0;
127         }
128
129         /* Look for the "Active Time" string. The "frame_date" structure should
130          * be located 32 bytes before the beginning of this string */
131         errno = WTAP_ERR_CANT_READ;
132         bytes_read = file_read(t_magic, 11, wth->fh);
133         if (bytes_read != 11) {
134                 *err = file_error(wth->fh, err_info);
135                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
136                         return -1;
137                 return 0;
138         }
139         while (memcmp(t_magic, active_time_magic, 11) != 0)
140         {
141                 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
142                         return -1;
143                 errno = WTAP_ERR_CANT_READ;
144                 bytes_read = file_read(t_magic, 11, wth->fh);
145                 if (bytes_read != 11) {
146                         *err = file_error(wth->fh, err_info);
147                         if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
148                                 return -1;
149                         return 0;
150                 }
151         }
152         if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
153
154         /* Get capture start time */
155         errno = WTAP_ERR_CANT_READ;
156         bytes_read = file_read(&start_date, sizeof(struct frame_date),
157                                wth->fh);
158         if (bytes_read != sizeof(struct frame_date)) {
159                 *err = file_error(wth->fh, err_info);
160                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
161                         return -1;
162                 return 0;
163         }
164
165         /* This is a radcom file */
166         wth->file_type = WTAP_FILE_RADCOM;
167         wth->subtype_read = radcom_read;
168         wth->subtype_seek_read = radcom_seek_read;
169         wth->snapshot_length = 0; /* not available in header, only in frame */
170         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
171
172 #if 0
173         tm.tm_year = pletohs(&start_date.year)-1900;
174         tm.tm_mon = start_date.month-1;
175         tm.tm_mday = start_date.day;
176         sec = pletohl(&start_date.sec);
177         tm.tm_hour = sec/3600;
178         tm.tm_min = (sec%3600)/60;
179         tm.tm_sec = sec%60;
180         tm.tm_isdst = -1;
181 #endif
182         if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
183                 return -1;
184
185         errno = WTAP_ERR_CANT_READ;
186         bytes_read = file_read(search_encap, 4, wth->fh);
187         if (bytes_read != 4) {
188                 goto read_error;
189         }
190         while (memcmp(encap_magic, search_encap, 4)) {
191                 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
192                         return -1;
193                 errno = WTAP_ERR_CANT_READ;
194                 bytes_read = file_read(search_encap, 4, wth->fh);
195                 if (bytes_read != 4) {
196                         goto read_error;
197                 }
198         }
199         if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
200                 return -1;
201         errno = WTAP_ERR_CANT_READ;
202         bytes_read = file_read(search_encap, 4, wth->fh);
203         if (bytes_read != 4) {
204                 goto read_error;
205         }
206         if (memcmp(search_encap, "LAPB", 4) == 0)
207                 wth->file_encap = WTAP_ENCAP_LAPB;
208         else if (memcmp(search_encap, "Ethe", 4) == 0)
209                 wth->file_encap = WTAP_ENCAP_ETHERNET;
210         else if (memcmp(search_encap, "ATM/", 4) == 0)
211                 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
212         else {
213                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
214                 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
215                 return -1;
216         }
217
218 #if 0
219         bytes_read = file_read(&next_date, sizeof(struct frame_date), wth->fh);
220         errno = WTAP_ERR_CANT_READ;
221         if (bytes_read != sizeof(struct frame_date)) {
222                 goto read_error;
223         }
224
225         while (memcmp(&start_date, &next_date, 4)) {
226                 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
227                         return -1;
228                 errno = WTAP_ERR_CANT_READ;
229                 bytes_read = file_read(&next_date, sizeof(struct frame_date),
230                                    wth->fh);
231                 if (bytes_read != sizeof(struct frame_date)) {
232                         goto read_error;
233                 }
234         }
235 #endif
236
237         if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
238                 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
239                         return -1;
240         } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
241                 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
242                         return -1;
243         } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
244                 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
245                         return -1;
246         }
247
248         return 1;
249
250 read_error:
251         *err = file_error(wth->fh, err_info);
252         if (*err != 0)
253                 return -1;
254         return 0;
255 }
256
257 /* Read the next packet */
258 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
259                             gint64 *data_offset)
260 {
261         int     ret;
262         struct radcomrec_hdr hdr;
263         guint16 data_length, real_length, length;
264         guint32 sec;
265         int     bytes_read;
266         struct tm tm;
267         guint8  phdr[8];
268         char    fcs[2];
269
270         /* Read record header. */
271         *data_offset = file_tell(wth->fh);
272         ret = radcom_read_rec_header(wth->fh, &hdr, err, err_info);
273         if (ret <= 0) {
274                 /* Read error or EOF */
275                 return FALSE;
276         }
277         data_length = pletohs(&hdr.data_length);
278         if (data_length == 0) {
279                 /*
280                  * The last record appears to have 0 in its "data_length"
281                  * field, but non-zero values in other fields, so we
282                  * check for that and treat it as an EOF indication.
283                  */
284                 *err = 0;
285                 return FALSE;
286         }
287         length = pletohs(&hdr.length);
288         real_length = pletohs(&hdr.real_length);
289
290         if (wth->file_encap == WTAP_ENCAP_LAPB) {
291                 length -= 2; /* FCS */
292                 real_length -= 2;
293         }
294
295         wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
296
297         wth->phdr.len = real_length;
298         wth->phdr.caplen = length;
299
300         tm.tm_year = pletohs(&hdr.date.year)-1900;
301         tm.tm_mon = (hdr.date.month&0x0f)-1;
302         tm.tm_mday = hdr.date.day;
303         sec = pletohl(&hdr.date.sec);
304         tm.tm_hour = sec/3600;
305         tm.tm_min = (sec%3600)/60;
306         tm.tm_sec = sec%60;
307         tm.tm_isdst = -1;
308         wth->phdr.ts.secs = mktime(&tm);
309         wth->phdr.ts.nsecs = pletohl(&hdr.date.usec) * 1000;
310
311         switch (wth->file_encap) {
312
313         case WTAP_ENCAP_ETHERNET:
314                 /* XXX - is there an FCS? */
315                 wth->phdr.pseudo_header.eth.fcs_len = -1;
316                 break;
317
318         case WTAP_ENCAP_LAPB:
319                 wth->phdr.pseudo_header.x25.flags = (hdr.dce & 0x1) ?
320                     0x00 : FROM_DCE;
321                 break;
322
323         case WTAP_ENCAP_ATM_RFC1483:
324                 /*
325                  * XXX - is this stuff a pseudo-header?
326                  * The direction appears to be in the "hdr.dce" field.
327                  */
328                 if (!radcom_read_rec_data(wth->fh, phdr, sizeof phdr, err,
329                     err_info))
330                         return FALSE;   /* Read error */
331                 length -= 8;
332                 wth->phdr.len -= 8;
333                 wth->phdr.caplen -= 8;
334                 break;
335         }
336
337         /*
338          * Read the packet data.
339          */
340         buffer_assure_space(wth->frame_buffer, length);
341         if (!radcom_read_rec_data(wth->fh,
342             buffer_start_ptr(wth->frame_buffer), length, err, err_info))
343                 return FALSE;   /* Read error */
344
345         if (wth->file_encap == WTAP_ENCAP_LAPB) {
346                 /* Read the FCS.
347                    XXX - should we have some way of indicating the
348                    presence and size of an FCS to our caller?
349                    That'd let us handle other file types as well. */
350                 errno = WTAP_ERR_CANT_READ;
351                 bytes_read = file_read(&fcs, sizeof fcs, wth->fh);
352                 if (bytes_read != sizeof fcs) {
353                         *err = file_error(wth->fh, err_info);
354                         if (*err == 0)
355                                 *err = WTAP_ERR_SHORT_READ;
356                         return FALSE;
357                 }
358         }
359
360         return TRUE;
361 }
362
363 static gboolean
364 radcom_seek_read(wtap *wth, gint64 seek_off,
365                  struct wtap_pkthdr *pkhdr, guint8 *pd, int length,
366                  int *err, gchar **err_info)
367 {
368         union wtap_pseudo_header *pseudo_header = &pkhdr->pseudo_header;
369         int     ret;
370         struct radcomrec_hdr hdr;
371         guint8  phdr[8];
372
373         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
374                 return FALSE;
375
376         /* Read record header. */
377         ret = radcom_read_rec_header(wth->random_fh, &hdr, err, err_info);
378         if (ret <= 0) {
379                 /* Read error or EOF */
380                 if (ret == 0) {
381                         /* EOF means "short read" in random-access mode */
382                         *err = WTAP_ERR_SHORT_READ;
383                 }
384                 return FALSE;
385         }
386
387         switch (wth->file_encap) {
388
389         case WTAP_ENCAP_ETHERNET:
390                 /* XXX - is there an FCS? */
391                 pseudo_header->eth.fcs_len = -1;
392                 break;
393
394         case WTAP_ENCAP_LAPB:
395                 pseudo_header->x25.flags = (hdr.dce & 0x1) ? 0x00 : FROM_DCE;
396                 break;
397
398         case WTAP_ENCAP_ATM_RFC1483:
399                 /*
400                  * XXX - is this stuff a pseudo-header?
401                  * The direction appears to be in the "hdr.dce" field.
402                  */
403                 if (!radcom_read_rec_data(wth->random_fh, phdr, sizeof phdr,
404                     err, err_info))
405                         return FALSE;   /* Read error */
406                 break;
407         }
408
409         /*
410          * Read the packet data.
411          */
412         return radcom_read_rec_data(wth->random_fh, pd, length, err, err_info);
413 }
414
415 static int
416 radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr, int *err,
417                        gchar **err_info)
418 {
419         int     bytes_read;
420
421         errno = WTAP_ERR_CANT_READ;
422         bytes_read = file_read(hdr, sizeof *hdr, fh);
423         if (bytes_read != sizeof *hdr) {
424                 *err = file_error(fh, err_info);
425                 if (*err != 0)
426                         return -1;
427                 if (bytes_read != 0) {
428                         *err = WTAP_ERR_SHORT_READ;
429                         return -1;
430                 }
431                 return 0;
432         }
433         return 1;
434 }
435
436 static gboolean
437 radcom_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
438                      gchar **err_info)
439 {
440         int     bytes_read;
441
442         errno = WTAP_ERR_CANT_READ;
443         bytes_read = file_read(pd, length, fh);
444
445         if (bytes_read != length) {
446                 *err = file_error(fh, err_info);
447                 if (*err == 0)
448                         *err = WTAP_ERR_SHORT_READ;
449                 return FALSE;
450         }
451         return TRUE;
452 }