Another "this is < WTAP_MAX_PACKET_SIZE so no checks are needed" note.
[metze/wireshark/wip.git] / wiretap / radcom.c
1 /* radcom.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #include <errno.h>
24 #include <string.h>
25 #include "wtap-int.h"
26 #include "file_wrappers.h"
27 #include "radcom.h"
28
29 struct frame_date {
30         guint16 year;
31         guint8  month;
32         guint8  day;
33         guint32 sec;            /* seconds since midnight */
34         guint32 usec;
35 };
36
37 struct unaligned_frame_date {
38         char    year[2];
39         char    month;
40         char    day;
41         char    sec[4];         /* seconds since midnight */
42         char    usec[4];
43 };
44
45 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
46  * different in some captures */
47 static const guint8 radcom_magic[8] = {
48         0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
49 };
50
51 static const guint8 encap_magic[4] = {
52         0x00, 0x42, 0x43, 0x09
53 };
54
55 static const guint8 active_time_magic[11] = {
56         'A', 'c', 't', 'i', 'v', 'e', ' ', 'T', 'i', 'm', 'e'
57 };
58
59 /* RADCOM record header - followed by frame data (perhaps including FCS).
60
61    "data_length" appears to be the length of packet data following
62    the record header.  It's 0 in the last record.
63
64    "length" appears to be the amount of captured packet data, and
65    "real_length" might be the actual length of the frame on the wire -
66    in some captures, it's the same as "length", and, in others,
67    it's greater than "length".  In the last record, however, those
68    may have bogus values (or is that some kind of trailer record?).
69
70    "xxx" appears to be all-zero in all but the last record in one
71    capture; if so, perhaps this indicates that the last record is,
72    in fact, a trailer of some sort, and some field in the header
73    is a record type. */
74 struct radcomrec_hdr {
75         char    xxx[4];         /* unknown */
76         char    data_length[2]; /* packet length? */
77         char    xxy[5];         /* unknown */
78         struct unaligned_frame_date date; /* date/time stamp of packet */
79         char    real_length[2]; /* actual length of packet */
80         char    length[2];      /* captured length of packet */
81         char    xxz[2];         /* unknown */
82         char    dce;            /* DCE/DTE flag (and other flags?) */
83         char    xxw[9];         /* unknown */
84 };
85
86 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
87         gint64 *data_offset);
88 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
89         struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
90 static gboolean radcom_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
91         Buffer *buf, int *err, gchar **err_info);
92
93 wtap_open_return_val radcom_open(wtap *wth, int *err, gchar **err_info)
94 {
95         guint8 r_magic[8], t_magic[11], search_encap[7];
96         struct frame_date start_date;
97 #if 0
98         guint32 sec;
99         struct tm tm;
100 #endif
101
102         /* Read in the string that should be at the start of a RADCOM file */
103         if (!wtap_read_bytes(wth->fh, r_magic, 8, err, err_info)) {
104                 if (*err != WTAP_ERR_SHORT_READ)
105                         return WTAP_OPEN_ERROR;
106                 return WTAP_OPEN_NOT_MINE;
107         }
108
109         /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
110          * captures. We force them to our standard value so that the test
111          * succeeds (until we find if they have a special meaning, perhaps a
112          * version number ?) */
113         r_magic[1] = 0xD2;
114         r_magic[2] = 0x00;
115         if (memcmp(r_magic, radcom_magic, 8) != 0) {
116                 return WTAP_OPEN_NOT_MINE;
117         }
118
119         /* Look for the "Active Time" string. The "frame_date" structure should
120          * be located 32 bytes before the beginning of this string */
121         if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
122                 if (*err != WTAP_ERR_SHORT_READ)
123                         return WTAP_OPEN_ERROR;
124                 return WTAP_OPEN_NOT_MINE;
125         }
126         while (memcmp(t_magic, active_time_magic, 11) != 0)
127         {
128                 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
129                         return WTAP_OPEN_ERROR;
130                 if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
131                         if (*err != WTAP_ERR_SHORT_READ)
132                                 return WTAP_OPEN_ERROR;
133                         return WTAP_OPEN_NOT_MINE;
134                 }
135         }
136         if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1)
137                 return WTAP_OPEN_ERROR;
138
139         /* Get capture start time */
140         if (!wtap_read_bytes(wth->fh, &start_date, sizeof(struct frame_date),
141             err, err_info)) {
142                 if (*err != WTAP_ERR_SHORT_READ)
143                         return WTAP_OPEN_ERROR;
144                 return WTAP_OPEN_NOT_MINE;
145         }
146
147         if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
148                 return WTAP_OPEN_ERROR;
149
150         for (;;) {
151                 if (!wtap_read_bytes(wth->fh, search_encap, 4,
152                     err, err_info)) {
153                         if (*err != WTAP_ERR_SHORT_READ)
154                                 return WTAP_OPEN_ERROR;
155                         return WTAP_OPEN_NOT_MINE;
156                 }
157
158                 if (memcmp(encap_magic, search_encap, 4) == 0)
159                         break;
160
161                 /*
162                  * OK, that's not it, go forward 1 byte - reading
163                  * the magic moved us forward 4 bytes, so seeking
164                  * backward 3 bytes moves forward 1 byte - and
165                  * try the 4 bytes at that offset.
166                  */
167                 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
168                         return WTAP_OPEN_ERROR;
169         }
170         if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
171                 return WTAP_OPEN_ERROR;
172         if (!wtap_read_bytes(wth->fh, search_encap, 4, err, err_info)) {
173                 if (*err != WTAP_ERR_SHORT_READ)
174                         return WTAP_OPEN_ERROR;
175                 return WTAP_OPEN_NOT_MINE;
176         }
177
178         /* This is a radcom file */
179         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_RADCOM;
180         wth->subtype_read = radcom_read;
181         wth->subtype_seek_read = radcom_seek_read;
182         wth->snapshot_length = 0; /* not available in header, only in frame */
183         wth->file_tsprec = WTAP_TSPREC_USEC;
184
185 #if 0
186         tm.tm_year = pletoh16(&start_date.year)-1900;
187         tm.tm_mon = start_date.month-1;
188         tm.tm_mday = start_date.day;
189         sec = pletoh32(&start_date.sec);
190         tm.tm_hour = sec/3600;
191         tm.tm_min = (sec%3600)/60;
192         tm.tm_sec = sec%60;
193         tm.tm_isdst = -1;
194 #endif
195
196         if (memcmp(search_encap, "LAPB", 4) == 0)
197                 wth->file_encap = WTAP_ENCAP_LAPB;
198         else if (memcmp(search_encap, "Ethe", 4) == 0)
199                 wth->file_encap = WTAP_ENCAP_ETHERNET;
200         else if (memcmp(search_encap, "ATM/", 4) == 0)
201                 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
202         else {
203                 *err = WTAP_ERR_UNSUPPORTED;
204                 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
205                 return WTAP_OPEN_ERROR;
206         }
207
208 #if 0
209         if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
210             err, err_info))
211                 return WTAP_OPEN_ERROR;
212
213         while (memcmp(&start_date, &next_date, 4)) {
214                 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
215                         return WTAP_OPEN_ERROR;
216                 if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
217                     err, err_info))
218                         return WTAP_OPEN_ERROR;
219         }
220 #endif
221
222         if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
223                 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
224                         return WTAP_OPEN_ERROR;
225         } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
226                 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
227                         return WTAP_OPEN_ERROR;
228         } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
229                 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
230                         return WTAP_OPEN_ERROR;
231         }
232
233         return WTAP_OPEN_MINE;
234 }
235
236 /* Read the next packet */
237 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
238                             gint64 *data_offset)
239 {
240         char    fcs[2];
241
242         *data_offset = file_tell(wth->fh);
243
244         /* Read record. */
245         if (!radcom_read_rec(wth, wth->fh, &wth->phdr, wth->frame_buffer,
246             err, err_info)) {
247                 /* Read error or EOF */
248                 return FALSE;
249         }
250
251         if (wth->file_encap == WTAP_ENCAP_LAPB) {
252                 /* Read the FCS.
253                    XXX - should we have some way of indicating the
254                    presence and size of an FCS to our caller?
255                    That'd let us handle other file types as well. */
256                 if (!wtap_read_bytes(wth->fh, &fcs, sizeof fcs, err, err_info))
257                         return FALSE;
258         }
259
260         return TRUE;
261 }
262
263 static gboolean
264 radcom_seek_read(wtap *wth, gint64 seek_off,
265                  struct wtap_pkthdr *phdr, Buffer *buf,
266                  int *err, gchar **err_info)
267 {
268         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
269                 return FALSE;
270
271         /* Read record. */
272         if (!radcom_read_rec(wth, wth->random_fh, phdr, buf, err,
273             err_info)) {
274                 /* Read error or EOF */
275                 if (*err == 0) {
276                         /* EOF means "short read" in random-access mode */
277                         *err = WTAP_ERR_SHORT_READ;
278                 }
279                 return FALSE;
280         }
281         return TRUE;
282 }
283
284 static gboolean
285 radcom_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
286                 int *err, gchar **err_info)
287 {
288         struct radcomrec_hdr hdr;
289         guint16 data_length, real_length, length;
290         guint32 sec;
291         struct tm tm;
292         guint8  atmhdr[8];
293
294         if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
295                 return FALSE;
296
297         data_length = pletoh16(&hdr.data_length);
298         if (data_length == 0) {
299                 /*
300                  * The last record appears to have 0 in its "data_length"
301                  * field, but non-zero values in other fields, so we
302                  * check for that and treat it as an EOF indication.
303                  */
304                 *err = 0;
305                 return FALSE;
306         }
307         length = pletoh16(&hdr.length);
308         real_length = pletoh16(&hdr.real_length);
309         /*
310          * The maximum value of length is 65535, which is less than
311          * WTAP_MAX_PACKET_SIZE will ever be, so we don't need to check
312          * it.
313          */
314
315         phdr->rec_type = REC_TYPE_PACKET;
316         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
317
318         tm.tm_year = pletoh16(&hdr.date.year)-1900;
319         tm.tm_mon = (hdr.date.month&0x0f)-1;
320         tm.tm_mday = hdr.date.day;
321         sec = pletoh32(&hdr.date.sec);
322         tm.tm_hour = sec/3600;
323         tm.tm_min = (sec%3600)/60;
324         tm.tm_sec = sec%60;
325         tm.tm_isdst = -1;
326         phdr->ts.secs = mktime(&tm);
327         phdr->ts.nsecs = pletoh32(&hdr.date.usec) * 1000;
328
329         switch (wth->file_encap) {
330
331         case WTAP_ENCAP_ETHERNET:
332                 /* XXX - is there an FCS? */
333                 phdr->pseudo_header.eth.fcs_len = -1;
334                 break;
335
336         case WTAP_ENCAP_LAPB:
337                 phdr->pseudo_header.x25.flags = (hdr.dce & 0x1) ?
338                     0x00 : FROM_DCE;
339                 length -= 2; /* FCS */
340                 real_length -= 2;
341                 break;
342
343         case WTAP_ENCAP_ATM_RFC1483:
344                 /*
345                  * XXX - is this stuff a pseudo-header?
346                  * The direction appears to be in the "hdr.dce" field.
347                  */
348                 if (!wtap_read_bytes(fh, atmhdr, sizeof atmhdr, err,
349                     err_info))
350                         return FALSE;   /* Read error */
351                 length -= 8;
352                 real_length -= 8;
353                 break;
354         }
355
356         phdr->len = real_length;
357         phdr->caplen = length;
358
359         /*
360          * Read the packet data.
361          */
362         if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
363                 return FALSE;   /* Read error */
364
365         return TRUE;
366 }
367
368 /*
369  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
370  *
371  * Local variables:
372  * c-basic-offset: 8
373  * tab-width: 8
374  * indent-tabs-mode: t
375  * End:
376  *
377  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
378  * :indentSize=8:tabSize=8:noTabs=false:
379  */