4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "file_wrappers.h"
21 guint32 sec; /* seconds since midnight */
25 struct unaligned_frame_date {
29 char sec[4]; /* seconds since midnight */
33 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
34 * different in some captures */
35 static const guint8 radcom_magic[8] = {
36 0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
39 static const guint8 encap_magic[4] = {
40 0x00, 0x42, 0x43, 0x09
43 static const guint8 active_time_magic[11] = {
44 'A', 'c', 't', 'i', 'v', 'e', ' ', 'T', 'i', 'm', 'e'
47 /* RADCOM record header - followed by frame data (perhaps including FCS).
49 "data_length" appears to be the length of packet data following
50 the record header. It's 0 in the last record.
52 "length" appears to be the amount of captured packet data, and
53 "real_length" might be the actual length of the frame on the wire -
54 in some captures, it's the same as "length", and, in others,
55 it's greater than "length". In the last record, however, those
56 may have bogus values (or is that some kind of trailer record?).
58 "xxx" appears to be all-zero in all but the last record in one
59 capture; if so, perhaps this indicates that the last record is,
60 in fact, a trailer of some sort, and some field in the header
62 struct radcomrec_hdr {
63 char xxx[4]; /* unknown */
64 char data_length[2]; /* packet length? */
65 char xxy[5]; /* unknown */
66 struct unaligned_frame_date date; /* date/time stamp of packet */
67 char real_length[2]; /* actual length of packet */
68 char length[2]; /* captured length of packet */
69 char xxz[2]; /* unknown */
70 char dce; /* DCE/DTE flag (and other flags?) */
71 char xxw[9]; /* unknown */
74 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
76 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
77 wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
78 static gboolean radcom_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec,
79 Buffer *buf, int *err, gchar **err_info);
81 wtap_open_return_val radcom_open(wtap *wth, int *err, gchar **err_info)
83 guint8 r_magic[8], t_magic[11], search_encap[7];
84 struct frame_date start_date;
90 /* Read in the string that should be at the start of a RADCOM file */
91 if (!wtap_read_bytes(wth->fh, r_magic, 8, err, err_info)) {
92 if (*err != WTAP_ERR_SHORT_READ)
93 return WTAP_OPEN_ERROR;
94 return WTAP_OPEN_NOT_MINE;
97 /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
98 * captures. We force them to our standard value so that the test
99 * succeeds (until we find if they have a special meaning, perhaps a
100 * version number ?) */
103 if (memcmp(r_magic, radcom_magic, 8) != 0) {
104 return WTAP_OPEN_NOT_MINE;
107 /* Look for the "Active Time" string. The "frame_date" structure should
108 * be located 32 bytes before the beginning of this string */
109 if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
110 if (*err != WTAP_ERR_SHORT_READ)
111 return WTAP_OPEN_ERROR;
112 return WTAP_OPEN_NOT_MINE;
114 while (memcmp(t_magic, active_time_magic, 11) != 0)
116 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
117 return WTAP_OPEN_ERROR;
118 if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
119 if (*err != WTAP_ERR_SHORT_READ)
120 return WTAP_OPEN_ERROR;
121 return WTAP_OPEN_NOT_MINE;
124 if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1)
125 return WTAP_OPEN_ERROR;
127 /* Get capture start time */
128 if (!wtap_read_bytes(wth->fh, &start_date, sizeof(struct frame_date),
130 if (*err != WTAP_ERR_SHORT_READ)
131 return WTAP_OPEN_ERROR;
132 return WTAP_OPEN_NOT_MINE;
135 /* So what time is this? */
136 if (!wtap_read_bytes(wth->fh, NULL, sizeof(struct frame_date),
138 if (*err != WTAP_ERR_SHORT_READ)
139 return WTAP_OPEN_ERROR;
140 return WTAP_OPEN_NOT_MINE;
144 if (!wtap_read_bytes(wth->fh, search_encap, 4,
146 if (*err != WTAP_ERR_SHORT_READ)
147 return WTAP_OPEN_ERROR;
148 return WTAP_OPEN_NOT_MINE;
151 if (memcmp(encap_magic, search_encap, 4) == 0)
155 * OK, that's not it, go forward 1 byte - reading
156 * the magic moved us forward 4 bytes, so seeking
157 * backward 3 bytes moves forward 1 byte - and
158 * try the 4 bytes at that offset.
160 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
161 return WTAP_OPEN_ERROR;
163 if (!wtap_read_bytes(wth->fh, NULL, 12, err, err_info)) {
164 if (*err != WTAP_ERR_SHORT_READ)
165 return WTAP_OPEN_ERROR;
166 return WTAP_OPEN_NOT_MINE;
168 if (!wtap_read_bytes(wth->fh, search_encap, 4, err, err_info)) {
169 if (*err != WTAP_ERR_SHORT_READ)
170 return WTAP_OPEN_ERROR;
171 return WTAP_OPEN_NOT_MINE;
174 /* This is a radcom file */
175 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_RADCOM;
176 wth->subtype_read = radcom_read;
177 wth->subtype_seek_read = radcom_seek_read;
178 wth->snapshot_length = 0; /* not available in header, only in frame */
179 wth->file_tsprec = WTAP_TSPREC_USEC;
182 tm.tm_year = pletoh16(&start_date.year)-1900;
183 tm.tm_mon = start_date.month-1;
184 tm.tm_mday = start_date.day;
185 sec = pletoh32(&start_date.sec);
186 tm.tm_hour = sec/3600;
187 tm.tm_min = (sec%3600)/60;
192 if (memcmp(search_encap, "LAPB", 4) == 0)
193 wth->file_encap = WTAP_ENCAP_LAPB;
194 else if (memcmp(search_encap, "Ethe", 4) == 0)
195 wth->file_encap = WTAP_ENCAP_ETHERNET;
196 else if (memcmp(search_encap, "ATM/", 4) == 0)
197 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
199 *err = WTAP_ERR_UNSUPPORTED;
200 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
201 return WTAP_OPEN_ERROR;
205 if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
207 return WTAP_OPEN_ERROR;
209 while (memcmp(&start_date, &next_date, 4)) {
210 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
211 return WTAP_OPEN_ERROR;
212 if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
214 return WTAP_OPEN_ERROR;
218 if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
219 if (!wtap_read_bytes(wth->fh, NULL, 294, err, err_info))
220 return WTAP_OPEN_ERROR;
221 } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
222 if (!wtap_read_bytes(wth->fh, NULL, 297, err, err_info))
223 return WTAP_OPEN_ERROR;
224 } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
225 if (!wtap_read_bytes(wth->fh, NULL, 504, err, err_info))
226 return WTAP_OPEN_ERROR;
229 return WTAP_OPEN_MINE;
232 /* Read the next packet */
233 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
238 *data_offset = file_tell(wth->fh);
241 if (!radcom_read_rec(wth, wth->fh, &wth->rec, wth->rec_data,
243 /* Read error or EOF */
247 if (wth->file_encap == WTAP_ENCAP_LAPB) {
249 XXX - should we have some way of indicating the
250 presence and size of an FCS to our caller?
251 That'd let us handle other file types as well. */
252 if (!wtap_read_bytes(wth->fh, &fcs, sizeof fcs, err, err_info))
260 radcom_seek_read(wtap *wth, gint64 seek_off,
261 wtap_rec *rec, Buffer *buf,
262 int *err, gchar **err_info)
264 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
268 if (!radcom_read_rec(wth, wth->random_fh, rec, buf, err,
270 /* Read error or EOF */
272 /* EOF means "short read" in random-access mode */
273 *err = WTAP_ERR_SHORT_READ;
281 radcom_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec, Buffer *buf,
282 int *err, gchar **err_info)
284 struct radcomrec_hdr hdr;
285 guint16 data_length, real_length, length;
290 if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
293 data_length = pletoh16(&hdr.data_length);
294 if (data_length == 0) {
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.
303 length = pletoh16(&hdr.length);
304 real_length = pletoh16(&hdr.real_length);
306 * The maximum value of length is 65535, which is less than
307 * WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
311 rec->rec_type = REC_TYPE_PACKET;
312 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
314 tm.tm_year = pletoh16(&hdr.date.year)-1900;
315 tm.tm_mon = (hdr.date.month&0x0f)-1;
316 tm.tm_mday = hdr.date.day;
317 sec = pletoh32(&hdr.date.sec);
318 tm.tm_hour = sec/3600;
319 tm.tm_min = (sec%3600)/60;
322 rec->ts.secs = mktime(&tm);
323 rec->ts.nsecs = pletoh32(&hdr.date.usec) * 1000;
325 switch (wth->file_encap) {
327 case WTAP_ENCAP_ETHERNET:
328 /* XXX - is there an FCS? */
329 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1;
332 case WTAP_ENCAP_LAPB:
333 rec->rec_header.packet_header.pseudo_header.dte_dce.flags = (hdr.dce & 0x1) ?
335 length -= 2; /* FCS */
339 case WTAP_ENCAP_ATM_RFC1483:
341 * XXX - is this stuff a pseudo-header?
342 * The direction appears to be in the "hdr.dce" field.
344 if (!wtap_read_bytes(fh, atmhdr, sizeof atmhdr, err,
346 return FALSE; /* Read error */
352 rec->rec_header.packet_header.len = real_length;
353 rec->rec_header.packet_header.caplen = length;
356 * Read the packet data.
358 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
359 return FALSE; /* Read error */
365 * Editor modelines - http://www.wireshark.org/tools/modelines.html
370 * indent-tabs-mode: t
373 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
374 * :indentSize=8:tabSize=8:noTabs=false: