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"
20 uint32_t sec
; /* seconds since midnight */
24 struct unaligned_frame_date
{
28 char sec
[4]; /* seconds since midnight */
32 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
33 * different in some captures */
34 static const uint8_t radcom_magic
[8] = {
35 0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
38 static const uint8_t encap_magic
[4] = {
39 0x00, 0x42, 0x43, 0x09
42 static const uint8_t active_time_magic
[11] = {
43 'A', 'c', 't', 'i', 'v', 'e', ' ', 'T', 'i', 'm', 'e'
46 /* RADCOM record header - followed by frame data (perhaps including FCS).
48 "data_length" appears to be the length of packet data following
49 the record header. It's 0 in the last record.
51 "length" appears to be the amount of captured packet data, and
52 "real_length" might be the actual length of the frame on the wire -
53 in some captures, it's the same as "length", and, in others,
54 it's greater than "length". In the last record, however, those
55 may have bogus values (or is that some kind of trailer record?).
57 "xxx" appears to be all-zero in all but the last record in one
58 capture; if so, perhaps this indicates that the last record is,
59 in fact, a trailer of some sort, and some field in the header
61 struct radcomrec_hdr
{
62 char xxx
[4]; /* unknown */
63 char data_length
[2]; /* packet length? */
64 char xxy
[5]; /* unknown */
65 struct unaligned_frame_date date
; /* date/time stamp of packet */
66 char real_length
[2]; /* actual length of packet */
67 char length
[2]; /* captured length of packet */
68 char xxz
[2]; /* unknown */
69 char dce
; /* DCE/DTE flag (and other flags?) */
70 char xxw
[9]; /* unknown */
73 static bool radcom_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
74 int *err
, char **err_info
, int64_t *data_offset
);
75 static bool radcom_seek_read(wtap
*wth
, int64_t seek_off
,
76 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
);
77 static bool radcom_read_rec(wtap
*wth
, FILE_T fh
, wtap_rec
*rec
,
78 Buffer
*buf
, int *err
, char **err_info
);
80 static int radcom_file_type_subtype
= -1;
82 void register_radcom(void);
84 wtap_open_return_val
radcom_open(wtap
*wth
, int *err
, char **err_info
)
86 uint8_t r_magic
[8], t_magic
[11], search_encap
[7];
87 struct frame_date start_date
;
93 /* Read in the string that should be at the start of a RADCOM file */
94 if (!wtap_read_bytes(wth
->fh
, r_magic
, 8, err
, err_info
)) {
95 if (*err
!= WTAP_ERR_SHORT_READ
)
96 return WTAP_OPEN_ERROR
;
97 return WTAP_OPEN_NOT_MINE
;
100 /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
101 * captures. We force them to our standard value so that the test
102 * succeeds (until we find if they have a special meaning, perhaps a
103 * version number ?) */
106 if (memcmp(r_magic
, radcom_magic
, 8) != 0) {
107 return WTAP_OPEN_NOT_MINE
;
110 /* Look for the "Active Time" string. The "frame_date" structure should
111 * be located 32 bytes before the beginning of this string */
112 if (!wtap_read_bytes(wth
->fh
, t_magic
, 11, err
, err_info
)) {
113 if (*err
!= WTAP_ERR_SHORT_READ
)
114 return WTAP_OPEN_ERROR
;
115 return WTAP_OPEN_NOT_MINE
;
117 while (memcmp(t_magic
, active_time_magic
, 11) != 0)
119 if (file_seek(wth
->fh
, -10, SEEK_CUR
, err
) == -1)
120 return WTAP_OPEN_ERROR
;
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
;
127 if (file_seek(wth
->fh
, -43, SEEK_CUR
, err
) == -1)
128 return WTAP_OPEN_ERROR
;
130 /* Get capture start time */
131 if (!wtap_read_bytes(wth
->fh
, &start_date
, sizeof(struct frame_date
),
133 if (*err
!= WTAP_ERR_SHORT_READ
)
134 return WTAP_OPEN_ERROR
;
135 return WTAP_OPEN_NOT_MINE
;
138 /* So what time is this? */
139 if (!wtap_read_bytes(wth
->fh
, NULL
, sizeof(struct frame_date
),
141 if (*err
!= WTAP_ERR_SHORT_READ
)
142 return WTAP_OPEN_ERROR
;
143 return WTAP_OPEN_NOT_MINE
;
147 if (!wtap_read_bytes(wth
->fh
, search_encap
, 4,
149 if (*err
!= WTAP_ERR_SHORT_READ
)
150 return WTAP_OPEN_ERROR
;
151 return WTAP_OPEN_NOT_MINE
;
154 if (memcmp(encap_magic
, search_encap
, 4) == 0)
158 * OK, that's not it, go forward 1 byte - reading
159 * the magic moved us forward 4 bytes, so seeking
160 * backward 3 bytes moves forward 1 byte - and
161 * try the 4 bytes at that offset.
163 if (file_seek(wth
->fh
, -3, SEEK_CUR
, err
) == -1)
164 return WTAP_OPEN_ERROR
;
166 if (!wtap_read_bytes(wth
->fh
, NULL
, 12, err
, err_info
)) {
167 if (*err
!= WTAP_ERR_SHORT_READ
)
168 return WTAP_OPEN_ERROR
;
169 return WTAP_OPEN_NOT_MINE
;
171 if (!wtap_read_bytes(wth
->fh
, search_encap
, 4, err
, err_info
)) {
172 if (*err
!= WTAP_ERR_SHORT_READ
)
173 return WTAP_OPEN_ERROR
;
174 return WTAP_OPEN_NOT_MINE
;
177 /* This is a radcom file */
178 wth
->file_type_subtype
= radcom_file_type_subtype
;
179 wth
->subtype_read
= radcom_read
;
180 wth
->subtype_seek_read
= radcom_seek_read
;
181 wth
->snapshot_length
= 0; /* not available in header, only in frame */
182 wth
->file_tsprec
= WTAP_TSPREC_USEC
;
185 tm
.tm_year
= pletoh16(&start_date
.year
)-1900;
186 tm
.tm_mon
= start_date
.month
-1;
187 tm
.tm_mday
= start_date
.day
;
188 sec
= pletoh32(&start_date
.sec
);
189 tm
.tm_hour
= sec
/3600;
190 tm
.tm_min
= (sec
%3600)/60;
195 if (memcmp(search_encap
, "LAPB", 4) == 0)
196 wth
->file_encap
= WTAP_ENCAP_LAPB
;
197 else if (memcmp(search_encap
, "Ethe", 4) == 0)
198 wth
->file_encap
= WTAP_ENCAP_ETHERNET
;
199 else if (memcmp(search_encap
, "ATM/", 4) == 0)
200 wth
->file_encap
= WTAP_ENCAP_ATM_RFC1483
;
202 *err
= WTAP_ERR_UNSUPPORTED
;
203 *err_info
= ws_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap
);
204 return WTAP_OPEN_ERROR
;
208 if (!wtap_read_bytes(wth
->fh
, &next_date
, sizeof(struct frame_date
),
210 return WTAP_OPEN_ERROR
;
212 while (memcmp(&start_date
, &next_date
, 4)) {
213 if (file_seek(wth
->fh
, 1-sizeof(struct frame_date
), SEEK_CUR
, err
) == -1)
214 return WTAP_OPEN_ERROR
;
215 if (!wtap_read_bytes(wth
->fh
, &next_date
, sizeof(struct frame_date
),
217 return WTAP_OPEN_ERROR
;
221 if (wth
->file_encap
== WTAP_ENCAP_ETHERNET
) {
222 if (!wtap_read_bytes(wth
->fh
, NULL
, 294, err
, err_info
))
223 return WTAP_OPEN_ERROR
;
224 } else if (wth
->file_encap
== WTAP_ENCAP_LAPB
) {
225 if (!wtap_read_bytes(wth
->fh
, NULL
, 297, err
, err_info
))
226 return WTAP_OPEN_ERROR
;
227 } else if (wth
->file_encap
== WTAP_ENCAP_ATM_RFC1483
) {
228 if (!wtap_read_bytes(wth
->fh
, NULL
, 504, err
, err_info
))
229 return WTAP_OPEN_ERROR
;
233 * Add an IDB; we don't know how many interfaces were involved,
234 * so we just say one interface, about which we only know
235 * the link-layer type, snapshot length, and time stamp
238 wtap_add_generated_idb(wth
);
240 return WTAP_OPEN_MINE
;
243 /* Read the next packet */
244 static bool radcom_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
245 int *err
, char **err_info
, int64_t *data_offset
)
249 *data_offset
= file_tell(wth
->fh
);
252 if (!radcom_read_rec(wth
, wth
->fh
, rec
, buf
, err
, err_info
)) {
253 /* Read error or EOF */
257 if (wth
->file_encap
== WTAP_ENCAP_LAPB
) {
259 XXX - should we have some way of indicating the
260 presence and size of an FCS to our caller?
261 That'd let us handle other file types as well. */
262 if (!wtap_read_bytes(wth
->fh
, &fcs
, sizeof fcs
, err
, err_info
))
270 radcom_seek_read(wtap
*wth
, int64_t seek_off
,
271 wtap_rec
*rec
, Buffer
*buf
,
272 int *err
, char **err_info
)
274 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
278 if (!radcom_read_rec(wth
, wth
->random_fh
, rec
, buf
, err
,
280 /* Read error or EOF */
282 /* EOF means "short read" in random-access mode */
283 *err
= WTAP_ERR_SHORT_READ
;
291 radcom_read_rec(wtap
*wth
, FILE_T fh
, wtap_rec
*rec
, Buffer
*buf
,
292 int *err
, char **err_info
)
294 struct radcomrec_hdr hdr
;
295 uint16_t data_length
, real_length
, length
;
300 if (!wtap_read_bytes_or_eof(fh
, &hdr
, sizeof hdr
, err
, err_info
))
303 data_length
= pletoh16(&hdr
.data_length
);
304 if (data_length
== 0) {
306 * The last record appears to have 0 in its "data_length"
307 * field, but non-zero values in other fields, so we
308 * check for that and treat it as an EOF indication.
313 length
= pletoh16(&hdr
.length
);
314 real_length
= pletoh16(&hdr
.real_length
);
316 * The maximum value of length is 65535, which is less than
317 * WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
321 rec
->rec_type
= REC_TYPE_PACKET
;
322 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
323 rec
->presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
325 tm
.tm_year
= pletoh16(&hdr
.date
.year
)-1900;
326 tm
.tm_mon
= (hdr
.date
.month
&0x0f)-1;
327 tm
.tm_mday
= hdr
.date
.day
;
328 sec
= pletoh32(&hdr
.date
.sec
);
329 tm
.tm_hour
= sec
/3600;
330 tm
.tm_min
= (sec
%3600)/60;
333 rec
->ts
.secs
= mktime(&tm
);
334 rec
->ts
.nsecs
= pletoh32(&hdr
.date
.usec
) * 1000;
336 switch (wth
->file_encap
) {
338 case WTAP_ENCAP_ETHERNET
:
339 /* XXX - is there an FCS? */
340 rec
->rec_header
.packet_header
.pseudo_header
.eth
.fcs_len
= -1;
343 case WTAP_ENCAP_LAPB
:
344 rec
->rec_header
.packet_header
.pseudo_header
.dte_dce
.flags
= (hdr
.dce
& 0x1) ?
346 length
-= 2; /* FCS */
350 case WTAP_ENCAP_ATM_RFC1483
:
352 * XXX - is this stuff a pseudo-header?
353 * The direction appears to be in the "hdr.dce" field.
355 if (!wtap_read_bytes(fh
, atmhdr
, sizeof atmhdr
, err
,
357 return false; /* Read error */
363 rec
->rec_header
.packet_header
.len
= real_length
;
364 rec
->rec_header
.packet_header
.caplen
= length
;
367 * Read the packet data.
369 if (!wtap_read_packet_bytes(fh
, buf
, length
, err
, err_info
))
370 return false; /* Read error */
375 static const struct supported_block_type radcom_blocks_supported
[] = {
377 * We support packet blocks, with no comments or other options.
379 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
382 static const struct file_type_subtype_info radcom_info
= {
383 "RADCOM WAN/LAN analyzer", "radcom", NULL
, NULL
,
384 false, BLOCKS_SUPPORTED(radcom_blocks_supported
),
388 void register_radcom(void)
390 radcom_file_type_subtype
= wtap_register_file_type_subtype(&radcom_info
);
393 * Register name for backwards compatibility with the
394 * wtap_filetypes table in Lua.
396 wtap_register_backwards_compatibility_lua_name("RADCOM",
397 radcom_file_type_subtype
);
401 * Editor modelines - https://www.wireshark.org/tools/modelines.html
406 * indent-tabs-mode: t
409 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
410 * :indentSize=8:tabSize=8:noTabs=false: