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