1500e92dde7da2506be51d09b5d7863789122043
[obnox/wireshark/wip.git] / wiretap / netxray.c
1 /* netxray.c
2  *
3  * $Id: netxray.c,v 1.56 2002/06/07 07:27:35 guy Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  * 
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.
12  * 
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.
17  * 
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include "wtap-int.h"
31 #include "file_wrappers.h"
32 #include "netxray.h"
33 #include "buffer.h"
34
35 /* Capture file header, *including* magic number, is padded to 128 bytes. */
36 #define CAPTUREFILE_HEADER_SIZE 128
37
38 /* Magic number in NetXRay 1.x files. */
39 static const char old_netxray_magic[] = {
40         'V', 'L', '\0', '\0'
41 };
42
43 /* Magic number in NetXRay 2.0 and later, and Windows Sniffer, files. */
44 static const char netxray_magic[] = {   /* magic header */
45         'X', 'C', 'P', '\0'
46 };
47
48 /* NetXRay file header (minus magic number). */
49 struct netxray_hdr {
50         char    version[8];     /* version number */
51         guint32 start_time;     /* UNIX time when capture started */
52         guint32 nframes;        /* number of packets */
53         guint32 xxx;            /* unknown */
54         guint32 start_offset;   /* offset of first packet in capture */
55         guint32 end_offset;     /* offset after last packet in capture */
56         guint32 xxy[3];         /* unknown */
57         guint16 network;        /* datalink type */
58         guint8  xxz[2];
59         guint8  timeunit;       /* encodes length of a tick */
60         guint8  xxa[3];
61         guint32 timelo;         /* lower 32 bits of time stamp of capture start */
62         guint32 timehi;         /* upper 32 bits of time stamp of capture start */
63         /*
64          * XXX - other stuff.
65          */
66 };
67
68 /*
69  * # of ticks that equal 1 second
70  */
71 static double TpS[] = { 1e6, 1193000.0, 1193180.0 };
72 #define NUM_NETXRAY_TIMEUNITS (sizeof TpS / sizeof TpS[0])
73
74 /* Version number strings. */
75 static const char vers_1_0[] = {
76         '0', '0', '1', '.', '0', '0', '0', '\0'
77 };
78
79 static const char vers_1_1[] = {
80         '0', '0', '1', '.', '1', '0', '0', '\0'
81 };
82
83 static const char vers_2_001[] = {
84         '0', '0', '2', '.', '0', '0', '1', '\0'
85 };
86
87 static const char vers_2_002[] = {
88         '0', '0', '2', '.', '0', '0', '2', '\0'
89 };
90
91 /* Old NetXRay data record format - followed by frame data. */
92 struct old_netxrayrec_hdr {
93         guint32 timelo;         /* lower 32 bits of time stamp */
94         guint32 timehi;         /* upper 32 bits of time stamp */
95         guint16 len;            /* packet length */
96         guint8  xxx[6];         /* unknown */
97 };
98
99 /* NetXRay format version 1.x data record format - followed by frame data. */
100 struct netxrayrec_1_x_hdr {
101         guint32 timelo;         /* lower 32 bits of time stamp */
102         guint32 timehi;         /* upper 32 bits of time stamp */
103         guint16 orig_len;       /* packet length */
104         guint16 incl_len;       /* capture length */
105         guint8  xxx[16];        /* unknown */
106 };
107
108 /* NetXRay format version 2.x data record format - followed by frame data. */
109 struct netxrayrec_2_x_hdr {
110         guint32 timelo;         /* lower 32 bits of time stamp */
111         guint32 timehi;         /* upper 32 bits of time stamp */
112         guint16 orig_len;       /* packet length */
113         guint16 incl_len;       /* capture length */
114         guint8  xxx[28];        /* unknown */
115         /* For 802.11 captures, "xxx" data appears to include:
116            the channel, in xxx[12];
117            the data rate, in .5 Mb/s units, in xxx[13];
118            the signal level, as a percentage, in xxx[14];
119            0xff, in xxx[15]. */
120 };
121
122 /*
123  * Union of the data record headers.
124  */
125 union netxrayrec_hdr {
126         struct old_netxrayrec_hdr old_hdr;
127         struct netxrayrec_1_x_hdr hdr_1_x;
128         struct netxrayrec_2_x_hdr hdr_2_x;
129 };
130
131 static gboolean netxray_read(wtap *wth, int *err, long *data_offset);
132 static gboolean netxray_seek_read(wtap *wth, long seek_off,
133     union wtap_pseudo_header *pseudo_header, u_char *pd, int length, int *err);
134 static int netxray_read_rec_header(wtap *wth, FILE_T fh,
135     union netxrayrec_hdr *hdr, int *err);
136 static void netxray_set_pseudo_header(wtap *wth,
137     union wtap_pseudo_header *pseudo_header, union netxrayrec_hdr *hdr);
138 static gboolean netxray_read_rec_data(FILE_T fh, guint8 *data_ptr,
139     guint32 packet_size, int *err);
140 static void netxray_close(wtap *wth);
141 static gboolean netxray_dump_1_1(wtap_dumper *wdh,
142     const struct wtap_pkthdr *phdr,
143     const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
144 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err);
145 static gboolean netxray_dump_2_0(wtap_dumper *wdh,
146     const struct wtap_pkthdr *phdr,
147     const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
148 static gboolean netxray_dump_close_2_0(wtap_dumper *wdh, int *err);
149
150 int netxray_open(wtap *wth, int *err)
151 {
152         int bytes_read;
153         char magic[sizeof netxray_magic];
154         gboolean is_old;
155         struct netxray_hdr hdr;
156         double timeunit;
157         int version_major;
158         int file_type;
159         double t;
160         static const int netxray_encap[] = {
161                 WTAP_ENCAP_ETHERNET,
162                 WTAP_ENCAP_TOKEN_RING,
163                 WTAP_ENCAP_FDDI_BITSWAPPED,
164                 WTAP_ENCAP_ETHERNET,    /* WAN(PPP), but shaped like Ethernet */
165                 WTAP_ENCAP_UNKNOWN,     /* LocalTalk */
166                 WTAP_ENCAP_UNKNOWN,     /* "DIX" - should not occur */
167                 WTAP_ENCAP_UNKNOWN,     /* ARCNET raw */
168                 WTAP_ENCAP_UNKNOWN,     /* ARCNET 878.2 */
169                 WTAP_ENCAP_ATM_RFC1483, /* ATM */
170                 WTAP_ENCAP_IEEE_802_11_WITH_RADIO,
171                                         /* Wireless WAN with radio information */
172                 WTAP_ENCAP_UNKNOWN      /* IrDA */
173         };
174         #define NUM_NETXRAY_ENCAPS (sizeof netxray_encap / sizeof netxray_encap[0])
175
176         /* Read in the string that should be at the start of a NetXRay
177          * file */
178         errno = WTAP_ERR_CANT_READ;
179         bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
180         if (bytes_read != sizeof magic) {
181                 *err = file_error(wth->fh);
182                 if (*err != 0)
183                         return -1;
184                 return 0;
185         }
186         wth->data_offset += sizeof magic;
187
188         if (memcmp(magic, netxray_magic, sizeof magic) == 0) {
189                 is_old = FALSE;
190         } else if (memcmp(magic, old_netxray_magic, sizeof magic) == 0) {
191                 is_old = TRUE;
192         } else {
193                 return 0;
194         }
195
196         /* Read the rest of the header. */
197         errno = WTAP_ERR_CANT_READ;
198         bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
199         if (bytes_read != sizeof hdr) {
200                 *err = file_error(wth->fh);
201                 if (*err != 0)
202                         return -1;
203                 return 0;
204         }
205         wth->data_offset += sizeof hdr;
206
207         if (is_old) {
208                 timeunit = 1000.0;
209                 version_major = 0;
210                 file_type = WTAP_FILE_NETXRAY_OLD;
211         } else {
212                 /* It appears that version 1.1 files (as produced by Windows
213                  * Sniffer Pro 2.0.01) have the time stamp in microseconds,
214                  * rather than the milliseconds version 1.0 files appear to
215                  * have.
216                  *
217                  * It also appears that version 2.001 files (as produced by
218                  * Windows(?) Sniffer Pro 2.50.05) have per-packet headers with
219                  * some extra fields. */
220                 if (memcmp(hdr.version, vers_1_0, sizeof vers_1_0) == 0) {
221                         timeunit = 1000.0;
222                         version_major = 1;
223                         file_type = WTAP_FILE_NETXRAY_1_0;
224                 } else if (memcmp(hdr.version, vers_1_1, sizeof vers_1_1) == 0) {
225                         timeunit = 1000000.0;
226                         version_major = 1;
227                         file_type = WTAP_FILE_NETXRAY_1_1;
228                 } else if (memcmp(hdr.version, vers_2_001, sizeof vers_2_001) == 0
229                     || memcmp(hdr.version, vers_2_002, sizeof vers_2_002) == 0) {
230                         if (hdr.timeunit > NUM_NETXRAY_TIMEUNITS) {
231                                 g_message("netxray: Unknown timeunit %u",
232                                           hdr.timeunit);
233                                 *err = WTAP_ERR_UNSUPPORTED;
234                                 return -1;
235                         }
236                         timeunit = TpS[hdr.timeunit];
237                         version_major = 2;
238                         file_type = WTAP_FILE_NETXRAY_2_00x;
239                 } else {
240                         g_message("netxray: version \"%.8s\" unsupported", hdr.version);
241                         *err = WTAP_ERR_UNSUPPORTED;
242                         return -1;
243                 }
244         }
245
246         hdr.network = pletohs(&hdr.network);
247         if (hdr.network >= NUM_NETXRAY_ENCAPS
248             || netxray_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
249                 g_message("netxray: network type %u unknown or unsupported",
250                     hdr.network);
251                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
252                 return -1;
253         }
254
255         /* This is a netxray file */
256         wth->file_type = file_type;
257         wth->capture.netxray = g_malloc(sizeof(netxray_t));
258         wth->subtype_read = netxray_read;
259         wth->subtype_seek_read = netxray_seek_read;
260         wth->subtype_close = netxray_close;
261         wth->file_encap = netxray_encap[hdr.network];
262         wth->snapshot_length = 0;       /* not available in header */
263         wth->capture.netxray->start_time = pletohl(&hdr.start_time);
264         wth->capture.netxray->timeunit = timeunit;
265         t = (double)pletohl(&hdr.timelo)
266             + (double)pletohl(&hdr.timehi)*4294967296.0;
267         t = t/timeunit;
268         wth->capture.netxray->start_timestamp = t;
269         wth->capture.netxray->version_major = version_major;
270
271         /*
272          * End-of-packet padding.  802.11 captures appear to have four
273          * bytes of it.
274          *
275          * We've seen what appears to be an FCS at the end of some frames
276          * in some Ethernet captures, but this stuff appears to be just
277          * padding - Sniffers don't show it, and it doesn't have values
278          * that look like FCS values.
279          */
280         wth->capture.netxray->padding = 0;
281         if (netxray_encap[hdr.network] == WTAP_ENCAP_IEEE_802_11_WITH_RADIO) {
282                 wth->capture.netxray->padding = 4;
283         }
284         /*wth->frame_number = 0;*/
285         /*wth->file_byte_offset = 0x10b;*/
286
287         /* Remember the offset after the last packet in the capture (which
288          * isn't necessarily the last packet in the file), as it appears
289          * there's sometimes crud after it. */
290         wth->capture.netxray->wrapped = FALSE;
291         wth->capture.netxray->end_offset = pletohl(&hdr.end_offset);
292
293         /* Seek to the beginning of the data records. */
294         if (file_seek(wth->fh, pletohl(&hdr.start_offset), SEEK_SET, err) == -1) {
295                 g_free(wth->capture.netxray);
296                 return -1;
297         }       
298         wth->data_offset = pletohl(&hdr.start_offset);
299
300         return 1;
301 }
302
303 /* Read the next packet */
304 static gboolean netxray_read(wtap *wth, int *err, long *data_offset)
305 {
306         guint32 packet_size;
307         union netxrayrec_hdr hdr;
308         int     hdr_size;
309         double  t;
310
311 reread:
312         /* Have we reached the end of the packet data? */
313         if (wth->data_offset == wth->capture.netxray->end_offset) {
314                 /* Yes. */
315                 *err = 0;       /* it's just an EOF, not an error */
316                 return FALSE;
317         }
318         /* Read record header. */
319         hdr_size = netxray_read_rec_header(wth, wth->fh, &hdr, err);
320         if (hdr_size == 0) {
321                 /*
322                  * Error or EOF.
323                  */
324                 if (*err != 0) {
325                         /*
326                          * Error of some sort; give up.
327                          */
328                         return FALSE;
329                 }
330
331                 /* We're at EOF.  Wrap? */
332                 if (!wth->capture.netxray->wrapped) {
333                         /* Yes.  Remember that we did. */
334                         wth->capture.netxray->wrapped = TRUE;
335                         if (file_seek(wth->fh, CAPTUREFILE_HEADER_SIZE,
336                             SEEK_SET, err) == -1)
337                                 return FALSE;
338                         wth->data_offset = CAPTUREFILE_HEADER_SIZE;
339                         goto reread;
340                 }
341
342                 /* We've already wrapped - don't wrap again. */
343                 return FALSE;
344         }
345
346         /*
347          * Return the offset of the record header, so we can reread it
348          * if we go back to this frame.
349          */
350         *data_offset = wth->data_offset;
351         wth->data_offset += hdr_size;
352
353         /*
354          * Read the packet data.
355          */
356         if (wth->capture.netxray->version_major == 0)
357                 packet_size = pletohs(&hdr.old_hdr.len);
358         else
359                 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
360         buffer_assure_space(wth->frame_buffer, packet_size);
361         if (!netxray_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
362             packet_size, err))
363                 return FALSE;
364         wth->data_offset += packet_size;
365
366         /*
367          * Set the pseudo-header.
368          */
369         netxray_set_pseudo_header(wth, &wth->pseudo_header, &hdr);
370
371         if (wth->capture.netxray->version_major == 0) {
372                 t = (double)pletohl(&hdr.old_hdr.timelo)
373                     + (double)pletohl(&hdr.old_hdr.timehi)*4294967296.0;
374                 t /= wth->capture.netxray->timeunit;
375                 t -= wth->capture.netxray->start_timestamp;
376                 wth->phdr.ts.tv_sec = wth->capture.netxray->start_time + (long)t;
377                 wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(unsigned long)(t))
378                         *1.0e6);
379                 /*
380                  * We subtract the padding from the packet size, so our caller
381                  * doesn't see it.
382                  */
383                 wth->phdr.caplen = packet_size - wth->capture.netxray->padding;
384                 wth->phdr.len = wth->phdr.caplen;
385         } else {
386                 t = (double)pletohl(&hdr.hdr_1_x.timelo)
387                     + (double)pletohl(&hdr.hdr_1_x.timehi)*4294967296.0;
388                 t /= wth->capture.netxray->timeunit;
389                 t -= wth->capture.netxray->start_timestamp;
390                 wth->phdr.ts.tv_sec = wth->capture.netxray->start_time + (long)t;
391                 wth->phdr.ts.tv_usec = (unsigned long)((t-(double)(unsigned long)(t))
392                         *1.0e6);
393                 /*
394                  * We subtract the padding from the packet size, so our caller
395                  * doesn't see it.
396                  */
397                 wth->phdr.caplen = packet_size - wth->capture.netxray->padding;
398                 wth->phdr.len = pletohs(&hdr.hdr_1_x.orig_len) - wth->capture.netxray->padding;
399         }
400         wth->phdr.pkt_encap = wth->file_encap;
401
402         return TRUE;
403 }
404
405 static gboolean
406 netxray_seek_read(wtap *wth, long seek_off,
407     union wtap_pseudo_header *pseudo_header, u_char *pd, int length, int *err)
408 {
409         union netxrayrec_hdr hdr;
410
411         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
412                 return FALSE;
413
414         if (!netxray_read_rec_header(wth, wth->random_fh, &hdr, err)) {
415                 if (*err == 0) {
416                         /*
417                          * EOF - we report that as a short read, as
418                          * we've read this once and know that it
419                          * should be there.
420                          */
421                         *err = WTAP_ERR_SHORT_READ;
422                 }
423                 return FALSE;
424         }
425
426         /*
427          * Set the pseudo-header.
428          */
429         netxray_set_pseudo_header(wth, pseudo_header, &hdr);
430
431         /*
432          * Read the packet data.
433          */
434         return netxray_read_rec_data(wth->random_fh, pd, length, err);
435 }
436
437 static int
438 netxray_read_rec_header(wtap *wth, FILE_T fh, union netxrayrec_hdr *hdr,
439     int *err)
440 {
441         int     bytes_read;
442         int     hdr_size = 0;
443
444         /* Read record header. */
445         switch (wth->capture.netxray->version_major) {
446
447         case 0:
448                 hdr_size = sizeof (struct old_netxrayrec_hdr);
449                 break;
450
451         case 1:
452                 hdr_size = sizeof (struct netxrayrec_1_x_hdr);
453                 break;
454
455         case 2:
456                 hdr_size = sizeof (struct netxrayrec_2_x_hdr);
457                 break;
458         }
459         errno = WTAP_ERR_CANT_READ;
460         bytes_read = file_read(hdr, 1, hdr_size, fh);
461         if (bytes_read != hdr_size) {
462                 *err = file_error(wth->fh);
463                 if (*err != 0)
464                         return 0;
465                 if (bytes_read != 0) {
466                         *err = WTAP_ERR_SHORT_READ;
467                         return 0;
468                 }
469
470                 /*
471                  * We're at EOF.  "*err" is 0; we return FALSE - that
472                  * combination tells our caller we're at EOF.
473                  */
474                 return 0;
475         }
476         return hdr_size;
477 }
478
479 static void
480 netxray_set_pseudo_header(wtap *wth, union wtap_pseudo_header *pseudo_header,
481     union netxrayrec_hdr *hdr)
482 {
483         /*
484          * If this is 802.11, set the pseudo-header.
485          */
486         if (wth->capture.netxray->version_major == 2 &&
487             wth->file_encap == WTAP_ENCAP_IEEE_802_11_WITH_RADIO) {
488                 pseudo_header->ieee_802_11.channel = hdr->hdr_2_x.xxx[12];
489                 pseudo_header->ieee_802_11.data_rate = hdr->hdr_2_x.xxx[13];
490                 pseudo_header->ieee_802_11.signal_level = hdr->hdr_2_x.xxx[14];
491         }
492 }
493
494 static gboolean
495 netxray_read_rec_data(FILE_T fh, guint8 *data_ptr, guint32 packet_size,
496     int *err)
497 {
498         int     bytes_read;
499
500         errno = WTAP_ERR_CANT_READ;
501         bytes_read = file_read(data_ptr, 1, packet_size, fh);
502
503         if (bytes_read <= 0 || (guint32)bytes_read != packet_size) {
504                 *err = file_error(fh);
505                 if (*err == 0)
506                         *err = WTAP_ERR_SHORT_READ;
507                 return FALSE;
508         }
509         return TRUE;
510 }
511
512 static void
513 netxray_close(wtap *wth)
514 {
515         g_free(wth->capture.netxray);
516 }
517
518 static const int wtap_encap[] = {
519     -1,         /* WTAP_ENCAP_UNKNOWN -> unsupported */
520     0,          /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
521     1,          /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
522     -1,         /* WTAP_ENCAP_SLIP -> unsupported */
523     -1,         /* WTAP_ENCAP_PPP -> unsupported */
524     2,          /* WTAP_ENCAP_FDDI -> NDIS FDDI */
525     2,          /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
526     -1,         /* WTAP_ENCAP_RAW_IP -> unsupported */
527     -1,         /* WTAP_ENCAP_ARCNET -> unsupported */
528     -1,         /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
529     -1,         /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
530     -1,         /* WTAP_ENCAP_LAPB -> unsupported */
531     -1,         /* WTAP_ENCAP_ATM_SNIFFER -> unsupported */
532     -1          /* WTAP_ENCAP_NULL -> unsupported */
533 };
534 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
535
536 /* Returns 0 if we could write the specified encapsulation type,
537    an error indication otherwise. */
538 int netxray_dump_can_write_encap(int encap)
539 {
540     /* Per-packet encapsulations aren't supported. */
541     if (encap == WTAP_ENCAP_PER_PACKET)
542         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
543
544     if (encap < 0 || (unsigned)encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
545         return WTAP_ERR_UNSUPPORTED_ENCAP;
546
547     return 0;
548 }
549
550 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
551    failure */
552 gboolean netxray_dump_open_1_1(wtap_dumper *wdh, int *err)
553 {
554     /* This is a netxray file */
555     wdh->subtype_write = netxray_dump_1_1;
556     wdh->subtype_close = netxray_dump_close_1_1;
557
558     /* We can't fill in all the fields in the file header, as we
559        haven't yet written any packets.  As we'll have to rewrite
560        the header when we've written out all the packets, we just
561        skip over the header for now. */
562     if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
563         *err = errno;
564         return FALSE;
565     }
566
567     wdh->dump.netxray = g_malloc(sizeof(netxray_dump_t));
568     wdh->dump.netxray->first_frame = TRUE;
569     wdh->dump.netxray->start.tv_sec = 0;
570     wdh->dump.netxray->start.tv_usec = 0;
571     wdh->dump.netxray->nframes = 0;
572
573     return TRUE;
574 }
575
576 /* Write a record for a packet to a dump file.
577    Returns TRUE on success, FALSE on failure. */
578 static gboolean netxray_dump_1_1(wtap_dumper *wdh,
579         const struct wtap_pkthdr *phdr,
580         const union wtap_pseudo_header *pseudo_header _U_,
581         const u_char *pd, int *err)
582 {
583     netxray_dump_t *netxray = wdh->dump.netxray;
584     guint32 timestamp;
585     struct netxrayrec_1_x_hdr rec_hdr;
586     size_t nwritten;
587
588     /* NetXRay/Windows Sniffer files have a capture start date/time
589        in the header, in a UNIX-style format, with one-second resolution,
590        and a start time stamp with microsecond resolution that's just
591        an arbitrary time stamp relative to some unknown time (boot
592        time?), and have times relative to the start time stamp in
593        the packet headers; pick the seconds value of the time stamp
594        of the first packet as the UNIX-style start date/time, and make
595        the high-resolution start time stamp 0, with the time stamp of
596        packets being the delta between the stamp of the packet and
597        the stamp of the first packet with the microseconds part 0. */
598     if (netxray->first_frame) {
599         netxray->first_frame = FALSE;
600         netxray->start = phdr->ts;
601     }
602
603     /* build the header for each packet */
604     memset(&rec_hdr, '\0', sizeof(rec_hdr));
605     timestamp = (phdr->ts.tv_sec - netxray->start.tv_sec)*1000000 +
606         phdr->ts.tv_usec;
607     rec_hdr.timelo = htolel(timestamp);
608     rec_hdr.timehi = htolel(0);
609     rec_hdr.orig_len = htoles(phdr->len);
610     rec_hdr.incl_len = htoles(phdr->caplen);
611         
612     nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
613     if (nwritten != sizeof(rec_hdr)) {
614         if (nwritten == 0 && ferror(wdh->fh))
615             *err = errno;
616         else
617             *err = WTAP_ERR_SHORT_WRITE;
618         return FALSE;
619     }
620
621     /* write the packet data */ 
622     nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
623     if (nwritten != phdr->caplen) {
624         if (nwritten == 0 && ferror(wdh->fh))
625             *err = errno;
626         else
627             *err = WTAP_ERR_SHORT_WRITE;
628         return FALSE;
629     }
630         
631     netxray->nframes++;
632
633     return TRUE;
634 }
635
636 /* Finish writing to a dump file.
637    Returns TRUE on success, FALSE on failure. */
638 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err)
639 {
640     char hdr_buf[CAPTUREFILE_HEADER_SIZE - sizeof(netxray_magic)];
641     netxray_dump_t *netxray = wdh->dump.netxray;
642     guint32 filelen;
643     struct netxray_hdr file_hdr;
644     size_t nwritten;
645
646     filelen = ftell(wdh->fh);
647
648     /* Go back to beginning */
649     fseek(wdh->fh, 0, SEEK_SET);
650
651     /* Rewrite the file header. */
652     nwritten = fwrite(netxray_magic, 1, sizeof netxray_magic, wdh->fh);
653     if (nwritten != sizeof netxray_magic) {
654         if (err != NULL) {
655             if (nwritten == 0 && ferror(wdh->fh))
656                 *err = errno;
657             else
658                 *err = WTAP_ERR_SHORT_WRITE;
659         }
660         return FALSE;
661     }
662
663     /* "sniffer" version ? */
664     memset(&file_hdr, '\0', sizeof file_hdr);
665     memcpy(file_hdr.version, vers_1_1, sizeof vers_1_1);
666     file_hdr.start_time = htolel(netxray->start.tv_sec);
667     file_hdr.nframes = htolel(netxray->nframes);
668     file_hdr.start_offset = htolel(CAPTUREFILE_HEADER_SIZE);
669     file_hdr.end_offset = htolel(filelen);
670     file_hdr.network = htoles(wtap_encap[wdh->encap]);
671     file_hdr.timelo = htolel(0);
672     file_hdr.timehi = htolel(0);
673
674     memset(hdr_buf, '\0', sizeof hdr_buf);
675     memcpy(hdr_buf, &file_hdr, sizeof(file_hdr));
676     nwritten = fwrite(hdr_buf, 1, sizeof hdr_buf, wdh->fh);
677     if (nwritten != sizeof hdr_buf) {
678         if (err != NULL) {
679             if (nwritten == 0 && ferror(wdh->fh))
680                 *err = errno;
681             else
682                 *err = WTAP_ERR_SHORT_WRITE;
683         }
684         return FALSE;
685     }
686         
687     return TRUE;
688 }
689
690 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
691    failure */
692 gboolean netxray_dump_open_2_0(wtap_dumper *wdh, int *err)
693 {
694     /* This is a netxray file */
695     wdh->subtype_write = netxray_dump_2_0;
696     wdh->subtype_close = netxray_dump_close_2_0;
697
698     /* We can't fill in all the fields in the file header, as we
699        haven't yet written any packets.  As we'll have to rewrite
700        the header when we've written out all the packets, we just
701        skip over the header for now. */
702     if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
703         *err = errno;
704         return FALSE;
705     }
706
707     wdh->dump.netxray = g_malloc(sizeof(netxray_dump_t));
708     wdh->dump.netxray->first_frame = TRUE;
709     wdh->dump.netxray->start.tv_sec = 0;
710     wdh->dump.netxray->start.tv_usec = 0;
711     wdh->dump.netxray->nframes = 0;
712
713     return TRUE;
714 }
715
716 /* Write a record for a packet to a dump file.
717    Returns TRUE on success, FALSE on failure. */
718 static gboolean netxray_dump_2_0(wtap_dumper *wdh,
719         const struct wtap_pkthdr *phdr,
720         const union wtap_pseudo_header *pseudo_header _U_,
721         const u_char *pd, int *err)
722 {
723     netxray_dump_t *netxray = wdh->dump.netxray;
724     guint32 timestamp;
725     struct netxrayrec_2_x_hdr rec_hdr;
726     size_t nwritten;
727
728     /* NetXRay/Windows Sniffer files have a capture start date/time
729        in the header, in a UNIX-style format, with one-second resolution,
730        and a start time stamp with microsecond resolution that's just
731        an arbitrary time stamp relative to some unknown time (boot
732        time?), and have times relative to the start time stamp in
733        the packet headers; pick the seconds value of the time stamp
734        of the first packet as the UNIX-style start date/time, and make
735        the high-resolution start time stamp 0, with the time stamp of
736        packets being the delta between the stamp of the packet and
737        the stamp of the first packet with the microseconds part 0. */
738     if (netxray->first_frame) {
739         netxray->first_frame = FALSE;
740         netxray->start = phdr->ts;
741     }
742
743     /* build the header for each packet */
744     memset(&rec_hdr, '\0', sizeof(rec_hdr));
745     timestamp = (phdr->ts.tv_sec - netxray->start.tv_sec)*1000000 +
746         phdr->ts.tv_usec;
747     rec_hdr.timelo = htolel(timestamp);
748     rec_hdr.timehi = htolel(0);
749     rec_hdr.orig_len = htoles(phdr->len);
750     rec_hdr.incl_len = htoles(phdr->caplen);
751
752     if (phdr->pkt_encap == WTAP_ENCAP_IEEE_802_11_WITH_RADIO)
753     {
754         rec_hdr.xxx[12] = pseudo_header->ieee_802_11.channel;
755         rec_hdr.xxx[13] = pseudo_header->ieee_802_11.data_rate;
756         rec_hdr.xxx[14] = pseudo_header->ieee_802_11.signal_level;
757     }
758
759     nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
760     if (nwritten != sizeof(rec_hdr)) {
761         if (nwritten == 0 && ferror(wdh->fh))
762             *err = errno;
763         else
764             *err = WTAP_ERR_SHORT_WRITE;
765         return FALSE;
766     }
767
768     /* write the packet data */ 
769     nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
770     if (nwritten != phdr->caplen) {
771         if (nwritten == 0 && ferror(wdh->fh))
772             *err = errno;
773         else
774             *err = WTAP_ERR_SHORT_WRITE;
775         return FALSE;
776     }
777         
778     netxray->nframes++;
779
780     return TRUE;
781 }
782
783 /* Finish writing to a dump file.
784    Returns TRUE on success, FALSE on failure. */
785 static gboolean netxray_dump_close_2_0(wtap_dumper *wdh, int *err)
786 {
787     char hdr_buf[CAPTUREFILE_HEADER_SIZE - sizeof(netxray_magic)];
788     netxray_dump_t *netxray = wdh->dump.netxray;
789     guint32 filelen;
790     struct netxray_hdr file_hdr;
791     size_t nwritten;
792
793     filelen = ftell(wdh->fh);
794
795     /* Go back to beginning */
796     fseek(wdh->fh, 0, SEEK_SET);
797
798     /* Rewrite the file header. */
799     nwritten = fwrite(netxray_magic, 1, sizeof netxray_magic, wdh->fh);
800     if (nwritten != sizeof netxray_magic) {
801         if (err != NULL) {
802             if (nwritten == 0 && ferror(wdh->fh))
803                 *err = errno;
804             else
805                 *err = WTAP_ERR_SHORT_WRITE;
806         }
807         return FALSE;
808     }
809
810     /* "sniffer" version ? */
811     memset(&file_hdr, '\0', sizeof file_hdr);
812     memcpy(file_hdr.version, vers_2_001, sizeof vers_2_001);
813     file_hdr.start_time = htolel(netxray->start.tv_sec);
814     file_hdr.nframes = htolel(netxray->nframes);
815     file_hdr.start_offset = htolel(CAPTUREFILE_HEADER_SIZE);
816     file_hdr.end_offset = htolel(filelen);
817     file_hdr.network = htoles(wtap_encap[wdh->encap]);
818     file_hdr.timelo = htolel(0);
819     file_hdr.timehi = htolel(0);
820
821     memset(hdr_buf, '\0', sizeof hdr_buf);
822     memcpy(hdr_buf, &file_hdr, sizeof(file_hdr));
823     nwritten = fwrite(hdr_buf, 1, sizeof hdr_buf, wdh->fh);
824     if (nwritten != sizeof hdr_buf) {
825         if (err != NULL) {
826             if (nwritten == 0 && ferror(wdh->fh))
827                 *err = errno;
828             else
829                 *err = WTAP_ERR_SHORT_WRITE;
830         }
831         return FALSE;
832     }
833         
834     return TRUE;
835 }