Have a pseudo-header for Ethernet packets, giving the size of the FCS -
[obnox/wireshark/wip.git] / wiretap / radcom.c
1 /* radcom.c
2  *
3  * $Id: radcom.c,v 1.42 2003/10/01 07:11:48 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, long *data_offset);
93 static gboolean radcom_seek_read(wtap *wth, long seek_off,
94         union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
95         int *err);
96 static int radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr,
97         int *err);
98 static gboolean radcom_read_rec_data(FILE_T fh, guchar *pd, int length,
99         int *err);
100
101 int radcom_open(wtap *wth, int *err)
102 {
103         int bytes_read;
104         guint8 r_magic[8], t_magic[11], search_encap[7];
105         struct frame_date start_date;
106         guint32 sec;
107         struct tm tm;
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, 1, 8, wth->fh);
112         if (bytes_read != 8) {
113                 *err = file_error(wth->fh);
114                 if (*err != 0)
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         wth->data_offset = 8;
132         errno = WTAP_ERR_CANT_READ;
133         bytes_read = file_read(t_magic, 1, 11, wth->fh);
134         if (bytes_read != 11) {
135                 *err = file_error(wth->fh);
136                 if (*err != 0)
137                         return -1;
138                 return 0;
139         }
140         while (memcmp(t_magic, active_time_magic, 11) != 0)
141         {
142             if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
143                 return -1;
144             wth->data_offset += 1;
145             errno = WTAP_ERR_CANT_READ;
146             bytes_read = file_read(t_magic, 1, 11, wth->fh);
147             if (bytes_read != 11) {
148                 *err = file_error(wth->fh);
149                 if (*err != 0)
150                     return -1;
151                 return 0;
152             }
153         }
154         if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
155         wth->data_offset -= 32;
156
157         /* Get capture start time */
158         errno = WTAP_ERR_CANT_READ;
159         bytes_read = file_read(&start_date, 1, sizeof(struct frame_date),
160                                wth->fh);
161         if (bytes_read != sizeof(struct frame_date)) {
162                 *err = file_error(wth->fh);
163                 if (*err != 0)
164                         return -1;
165                 return 0;
166         }
167         wth->data_offset += sizeof(struct frame_date);
168
169         /* This is a radcom file */
170         wth->file_type = WTAP_FILE_RADCOM;
171         wth->subtype_read = radcom_read;
172         wth->subtype_seek_read = radcom_seek_read;
173         wth->snapshot_length = 0; /* not available in header, only in frame */
174
175         tm.tm_year = pletohs(&start_date.year)-1900;
176         tm.tm_mon = start_date.month-1;
177         tm.tm_mday = start_date.day;
178         sec = pletohl(&start_date.sec);
179         tm.tm_hour = sec/3600;
180         tm.tm_min = (sec%3600)/60;
181         tm.tm_sec = sec%60;
182         tm.tm_isdst = -1;
183
184         if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
185                 return -1;
186         wth->data_offset += sizeof(struct frame_date);
187
188         errno = WTAP_ERR_CANT_READ;
189         bytes_read = file_read(search_encap, 1, 4, wth->fh);
190         if (bytes_read != 4) {
191                 goto read_error;
192         }
193         wth->data_offset += 4;
194         while (memcmp(encap_magic, search_encap, 4)) {
195                 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
196                         return -1;
197                 wth->data_offset -= 3;
198                 errno = WTAP_ERR_CANT_READ;
199                 bytes_read = file_read(search_encap, 1, 4, wth->fh);
200                 if (bytes_read != 4) {
201                         goto read_error;
202                 }
203                 wth->data_offset += 4;
204         }
205         if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
206                 return -1;
207         wth->data_offset += 12;
208         errno = WTAP_ERR_CANT_READ;
209         bytes_read = file_read(search_encap, 1, 4, wth->fh);
210         if (bytes_read != 4) {
211                 goto read_error;
212         }
213         wth->data_offset += 4;
214         if (memcmp(search_encap, "LAPB", 4) == 0)
215                 wth->file_encap = WTAP_ENCAP_LAPB;
216         else if (memcmp(search_encap, "Ethe", 4) == 0)
217                 wth->file_encap = WTAP_ENCAP_ETHERNET;
218         else if (memcmp(search_encap, "ATM/", 4) == 0)
219                 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
220         else {
221                 g_message("pcap: network type \"%.4s\" unknown", search_encap);
222                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
223                 return -1;
224         }
225
226         /*bytes_read = file_read(&next_date, 1, sizeof(struct frame_date), wth->fh);
227         errno = WTAP_ERR_CANT_READ;
228         if (bytes_read != sizeof(struct frame_date)) {
229                 goto read_error;
230         }
231
232         while (memcmp(&start_date, &next_date, 4)) {
233                 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
234                         return -1;
235                 errno = WTAP_ERR_CANT_READ;
236                 bytes_read = file_read(&next_date, 1, sizeof(struct frame_date),
237                                    wth->fh);
238                 if (bytes_read != sizeof(struct frame_date)) {
239                         goto read_error;
240                 }
241         }*/
242
243         if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
244                 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
245                         return -1;
246                 wth->data_offset += 294;
247         } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
248                 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
249                         return -1;
250                 wth->data_offset += 297;
251         } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
252                 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
253                         return -1;
254                 wth->data_offset += 504;
255         }
256
257         return 1;
258
259 read_error:
260         *err = file_error(wth->fh);
261         if (*err != 0)
262                 return -1;
263         return 0;
264 }
265
266 /* Read the next packet */
267 static gboolean radcom_read(wtap *wth, int *err, long *data_offset)
268 {
269         int     ret;
270         struct radcomrec_hdr hdr;
271         guint16 data_length, real_length, length;
272         guint32 sec;
273         int     bytes_read;
274         struct tm tm;
275         char    phdr[8];
276         char    fcs[2];
277
278         /* Read record header. */
279         *data_offset = wth->data_offset;
280         ret = radcom_read_rec_header(wth->fh, &hdr, err);
281         if (ret <= 0) {
282                 /* Read error or EOF */
283                 return FALSE;
284         }
285         wth->data_offset += sizeof hdr;
286         data_length = pletohs(&hdr.data_length);
287         if (data_length == 0) {
288                 /*
289                  * The last record appears to have 0 in its "data_length"
290                  * field, but non-zero values in other fields, so we
291                  * check for that and treat it as an EOF indication.
292                  */
293                 return FALSE;
294         }
295         length = pletohs(&hdr.length);
296         real_length = pletohs(&hdr.real_length);
297
298         if (wth->file_encap == WTAP_ENCAP_LAPB) {
299                 length -= 2; /* FCS */
300                 real_length -= 2;
301         }
302
303         wth->phdr.len = real_length;
304         wth->phdr.caplen = length;
305
306         tm.tm_year = pletohs(&hdr.date.year)-1900;
307         tm.tm_mon = (hdr.date.month&0x0f)-1;
308         tm.tm_mday = hdr.date.day;
309         sec = pletohl(&hdr.date.sec);
310         tm.tm_hour = sec/3600;
311         tm.tm_min = (sec%3600)/60;
312         tm.tm_sec = sec%60;
313         tm.tm_isdst = -1;
314         wth->phdr.ts.tv_sec = mktime(&tm);
315         wth->phdr.ts.tv_usec = pletohl(&hdr.date.usec);
316
317         switch (wth->file_encap) {
318
319         case WTAP_ENCAP_ETHERNET:
320                 /* XXX - is there an FCS? */
321                 wth->pseudo_header.eth.fcs_len = -1;
322                 break;
323
324         case WTAP_ENCAP_LAPB:
325                 wth->pseudo_header.x25.flags = (hdr.dce & 0x1) ?
326                     0x00 : FROM_DCE;
327                 break;
328
329         case WTAP_ENCAP_ATM_RFC1483:
330                 /*
331                  * XXX - is this stuff a pseudo-header?
332                  * The direction appears to be in the "hdr.dce" field.
333                  */
334                 if (!radcom_read_rec_data(wth->fh, phdr, sizeof phdr, err))
335                         return FALSE;   /* Read error */
336                 wth->data_offset += 8;
337                 length -= 8;
338                 wth->phdr.len -= 8;
339                 wth->phdr.caplen -= 8;
340                 break;
341         }
342
343         /*
344          * Read the packet data.
345          */
346         buffer_assure_space(wth->frame_buffer, length);
347         if (!radcom_read_rec_data(wth->fh,
348             buffer_start_ptr(wth->frame_buffer), length, err))
349                 return FALSE;   /* Read error */
350         wth->data_offset += length;
351
352         wth->phdr.pkt_encap = wth->file_encap;
353
354         if (wth->file_encap == WTAP_ENCAP_LAPB) {
355                 /* Read the FCS.
356                    XXX - should we have some way of indicating the
357                    presence and size of an FCS to our caller?
358                    That'd let us handle other file types as well. */
359                 errno = WTAP_ERR_CANT_READ;
360                 bytes_read = file_read(&fcs, 1, sizeof fcs, wth->fh);
361                 if (bytes_read != sizeof fcs) {
362                         *err = file_error(wth->fh);
363                         if (*err == 0)
364                                 *err = WTAP_ERR_SHORT_READ;
365                         return FALSE;
366                 }
367                 wth->data_offset += sizeof fcs;
368         }
369
370         return TRUE;
371 }
372
373 static gboolean
374 radcom_seek_read(wtap *wth, long seek_off,
375     union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err)
376 {
377         int     ret;
378         struct radcomrec_hdr hdr;
379         char    phdr[8];
380
381         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
382                 return FALSE;
383
384         /* Read record header. */
385         ret = radcom_read_rec_header(wth->random_fh, &hdr, err);
386         if (ret <= 0) {
387                 /* Read error or EOF */
388                 if (ret == 0) {
389                         /* EOF means "short read" in random-access mode */
390                         *err = WTAP_ERR_SHORT_READ;
391                 }
392                 return FALSE;
393         }
394
395         switch (wth->file_encap) {
396
397         case WTAP_ENCAP_ETHERNET:
398                 /* XXX - is there an FCS? */
399                 pseudo_header->eth.fcs_len = -1;
400                 break;
401
402         case WTAP_ENCAP_LAPB:
403                 pseudo_header->x25.flags = (hdr.dce & 0x1) ? 0x00 : FROM_DCE;
404                 break;
405
406         case WTAP_ENCAP_ATM_RFC1483:
407                 /*
408                  * XXX - is this stuff a pseudo-header?
409                  * The direction appears to be in the "hdr.dce" field.
410                  */
411                 if (!radcom_read_rec_data(wth->random_fh, phdr, sizeof phdr,
412                     err))
413                         return FALSE;   /* Read error */
414                 break;
415         }
416
417         /*
418          * Read the packet data.
419          */
420         return radcom_read_rec_data(wth->random_fh, pd, length, err);
421 }
422
423 static int
424 radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr, int *err)
425 {
426         int     bytes_read;
427
428         errno = WTAP_ERR_CANT_READ;
429         bytes_read = file_read(hdr, 1, sizeof *hdr, fh);
430         if (bytes_read != sizeof *hdr) {
431                 *err = file_error(fh);
432                 if (*err != 0)
433                         return -1;
434                 if (bytes_read != 0) {
435                         *err = WTAP_ERR_SHORT_READ;
436                         return -1;
437                 }
438                 return 0;
439         }
440         return 1;
441 }
442
443 static gboolean
444 radcom_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
445 {
446         int     bytes_read;
447
448         errno = WTAP_ERR_CANT_READ;
449         bytes_read = file_read(pd, 1, length, fh);
450
451         if (bytes_read != length) {
452                 *err = file_error(fh);
453                 if (*err == 0)
454                         *err = WTAP_ERR_SHORT_READ;
455                 return FALSE;
456         }
457         return TRUE;
458 }