6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
30 #include "file_wrappers.h"
38 guint32 sec; /* seconds since midnight */
42 struct unaligned_frame_date {
46 char sec[4]; /* seconds since midnight */
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
56 static const guint8 encap_magic[4] = {
57 0x00, 0x42, 0x43, 0x09
60 static const guint8 active_time_magic[11] = {
61 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65
64 /* RADCOM record header - followed by frame data (perhaps including FCS).
66 "data_length" appears to be the length of packet data following
67 the record header. It's 0 in the last record.
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?).
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
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 */
91 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
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);
101 int radcom_open(wtap *wth, int *err, gchar **err_info)
104 guint8 r_magic[8], t_magic[11], search_encap[7];
105 struct frame_date start_date;
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);
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 ?) */
127 if (memcmp(r_magic, radcom_magic, 8) != 0) {
131 /* Look for the "Active Time" string. The "frame_date" structure should
132 * be located 32 bytes before the beginning of this string */
133 errno = WTAP_ERR_CANT_READ;
134 bytes_read = file_read(t_magic, 11, wth->fh);
135 if (bytes_read != 11) {
136 *err = file_error(wth->fh, err_info);
141 while (memcmp(t_magic, active_time_magic, 11) != 0)
143 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
145 errno = WTAP_ERR_CANT_READ;
146 bytes_read = file_read(t_magic, 11, wth->fh);
147 if (bytes_read != 11) {
148 *err = file_error(wth->fh, err_info);
154 if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
156 /* Get capture start time */
157 errno = WTAP_ERR_CANT_READ;
158 bytes_read = file_read(&start_date, sizeof(struct frame_date),
160 if (bytes_read != sizeof(struct frame_date)) {
161 *err = file_error(wth->fh, err_info);
167 /* This is a radcom file */
168 wth->file_type = WTAP_FILE_RADCOM;
169 wth->subtype_read = radcom_read;
170 wth->subtype_seek_read = radcom_seek_read;
171 wth->snapshot_length = 0; /* not available in header, only in frame */
172 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
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;
184 if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
187 errno = WTAP_ERR_CANT_READ;
188 bytes_read = file_read(search_encap, 4, wth->fh);
189 if (bytes_read != 4) {
192 while (memcmp(encap_magic, search_encap, 4)) {
193 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
195 errno = WTAP_ERR_CANT_READ;
196 bytes_read = file_read(search_encap, 4, wth->fh);
197 if (bytes_read != 4) {
201 if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
203 errno = WTAP_ERR_CANT_READ;
204 bytes_read = file_read(search_encap, 4, wth->fh);
205 if (bytes_read != 4) {
208 if (memcmp(search_encap, "LAPB", 4) == 0)
209 wth->file_encap = WTAP_ENCAP_LAPB;
210 else if (memcmp(search_encap, "Ethe", 4) == 0)
211 wth->file_encap = WTAP_ENCAP_ETHERNET;
212 else if (memcmp(search_encap, "ATM/", 4) == 0)
213 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
215 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
216 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
221 bytes_read = file_read(&next_date, sizeof(struct frame_date), wth->fh);
222 errno = WTAP_ERR_CANT_READ;
223 if (bytes_read != sizeof(struct frame_date)) {
227 while (memcmp(&start_date, &next_date, 4)) {
228 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
230 errno = WTAP_ERR_CANT_READ;
231 bytes_read = file_read(&next_date, sizeof(struct frame_date),
233 if (bytes_read != sizeof(struct frame_date)) {
239 if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
240 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
242 } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
243 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
245 } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
246 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
253 *err = file_error(wth->fh, err_info);
259 /* Read the next packet */
260 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
264 struct radcomrec_hdr hdr;
265 guint16 data_length, real_length, length;
272 /* Read record header. */
273 *data_offset = file_tell(wth->fh);
274 ret = radcom_read_rec_header(wth->fh, &hdr, err, err_info);
276 /* Read error or EOF */
279 data_length = pletohs(&hdr.data_length);
280 if (data_length == 0) {
282 * The last record appears to have 0 in its "data_length"
283 * field, but non-zero values in other fields, so we
284 * check for that and treat it as an EOF indication.
289 length = pletohs(&hdr.length);
290 real_length = pletohs(&hdr.real_length);
292 if (wth->file_encap == WTAP_ENCAP_LAPB) {
293 length -= 2; /* FCS */
297 wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
299 wth->phdr.len = real_length;
300 wth->phdr.caplen = length;
302 tm.tm_year = pletohs(&hdr.date.year)-1900;
303 tm.tm_mon = (hdr.date.month&0x0f)-1;
304 tm.tm_mday = hdr.date.day;
305 sec = pletohl(&hdr.date.sec);
306 tm.tm_hour = sec/3600;
307 tm.tm_min = (sec%3600)/60;
310 wth->phdr.ts.secs = mktime(&tm);
311 wth->phdr.ts.nsecs = pletohl(&hdr.date.usec) * 1000;
313 switch (wth->file_encap) {
315 case WTAP_ENCAP_ETHERNET:
316 /* XXX - is there an FCS? */
317 wth->pseudo_header.eth.fcs_len = -1;
320 case WTAP_ENCAP_LAPB:
321 wth->pseudo_header.x25.flags = (hdr.dce & 0x1) ?
325 case WTAP_ENCAP_ATM_RFC1483:
327 * XXX - is this stuff a pseudo-header?
328 * The direction appears to be in the "hdr.dce" field.
330 if (!radcom_read_rec_data(wth->fh, phdr, sizeof phdr, err,
332 return FALSE; /* Read error */
335 wth->phdr.caplen -= 8;
340 * Read the packet data.
342 buffer_assure_space(wth->frame_buffer, length);
343 if (!radcom_read_rec_data(wth->fh,
344 buffer_start_ptr(wth->frame_buffer), length, err, err_info))
345 return FALSE; /* Read error */
347 if (wth->file_encap == WTAP_ENCAP_LAPB) {
349 XXX - should we have some way of indicating the
350 presence and size of an FCS to our caller?
351 That'd let us handle other file types as well. */
352 errno = WTAP_ERR_CANT_READ;
353 bytes_read = file_read(&fcs, sizeof fcs, wth->fh);
354 if (bytes_read != sizeof fcs) {
355 *err = file_error(wth->fh, err_info);
357 *err = WTAP_ERR_SHORT_READ;
366 radcom_seek_read(wtap *wth, gint64 seek_off,
367 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
368 int *err, gchar **err_info)
371 struct radcomrec_hdr hdr;
374 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
377 /* Read record header. */
378 ret = radcom_read_rec_header(wth->random_fh, &hdr, err, err_info);
380 /* Read error or EOF */
382 /* EOF means "short read" in random-access mode */
383 *err = WTAP_ERR_SHORT_READ;
388 switch (wth->file_encap) {
390 case WTAP_ENCAP_ETHERNET:
391 /* XXX - is there an FCS? */
392 pseudo_header->eth.fcs_len = -1;
395 case WTAP_ENCAP_LAPB:
396 pseudo_header->x25.flags = (hdr.dce & 0x1) ? 0x00 : FROM_DCE;
399 case WTAP_ENCAP_ATM_RFC1483:
401 * XXX - is this stuff a pseudo-header?
402 * The direction appears to be in the "hdr.dce" field.
404 if (!radcom_read_rec_data(wth->random_fh, phdr, sizeof phdr,
406 return FALSE; /* Read error */
411 * Read the packet data.
413 return radcom_read_rec_data(wth->random_fh, pd, length, err, err_info);
417 radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr, int *err,
422 errno = WTAP_ERR_CANT_READ;
423 bytes_read = file_read(hdr, sizeof *hdr, fh);
424 if (bytes_read != sizeof *hdr) {
425 *err = file_error(fh, err_info);
428 if (bytes_read != 0) {
429 *err = WTAP_ERR_SHORT_READ;
438 radcom_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
443 errno = WTAP_ERR_CANT_READ;
444 bytes_read = file_read(pd, length, fh);
446 if (bytes_read != length) {
447 *err = file_error(fh, err_info);
449 *err = WTAP_ERR_SHORT_READ;