dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / wiretap / radcom.c
blob6e216e67df911d21a897c126b3aea6f5277bee37
1 /* radcom.c
3 * Wiretap Library
4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
10 #include "radcom.h"
12 #include <string.h>
13 #include "wtap-int.h"
14 #include "file_wrappers.h"
16 struct frame_date {
17 uint16_t year;
18 uint8_t month;
19 uint8_t day;
20 uint32_t sec; /* seconds since midnight */
21 uint32_t usec;
24 struct unaligned_frame_date {
25 char year[2];
26 char month;
27 char day;
28 char sec[4]; /* seconds since midnight */
29 char usec[4];
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
60 is a record type. */
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;
88 #if 0
89 uint32_t sec;
90 struct tm tm;
91 #endif
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 ?) */
104 r_magic[1] = 0xD2;
105 r_magic[2] = 0x00;
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),
132 err, err_info)) {
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),
140 err, err_info)) {
141 if (*err != WTAP_ERR_SHORT_READ)
142 return WTAP_OPEN_ERROR;
143 return WTAP_OPEN_NOT_MINE;
146 for (;;) {
147 if (!wtap_read_bytes(wth->fh, search_encap, 4,
148 err, err_info)) {
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)
155 break;
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;
184 #if 0
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;
191 tm.tm_sec = sec%60;
192 tm.tm_isdst = -1;
193 #endif
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;
201 else {
202 *err = WTAP_ERR_UNSUPPORTED;
203 *err_info = ws_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
204 return WTAP_OPEN_ERROR;
207 #if 0
208 if (!wtap_read_bytes(wth->fh, &next_date, sizeof(struct frame_date),
209 err, err_info))
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),
216 err, err_info))
217 return WTAP_OPEN_ERROR;
219 #endif
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
236 * resolution.
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)
247 char fcs[2];
249 *data_offset = file_tell(wth->fh);
251 /* Read record. */
252 if (!radcom_read_rec(wth, wth->fh, rec, buf, err, err_info)) {
253 /* Read error or EOF */
254 return false;
257 if (wth->file_encap == WTAP_ENCAP_LAPB) {
258 /* Read the FCS.
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))
263 return false;
266 return true;
269 static bool
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)
275 return false;
277 /* Read record. */
278 if (!radcom_read_rec(wth, wth->random_fh, rec, buf, err,
279 err_info)) {
280 /* Read error or EOF */
281 if (*err == 0) {
282 /* EOF means "short read" in random-access mode */
283 *err = WTAP_ERR_SHORT_READ;
285 return false;
287 return true;
290 static bool
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;
296 uint32_t sec;
297 struct tm tm;
298 uint8_t atmhdr[8];
300 if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
301 return false;
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.
310 *err = 0;
311 return false;
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
318 * it.
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;
331 tm.tm_sec = sec%60;
332 tm.tm_isdst = -1;
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;
341 break;
343 case WTAP_ENCAP_LAPB:
344 rec->rec_header.packet_header.pseudo_header.dte_dce.flags = (hdr.dce & 0x1) ?
345 0x00 : FROM_DCE;
346 length -= 2; /* FCS */
347 real_length -= 2;
348 break;
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,
356 err_info))
357 return false; /* Read error */
358 length -= 8;
359 real_length -= 8;
360 break;
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 */
372 return true;
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),
385 NULL, NULL, NULL
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
403 * Local variables:
404 * c-basic-offset: 8
405 * tab-width: 8
406 * indent-tabs-mode: t
407 * End:
409 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
410 * :indentSize=8:tabSize=8:noTabs=false: