3 * $Id: netxray.c,v 1.25 2000/03/22 07:06:55 guy Exp $
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@xiexie.org>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include "file_wrappers.h"
36 /* Capture file header, *including* magic number, is padded to 128 bytes. */
37 #define CAPTUREFILE_HEADER_SIZE 128
39 /* Magic number in NetXRay files. */
40 static const char netxray_magic[] = { /* magic header */
44 /* NetXRay file header (minus magic number). */
46 char version[8]; /* version number */
47 guint32 start_time; /* UNIX time when capture started */
48 guint32 nframes; /* number of packets */
49 guint32 xxx; /* unknown */
50 guint32 start_offset; /* offset of first packet in capture */
51 guint32 end_offset; /* offset after last packet in capture */
52 guint32 xxy[3]; /* unknown */
53 guint16 network; /* datalink type */
55 guint32 timelo; /* lower 32 bits of time stamp of capture start */
56 guint32 timehi; /* upper 32 bits of time stamp of capture start */
62 /* Version number strings. */
63 static const char vers_1_0[] = {
64 '0', '0', '1', '.', '0', '0', '0', '\0'
67 static const char vers_1_1[] = {
68 '0', '0', '1', '.', '1', '0', '0', '\0'
71 static const char vers_2_001[] = {
72 '0', '0', '2', '.', '0', '0', '1', '\0'
75 /* NetXRay 1.x data record format - followed by frame data. */
76 struct netxrayrec_1_x_hdr {
77 guint32 timelo; /* lower 32 bits of time stamp */
78 guint32 timehi; /* upper 32 bits of time stamp */
79 guint16 orig_len; /* packet length */
80 guint16 incl_len; /* capture length */
81 guint32 xxx[4]; /* unknown */
84 /* NetXRay 2.x data record format - followed by frame data. */
85 struct netxrayrec_2_x_hdr {
86 guint32 timelo; /* lower 32 bits of time stamp */
87 guint32 timehi; /* upper 32 bits of time stamp */
88 guint16 orig_len; /* packet length */
89 guint16 incl_len; /* capture length */
90 guint32 xxx[7]; /* unknown */
93 static int netxray_read(wtap *wth, int *err);
94 static void netxray_close(wtap *wth);
95 static gboolean netxray_dump_1_1(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
96 const u_char *pd, int *err);
97 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err);
99 int netxray_open(wtap *wth, int *err)
102 char magic[sizeof netxray_magic];
103 struct netxray_hdr hdr;
108 static const int netxray_encap[] = {
111 WTAP_ENCAP_FDDI_BITSWAPPED,
112 WTAP_ENCAP_ETHERNET, /* WAN(PPP), but shaped like ethernet */
113 WTAP_ENCAP_UNKNOWN, /* LocalTalk */
114 WTAP_ENCAP_UNKNOWN, /* "DIX" - should not occur */
115 WTAP_ENCAP_UNKNOWN, /* ARCNET raw */
116 WTAP_ENCAP_UNKNOWN, /* ARCNET 878.2 */
117 WTAP_ENCAP_UNKNOWN, /* ATM */
118 WTAP_ENCAP_UNKNOWN, /* Wireless WAN */
119 WTAP_ENCAP_UNKNOWN /* IrDA */
121 #define NUM_NETXRAY_ENCAPS (sizeof netxray_encap / sizeof netxray_encap[0])
123 /* Read in the string that should be at the start of a NetXRay
125 file_seek(wth->fh, 0, SEEK_SET);
126 wth->data_offset = 0;
127 errno = WTAP_ERR_CANT_READ;
128 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
129 if (bytes_read != sizeof magic) {
130 *err = file_error(wth->fh);
135 wth->data_offset += sizeof magic;
137 if (memcmp(magic, netxray_magic, sizeof netxray_magic) != 0) {
141 /* Read the rest of the header. */
142 errno = WTAP_ERR_CANT_READ;
143 bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
144 if (bytes_read != sizeof hdr) {
145 *err = file_error(wth->fh);
150 wth->data_offset += sizeof hdr;
152 /* It appears that version 1.1 files (as produced by Windows
153 * Sniffer Pro 2.0.01) have the time stamp in microseconds,
154 * rather than the milliseconds version 1.0 files appear to have.
156 * It also appears that version 2.001 files (as produced by
157 * Windows(?) Sniffer Pro 2.50.05) have per-packet headers with
158 * some extra fields. */
159 if (memcmp(hdr.version, vers_1_0, sizeof vers_1_0) == 0) {
162 file_type = WTAP_FILE_NETXRAY_1_0;
163 } else if (memcmp(hdr.version, vers_1_1, sizeof vers_1_1) == 0) {
164 timeunit = 1000000.0;
166 file_type = WTAP_FILE_NETXRAY_1_1;
167 } else if (memcmp(hdr.version, vers_2_001, sizeof vers_2_001) == 0) {
168 timeunit = 1000000.0;
170 file_type = WTAP_FILE_NETXRAY_2_001;
172 g_message("netxray: version \"%.8s\" unsupported", hdr.version);
173 *err = WTAP_ERR_UNSUPPORTED;
177 hdr.network = pletohs(&hdr.network);
178 if (hdr.network >= NUM_NETXRAY_ENCAPS
179 || netxray_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
180 g_message("netxray: network type %u unknown or unsupported",
182 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
186 /* This is a netxray file */
187 wth->file_type = file_type;
188 wth->capture.netxray = g_malloc(sizeof(netxray_t));
189 wth->subtype_read = netxray_read;
190 wth->subtype_close = netxray_close;
191 wth->file_encap = netxray_encap[hdr.network];
192 wth->snapshot_length = 16384; /* XXX - not available in header */
193 wth->capture.netxray->start_time = pletohl(&hdr.start_time);
194 wth->capture.netxray->timeunit = timeunit;
195 t = (double)pletohl(&hdr.timelo)
196 + (double)pletohl(&hdr.timehi)*4294967296.0;
198 wth->capture.netxray->start_timestamp = t;
199 wth->capture.netxray->version_major = version_major;
200 /*wth->frame_number = 0;*/
201 /*wth->file_byte_offset = 0x10b;*/
203 /* Remember the offset after the last packet in the capture (which
204 * isn't necessarily the last packet in the file), as it appears
205 * there's sometimes crud after it. */
206 wth->capture.netxray->wrapped = 0;
207 wth->capture.netxray->end_offset = pletohl(&hdr.end_offset);
209 /* Seek to the beginning of the data records. */
210 file_seek(wth->fh, pletohl(&hdr.start_offset), SEEK_SET);
211 wth->data_offset = pletohl(&hdr.start_offset);
216 /* Read the next packet */
217 static int netxray_read(wtap *wth, int *err)
222 struct netxrayrec_1_x_hdr hdr_1_x;
223 struct netxrayrec_2_x_hdr hdr_2_x;
230 /* Have we reached the end of the packet data? */
231 if (wth->data_offset == wth->capture.netxray->end_offset) {
235 /* Read record header. */
236 switch (wth->capture.netxray->version_major) {
239 hdr_size = sizeof (struct netxrayrec_1_x_hdr);
243 hdr_size = sizeof (struct netxrayrec_2_x_hdr);
246 errno = WTAP_ERR_CANT_READ;
247 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
248 if (bytes_read != hdr_size) {
249 *err = file_error(wth->fh);
252 if (bytes_read != 0) {
253 *err = WTAP_ERR_SHORT_READ;
257 /* We're at EOF. Wrap? */
258 if (!wth->capture.netxray->wrapped) {
259 /* Yes. Remember that we did. */
260 wth->capture.netxray->wrapped = 1;
261 file_seek(wth->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET);
262 wth->data_offset = CAPTUREFILE_HEADER_SIZE;
266 /* We've already wrapped - don't wrap again. */
269 wth->data_offset += hdr_size;
271 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
272 buffer_assure_space(wth->frame_buffer, packet_size);
273 data_offset = wth->data_offset;
274 errno = WTAP_ERR_CANT_READ;
275 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
276 packet_size, wth->fh);
278 if (bytes_read != packet_size) {
279 *err = file_error(wth->fh);
281 *err = WTAP_ERR_SHORT_READ;
284 wth->data_offset += packet_size;
286 t = (double)pletohl(&hdr.hdr_1_x.timelo)
287 + (double)pletohl(&hdr.hdr_1_x.timehi)*4294967296.0;
288 t /= wth->capture.netxray->timeunit;
289 t -= wth->capture.netxray->start_timestamp;
290 wth->phdr.ts.tv_sec = wth->capture.netxray->start_time + (long)t;
291 wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(unsigned long)(t))
293 wth->phdr.caplen = packet_size;
294 wth->phdr.len = pletohs(&hdr.hdr_1_x.orig_len);
295 wth->phdr.pkt_encap = wth->file_encap;
301 netxray_close(wtap *wth)
303 g_free(wth->capture.netxray);
306 static const int wtap_encap[] = {
307 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
308 0, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
309 1, /* WTAP_ENCAP_TR -> NDIS Token Ring */
310 -1, /* WTAP_ENCAP_SLIP -> unsupported */
311 -1, /* WTAP_ENCAP_PPP -> unsupported */
312 2, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
313 2, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
314 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
315 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
316 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
317 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
318 -1, /* WTAP_ENCAP_LAPB -> unsupported */
319 -1, /* WTAP_ENCAP_ATM_SNIFFER -> unsupported */
320 -1 /* WTAP_ENCAP_NULL -> unsupported */
322 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
324 /* Returns 0 if we could write the specified encapsulation type,
325 an error indication otherwise. */
326 int netxray_dump_can_write_encap(int filetype, int encap)
328 /* Per-packet encapsulations aren't supported. */
329 if (encap == WTAP_ENCAP_PER_PACKET)
330 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
332 if (encap < 0 || encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
333 return WTAP_ERR_UNSUPPORTED_ENCAP;
338 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
340 gboolean netxray_dump_open_1_1(wtap_dumper *wdh, int *err)
342 /* This is a netxray file */
343 wdh->subtype_write = netxray_dump_1_1;
344 wdh->subtype_close = netxray_dump_close_1_1;
346 /* We can't fill in all the fields in the file header, as we
347 haven't yet written any packets. As we'll have to rewrite
348 the header when we've written out all the packets, we just
349 skip over the header for now. */
350 fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET);
352 wdh->private.netxray = g_malloc(sizeof(netxray_dump_t));
353 wdh->private.netxray->first_frame = TRUE;
354 wdh->private.netxray->start.tv_sec = 0;
355 wdh->private.netxray->start.tv_usec = 0;
356 wdh->private.netxray->nframes = 0;
361 /* Write a record for a packet to a dump file.
362 Returns TRUE on success, FALSE on failure. */
363 static gboolean netxray_dump_1_1(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
364 const u_char *pd, int *err)
366 netxray_dump_t *priv = wdh->private.netxray;
368 struct netxrayrec_1_x_hdr rec_hdr;
371 /* NetXRay/Windows Sniffer files have a capture start date/time
372 in the header, in a UNIX-style format, with one-second resolution,
373 and a start time stamp with microsecond resolution that's just
374 an arbitrary time stamp relative to some unknown time (boot
375 time?), and have times relative to the start time stamp in
376 the packet headers; pick the seconds value of the time stamp
377 of the first packet as the UNIX-style start date/time, and make
378 the high-resolution start time stamp 0, with the time stamp of
379 packets being the delta between the stamp of the packet and
380 the stamp of the first packet with the microseconds part 0. */
381 if (priv->first_frame) {
382 priv->first_frame = FALSE;
383 priv->start = phdr->ts;
386 /* build the header for each packet */
387 memset(&rec_hdr, '\0', sizeof(rec_hdr));
388 timestamp = (phdr->ts.tv_sec - priv->start.tv_sec)*1000000 +
390 rec_hdr.timelo = htolel(timestamp);
391 rec_hdr.timehi = htolel(0);
392 rec_hdr.orig_len = htoles(phdr->len);
393 rec_hdr.incl_len = htoles(phdr->caplen);
395 nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
396 if (nwritten != sizeof(rec_hdr)) {
400 *err = WTAP_ERR_SHORT_WRITE;
404 /* write the packet data */
405 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
406 if (nwritten != phdr->caplen) {
410 *err = WTAP_ERR_SHORT_WRITE;
419 /* Finish writing to a dump file.
420 Returns TRUE on success, FALSE on failure. */
421 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err)
423 char hdr_buf[CAPTUREFILE_HEADER_SIZE - sizeof(netxray_magic)];
424 netxray_dump_t *priv = wdh->private.netxray;
426 struct netxray_hdr file_hdr;
429 filelen = ftell(wdh->fh);
431 /* Go back to beginning */
432 fseek(wdh->fh, 0, SEEK_SET);
434 /* Rewrite the file header. */
435 nwritten = fwrite(netxray_magic, 1, sizeof netxray_magic, wdh->fh);
436 if (nwritten != sizeof netxray_magic) {
440 *err = WTAP_ERR_SHORT_WRITE;
444 /* "sniffer" version ? */
445 memset(&file_hdr, '\0', sizeof file_hdr);
446 memcpy(file_hdr.version, vers_1_1, sizeof vers_1_1);
447 file_hdr.start_time = htolel(priv->start.tv_sec);
448 file_hdr.nframes = htolel(priv->nframes);
449 file_hdr.start_offset = htolel(CAPTUREFILE_HEADER_SIZE);
450 file_hdr.end_offset = htolel(filelen);
451 file_hdr.network = htoles(wtap_encap[wdh->encap]);
452 file_hdr.timelo = htolel(0);
453 file_hdr.timehi = htolel(0);
455 memset(hdr_buf, '\0', sizeof hdr_buf);
456 memcpy(hdr_buf, &file_hdr, sizeof(file_hdr));
457 nwritten = fwrite(hdr_buf, 1, sizeof hdr_buf, wdh->fh);
458 if (nwritten != sizeof hdr_buf) {
462 *err = WTAP_ERR_SHORT_WRITE;