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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "file_wrappers.h"
36 guint32 sec; /* seconds since midnight */
40 struct unaligned_frame_date {
44 char sec[4]; /* seconds since midnight */
48 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
49 * different in some captures */
50 static const guint8 radcom_magic[8] = {
51 0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
54 static const guint8 encap_magic[4] = {
55 0x00, 0x42, 0x43, 0x09
58 static const guint8 active_time_magic[11] = {
59 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65
62 /* RADCOM record header - followed by frame data (perhaps including FCS).
64 "data_length" appears to be the length of packet data following
65 the record header. It's 0 in the last record.
67 "length" appears to be the amount of captured packet data, and
68 "real_length" might be the actual length of the frame on the wire -
69 in some captures, it's the same as "length", and, in others,
70 it's greater than "length". In the last record, however, those
71 may have bogus values (or is that some kind of trailer record?).
73 "xxx" appears to be all-zero in all but the last record in one
74 capture; if so, perhaps this indicates that the last record is,
75 in fact, a trailer of some sort, and some field in the header
77 struct radcomrec_hdr {
78 char xxx[4]; /* unknown */
79 char data_length[2]; /* packet length? */
80 char xxy[5]; /* unknown */
81 struct unaligned_frame_date date; /* date/time stamp of packet */
82 char real_length[2]; /* actual length of packet */
83 char length[2]; /* captured length of packet */
84 char xxz[2]; /* unknown */
85 char dce; /* DCE/DTE flag (and other flags?) */
86 char xxw[9]; /* unknown */
89 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
91 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
92 struct wtap_pkthdr *pkhdr, guint8 *pd, int length,
93 int *err, gchar **err_info);
94 static int radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr,
95 int *err, gchar **err_info);
96 static gboolean radcom_read_rec_data(FILE_T fh, guint8 *pd, int length,
97 int *err, gchar **err_info);
99 int radcom_open(wtap *wth, int *err, gchar **err_info)
102 guint8 r_magic[8], t_magic[11], search_encap[7];
103 struct frame_date start_date;
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, 8, wth->fh);
112 if (bytes_read != 8) {
113 *err = file_error(wth->fh, err_info);
114 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
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 ?) */
125 if (memcmp(r_magic, radcom_magic, 8) != 0) {
129 /* Look for the "Active Time" string. The "frame_date" structure should
130 * be located 32 bytes before the beginning of this string */
131 errno = WTAP_ERR_CANT_READ;
132 bytes_read = file_read(t_magic, 11, wth->fh);
133 if (bytes_read != 11) {
134 *err = file_error(wth->fh, err_info);
135 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
139 while (memcmp(t_magic, active_time_magic, 11) != 0)
141 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
143 errno = WTAP_ERR_CANT_READ;
144 bytes_read = file_read(t_magic, 11, wth->fh);
145 if (bytes_read != 11) {
146 *err = file_error(wth->fh, err_info);
147 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
152 if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
154 /* Get capture start time */
155 errno = WTAP_ERR_CANT_READ;
156 bytes_read = file_read(&start_date, sizeof(struct frame_date),
158 if (bytes_read != sizeof(struct frame_date)) {
159 *err = file_error(wth->fh, err_info);
160 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
165 /* This is a radcom file */
166 wth->file_type = WTAP_FILE_RADCOM;
167 wth->subtype_read = radcom_read;
168 wth->subtype_seek_read = radcom_seek_read;
169 wth->snapshot_length = 0; /* not available in header, only in frame */
170 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
173 tm.tm_year = pletohs(&start_date.year)-1900;
174 tm.tm_mon = start_date.month-1;
175 tm.tm_mday = start_date.day;
176 sec = pletohl(&start_date.sec);
177 tm.tm_hour = sec/3600;
178 tm.tm_min = (sec%3600)/60;
182 if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
185 errno = WTAP_ERR_CANT_READ;
186 bytes_read = file_read(search_encap, 4, wth->fh);
187 if (bytes_read != 4) {
190 while (memcmp(encap_magic, search_encap, 4)) {
191 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
193 errno = WTAP_ERR_CANT_READ;
194 bytes_read = file_read(search_encap, 4, wth->fh);
195 if (bytes_read != 4) {
199 if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
201 errno = WTAP_ERR_CANT_READ;
202 bytes_read = file_read(search_encap, 4, wth->fh);
203 if (bytes_read != 4) {
206 if (memcmp(search_encap, "LAPB", 4) == 0)
207 wth->file_encap = WTAP_ENCAP_LAPB;
208 else if (memcmp(search_encap, "Ethe", 4) == 0)
209 wth->file_encap = WTAP_ENCAP_ETHERNET;
210 else if (memcmp(search_encap, "ATM/", 4) == 0)
211 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
213 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
214 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
219 bytes_read = file_read(&next_date, sizeof(struct frame_date), wth->fh);
220 errno = WTAP_ERR_CANT_READ;
221 if (bytes_read != sizeof(struct frame_date)) {
225 while (memcmp(&start_date, &next_date, 4)) {
226 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
228 errno = WTAP_ERR_CANT_READ;
229 bytes_read = file_read(&next_date, sizeof(struct frame_date),
231 if (bytes_read != sizeof(struct frame_date)) {
237 if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
238 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
240 } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
241 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
243 } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
244 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
251 *err = file_error(wth->fh, err_info);
257 /* Read the next packet */
258 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
262 struct radcomrec_hdr hdr;
263 guint16 data_length, real_length, length;
270 /* Read record header. */
271 *data_offset = file_tell(wth->fh);
272 ret = radcom_read_rec_header(wth->fh, &hdr, err, err_info);
274 /* Read error or EOF */
277 data_length = pletohs(&hdr.data_length);
278 if (data_length == 0) {
280 * The last record appears to have 0 in its "data_length"
281 * field, but non-zero values in other fields, so we
282 * check for that and treat it as an EOF indication.
287 length = pletohs(&hdr.length);
288 real_length = pletohs(&hdr.real_length);
290 if (wth->file_encap == WTAP_ENCAP_LAPB) {
291 length -= 2; /* FCS */
295 wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
297 wth->phdr.len = real_length;
298 wth->phdr.caplen = length;
300 tm.tm_year = pletohs(&hdr.date.year)-1900;
301 tm.tm_mon = (hdr.date.month&0x0f)-1;
302 tm.tm_mday = hdr.date.day;
303 sec = pletohl(&hdr.date.sec);
304 tm.tm_hour = sec/3600;
305 tm.tm_min = (sec%3600)/60;
308 wth->phdr.ts.secs = mktime(&tm);
309 wth->phdr.ts.nsecs = pletohl(&hdr.date.usec) * 1000;
311 switch (wth->file_encap) {
313 case WTAP_ENCAP_ETHERNET:
314 /* XXX - is there an FCS? */
315 wth->phdr.pseudo_header.eth.fcs_len = -1;
318 case WTAP_ENCAP_LAPB:
319 wth->phdr.pseudo_header.x25.flags = (hdr.dce & 0x1) ?
323 case WTAP_ENCAP_ATM_RFC1483:
325 * XXX - is this stuff a pseudo-header?
326 * The direction appears to be in the "hdr.dce" field.
328 if (!radcom_read_rec_data(wth->fh, phdr, sizeof phdr, err,
330 return FALSE; /* Read error */
333 wth->phdr.caplen -= 8;
338 * Read the packet data.
340 buffer_assure_space(wth->frame_buffer, length);
341 if (!radcom_read_rec_data(wth->fh,
342 buffer_start_ptr(wth->frame_buffer), length, err, err_info))
343 return FALSE; /* Read error */
345 if (wth->file_encap == WTAP_ENCAP_LAPB) {
347 XXX - should we have some way of indicating the
348 presence and size of an FCS to our caller?
349 That'd let us handle other file types as well. */
350 errno = WTAP_ERR_CANT_READ;
351 bytes_read = file_read(&fcs, sizeof fcs, wth->fh);
352 if (bytes_read != sizeof fcs) {
353 *err = file_error(wth->fh, err_info);
355 *err = WTAP_ERR_SHORT_READ;
364 radcom_seek_read(wtap *wth, gint64 seek_off,
365 struct wtap_pkthdr *pkhdr, guint8 *pd, int length,
366 int *err, gchar **err_info)
368 union wtap_pseudo_header *pseudo_header = &pkhdr->pseudo_header;
370 struct radcomrec_hdr hdr;
373 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
376 /* Read record header. */
377 ret = radcom_read_rec_header(wth->random_fh, &hdr, err, err_info);
379 /* Read error or EOF */
381 /* EOF means "short read" in random-access mode */
382 *err = WTAP_ERR_SHORT_READ;
387 switch (wth->file_encap) {
389 case WTAP_ENCAP_ETHERNET:
390 /* XXX - is there an FCS? */
391 pseudo_header->eth.fcs_len = -1;
394 case WTAP_ENCAP_LAPB:
395 pseudo_header->x25.flags = (hdr.dce & 0x1) ? 0x00 : FROM_DCE;
398 case WTAP_ENCAP_ATM_RFC1483:
400 * XXX - is this stuff a pseudo-header?
401 * The direction appears to be in the "hdr.dce" field.
403 if (!radcom_read_rec_data(wth->random_fh, phdr, sizeof phdr,
405 return FALSE; /* Read error */
410 * Read the packet data.
412 return radcom_read_rec_data(wth->random_fh, pd, length, err, err_info);
416 radcom_read_rec_header(FILE_T fh, struct radcomrec_hdr *hdr, int *err,
421 errno = WTAP_ERR_CANT_READ;
422 bytes_read = file_read(hdr, sizeof *hdr, fh);
423 if (bytes_read != sizeof *hdr) {
424 *err = file_error(fh, err_info);
427 if (bytes_read != 0) {
428 *err = WTAP_ERR_SHORT_READ;
437 radcom_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
442 errno = WTAP_ERR_CANT_READ;
443 bytes_read = file_read(pd, length, fh);
445 if (bytes_read != length) {
446 *err = file_error(fh, err_info);
448 *err = WTAP_ERR_SHORT_READ;