3 * $Id: netxray.c,v 1.43 2001/11/13 23:55:43 gram Exp $
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include "file_wrappers.h"
35 /* Capture file header, *including* magic number, is padded to 128 bytes. */
36 #define CAPTUREFILE_HEADER_SIZE 128
38 /* Magic number in NetXRay files. */
39 static const char netxray_magic[] = { /* magic header */
43 /* NetXRay file header (minus magic number). */
45 char version[8]; /* version number */
46 guint32 start_time; /* UNIX time when capture started */
47 guint32 nframes; /* number of packets */
48 guint32 xxx; /* unknown */
49 guint32 start_offset; /* offset of first packet in capture */
50 guint32 end_offset; /* offset after last packet in capture */
51 guint32 xxy[3]; /* unknown */
52 guint16 network; /* datalink type */
54 guint8 timeunit; /* encodes length of a tick */
56 guint32 timelo; /* lower 32 bits of time stamp of capture start */
57 guint32 timehi; /* upper 32 bits of time stamp of capture start */
64 * # of ticks that equal 1 second
66 static double TpS[] = { 1e6, 1193000.0, 1193180.0 };
67 #define NUM_NETXRAY_TIMEUNITS (sizeof TpS / sizeof TpS[0])
69 /* Version number strings. */
70 static const char vers_1_0[] = {
71 '0', '0', '1', '.', '0', '0', '0', '\0'
74 static const char vers_1_1[] = {
75 '0', '0', '1', '.', '1', '0', '0', '\0'
78 static const char vers_2_001[] = {
79 '0', '0', '2', '.', '0', '0', '1', '\0'
82 static const char vers_2_002[] = {
83 '0', '0', '2', '.', '0', '0', '2', '\0'
86 /* NetXRay 1.x data record format - followed by frame data. */
87 struct netxrayrec_1_x_hdr {
88 guint32 timelo; /* lower 32 bits of time stamp */
89 guint32 timehi; /* upper 32 bits of time stamp */
90 guint16 orig_len; /* packet length */
91 guint16 incl_len; /* capture length */
92 guint32 xxx[4]; /* unknown */
95 /* NetXRay 2.x data record format - followed by frame data. */
96 struct netxrayrec_2_x_hdr {
97 guint32 timelo; /* lower 32 bits of time stamp */
98 guint32 timehi; /* upper 32 bits of time stamp */
99 guint16 orig_len; /* packet length */
100 guint16 incl_len; /* capture length */
101 guint32 xxx[7]; /* unknown */
104 static gboolean netxray_read(wtap *wth, int *err, long *data_offset);
105 static void netxray_close(wtap *wth);
106 static gboolean netxray_dump_1_1(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
107 const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
108 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err);
110 int netxray_open(wtap *wth, int *err)
113 char magic[sizeof netxray_magic];
114 struct netxray_hdr hdr;
119 static const int netxray_encap[] = {
121 WTAP_ENCAP_TOKEN_RING,
122 WTAP_ENCAP_FDDI_BITSWAPPED,
123 WTAP_ENCAP_ETHERNET, /* WAN(PPP), but shaped like ethernet */
124 WTAP_ENCAP_UNKNOWN, /* LocalTalk */
125 WTAP_ENCAP_UNKNOWN, /* "DIX" - should not occur */
126 WTAP_ENCAP_UNKNOWN, /* ARCNET raw */
127 WTAP_ENCAP_UNKNOWN, /* ARCNET 878.2 */
128 WTAP_ENCAP_ATM_RFC1483, /* ATM */
129 WTAP_ENCAP_UNKNOWN, /* Wireless WAN */
130 WTAP_ENCAP_UNKNOWN /* IrDA */
132 #define NUM_NETXRAY_ENCAPS (sizeof netxray_encap / sizeof netxray_encap[0])
134 /* Read in the string that should be at the start of a NetXRay
136 errno = WTAP_ERR_CANT_READ;
137 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
138 if (bytes_read != sizeof magic) {
139 *err = file_error(wth->fh);
144 wth->data_offset += sizeof magic;
146 if (memcmp(magic, netxray_magic, sizeof netxray_magic) != 0) {
150 /* Read the rest of the header. */
151 errno = WTAP_ERR_CANT_READ;
152 bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
153 if (bytes_read != sizeof hdr) {
154 *err = file_error(wth->fh);
159 wth->data_offset += sizeof hdr;
161 /* It appears that version 1.1 files (as produced by Windows
162 * Sniffer Pro 2.0.01) have the time stamp in microseconds,
163 * rather than the milliseconds version 1.0 files appear to have.
165 * It also appears that version 2.001 files (as produced by
166 * Windows(?) Sniffer Pro 2.50.05) have per-packet headers with
167 * some extra fields. */
168 if (memcmp(hdr.version, vers_1_0, sizeof vers_1_0) == 0) {
171 file_type = WTAP_FILE_NETXRAY_1_0;
172 } else if (memcmp(hdr.version, vers_1_1, sizeof vers_1_1) == 0) {
173 timeunit = 1000000.0;
175 file_type = WTAP_FILE_NETXRAY_1_1;
176 } else if (memcmp(hdr.version, vers_2_001, sizeof vers_2_001) == 0
177 || memcmp(hdr.version, vers_2_002, sizeof vers_2_002) == 0) {
178 if (hdr.timeunit > NUM_NETXRAY_TIMEUNITS) {
179 g_message("netxray: Unknown timeunit %u",
181 *err = WTAP_ERR_UNSUPPORTED;
184 timeunit = TpS[hdr.timeunit];
186 file_type = WTAP_FILE_NETXRAY_2_00x;
188 g_message("netxray: version \"%.8s\" unsupported", hdr.version);
189 *err = WTAP_ERR_UNSUPPORTED;
193 hdr.network = pletohs(&hdr.network);
194 if (hdr.network >= NUM_NETXRAY_ENCAPS
195 || netxray_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
196 g_message("netxray: network type %u unknown or unsupported",
198 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
202 /* This is a netxray file */
203 wth->file_type = file_type;
204 wth->capture.netxray = g_malloc(sizeof(netxray_t));
205 wth->subtype_read = netxray_read;
206 wth->subtype_seek_read = wtap_def_seek_read;
207 wth->subtype_close = netxray_close;
208 wth->file_encap = netxray_encap[hdr.network];
209 wth->snapshot_length = 16384; /* XXX - not available in header */
210 wth->capture.netxray->start_time = pletohl(&hdr.start_time);
211 wth->capture.netxray->timeunit = timeunit;
212 t = (double)pletohl(&hdr.timelo)
213 + (double)pletohl(&hdr.timehi)*4294967296.0;
215 wth->capture.netxray->start_timestamp = t;
216 wth->capture.netxray->version_major = version_major;
217 /*wth->frame_number = 0;*/
218 /*wth->file_byte_offset = 0x10b;*/
220 /* Remember the offset after the last packet in the capture (which
221 * isn't necessarily the last packet in the file), as it appears
222 * there's sometimes crud after it. */
223 wth->capture.netxray->wrapped = 0;
224 wth->capture.netxray->end_offset = pletohl(&hdr.end_offset);
226 /* Seek to the beginning of the data records. */
227 file_seek(wth->fh, pletohl(&hdr.start_offset), SEEK_SET);
228 wth->data_offset = pletohl(&hdr.start_offset);
233 /* Read the next packet */
234 static gboolean netxray_read(wtap *wth, int *err, long *data_offset)
239 struct netxrayrec_1_x_hdr hdr_1_x;
240 struct netxrayrec_2_x_hdr hdr_2_x;
246 /* Have we reached the end of the packet data? */
247 if (wth->data_offset == wth->capture.netxray->end_offset) {
249 *err = 0; /* it's just an EOF, not an error */
252 /* Read record header. */
253 switch (wth->capture.netxray->version_major) {
256 hdr_size = sizeof (struct netxrayrec_1_x_hdr);
260 hdr_size = sizeof (struct netxrayrec_2_x_hdr);
263 errno = WTAP_ERR_CANT_READ;
264 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
265 if (bytes_read != hdr_size) {
266 *err = file_error(wth->fh);
269 if (bytes_read != 0) {
270 *err = WTAP_ERR_SHORT_READ;
274 /* We're at EOF. Wrap? */
275 if (!wth->capture.netxray->wrapped) {
276 /* Yes. Remember that we did. */
277 wth->capture.netxray->wrapped = 1;
278 file_seek(wth->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET);
279 wth->data_offset = CAPTUREFILE_HEADER_SIZE;
283 /* We've already wrapped - don't wrap again. */
286 wth->data_offset += hdr_size;
288 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
289 buffer_assure_space(wth->frame_buffer, packet_size);
290 *data_offset = wth->data_offset;
291 errno = WTAP_ERR_CANT_READ;
292 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
293 packet_size, wth->fh);
295 if ((guint32)bytes_read != packet_size) {
296 *err = file_error(wth->fh);
298 *err = WTAP_ERR_SHORT_READ;
301 wth->data_offset += packet_size;
303 t = (double)pletohl(&hdr.hdr_1_x.timelo)
304 + (double)pletohl(&hdr.hdr_1_x.timehi)*4294967296.0;
305 t /= wth->capture.netxray->timeunit;
306 t -= wth->capture.netxray->start_timestamp;
307 wth->phdr.ts.tv_sec = wth->capture.netxray->start_time + (long)t;
308 wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(unsigned long)(t))
310 wth->phdr.caplen = packet_size;
311 wth->phdr.len = pletohs(&hdr.hdr_1_x.orig_len);
312 wth->phdr.pkt_encap = wth->file_encap;
318 netxray_close(wtap *wth)
320 g_free(wth->capture.netxray);
323 static const int wtap_encap[] = {
324 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
325 0, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
326 1, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
327 -1, /* WTAP_ENCAP_SLIP -> unsupported */
328 -1, /* WTAP_ENCAP_PPP -> unsupported */
329 2, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
330 2, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
331 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
332 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
333 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
334 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
335 -1, /* WTAP_ENCAP_LAPB -> unsupported */
336 -1, /* WTAP_ENCAP_ATM_SNIFFER -> unsupported */
337 -1 /* WTAP_ENCAP_NULL -> unsupported */
339 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
341 /* Returns 0 if we could write the specified encapsulation type,
342 an error indication otherwise. */
343 int netxray_dump_can_write_encap(int filetype, int encap)
345 /* Per-packet encapsulations aren't supported. */
346 if (encap == WTAP_ENCAP_PER_PACKET)
347 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
349 if (encap < 0 || (unsigned)encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
350 return WTAP_ERR_UNSUPPORTED_ENCAP;
355 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
357 gboolean netxray_dump_open_1_1(wtap_dumper *wdh, int *err)
359 /* This is a netxray file */
360 wdh->subtype_write = netxray_dump_1_1;
361 wdh->subtype_close = netxray_dump_close_1_1;
363 /* We can't fill in all the fields in the file header, as we
364 haven't yet written any packets. As we'll have to rewrite
365 the header when we've written out all the packets, we just
366 skip over the header for now. */
367 fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET);
369 wdh->dump.netxray = g_malloc(sizeof(netxray_dump_t));
370 wdh->dump.netxray->first_frame = TRUE;
371 wdh->dump.netxray->start.tv_sec = 0;
372 wdh->dump.netxray->start.tv_usec = 0;
373 wdh->dump.netxray->nframes = 0;
378 /* Write a record for a packet to a dump file.
379 Returns TRUE on success, FALSE on failure. */
380 static gboolean netxray_dump_1_1(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
381 const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
383 netxray_dump_t *netxray = wdh->dump.netxray;
385 struct netxrayrec_1_x_hdr rec_hdr;
388 /* NetXRay/Windows Sniffer files have a capture start date/time
389 in the header, in a UNIX-style format, with one-second resolution,
390 and a start time stamp with microsecond resolution that's just
391 an arbitrary time stamp relative to some unknown time (boot
392 time?), and have times relative to the start time stamp in
393 the packet headers; pick the seconds value of the time stamp
394 of the first packet as the UNIX-style start date/time, and make
395 the high-resolution start time stamp 0, with the time stamp of
396 packets being the delta between the stamp of the packet and
397 the stamp of the first packet with the microseconds part 0. */
398 if (netxray->first_frame) {
399 netxray->first_frame = FALSE;
400 netxray->start = phdr->ts;
403 /* build the header for each packet */
404 memset(&rec_hdr, '\0', sizeof(rec_hdr));
405 timestamp = (phdr->ts.tv_sec - netxray->start.tv_sec)*1000000 +
407 rec_hdr.timelo = htolel(timestamp);
408 rec_hdr.timehi = htolel(0);
409 rec_hdr.orig_len = htoles(phdr->len);
410 rec_hdr.incl_len = htoles(phdr->caplen);
412 nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
413 if (nwritten != sizeof(rec_hdr)) {
414 if (nwritten == 0 && ferror(wdh->fh))
417 *err = WTAP_ERR_SHORT_WRITE;
421 /* write the packet data */
422 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
423 if (nwritten != phdr->caplen) {
424 if (nwritten == 0 && ferror(wdh->fh))
427 *err = WTAP_ERR_SHORT_WRITE;
436 /* Finish writing to a dump file.
437 Returns TRUE on success, FALSE on failure. */
438 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err)
440 char hdr_buf[CAPTUREFILE_HEADER_SIZE - sizeof(netxray_magic)];
441 netxray_dump_t *netxray = wdh->dump.netxray;
443 struct netxray_hdr file_hdr;
446 filelen = ftell(wdh->fh);
448 /* Go back to beginning */
449 fseek(wdh->fh, 0, SEEK_SET);
451 /* Rewrite the file header. */
452 nwritten = fwrite(netxray_magic, 1, sizeof netxray_magic, wdh->fh);
453 if (nwritten != sizeof netxray_magic) {
454 if (nwritten == 0 && ferror(wdh->fh))
457 *err = WTAP_ERR_SHORT_WRITE;
461 /* "sniffer" version ? */
462 memset(&file_hdr, '\0', sizeof file_hdr);
463 memcpy(file_hdr.version, vers_1_1, sizeof vers_1_1);
464 file_hdr.start_time = htolel(netxray->start.tv_sec);
465 file_hdr.nframes = htolel(netxray->nframes);
466 file_hdr.start_offset = htolel(CAPTUREFILE_HEADER_SIZE);
467 file_hdr.end_offset = htolel(filelen);
468 file_hdr.network = htoles(wtap_encap[wdh->encap]);
469 file_hdr.timelo = htolel(0);
470 file_hdr.timehi = htolel(0);
472 memset(hdr_buf, '\0', sizeof hdr_buf);
473 memcpy(hdr_buf, &file_hdr, sizeof(file_hdr));
474 nwritten = fwrite(hdr_buf, 1, sizeof hdr_buf, wdh->fh);
475 if (nwritten != sizeof hdr_buf) {
476 if (nwritten == 0 && ferror(wdh->fh))
479 *err = WTAP_ERR_SHORT_WRITE;