1 /* radcom.c
2 *
3 * Wiretap Library
4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "config.h"
10
11 #include <errno.h>
12 #include <string.h>
13 #include "wtap-int.h"
14 #include "file_wrappers.h"
15 #include "radcom.h"
16
17 struct frame_date {
18 guint16 year;
19 guint8 month;
20 guint8 day;
21 guint32 sec; /* seconds since midnight */
22 guint32 usec;
23 };
24
25 struct unaligned_frame_date {
26 char year[2];
27 char month;
28 char day;
29 char sec[4]; /* seconds since midnight */
30 char usec[4];
31 };
32
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
37 };
38
39 static const guint8 encap_magic[4] = {
40 0x00, 0x42, 0x43, 0x09
41 };
42
43 static const guint8 active_time_magic[11] = {
44 'A', 'c', 't', 'i', 'v', 'e', ' ', 'T', 'i', 'm', 'e'
45 };
46
47 /* RADCOM record header - followed by frame data (perhaps including FCS).
48
49 "data_length" appears to be the length of packet data following
50 the record header. It's 0 in the last record.
51
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?).
57
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
61 is a record type. */
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 */
72 };
73
74 static gboolean radcom_read(wtap *wth, wtap_rec *rec, Buffer *buf,
75 int *err, gchar **err_info, gint64 *data_offset);
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);
80
81 static int radcom_file_type_subtype = -1;
82
83 void register_radcom(void);
84
radcom_open(wtap * wth,int * err,gchar ** err_info)85 wtap_open_return_val radcom_open(wtap *wth, int *err, gchar **err_info)
86 {
87 guint8 r_magic[8], t_magic[11], search_encap[7];
88 struct frame_date start_date;
89 #if 0
90 guint32 sec;
91 struct tm tm;
92 #endif
93
94 /* Read in the string that should be at the start of a RADCOM file */
95 if (!wtap_read_bytes(wth->fh, r_magic, 8, err, err_info)) {
96 if (*err != WTAP_ERR_SHORT_READ)
97 return WTAP_OPEN_ERROR;
98 return WTAP_OPEN_NOT_MINE;
99 }
100
101 /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
102 * captures. We force them to our standard value so that the test
103 * succeeds (until we find if they have a special meaning, perhaps a
104 * version number ?) */
105 r_magic[1] = 0xD2;
106 r_magic[2] = 0x00;
107 if (memcmp(r_magic, radcom_magic, 8) != 0) {
108 return WTAP_OPEN_NOT_MINE;
109 }
110
111 /* Look for the "Active Time" string. The "frame_date" structure should
112 * be located 32 bytes before the beginning of this string */
113 if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
114 if (*err != WTAP_ERR_SHORT_READ)
115 return WTAP_OPEN_ERROR;
116 return WTAP_OPEN_NOT_MINE;
117 }
118 while (memcmp(t_magic, active_time_magic, 11) != 0)
119 {
120 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
121 return WTAP_OPEN_ERROR;
122 if (!wtap_read_bytes(wth->fh, t_magic, 11, err, err_info)) {
123 if (*err != WTAP_ERR_SHORT_READ)
124 return WTAP_OPEN_ERROR;
125 return WTAP_OPEN_NOT_MINE;
126 }
127 }
128 if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1)
129 return WTAP_OPEN_ERROR;
130
131 /* Get capture start time */
132 if (!wtap_read_bytes(wth->fh, &start_date, sizeof(struct frame_date),
133 err, err_info)) {
134 if (*err != WTAP_ERR_SHORT_READ)
135 return WTAP_OPEN_ERROR;
136 return WTAP_OPEN_NOT_MINE;
137 }
138
139 /* So what time is this? */
140 if (!wtap_read_bytes(wth->fh, NULL, sizeof(struct frame_date),
141 err, err_info)) {
142 if (*err != WTAP_ERR_SHORT_READ)
143 return WTAP_OPEN_ERROR;
144 return WTAP_OPEN_NOT_MINE;
145 }
146
147 for (;;) {
148 if (!wtap_read_bytes(wth->fh, search_encap, 4,
149 err, err_info)) {
150 if (*err != WTAP_ERR_SHORT_READ)
151 return WTAP_OPEN_ERROR;
152 return WTAP_OPEN_NOT_MINE;
153 }
154
155 if (memcmp(encap_magic, search_encap, 4) == 0)
156 break;
157
158 /*
159 * OK, that's not it, go forward 1 byte - reading
160 * the magic moved us forward 4 bytes, so seeking
161 * backward 3 bytes moves forward 1 byte - and
162 * try the 4 bytes at that offset.
163 */
164 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
165 return WTAP_OPEN_ERROR;
166 }
167 if (!wtap_read_bytes(wth->fh, NULL, 12, err, err_info)) {
168 if (*err != WTAP_ERR_SHORT_READ)
169 return WTAP_OPEN_ERROR;
170 return WTAP_OPEN_NOT_MINE;
171 }
172 if (!wtap_read_bytes(wth->fh, search_encap, 4, err, err_info)) {
173 if (*err != WTAP_ERR_SHORT_READ)
174 return WTAP_OPEN_ERROR;
175 return WTAP_OPEN_NOT_MINE;
176 }
177
178 /* This is a radcom file */
179 wth->file_type_subtype = radcom_file_type_subtype;
180 wth->subtype_read = radcom_read;
181 wth->subtype_seek_read = radcom_seek_read;
182 wth->snapshot_length = 0; /* not available in header, only in frame */
183 wth->file_tsprec = WTAP_TSPREC_USEC;
184
185 #if 0
186 tm.tm_year = pletoh16(&start_date.year)-1900;
187 tm.tm_mon = start_date.month-1;
188 tm.tm_mday = start_date.day;
189 sec = pletoh32(&start_date.sec);
190 tm.tm_hour = sec/3600;
191 tm.tm_min = (sec%3600)/60;
192 tm.tm_sec = sec%60;
193 tm.tm_isdst = -1;
194 #endif
195
196 if (memcmp(search_encap, "LAPB", 4) == 0)
197 wth->file_encap = WTAP_ENCAP_LAPB;
198 else if (memcmp(search_encap, "Ethe", 4) == 0)
199 wth->file_encap = WTAP_ENCAP_ETHERNET;
200 else if (memcmp(search_encap, "ATM/", 4) == 0)
201 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
202 else {
203 *err = WTAP_ERR_UNSUPPORTED;
204 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
205 return WTAP_OPEN_ERROR;
206 }
207
208 #if 0
209 if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
210 err, err_info))
211 return WTAP_OPEN_ERROR;
212
213 while (memcmp(&start_date, &next_date, 4)) {
214 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
215 return WTAP_OPEN_ERROR;
216 if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
217 err, err_info))
218 return WTAP_OPEN_ERROR;
219 }
220 #endif
221
222 if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
223 if (!wtap_read_bytes(wth->fh, NULL, 294, err, err_info))
224 return WTAP_OPEN_ERROR;
225 } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
226 if (!wtap_read_bytes(wth->fh, NULL, 297, err, err_info))
227 return WTAP_OPEN_ERROR;
228 } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
229 if (!wtap_read_bytes(wth->fh, NULL, 504, err, err_info))
230 return WTAP_OPEN_ERROR;
231 }
232
233 /*
234 * Add an IDB; we don't know how many interfaces were involved,
235 * so we just say one interface, about which we only know
236 * the link-layer type, snapshot length, and time stamp
237 * resolution.
238 */
239 wtap_add_generated_idb(wth);
240
241 return WTAP_OPEN_MINE;
242 }
243
244 /* Read the next packet */
radcom_read(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)245 static gboolean radcom_read(wtap *wth, wtap_rec *rec, Buffer *buf,
246 int *err, gchar **err_info, gint64 *data_offset)
247 {
248 char fcs[2];
249
250 *data_offset = file_tell(wth->fh);
251
252 /* Read record. */
253 if (!radcom_read_rec(wth, wth->fh, rec, buf, err, err_info)) {
254 /* Read error or EOF */
255 return FALSE;
256 }
257
258 if (wth->file_encap == WTAP_ENCAP_LAPB) {
259 /* Read the FCS.
260 XXX - should we have some way of indicating the
261 presence and size of an FCS to our caller?
262 That'd let us handle other file types as well. */
263 if (!wtap_read_bytes(wth->fh, &fcs, sizeof fcs, err, err_info))
264 return FALSE;
265 }
266
267 return TRUE;
268 }
269
270 static gboolean
radcom_seek_read(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)271 radcom_seek_read(wtap *wth, gint64 seek_off,
272 wtap_rec *rec, Buffer *buf,
273 int *err, gchar **err_info)
274 {
275 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
276 return FALSE;
277
278 /* Read record. */
279 if (!radcom_read_rec(wth, wth->random_fh, rec, buf, err,
280 err_info)) {
281 /* Read error or EOF */
282 if (*err == 0) {
283 /* EOF means "short read" in random-access mode */
284 *err = WTAP_ERR_SHORT_READ;
285 }
286 return FALSE;
287 }
288 return TRUE;
289 }
290
291 static gboolean
radcom_read_rec(wtap * wth,FILE_T fh,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)292 radcom_read_rec(wtap *wth, FILE_T fh, wtap_rec *rec, Buffer *buf,
293 int *err, gchar **err_info)
294 {
295 struct radcomrec_hdr hdr;
296 guint16 data_length, real_length, length;
297 guint32 sec;
298 struct tm tm;
299 guint8 atmhdr[8];
300
301 if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
302 return FALSE;
303
304 data_length = pletoh16(&hdr.data_length);
305 if (data_length == 0) {
306 /*
307 * The last record appears to have 0 in its "data_length"
308 * field, but non-zero values in other fields, so we
309 * check for that and treat it as an EOF indication.
310 */
311 *err = 0;
312 return FALSE;
313 }
314 length = pletoh16(&hdr.length);
315 real_length = pletoh16(&hdr.real_length);
316 /*
317 * The maximum value of length is 65535, which is less than
318 * WTAP_MAX_PACKET_SIZE_STANDARD will ever be, so we don't need to check
319 * it.
320 */
321
322 rec->rec_type = REC_TYPE_PACKET;
323 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
324 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
325
326 tm.tm_year = pletoh16(&hdr.date.year)-1900;
327 tm.tm_mon = (hdr.date.month&0x0f)-1;
328 tm.tm_mday = hdr.date.day;
329 sec = pletoh32(&hdr.date.sec);
330 tm.tm_hour = sec/3600;
331 tm.tm_min = (sec%3600)/60;
332 tm.tm_sec = sec%60;
333 tm.tm_isdst = -1;
334 rec->ts.secs = mktime(&tm);
335 rec->ts.nsecs = pletoh32(&hdr.date.usec) * 1000;
336
337 switch (wth->file_encap) {
338
339 case WTAP_ENCAP_ETHERNET:
340 /* XXX - is there an FCS? */
341 rec->rec_header.packet_header.pseudo_header.eth.fcs_len = -1;
342 break;
343
344 case WTAP_ENCAP_LAPB:
345 rec->rec_header.packet_header.pseudo_header.dte_dce.flags = (hdr.dce & 0x1) ?
346 0x00 : FROM_DCE;
347 length -= 2; /* FCS */
348 real_length -= 2;
349 break;
350
351 case WTAP_ENCAP_ATM_RFC1483:
352 /*
353 * XXX - is this stuff a pseudo-header?
354 * The direction appears to be in the "hdr.dce" field.
355 */
356 if (!wtap_read_bytes(fh, atmhdr, sizeof atmhdr, err,
357 err_info))
358 return FALSE; /* Read error */
359 length -= 8;
360 real_length -= 8;
361 break;
362 }
363
364 rec->rec_header.packet_header.len = real_length;
365 rec->rec_header.packet_header.caplen = length;
366
367 /*
368 * Read the packet data.
369 */
370 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
371 return FALSE; /* Read error */
372
373 return TRUE;
374 }
375
376 static const struct supported_block_type radcom_blocks_supported[] = {
377 /*
378 * We support packet blocks, with no comments or other options.
379 */
380 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
381 };
382
383 static const struct file_type_subtype_info radcom_info = {
384 "RADCOM WAN/LAN analyzer", "radcom", NULL, NULL,
385 FALSE, BLOCKS_SUPPORTED(radcom_blocks_supported),
386 NULL, NULL, NULL
387 };
388
register_radcom(void)389 void register_radcom(void)
390 {
391 radcom_file_type_subtype = wtap_register_file_type_subtype(&radcom_info);
392
393 /*
394 * Register name for backwards compatibility with the
395 * wtap_filetypes table in Lua.
396 */
397 wtap_register_backwards_compatibility_lua_name("RADCOM",
398 radcom_file_type_subtype);
399 }
400
401 /*
402 * Editor modelines - https://www.wireshark.org/tools/modelines.html
403 *
404 * Local variables:
405 * c-basic-offset: 8
406 * tab-width: 8
407 * indent-tabs-mode: t
408 * End:
409 *
410 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
411 * :indentSize=8:tabSize=8:noTabs=false:
412 */
413