19cdf277676cb69a8321174b8a8fc79bd24a8fd7
[obnox/wireshark/wip.git] / wiretap / netxray.c
1 /* netxray.c
2  *
3  * $Id: netxray.c,v 1.58 2002/07/29 06:09:59 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, guchar *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 guchar *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 guchar *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, guchar *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, gboolean cant_seek, int *err)
553 {
554     /* This is a NetXRay file.  We can't fill in some fields in the header
555        until all the packets have been written, so we can't write to a
556        pipe. */
557     if (cant_seek) {
558         *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
559         return FALSE;
560     }
561
562     wdh->subtype_write = netxray_dump_1_1;
563     wdh->subtype_close = netxray_dump_close_1_1;
564
565     /* We can't fill in all the fields in the file header, as we
566        haven't yet written any packets.  As we'll have to rewrite
567        the header when we've written out all the packets, we just
568        skip over the header for now. */
569     if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
570         *err = errno;
571         return FALSE;
572     }
573
574     wdh->dump.netxray = g_malloc(sizeof(netxray_dump_t));
575     wdh->dump.netxray->first_frame = TRUE;
576     wdh->dump.netxray->start.tv_sec = 0;
577     wdh->dump.netxray->start.tv_usec = 0;
578     wdh->dump.netxray->nframes = 0;
579
580     return TRUE;
581 }
582
583 /* Write a record for a packet to a dump file.
584    Returns TRUE on success, FALSE on failure. */
585 static gboolean netxray_dump_1_1(wtap_dumper *wdh,
586         const struct wtap_pkthdr *phdr,
587         const union wtap_pseudo_header *pseudo_header _U_,
588         const guchar *pd, int *err)
589 {
590     netxray_dump_t *netxray = wdh->dump.netxray;
591     guint32 timestamp;
592     struct netxrayrec_1_x_hdr rec_hdr;
593     size_t nwritten;
594
595     /* NetXRay/Windows Sniffer files have a capture start date/time
596        in the header, in a UNIX-style format, with one-second resolution,
597        and a start time stamp with microsecond resolution that's just
598        an arbitrary time stamp relative to some unknown time (boot
599        time?), and have times relative to the start time stamp in
600        the packet headers; pick the seconds value of the time stamp
601        of the first packet as the UNIX-style start date/time, and make
602        the high-resolution start time stamp 0, with the time stamp of
603        packets being the delta between the stamp of the packet and
604        the stamp of the first packet with the microseconds part 0. */
605     if (netxray->first_frame) {
606         netxray->first_frame = FALSE;
607         netxray->start = phdr->ts;
608     }
609
610     /* build the header for each packet */
611     memset(&rec_hdr, '\0', sizeof(rec_hdr));
612     timestamp = (phdr->ts.tv_sec - netxray->start.tv_sec)*1000000 +
613         phdr->ts.tv_usec;
614     rec_hdr.timelo = htolel(timestamp);
615     rec_hdr.timehi = htolel(0);
616     rec_hdr.orig_len = htoles(phdr->len);
617     rec_hdr.incl_len = htoles(phdr->caplen);
618         
619     nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
620     if (nwritten != sizeof(rec_hdr)) {
621         if (nwritten == 0 && ferror(wdh->fh))
622             *err = errno;
623         else
624             *err = WTAP_ERR_SHORT_WRITE;
625         return FALSE;
626     }
627
628     /* write the packet data */ 
629     nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
630     if (nwritten != phdr->caplen) {
631         if (nwritten == 0 && ferror(wdh->fh))
632             *err = errno;
633         else
634             *err = WTAP_ERR_SHORT_WRITE;
635         return FALSE;
636     }
637         
638     netxray->nframes++;
639
640     return TRUE;
641 }
642
643 /* Finish writing to a dump file.
644    Returns TRUE on success, FALSE on failure. */
645 static gboolean netxray_dump_close_1_1(wtap_dumper *wdh, int *err)
646 {
647     char hdr_buf[CAPTUREFILE_HEADER_SIZE - sizeof(netxray_magic)];
648     netxray_dump_t *netxray = wdh->dump.netxray;
649     guint32 filelen;
650     struct netxray_hdr file_hdr;
651     size_t nwritten;
652
653     filelen = ftell(wdh->fh);
654
655     /* Go back to beginning */
656     fseek(wdh->fh, 0, SEEK_SET);
657
658     /* Rewrite the file header. */
659     nwritten = fwrite(netxray_magic, 1, sizeof netxray_magic, wdh->fh);
660     if (nwritten != sizeof netxray_magic) {
661         if (err != NULL) {
662             if (nwritten == 0 && ferror(wdh->fh))
663                 *err = errno;
664             else
665                 *err = WTAP_ERR_SHORT_WRITE;
666         }
667         return FALSE;
668     }
669
670     /* "sniffer" version ? */
671     memset(&file_hdr, '\0', sizeof file_hdr);
672     memcpy(file_hdr.version, vers_1_1, sizeof vers_1_1);
673     file_hdr.start_time = htolel(netxray->start.tv_sec);
674     file_hdr.nframes = htolel(netxray->nframes);
675     file_hdr.start_offset = htolel(CAPTUREFILE_HEADER_SIZE);
676     file_hdr.end_offset = htolel(filelen);
677     file_hdr.network = htoles(wtap_encap[wdh->encap]);
678     file_hdr.timelo = htolel(0);
679     file_hdr.timehi = htolel(0);
680
681     memset(hdr_buf, '\0', sizeof hdr_buf);
682     memcpy(hdr_buf, &file_hdr, sizeof(file_hdr));
683     nwritten = fwrite(hdr_buf, 1, sizeof hdr_buf, wdh->fh);
684     if (nwritten != sizeof hdr_buf) {
685         if (err != NULL) {
686             if (nwritten == 0 && ferror(wdh->fh))
687                 *err = errno;
688             else
689                 *err = WTAP_ERR_SHORT_WRITE;
690         }
691         return FALSE;
692     }
693         
694     return TRUE;
695 }
696
697 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
698    failure */
699 gboolean netxray_dump_open_2_0(wtap_dumper *wdh, gboolean cant_seek, int *err)
700 {
701     /* This is a NetXRay file.  We can't fill in some fields in the header
702        until all the packets have been written, so we can't write to a
703        pipe. */
704     if (cant_seek) {
705         *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
706         return FALSE;
707     }
708
709     wdh->subtype_write = netxray_dump_2_0;
710     wdh->subtype_close = netxray_dump_close_2_0;
711
712     /* We can't fill in all the fields in the file header, as we
713        haven't yet written any packets.  As we'll have to rewrite
714        the header when we've written out all the packets, we just
715        skip over the header for now. */
716     if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
717         *err = errno;
718         return FALSE;
719     }
720
721     wdh->dump.netxray = g_malloc(sizeof(netxray_dump_t));
722     wdh->dump.netxray->first_frame = TRUE;
723     wdh->dump.netxray->start.tv_sec = 0;
724     wdh->dump.netxray->start.tv_usec = 0;
725     wdh->dump.netxray->nframes = 0;
726
727     return TRUE;
728 }
729
730 /* Write a record for a packet to a dump file.
731    Returns TRUE on success, FALSE on failure. */
732 static gboolean netxray_dump_2_0(wtap_dumper *wdh,
733         const struct wtap_pkthdr *phdr,
734         const union wtap_pseudo_header *pseudo_header _U_,
735         const guchar *pd, int *err)
736 {
737     netxray_dump_t *netxray = wdh->dump.netxray;
738     guint32 timestamp;
739     struct netxrayrec_2_x_hdr rec_hdr;
740     size_t nwritten;
741
742     /* NetXRay/Windows Sniffer files have a capture start date/time
743        in the header, in a UNIX-style format, with one-second resolution,
744        and a start time stamp with microsecond resolution that's just
745        an arbitrary time stamp relative to some unknown time (boot
746        time?), and have times relative to the start time stamp in
747        the packet headers; pick the seconds value of the time stamp
748        of the first packet as the UNIX-style start date/time, and make
749        the high-resolution start time stamp 0, with the time stamp of
750        packets being the delta between the stamp of the packet and
751        the stamp of the first packet with the microseconds part 0. */
752     if (netxray->first_frame) {
753         netxray->first_frame = FALSE;
754         netxray->start = phdr->ts;
755     }
756
757     /* build the header for each packet */
758     memset(&rec_hdr, '\0', sizeof(rec_hdr));
759     timestamp = (phdr->ts.tv_sec - netxray->start.tv_sec)*1000000 +
760         phdr->ts.tv_usec;
761     rec_hdr.timelo = htolel(timestamp);
762     rec_hdr.timehi = htolel(0);
763     rec_hdr.orig_len = htoles(phdr->len);
764     rec_hdr.incl_len = htoles(phdr->caplen);
765
766     if (phdr->pkt_encap == WTAP_ENCAP_IEEE_802_11_WITH_RADIO)
767     {
768         rec_hdr.xxx[12] = pseudo_header->ieee_802_11.channel;
769         rec_hdr.xxx[13] = pseudo_header->ieee_802_11.data_rate;
770         rec_hdr.xxx[14] = pseudo_header->ieee_802_11.signal_level;
771     }
772
773     nwritten = fwrite(&rec_hdr, 1, sizeof(rec_hdr), wdh->fh);
774     if (nwritten != sizeof(rec_hdr)) {
775         if (nwritten == 0 && ferror(wdh->fh))
776             *err = errno;
777         else
778             *err = WTAP_ERR_SHORT_WRITE;
779         return FALSE;
780     }
781
782     /* write the packet data */ 
783     nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
784     if (nwritten != phdr->caplen) {
785         if (nwritten == 0 && ferror(wdh->fh))
786             *err = errno;
787         else
788             *err = WTAP_ERR_SHORT_WRITE;
789         return FALSE;
790     }
791         
792     netxray->nframes++;
793
794     return TRUE;
795 }
796
797 /* Finish writing to a dump file.
798    Returns TRUE on success, FALSE on failure. */
799 static gboolean netxray_dump_close_2_0(wtap_dumper *wdh, int *err)
800 {
801     char hdr_buf[CAPTUREFILE_HEADER_SIZE - sizeof(netxray_magic)];
802     netxray_dump_t *netxray = wdh->dump.netxray;
803     guint32 filelen;
804     struct netxray_hdr file_hdr;
805     size_t nwritten;
806
807     filelen = ftell(wdh->fh);
808
809     /* Go back to beginning */
810     fseek(wdh->fh, 0, SEEK_SET);
811
812     /* Rewrite the file header. */
813     nwritten = fwrite(netxray_magic, 1, sizeof netxray_magic, wdh->fh);
814     if (nwritten != sizeof netxray_magic) {
815         if (err != NULL) {
816             if (nwritten == 0 && ferror(wdh->fh))
817                 *err = errno;
818             else
819                 *err = WTAP_ERR_SHORT_WRITE;
820         }
821         return FALSE;
822     }
823
824     /* "sniffer" version ? */
825     memset(&file_hdr, '\0', sizeof file_hdr);
826     memcpy(file_hdr.version, vers_2_001, sizeof vers_2_001);
827     file_hdr.start_time = htolel(netxray->start.tv_sec);
828     file_hdr.nframes = htolel(netxray->nframes);
829     file_hdr.start_offset = htolel(CAPTUREFILE_HEADER_SIZE);
830     file_hdr.end_offset = htolel(filelen);
831     file_hdr.network = htoles(wtap_encap[wdh->encap]);
832     file_hdr.timelo = htolel(0);
833     file_hdr.timehi = htolel(0);
834
835     memset(hdr_buf, '\0', sizeof hdr_buf);
836     memcpy(hdr_buf, &file_hdr, sizeof(file_hdr));
837     nwritten = fwrite(hdr_buf, 1, sizeof hdr_buf, wdh->fh);
838     if (nwritten != sizeof hdr_buf) {
839         if (err != NULL) {
840             if (nwritten == 0 && ferror(wdh->fh))
841                 *err = errno;
842             else
843                 *err = WTAP_ERR_SHORT_WRITE;
844         }
845         return FALSE;
846     }
847         
848     return TRUE;
849 }