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