DCERPC: factor out proto_tree_add_dcerpc_drep()
[wireshark-wip.git] / wiretap / radcom.c
blob8efcb91efc648b1c473021693e8d90b52e910445
1 /* radcom.c
3 * $Id$
5 * Wiretap Library
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "config.h"
25 #include <errno.h>
26 #include <string.h>
27 #include "wtap-int.h"
28 #include "file_wrappers.h"
29 #include "buffer.h"
30 #include "radcom.h"
32 struct frame_date {
33 guint16 year;
34 guint8 month;
35 guint8 day;
36 guint32 sec; /* seconds since midnight */
37 guint32 usec;
40 struct unaligned_frame_date {
41 char year[2];
42 char month;
43 char day;
44 char sec[4]; /* seconds since midnight */
45 char usec[4];
48 /* Found at the beginning of the file. Bytes 2 and 3 (D2:00) seem to be
49 * different in some captures */
50 static const guint8 radcom_magic[8] = {
51 0x42, 0xD2, 0x00, 0x34, 0x12, 0x66, 0x22, 0x88
54 static const guint8 encap_magic[4] = {
55 0x00, 0x42, 0x43, 0x09
58 static const guint8 active_time_magic[11] = {
59 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65
62 /* RADCOM record header - followed by frame data (perhaps including FCS).
64 "data_length" appears to be the length of packet data following
65 the record header. It's 0 in the last record.
67 "length" appears to be the amount of captured packet data, and
68 "real_length" might be the actual length of the frame on the wire -
69 in some captures, it's the same as "length", and, in others,
70 it's greater than "length". In the last record, however, those
71 may have bogus values (or is that some kind of trailer record?).
73 "xxx" appears to be all-zero in all but the last record in one
74 capture; if so, perhaps this indicates that the last record is,
75 in fact, a trailer of some sort, and some field in the header
76 is a record type. */
77 struct radcomrec_hdr {
78 char xxx[4]; /* unknown */
79 char data_length[2]; /* packet length? */
80 char xxy[5]; /* unknown */
81 struct unaligned_frame_date date; /* date/time stamp of packet */
82 char real_length[2]; /* actual length of packet */
83 char length[2]; /* captured length of packet */
84 char xxz[2]; /* unknown */
85 char dce; /* DCE/DTE flag (and other flags?) */
86 char xxw[9]; /* unknown */
89 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
90 gint64 *data_offset);
91 static gboolean radcom_seek_read(wtap *wth, gint64 seek_off,
92 struct wtap_pkthdr *phdr, Buffer *buf, int length,
93 int *err, gchar **err_info);
94 static gboolean radcom_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
95 Buffer *buf, int *err, gchar **err_info);
96 static gboolean radcom_read_rec_data(FILE_T fh, guint8 *pd, int length,
97 int *err, gchar **err_info);
99 int radcom_open(wtap *wth, int *err, gchar **err_info)
101 int bytes_read;
102 guint8 r_magic[8], t_magic[11], search_encap[7];
103 struct frame_date start_date;
104 #if 0
105 guint32 sec;
106 struct tm tm;
107 #endif
109 /* Read in the string that should be at the start of a RADCOM file */
110 errno = WTAP_ERR_CANT_READ;
111 bytes_read = file_read(r_magic, 8, wth->fh);
112 if (bytes_read != 8) {
113 *err = file_error(wth->fh, err_info);
114 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
115 return -1;
116 return 0;
119 /* XXX: bytes 2 and 3 of the "magic" header seem to be different in some
120 * captures. We force them to our standard value so that the test
121 * succeeds (until we find if they have a special meaning, perhaps a
122 * version number ?) */
123 r_magic[1] = 0xD2;
124 r_magic[2] = 0x00;
125 if (memcmp(r_magic, radcom_magic, 8) != 0) {
126 return 0;
129 /* Look for the "Active Time" string. The "frame_date" structure should
130 * be located 32 bytes before the beginning of this string */
131 errno = WTAP_ERR_CANT_READ;
132 bytes_read = file_read(t_magic, 11, wth->fh);
133 if (bytes_read != 11) {
134 *err = file_error(wth->fh, err_info);
135 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
136 return -1;
137 return 0;
139 while (memcmp(t_magic, active_time_magic, 11) != 0)
141 if (file_seek(wth->fh, -10, SEEK_CUR, err) == -1)
142 return -1;
143 errno = WTAP_ERR_CANT_READ;
144 bytes_read = file_read(t_magic, 11, wth->fh);
145 if (bytes_read != 11) {
146 *err = file_error(wth->fh, err_info);
147 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
148 return -1;
149 return 0;
152 if (file_seek(wth->fh, -43, SEEK_CUR, err) == -1) return -1;
154 /* Get capture start time */
155 errno = WTAP_ERR_CANT_READ;
156 bytes_read = file_read(&start_date, sizeof(struct frame_date),
157 wth->fh);
158 if (bytes_read != sizeof(struct frame_date)) {
159 *err = file_error(wth->fh, err_info);
160 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
161 return -1;
162 return 0;
165 /* This is a radcom file */
166 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_RADCOM;
167 wth->subtype_read = radcom_read;
168 wth->subtype_seek_read = radcom_seek_read;
169 wth->snapshot_length = 0; /* not available in header, only in frame */
170 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
172 #if 0
173 tm.tm_year = pletohs(&start_date.year)-1900;
174 tm.tm_mon = start_date.month-1;
175 tm.tm_mday = start_date.day;
176 sec = pletohl(&start_date.sec);
177 tm.tm_hour = sec/3600;
178 tm.tm_min = (sec%3600)/60;
179 tm.tm_sec = sec%60;
180 tm.tm_isdst = -1;
181 #endif
182 if (file_seek(wth->fh, sizeof(struct frame_date), SEEK_CUR, err) == -1)
183 return -1;
185 errno = WTAP_ERR_CANT_READ;
186 bytes_read = file_read(search_encap, 4, wth->fh);
187 if (bytes_read != 4) {
188 goto read_error;
190 while (memcmp(encap_magic, search_encap, 4)) {
191 if (file_seek(wth->fh, -3, SEEK_CUR, err) == -1)
192 return -1;
193 errno = WTAP_ERR_CANT_READ;
194 bytes_read = file_read(search_encap, 4, wth->fh);
195 if (bytes_read != 4) {
196 goto read_error;
199 if (file_seek(wth->fh, 12, SEEK_CUR, err) == -1)
200 return -1;
201 errno = WTAP_ERR_CANT_READ;
202 bytes_read = file_read(search_encap, 4, wth->fh);
203 if (bytes_read != 4) {
204 goto read_error;
206 if (memcmp(search_encap, "LAPB", 4) == 0)
207 wth->file_encap = WTAP_ENCAP_LAPB;
208 else if (memcmp(search_encap, "Ethe", 4) == 0)
209 wth->file_encap = WTAP_ENCAP_ETHERNET;
210 else if (memcmp(search_encap, "ATM/", 4) == 0)
211 wth->file_encap = WTAP_ENCAP_ATM_RFC1483;
212 else {
213 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
214 *err_info = g_strdup_printf("radcom: network type \"%.4s\" unknown", search_encap);
215 return -1;
218 #if 0
219 bytes_read = file_read(&next_date, sizeof(struct frame_date), wth->fh);
220 errno = WTAP_ERR_CANT_READ;
221 if (bytes_read != sizeof(struct frame_date)) {
222 goto read_error;
225 while (memcmp(&start_date, &next_date, 4)) {
226 if (file_seek(wth->fh, 1-sizeof(struct frame_date), SEEK_CUR, err) == -1)
227 return -1;
228 errno = WTAP_ERR_CANT_READ;
229 bytes_read = file_read(&next_date, sizeof(struct frame_date),
230 wth->fh);
231 if (bytes_read != sizeof(struct frame_date)) {
232 goto read_error;
235 #endif
237 if (wth->file_encap == WTAP_ENCAP_ETHERNET) {
238 if (file_seek(wth->fh, 294, SEEK_CUR, err) == -1)
239 return -1;
240 } else if (wth->file_encap == WTAP_ENCAP_LAPB) {
241 if (file_seek(wth->fh, 297, SEEK_CUR, err) == -1)
242 return -1;
243 } else if (wth->file_encap == WTAP_ENCAP_ATM_RFC1483) {
244 if (file_seek(wth->fh, 504, SEEK_CUR, err) == -1)
245 return -1;
248 return 1;
250 read_error:
251 *err = file_error(wth->fh, err_info);
252 if (*err != 0)
253 return -1;
254 return 0;
257 /* Read the next packet */
258 static gboolean radcom_read(wtap *wth, int *err, gchar **err_info,
259 gint64 *data_offset)
261 int bytes_read;
262 char fcs[2];
264 *data_offset = file_tell(wth->fh);
266 /* Read record header. */
267 if (!radcom_read_rec(wth, wth->fh, &wth->phdr, wth->frame_buffer,
268 err, err_info)) {
269 /* Read error or EOF */
270 return FALSE;
273 if (wth->file_encap == WTAP_ENCAP_LAPB) {
274 /* Read the FCS.
275 XXX - should we have some way of indicating the
276 presence and size of an FCS to our caller?
277 That'd let us handle other file types as well. */
278 errno = WTAP_ERR_CANT_READ;
279 bytes_read = file_read(&fcs, sizeof fcs, wth->fh);
280 if (bytes_read != sizeof fcs) {
281 *err = file_error(wth->fh, err_info);
282 if (*err == 0)
283 *err = WTAP_ERR_SHORT_READ;
284 return FALSE;
288 return TRUE;
291 static gboolean
292 radcom_seek_read(wtap *wth, gint64 seek_off,
293 struct wtap_pkthdr *phdr, Buffer *buf, int length _U_,
294 int *err, gchar **err_info)
296 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
297 return FALSE;
299 /* Read record. */
300 if (!radcom_read_rec(wth, wth->random_fh, phdr, buf, err,
301 err_info)) {
302 /* Read error or EOF */
303 if (*err == 0) {
304 /* EOF means "short read" in random-access mode */
305 *err = WTAP_ERR_SHORT_READ;
307 return FALSE;
309 return TRUE;
312 static gboolean
313 radcom_read_rec(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
314 int *err, gchar **err_info)
316 struct radcomrec_hdr hdr;
317 int bytes_read;
318 guint16 data_length, real_length, length;
319 guint32 sec;
320 struct tm tm;
321 guint8 atmhdr[8];
323 errno = WTAP_ERR_CANT_READ;
324 bytes_read = file_read(&hdr, sizeof hdr, fh);
325 if (bytes_read != sizeof hdr) {
326 *err = file_error(fh, err_info);
327 if (*err == 0 && bytes_read != 0)
328 *err = WTAP_ERR_SHORT_READ;
329 return FALSE;
332 data_length = pletohs(&hdr.data_length);
333 if (data_length == 0) {
335 * The last record appears to have 0 in its "data_length"
336 * field, but non-zero values in other fields, so we
337 * check for that and treat it as an EOF indication.
339 *err = 0;
340 return FALSE;
342 length = pletohs(&hdr.length);
343 real_length = pletohs(&hdr.real_length);
345 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
347 tm.tm_year = pletohs(&hdr.date.year)-1900;
348 tm.tm_mon = (hdr.date.month&0x0f)-1;
349 tm.tm_mday = hdr.date.day;
350 sec = pletohl(&hdr.date.sec);
351 tm.tm_hour = sec/3600;
352 tm.tm_min = (sec%3600)/60;
353 tm.tm_sec = sec%60;
354 tm.tm_isdst = -1;
355 phdr->ts.secs = mktime(&tm);
356 phdr->ts.nsecs = pletohl(&hdr.date.usec) * 1000;
358 switch (wth->file_encap) {
360 case WTAP_ENCAP_ETHERNET:
361 /* XXX - is there an FCS? */
362 phdr->pseudo_header.eth.fcs_len = -1;
363 break;
365 case WTAP_ENCAP_LAPB:
366 phdr->pseudo_header.x25.flags = (hdr.dce & 0x1) ?
367 0x00 : FROM_DCE;
368 length -= 2; /* FCS */
369 real_length -= 2;
370 break;
372 case WTAP_ENCAP_ATM_RFC1483:
374 * XXX - is this stuff a pseudo-header?
375 * The direction appears to be in the "hdr.dce" field.
377 if (!radcom_read_rec_data(wth->fh, atmhdr, sizeof atmhdr, err,
378 err_info))
379 return FALSE; /* Read error */
380 length -= 8;
381 real_length -= 8;
382 break;
385 phdr->len = real_length;
386 phdr->caplen = length;
389 * Read the packet data.
391 if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
392 return FALSE; /* Read error */
394 return TRUE;
397 static gboolean
398 radcom_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
399 gchar **err_info)
401 int bytes_read;
403 errno = WTAP_ERR_CANT_READ;
404 bytes_read = file_read(pd, length, fh);
406 if (bytes_read != length) {
407 *err = file_error(fh, err_info);
408 if (*err == 0)
409 *err = WTAP_ERR_SHORT_READ;
410 return FALSE;
412 return TRUE;