4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
26 #include "file_wrappers.h"
34 guint32 sec; /* seconds since midnight */
38 struct unaligned_frame_date {
42 char sec[4]; /* seconds since midnight */
46 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
47 * different in some captures */
48 static const guint8 radcom_magic[8] = {
49 0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
52 static const guint8 encap_magic[4] = {
53 0x00, 0x42, 0x43, 0x09
56 static const guint8 active_time_magic[11] = {
57 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65
60 /* RADCOM record header - followed by frame data (perhaps including FCS).
62 "data_length" appears to be the length of packet data following
63 the record header. It's 0 in the last record.
65 "length" appears to be the amount of captured packet data, and
66 "real_length" might be the actual length of the frame on the wire -
67 in some captures, it's the same as "length", and, in others,
68 it's greater than "length". In the last record, however, those
69 may have bogus values (or is that some kind of trailer record?).
71 "xxx" appears to be all-zero in all but the last record in one
72 capture; if so, perhaps this indicates that the last record is,
73 in fact, a trailer of some sort, and some field in the header
75 struct radcomrec_hdr {
76 char xxx[4]; /* unknown */
77 char data_length[2]; /* packet length? */
78 char xxy[5]; /* unknown */
79 struct unaligned_frame_date date; /* date/time stamp of packet */
80 char real_length[2]; /* actual length of packet */
81 char length[2]; /* captured length of packet */
82 char xxz[2]; /* unknown */
83 char dce; /* DCE/DTE flag (and other flags?) */
84 char xxw[9]; /* unknown */
87 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
89 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
90 struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
91 static gboolean radcom_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
92 Buffer *buf, int *err, gchar **err_info);
93 static gboolean radcom_read_rec_data(FILE_T fh, guint8 *pd, int length,
94 int *err, gchar **err_info);
96 int radcom_open(wtap *wth, int *err, gchar **err_info)
99 guint8 r_magic[8], t_magic[11], search_encap[7];
100 struct frame_date start_date;
106 /* Read in the string that should be at the start of a RADCOM file */
107 errno = WTAP_ERR_CANT_READ;
108 bytes_read = file_read(r_magic, 8, wth->fh);
109 if (bytes_read != 8) {
110 *err = file_error(wth->fh, err_info);
111 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
116 /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
117 * captures. We force them to our standard value so that the test
118 * succeeds (until we find if they have a special meaning, perhaps a
119 * version number ?) */
122 if (memcmp(r_magic, radcom_magic, 8) != 0) {
126 /* Look for the "Active Time" string. The "frame_date" structure should
127 * be located 32 bytes before the beginning of this string */
128 errno = WTAP_ERR_CANT_READ;
129 bytes_read = file_read(t_magic, 11, wth->fh);
130 if (bytes_read != 11) {
131 *err = file_error(wth->fh, err_info);
132 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
136 while (memcmp(t_magic, active_time_magic, 11) != 0)
138 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
140 errno = WTAP_ERR_CANT_READ;
141 bytes_read = file_read(t_magic, 11, wth->fh);
142 if (bytes_read != 11) {
143 *err = file_error(wth->fh, err_info);
144 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
149 if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
151 /* Get capture start time */
152 errno = WTAP_ERR_CANT_READ;
153 bytes_read = file_read(&start_date, sizeof(struct frame_date),
155 if (bytes_read != sizeof(struct frame_date)) {
156 *err = file_error(wth->fh, err_info);
157 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
162 /* This is a radcom file */
163 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_RADCOM;
164 wth->subtype_read = radcom_read;
165 wth->subtype_seek_read = radcom_seek_read;
166 wth->snapshot_length = 0; /* not available in header, only in frame */
167 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
170 tm.tm_year = pletoh16(&start_date.year)-1900;
171 tm.tm_mon = start_date.month-1;
172 tm.tm_mday = start_date.day;
173 sec = pletoh32(&start_date.sec);
174 tm.tm_hour = sec/3600;
175 tm.tm_min = (sec%3600)/60;
179 if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
182 errno = WTAP_ERR_CANT_READ;
183 bytes_read = file_read(search_encap, 4, wth->fh);
184 if (bytes_read != 4) {
187 while (memcmp(encap_magic, search_encap, 4)) {
188 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
190 errno = WTAP_ERR_CANT_READ;
191 bytes_read = file_read(search_encap, 4, wth->fh);
192 if (bytes_read != 4) {
196 if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
198 errno = WTAP_ERR_CANT_READ;
199 bytes_read = file_read(search_encap, 4, wth->fh);
200 if (bytes_read != 4) {
203 if (memcmp(search_encap, "LAPB", 4) == 0)
204 wth->file_encap = WTAP_ENCAP_LAPB;
205 else if (memcmp(search_encap, "Ethe", 4) == 0)
206 wth->file_encap = WTAP_ENCAP_ETHERNET;
207 else if (memcmp(search_encap, "ATM/", 4) == 0)
208 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
210 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
211 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
216 bytes_read = file_read(&next_date, sizeof(struct frame_date), wth->fh);
217 errno = WTAP_ERR_CANT_READ;
218 if (bytes_read != sizeof(struct frame_date)) {
222 while (memcmp(&start_date, &next_date, 4)) {
223 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
225 errno = WTAP_ERR_CANT_READ;
226 bytes_read = file_read(&next_date, sizeof(struct frame_date),
228 if (bytes_read != sizeof(struct frame_date)) {
234 if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
235 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
237 } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
238 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
240 } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
241 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
248 *err = file_error(wth->fh, err_info);
254 /* Read the next packet */
255 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
261 *data_offset = file_tell(wth->fh);
263 /* Read record header. */
264 if (!radcom_read_rec(wth, wth->fh, &wth->phdr, wth->frame_buffer,
266 /* Read error or EOF */
270 if (wth->file_encap == WTAP_ENCAP_LAPB) {
272 XXX - should we have some way of indicating the
273 presence and size of an FCS to our caller?
274 That'd let us handle other file types as well. */
275 errno = WTAP_ERR_CANT_READ;
276 bytes_read = file_read(&fcs, sizeof fcs, wth->fh);
277 if (bytes_read != sizeof fcs) {
278 *err = file_error(wth->fh, err_info);
280 *err = WTAP_ERR_SHORT_READ;
289 radcom_seek_read(wtap *wth, gint64 seek_off,
290 struct wtap_pkthdr *phdr, Buffer *buf,
291 int *err, gchar **err_info)
293 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
297 if (!radcom_read_rec(wth, wth->random_fh, phdr, buf, err,
299 /* Read error or EOF */
301 /* EOF means "short read" in random-access mode */
302 *err = WTAP_ERR_SHORT_READ;
310 radcom_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
311 int *err, gchar **err_info)
313 struct radcomrec_hdr hdr;
315 guint16 data_length, real_length, length;
320 errno = WTAP_ERR_CANT_READ;
321 bytes_read = file_read(&hdr, sizeof hdr, fh);
322 if (bytes_read != sizeof hdr) {
323 *err = file_error(fh, err_info);
324 if (*err == 0 && bytes_read != 0)
325 *err = WTAP_ERR_SHORT_READ;
329 data_length = pletoh16(&hdr.data_length);
330 if (data_length == 0) {
332 * The last record appears to have 0 in its "data_length"
333 * field, but non-zero values in other fields, so we
334 * check for that and treat it as an EOF indication.
339 length = pletoh16(&hdr.length);
340 real_length = pletoh16(&hdr.real_length);
342 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
344 tm.tm_year = pletoh16(&hdr.date.year)-1900;
345 tm.tm_mon = (hdr.date.month&0x0f)-1;
346 tm.tm_mday = hdr.date.day;
347 sec = pletoh32(&hdr.date.sec);
348 tm.tm_hour = sec/3600;
349 tm.tm_min = (sec%3600)/60;
352 phdr->ts.secs = mktime(&tm);
353 phdr->ts.nsecs = pletoh32(&hdr.date.usec) * 1000;
355 switch (wth->file_encap) {
357 case WTAP_ENCAP_ETHERNET:
358 /* XXX - is there an FCS? */
359 phdr->pseudo_header.eth.fcs_len = -1;
362 case WTAP_ENCAP_LAPB:
363 phdr->pseudo_header.x25.flags = (hdr.dce & 0x1) ?
365 length -= 2; /* FCS */
369 case WTAP_ENCAP_ATM_RFC1483:
371 * XXX - is this stuff a pseudo-header?
372 * The direction appears to be in the "hdr.dce" field.
374 if (!radcom_read_rec_data(wth->fh, atmhdr, sizeof atmhdr, err,
376 return FALSE; /* Read error */
382 phdr->len = real_length;
383 phdr->caplen = length;
386 * Read the packet data.
388 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
389 return FALSE; /* Read error */
395 radcom_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
400 errno = WTAP_ERR_CANT_READ;
401 bytes_read = file_read(pd, length, fh);
403 if (bytes_read != length) {
404 *err = file_error(fh, err_info);
406 *err = WTAP_ERR_SHORT_READ;