9f5d1b55783b63931c6786ee5bebcef3457cd012
[metze/wireshark/wip.git] / wiretap / netmon.c
1 /* netmon.c
2  *
3  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include <errno.h>
25 #include <string.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "buffer.h"
29 #include "atm.h"
30 #include "pcap-encap.h"
31 #include "netmon.h"
32
33 /* The file at
34  *
35  *      ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
36  *
37  * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
38  * for the header of a Microsoft Network Monitor 1.x capture file.
39  *
40  * The help files for Network Monitor 3.x document the 2.x file format.
41  */
42
43 /* Capture file header, *including* magic number, is padded to 128 bytes. */
44 #define CAPTUREFILE_HEADER_SIZE 128
45
46 /* Magic number size, for both 1.x and 2.x. */
47 #define MAGIC_SIZE      4
48
49 /* Magic number in Network Monitor 1.x files. */
50 static const char netmon_1_x_magic[MAGIC_SIZE] = {
51         'R', 'T', 'S', 'S'
52 };
53
54 /* Magic number in Network Monitor 2.x files. */
55 static const char netmon_2_x_magic[MAGIC_SIZE] = {
56         'G', 'M', 'B', 'U'
57 };
58
59 /* Network Monitor file header (minus magic number). */
60 struct netmon_hdr {
61         guint8  ver_minor;      /* minor version number */
62         guint8  ver_major;      /* major version number */
63         guint16 network;        /* network type */
64         guint16 ts_year;        /* year of capture start */
65         guint16 ts_month;       /* month of capture start (January = 1) */
66         guint16 ts_dow;         /* day of week of capture start (Sun = 0) */
67         guint16 ts_day;         /* day of month of capture start */
68         guint16 ts_hour;        /* hour of capture start */
69         guint16 ts_min;         /* minute of capture start */
70         guint16 ts_sec;         /* second of capture start */
71         guint16 ts_msec;        /* millisecond of capture start */
72         guint32 frametableoffset;       /* frame index table offset */
73         guint32 frametablelength;       /* frame index table size */
74         guint32 userdataoffset;         /* user data offset */
75         guint32 userdatalength;         /* user data size */
76         guint32 commentdataoffset;      /* comment data offset */
77         guint32 commentdatalength;      /* comment data size */
78         guint32 statisticsoffset;       /* offset to statistics structure */
79         guint32 statisticslength;       /* length of statistics structure */
80         guint32 networkinfooffset;      /* offset to network info structure */
81         guint32 networkinfolength;      /* length of network info structure */
82 };
83
84 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
85  * looking at capture files. */
86 struct netmonrec_1_x_hdr {
87         guint32 ts_delta;       /* time stamp - msecs since start of capture */
88         guint16 orig_len;       /* actual length of packet */
89         guint16 incl_len;       /* number of octets captured in file */
90 };
91
92 /*
93  * Network Monitor 2.x record header, as documented in NetMon 3.x's
94  * help files.
95  */
96 struct netmonrec_2_x_hdr {
97         guint64 ts_delta;       /* time stamp - usecs since start of capture */
98         guint32 orig_len;       /* actual length of packet */
99         guint32 incl_len;       /* number of octets captured in file */
100 };
101
102 /*
103  * Network Monitor 2.1 and later record trailers; documented in the Network
104  * Monitor 3.x help files, for 3.3 and later, although they don't clearly
105  * state how the trailer format changes from version to version.
106  *
107  * Some fields are multi-byte integers, but they're not aligned on their
108  * natural boundaries.
109  */
110 struct netmonrec_2_1_trlr {
111         guint8 network[2];              /* network type for this packet */
112 };
113
114 struct netmonrec_2_2_trlr {
115         guint8 network[2];              /* network type for this packet */
116         guint8 process_info_index[4];   /* index into the process info table */
117 };
118
119 struct netmonrec_2_3_trlr {
120         guint8 network[2];              /* network type for this packet */
121         guint8 process_info_index[4];   /* index into the process info table */
122         guint8 utc_timestamp[8];        /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
123         guint8 timezone_index;          /* index of time zone information */
124 };
125
126 /*
127  * The link-layer header on ATM packets.
128  */
129 struct netmon_atm_hdr {
130         guint8  dest[6];        /* "Destination address" - what is it? */
131         guint8  src[6];         /* "Source address" - what is it? */
132         guint16 vpi;            /* VPI */
133         guint16 vci;            /* VCI */
134 };
135
136 typedef struct {
137         time_t  start_secs;
138         guint32 start_nsecs;
139         guint8  version_major;
140         guint8  version_minor;
141         guint32 *frame_table;
142         guint32 frame_table_size;
143         guint   current_frame;
144 } netmon_t;
145
146 /*
147  * XXX - at least in some NetMon 3.4 VPN captures, the per-packet
148  * link-layer type is 0, but the packets have Ethernet headers.
149  * We handle this by mapping 0 to WTAP_ENCAP_ETHERNET; should we,
150  * instead, use the per-file link-layer type?
151  */
152 static const int netmon_encap[] = {
153         WTAP_ENCAP_ETHERNET,
154         WTAP_ENCAP_ETHERNET,
155         WTAP_ENCAP_TOKEN_RING,
156         WTAP_ENCAP_FDDI_BITSWAPPED,
157         WTAP_ENCAP_ATM_PDUS,    /* NDIS WAN - this is what's used for ATM */
158         WTAP_ENCAP_UNKNOWN,     /* NDIS LocalTalk, but format 2.x uses it for IP-over-IEEE 1394 */
159         WTAP_ENCAP_IEEE_802_11_NETMON,
160                                 /* NDIS "DIX", but format 2.x uses it for 802.11 */
161         WTAP_ENCAP_RAW_IP,      /* NDIS ARCNET raw, but format 2.x uses it for "Tunneling interfaces" */
162         WTAP_ENCAP_RAW_IP,      /* NDIS ARCNET 878.2, but format 2.x uses it for "Wireless WAN" */
163         WTAP_ENCAP_RAW_IP,      /* NDIS ATM (no, this is NOT used for ATM); format 2.x uses it for "Raw IP Frames" */
164         WTAP_ENCAP_UNKNOWN,     /* NDIS Wireless WAN */
165         WTAP_ENCAP_UNKNOWN      /* NDIS IrDA */
166 };
167 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
168
169 /*
170  * Special link-layer types.
171  */
172 #define NETMON_NET_PCAP_BASE            0xE000
173 #define NETMON_NET_NETEVENT             0xFFE0
174 #define NETMON_NET_NETWORK_INFO_EX      0xFFFB
175 #define NETMON_NET_PAYLOAD_HEADER       0xFFFC
176 #define NETMON_NET_NETWORK_INFO         0xFFFD
177 #define NETMON_NET_DNS_CACHE            0xFFFE
178 #define NETMON_NET_NETMON_FILTER        0xFFFF
179
180 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
181     gint64 *data_offset);
182 static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
183     struct wtap_pkthdr *phdr, guint8 *pd, int length,
184     int *err, gchar **err_info);
185 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
186     union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
187 static gboolean netmon_read_rec_data(FILE_T fh, guint8 *pd, int length,
188     int *err, gchar **err_info);
189 static int netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err,
190     gchar **err_info);
191 static void netmon_sequential_close(wtap *wth);
192 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
193     const guint8 *pd, int *err);
194 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
195
196 int netmon_open(wtap *wth, int *err, gchar **err_info)
197 {
198         int bytes_read;
199         char magic[MAGIC_SIZE];
200         struct netmon_hdr hdr;
201         int file_type;
202         struct tm tm;
203         guint32 frame_table_offset;
204         guint32 frame_table_length;
205         guint32 frame_table_size;
206         guint32 *frame_table;
207 #ifdef WORDS_BIGENDIAN
208         unsigned int i;
209 #endif
210         netmon_t *netmon;
211
212         /* Read in the string that should be at the start of a Network
213          * Monitor file */
214         errno = WTAP_ERR_CANT_READ;
215         bytes_read = file_read(magic, MAGIC_SIZE, wth->fh);
216         if (bytes_read != MAGIC_SIZE) {
217                 *err = file_error(wth->fh, err_info);
218                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
219                         return -1;
220                 return 0;
221         }
222
223         if (memcmp(magic, netmon_1_x_magic, MAGIC_SIZE) != 0 &&
224             memcmp(magic, netmon_2_x_magic, MAGIC_SIZE) != 0) {
225                 return 0;
226         }
227
228         /* Read the rest of the header. */
229         errno = WTAP_ERR_CANT_READ;
230         bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
231         if (bytes_read != sizeof hdr) {
232                 *err = file_error(wth->fh, err_info);
233                 if (*err == 0)
234                         *err = WTAP_ERR_SHORT_READ;
235                 return -1;
236         }
237
238         switch (hdr.ver_major) {
239
240         case 1:
241                 file_type = WTAP_FILE_NETMON_1_x;
242                 break;
243
244         case 2:
245                 file_type = WTAP_FILE_NETMON_2_x;
246                 break;
247
248         default:
249                 *err = WTAP_ERR_UNSUPPORTED;
250                 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
251                 return -1;
252         }
253
254         hdr.network = pletohs(&hdr.network);
255         if (hdr.network >= NUM_NETMON_ENCAPS
256             || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
257                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
258                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
259                     hdr.network);
260                 return -1;
261         }
262
263         /* This is a netmon file */
264         wth->file_type = file_type;
265         netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
266         wth->priv = (void *)netmon;
267         wth->subtype_read = netmon_read;
268         wth->subtype_seek_read = netmon_seek_read;
269         wth->subtype_sequential_close = netmon_sequential_close;
270
271         /* NetMon capture file formats v2.1+ use per-packet encapsulation types.  NetMon 3 sets the value in
272          * the header to 1 (Ethernet) for backwards compability. */
273         if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
274                 wth->file_encap = WTAP_ENCAP_PER_PACKET;
275         else
276                 wth->file_encap = netmon_encap[hdr.network];
277
278         wth->snapshot_length = 0;       /* not available in header */
279         /*
280          * Convert the time stamp to a "time_t" and a number of
281          * milliseconds.
282          */
283         tm.tm_year = pletohs(&hdr.ts_year) - 1900;
284         tm.tm_mon = pletohs(&hdr.ts_month) - 1;
285         tm.tm_mday = pletohs(&hdr.ts_day);
286         tm.tm_hour = pletohs(&hdr.ts_hour);
287         tm.tm_min = pletohs(&hdr.ts_min);
288         tm.tm_sec = pletohs(&hdr.ts_sec);
289         tm.tm_isdst = -1;
290         netmon->start_secs = mktime(&tm);
291         /*
292          * XXX - what if "secs" is -1?  Unlikely, but if the capture was
293          * done in a time zone that switches between standard and summer
294          * time sometime other than when we do, and thus the time was one
295          * that doesn't exist here because a switch from standard to summer
296          * time zips over it, it could happen.
297          *
298          * On the other hand, if the capture was done in a different time
299          * zone, this won't work right anyway; unfortunately, the time
300          * zone isn't stored in the capture file (why the hell didn't
301          * they stuff a FILETIME, which is the number of 100-nanosecond
302          * intervals since 1601-01-01 00:00:00 "UTC", there, instead
303          * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
304          */
305         netmon->start_nsecs = pletohs(&hdr.ts_msec)*1000000;
306
307         netmon->version_major = hdr.ver_major;
308         netmon->version_minor = hdr.ver_minor;
309
310         /*
311          * Get the offset of the frame index table.
312          */
313         frame_table_offset = pletohl(&hdr.frametableoffset);
314
315         /*
316          * It appears that some NetMon 2.x files don't have the
317          * first packet starting exactly 128 bytes into the file.
318          *
319          * Furthermore, it also appears that there are "holes" in
320          * the file, i.e. frame N+1 doesn't always follow immediately
321          * after frame N.
322          *
323          * Therefore, we must read the frame table, and use the offsets
324          * in it as the offsets of the frames.
325          */
326         frame_table_length = pletohl(&hdr.frametablelength);
327         frame_table_size = frame_table_length / (guint32)sizeof (guint32);
328         if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
329                 *err = WTAP_ERR_BAD_FILE;
330                 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
331                     frame_table_length);
332                 return -1;
333         }
334         if (frame_table_size == 0) {
335                 *err = WTAP_ERR_BAD_FILE;
336                 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
337                     frame_table_length);
338                 return -1;
339         }
340         /*
341          * XXX - clamp the size of the frame table, so that we don't
342          * attempt to allocate a huge frame table and fail.
343          *
344          * Given that file offsets in the frame table are 32-bit,
345          * a NetMon file cannot be bigger than 2^32 bytes.
346          * Given that a NetMon 1.x-format packet header is 8 bytes,
347          * that means a NetMon file cannot have more than
348          * 512*2^20 packets.  We'll pick that as the limit for
349          * now; it's 1/8th of a 32-bit address space, which is
350          * probably not going to exhaust the address space all by
351          * itself, and probably won't exhaust the backing store.
352          */
353         if (frame_table_size > 512*1024*1024) {
354                 *err = WTAP_ERR_BAD_FILE;
355                 *err_info = g_strdup_printf("netmon: frame table length is %u, which is larger than we support",
356                     frame_table_length);
357                 return -1;
358         }
359         if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
360                 return -1;
361         }
362         frame_table = (guint32 *)g_try_malloc(frame_table_length);
363         if (frame_table_length != 0 && frame_table == NULL) {
364                 *err = ENOMEM;  /* we assume we're out of memory */
365                 return -1;
366         }
367         errno = WTAP_ERR_CANT_READ;
368         bytes_read = file_read(frame_table, frame_table_length, wth->fh);
369         if ((guint32)bytes_read != frame_table_length) {
370                 *err = file_error(wth->fh, err_info);
371                 if (*err == 0)
372                         *err = WTAP_ERR_SHORT_READ;
373                 g_free(frame_table);
374                 return -1;
375         }
376         netmon->frame_table_size = frame_table_size;
377         netmon->frame_table = frame_table;
378
379 #ifdef WORDS_BIGENDIAN
380         /*
381          * OK, now byte-swap the frame table.
382          */
383         for (i = 0; i < frame_table_size; i++)
384                 frame_table[i] = pletohl(&frame_table[i]);
385 #endif
386
387         /* Set up to start reading at the first frame. */
388         netmon->current_frame = 0;
389         switch (netmon->version_major) {
390
391         case 1:
392                 /*
393                  * Version 1.x of the file format supports
394                  * millisecond precision.
395                  */
396                 wth->tsprecision = WTAP_FILE_TSPREC_MSEC;
397                 break;
398
399         case 2:
400                 /*
401                  * Version 1.x of the file format supports
402                  * 100-nanosecond precision; we don't
403                  * currently support that, so say
404                  * "nanosecond precision" for now.
405                  */
406                 wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
407                 break;
408         }
409         return 1;
410 }
411
412 static size_t
413 netmon_trailer_size(netmon_t *netmon)
414 {
415         if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
416             netmon->version_major > 2) {
417                 if (netmon->version_major > 2) {
418                         /*
419                          * Asssume 2.3 format, for now.
420                          */
421                         return sizeof (struct netmonrec_2_3_trlr);
422                 } else {
423                         switch (netmon->version_minor) {
424
425                         case 1:
426                                 return sizeof (struct netmonrec_2_1_trlr);
427
428                         case 2:
429                                 return sizeof (struct netmonrec_2_2_trlr);
430
431                         default:
432                                 return sizeof (struct netmonrec_2_3_trlr);
433                         }
434                 }
435         }
436         return 0;       /* no trailer */
437 }
438
439 static void
440 netmon_set_pseudo_header_info(int pkt_encap,
441     union wtap_pseudo_header *pseudo_header, guint8 *pd, int length)
442 {
443         switch (pkt_encap) {
444
445         case WTAP_ENCAP_ATM_PDUS:
446                 /*
447                  * Attempt to guess from the packet data, the VPI, and
448                  * the VCIinformation about the type of traffic.
449                  */
450                 atm_guess_traffic_type(pd, length, pseudo_header);
451                 break;
452
453         case WTAP_ENCAP_ETHERNET:
454                 /*
455                  * We assume there's no FCS in this frame.
456                  */
457                 pseudo_header->eth.fcs_len = 0;
458                 break;
459
460         case WTAP_ENCAP_IEEE_802_11_NETMON:
461                 /*
462                  * It appears to be the case that management
463                  * frames have an FCS and data frames don't;
464                  * I'm not sure about control frames.  An
465                  * "FCS length" of -2 means "NetMon weirdness".
466                  */
467                 pseudo_header->ieee_802_11.fcs_len = -2;
468                 pseudo_header->ieee_802_11.decrypted = FALSE;
469                 break;
470         }
471 }
472
473 static gboolean netmon_process_rec_header(wtap *wth, FILE_T fh,
474     struct wtap_pkthdr *phdr, int *err, gchar **err_info)
475 {
476         netmon_t *netmon = (netmon_t *)wth->priv;
477         int     hdr_size = 0;
478         union {
479                 struct netmonrec_1_x_hdr hdr_1_x;
480                 struct netmonrec_2_x_hdr hdr_2_x;
481         }       hdr;
482         int     bytes_read;
483         gint64  delta = 0;      /* signed - frame times can be before the nominal start */
484         gint64  t;
485         time_t  secs;
486         guint32 nsecs;
487         guint32 packet_size = 0;
488         guint32 orig_size = 0;
489
490         /* Read record header. */
491         switch (netmon->version_major) {
492
493         case 1:
494                 hdr_size = sizeof (struct netmonrec_1_x_hdr);
495                 break;
496
497         case 2:
498                 hdr_size = sizeof (struct netmonrec_2_x_hdr);
499                 break;
500         }
501         errno = WTAP_ERR_CANT_READ;
502
503         bytes_read = file_read(&hdr, hdr_size, fh);
504         if (bytes_read != hdr_size) {
505                 *err = file_error(fh, err_info);
506                 if (*err == 0 && bytes_read != 0) {
507                         *err = WTAP_ERR_SHORT_READ;
508                 }
509                 return FALSE;
510         }
511
512         switch (netmon->version_major) {
513
514         case 1:
515                 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
516                 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
517                 break;
518
519         case 2:
520                 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
521                 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
522                 break;
523         }
524         if (packet_size > WTAP_MAX_PACKET_SIZE) {
525                 /*
526                  * Probably a corrupt capture file; don't blow up trying
527                  * to allocate space for an immensely-large packet.
528                  */
529                 *err = WTAP_ERR_BAD_FILE;
530                 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
531                     packet_size, WTAP_MAX_PACKET_SIZE);
532                 return FALSE;
533         }
534
535         /*
536          * If this is an ATM packet, the first
537          * "sizeof (struct netmon_atm_hdr)" bytes have destination and
538          * source addresses (6 bytes - MAC addresses of some sort?)
539          * and the VPI and VCI; read them and generate the pseudo-header
540          * from them.
541          */
542         switch (wth->file_encap) {
543
544         case WTAP_ENCAP_ATM_PDUS:
545                 if (packet_size < sizeof (struct netmon_atm_hdr)) {
546                         /*
547                          * Uh-oh, the packet isn't big enough to even
548                          * have a pseudo-header.
549                          */
550                         *err = WTAP_ERR_BAD_FILE;
551                         *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
552                             packet_size);
553                         return FALSE;
554                 }
555                 if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
556                     err, err_info))
557                         return FALSE;   /* Read error */
558
559                 /*
560                  * Don't count the pseudo-header as part of the packet.
561                  */
562                 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
563                 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
564                 break;
565
566         default:
567                 break;
568         }
569
570         switch (netmon->version_major) {
571
572         case 1:
573                 /*
574                  * According to Paul Long, this offset is unsigned.
575                  * It's 32 bits, so the maximum value will fit in
576                  * a gint64 such as delta, even after multiplying
577                  * it by 1000000.
578                  *
579                  * pletohl() returns a guint32; we cast it to gint64
580                  * before multiplying, so that the product doesn't
581                  * overflow a guint32.
582                  */
583                 delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000000;
584                 break;
585
586         case 2:
587                 /*
588                  * OK, this is weird.  Microsoft's documentation
589                  * says this is in microseconds and is a 64-bit
590                  * unsigned number, but it can be negative; they
591                  * say what appears to amount to "treat it as an
592                  * unsigned number, multiply it by 10, and then
593                  * interpret the resulting 64-bit quantity as a
594                  * signed number".  That operation can turn a
595                  * value with the uppermost bit 0 to a value with
596                  * the uppermost bit 1, hence turning a large
597                  * positive number-of-microseconds into a small
598                  * negative number-of-100-nanosecond-increments.
599                  */
600                 delta = pletohll(&hdr.hdr_2_x.ts_delta)*10;
601
602                 /*
603                  * OK, it's now a signed value in 100-nanosecond
604                  * units.  Now convert it to nanosecond units.
605                  */
606                 delta *= 100;
607                 break;
608         }
609         secs = 0;
610         t = netmon->start_nsecs + delta;
611         while (t < 0) {
612                 /*
613                  * Propagate a borrow into the seconds.
614                  * The seconds is a time_t, and can be < 0
615                  * (unlikely, as Windows didn't exist before
616                  * January 1, 1970, 00:00:00 UTC), while the
617                  * nanoseconds should be positive, as in
618                  * "nanoseconds since the instant of time
619                  * represented by the seconds".
620                  *
621                  * We do not want t to be negative, as, according
622                  * to the C90 standard, "if either operand [of /
623                  * or %] is negative, whether the result of the
624                  * / operator is the largest integer less than or
625                  * equal to the algebraic quotient or the smallest
626                  * greater than or equal to the algebraic quotient
627                  * is implementation-defined, as is the sign of
628                  * the result of the % operator", and we want
629                  * the result of the division and remainder
630                  * operations to be the same on all platforms.
631                  */
632                 t += 1000000000;
633                 secs--;
634         }
635         secs += (time_t)(t/1000000000);
636         nsecs = (guint32)(t%1000000000);
637         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
638         phdr->ts.secs = netmon->start_secs + secs;
639         phdr->ts.nsecs = nsecs;
640         phdr->caplen = packet_size;
641         phdr->len = orig_size;
642
643         return TRUE;
644 }
645
646 typedef enum {
647         SUCCESS,
648         FAILURE,
649         RETRY
650 } process_trailer_retval;
651
652 static process_trailer_retval netmon_process_rec_trailer(netmon_t *netmon,
653     FILE_T fh, struct wtap_pkthdr *phdr, int *err, gchar **err_info)
654 {
655         int     trlr_size;
656
657         trlr_size = (int)netmon_trailer_size(netmon);
658         if (trlr_size != 0) {
659                 /*
660                  * I haz a trailer.
661                  */
662                 phdr->pkt_encap = netmon_read_rec_trailer(fh,
663                     trlr_size, err, err_info);
664                 if (phdr->pkt_encap == -1)
665                         return FAILURE; /* error */
666                 if (phdr->pkt_encap == 0)
667                         return RETRY;
668         }
669
670         return SUCCESS;
671 }
672
673 /* Read the next packet */
674 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
675     gint64 *data_offset)
676 {
677         netmon_t *netmon = (netmon_t *)wth->priv;
678         gint64  rec_offset;
679         guint8  *data_ptr;
680
681 again:
682         /* Have we reached the end of the packet data? */
683         if (netmon->current_frame >= netmon->frame_table_size) {
684                 /* Yes.  We won't need the frame table any more;
685                    free it. */
686                 g_free(netmon->frame_table);
687                 netmon->frame_table = NULL;
688                 *err = 0;       /* it's just an EOF, not an error */
689                 return FALSE;
690         }
691
692         /* Seek to the beginning of the current record, if we're
693            not there already (seeking to the current position
694            may still cause a seek and a read of the underlying file,
695            so we don't want to do it unconditionally).
696
697            Yes, the current record could be before the previous
698            record.  At least some captures put the trailer record
699            with statistics as the first physical record in the
700            file, but set the frame table up so it's the last
701            record in sequence. */
702         rec_offset = netmon->frame_table[netmon->current_frame];
703         if (file_tell(wth->fh) != rec_offset) {
704                 if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
705                         return FALSE;
706         }
707         netmon->current_frame++;
708
709         *data_offset = file_tell(wth->fh);
710
711         if (!netmon_process_rec_header(wth, wth->fh, &wth->phdr,
712             err, err_info))
713                 return FALSE;
714
715         buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
716         data_ptr = buffer_start_ptr(wth->frame_buffer);
717         if (!netmon_read_rec_data(wth->fh, data_ptr, wth->phdr.caplen, err,
718             err_info))
719                 return FALSE;   /* Read error */
720
721         /*
722          * For version 2.1 and later, there's additional information
723          * after the frame data.
724          */
725         switch (netmon_process_rec_trailer(netmon, wth->fh, &wth->phdr,
726             err, err_info)) {
727
728         case RETRY:
729                 goto again;
730
731         case SUCCESS:
732                 break;
733
734         case FAILURE:
735                 return FALSE;
736         }
737
738         netmon_set_pseudo_header_info(wth->phdr.pkt_encap,
739             &wth->phdr.pseudo_header, data_ptr, wth->phdr.caplen);
740         return TRUE;
741 }
742
743 static gboolean
744 netmon_seek_read(wtap *wth, gint64 seek_off,
745     struct wtap_pkthdr *phdr, guint8 *pd, int length,
746     int *err, gchar **err_info)
747 {
748         netmon_t *netmon = (netmon_t *)wth->priv;
749
750         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
751                 return FALSE;
752
753         if (!netmon_process_rec_header(wth, wth->random_fh, phdr,
754             err, err_info))
755                 return FALSE;
756
757         /*
758          * Read the packet data.
759          */
760         if (!netmon_read_rec_data(wth->random_fh, pd, length, err, err_info))
761                 return FALSE;
762
763         /*
764          * For version 2.1 and later, there's additional information
765          * after the frame data.
766          */
767         switch (netmon_process_rec_trailer(netmon, wth->random_fh, phdr,
768             err, err_info)) {
769
770         case RETRY:
771                 /*
772                  * This should not happen.
773                  */
774                 *err = WTAP_ERR_BAD_FILE;
775                 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
776                 return FALSE;
777
778         case SUCCESS:
779                 break;
780
781         case FAILURE:
782                 return FALSE;
783         }
784
785         netmon_set_pseudo_header_info(phdr->pkt_encap,
786             &phdr->pseudo_header, pd, phdr->caplen);
787
788         return TRUE;
789 }
790
791 static gboolean
792 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
793     int *err, gchar **err_info)
794 {
795         struct netmon_atm_hdr atm_phdr;
796         int     bytes_read;
797         guint16 vpi, vci;
798
799         errno = WTAP_ERR_CANT_READ;
800         bytes_read = file_read(&atm_phdr, sizeof (struct netmon_atm_hdr), fh);
801         if (bytes_read != sizeof (struct netmon_atm_hdr)) {
802                 *err = file_error(fh, err_info);
803                 if (*err == 0)
804                         *err = WTAP_ERR_SHORT_READ;
805                 return FALSE;
806         }
807
808         vpi = g_ntohs(atm_phdr.vpi);
809         vci = g_ntohs(atm_phdr.vci);
810
811         pseudo_header->atm.vpi = vpi;
812         pseudo_header->atm.vci = vci;
813
814         /* We don't have this information */
815         pseudo_header->atm.flags = 0;
816         pseudo_header->atm.channel = 0;
817         pseudo_header->atm.cells = 0;
818         pseudo_header->atm.aal5t_u2u = 0;
819         pseudo_header->atm.aal5t_len = 0;
820         pseudo_header->atm.aal5t_chksum = 0;
821
822         return TRUE;
823 }
824
825 static gboolean
826 netmon_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
827     gchar **err_info)
828 {
829         int     bytes_read;
830
831         errno = WTAP_ERR_CANT_READ;
832         bytes_read = file_read(pd, length, fh);
833
834         if (bytes_read != length) {
835                 *err = file_error(fh, err_info);
836                 if (*err == 0)
837                         *err = WTAP_ERR_SHORT_READ;
838                 return FALSE;
839         }
840         return TRUE;
841 }
842
843 /*
844  * Read a record trailer.
845  * On success, returns the packet encapsulation type.
846  * On error, returns -1 (which is WTAP_ENCAP_PER_PACKET, but we'd
847  * never return that on success).
848  * For metadata packets, returns 0 (which is WTAP_ENCAP_UNKNOWN, but
849  * we'd never return that on success).
850  */
851 static int
852 netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err, gchar **err_info)
853 {
854         int     bytes_read;
855         union {
856                 struct netmonrec_2_1_trlr trlr_2_1;
857                 struct netmonrec_2_2_trlr trlr_2_2;
858                 struct netmonrec_2_3_trlr trlr_2_3;
859         }       trlr;
860         guint16 network;
861         int     pkt_encap;
862
863         errno = WTAP_ERR_CANT_READ;
864         bytes_read = file_read(&trlr, trlr_size, fh);
865         if (bytes_read != trlr_size) {
866                 *err = file_error(fh, err_info);
867                 if (*err == 0 && bytes_read != 0) {
868                         *err = WTAP_ERR_SHORT_READ;
869                 }
870                 return -1;      /* error */
871         }
872
873         network = pletohs(trlr.trlr_2_1.network);
874         if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
875                 /*
876                  * Converted pcap file - the LINKTYPE_ value
877                  * is the network value with 0xF000 masked off.
878                  */
879                 network &= 0x0FFF;
880                 pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
881                 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
882                         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
883                         *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
884                             network);
885                         return -1;      /* error */
886                 }
887         } else if (network < NUM_NETMON_ENCAPS) {
888                 /*
889                  * Regular NetMon encapsulation.
890                  */
891                 pkt_encap = netmon_encap[network];
892                 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
893                         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
894                         *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
895                             network);
896                         return -1;      /* error */
897                 }
898         } else {
899                 /*
900                  * Special packet type for metadata.
901                  */
902                 switch (network) {
903
904                 case NETMON_NET_NETEVENT:
905                 case NETMON_NET_NETWORK_INFO_EX:
906                 case NETMON_NET_PAYLOAD_HEADER:
907                 case NETMON_NET_NETWORK_INFO:
908                 case NETMON_NET_DNS_CACHE:
909                 case NETMON_NET_NETMON_FILTER:
910                         /*
911                          * Just ignore those record types, for
912                          * now.  Tell our caller to read the next
913                          * record.
914                          */
915                         return 0;
916
917                 default:
918                         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
919                         *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
920                             network);
921                         return -1;      /* error */
922                 }
923         }
924
925         return pkt_encap;       /* success */
926 }
927
928 /* Throw away the frame table used by the sequential I/O stream. */
929 static void
930 netmon_sequential_close(wtap *wth)
931 {
932         netmon_t *netmon = (netmon_t *)wth->priv;
933
934         if (netmon->frame_table != NULL) {
935                 g_free(netmon->frame_table);
936                 netmon->frame_table = NULL;
937         }
938 }
939
940 typedef struct {
941         gboolean got_first_record_time;
942         struct wtap_nstime first_record_time;
943         guint32 frame_table_offset;
944         guint32 *frame_table;
945         guint   frame_table_index;
946         guint   frame_table_size;
947         gboolean no_more_room;          /* TRUE if no more records can be written */
948 } netmon_dump_t;
949
950 static const int wtap_encap[] = {
951         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
952         1,              /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
953         2,              /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
954         -1,             /* WTAP_ENCAP_SLIP -> unsupported */
955         -1,             /* WTAP_ENCAP_PPP -> unsupported */
956         3,              /* WTAP_ENCAP_FDDI -> NDIS FDDI */
957         3,              /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
958         -1,             /* WTAP_ENCAP_RAW_IP -> unsupported */
959         -1,             /* WTAP_ENCAP_ARCNET -> unsupported */
960         -1,             /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
961         -1,             /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
962         -1,             /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
963         -1,             /* WTAP_ENCAP_LAPB -> unsupported*/
964         4,              /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
965 };
966 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
967
968 /* Returns 0 if we could write the specified encapsulation type,
969    an error indication otherwise. */
970 int netmon_dump_can_write_encap_1_x(int encap)
971 {
972         /*
973          * Per-packet encapsulations are *not* supported in NetMon 1.x
974          * format.
975          */
976         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
977                 return WTAP_ERR_UNSUPPORTED_ENCAP;
978
979         return 0;
980 }
981
982 int netmon_dump_can_write_encap_2_x(int encap)
983 {
984         /*
985          * Per-packet encapsulations are supported in NetMon 2.1
986          * format.
987          */
988         if (encap == WTAP_ENCAP_PER_PACKET)
989                 return 0;
990
991         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
992                 return WTAP_ERR_UNSUPPORTED_ENCAP;
993
994         return 0;
995 }
996
997 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
998    failure */
999 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
1000 {
1001         netmon_dump_t *netmon;
1002
1003         /* We can't fill in all the fields in the file header, as we
1004            haven't yet written any packets.  As we'll have to rewrite
1005            the header when we've written out all the packets, we just
1006            skip over the header for now. */
1007         if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1) 
1008                 return FALSE;
1009
1010         wdh->subtype_write = netmon_dump;
1011         wdh->subtype_close = netmon_dump_close;
1012
1013         netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
1014         wdh->priv = (void *)netmon;
1015         netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
1016         netmon->got_first_record_time = FALSE;
1017         netmon->frame_table = NULL;
1018         netmon->frame_table_index = 0;
1019         netmon->frame_table_size = 0;
1020         netmon->no_more_room = FALSE;
1021
1022         return TRUE;
1023 }
1024
1025 /* Write a record for a packet to a dump file.
1026    Returns TRUE on success, FALSE on failure. */
1027 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1028     const guint8 *pd, int *err)
1029 {
1030         const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
1031         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1032         struct netmonrec_1_x_hdr rec_1_x_hdr;
1033         struct netmonrec_2_x_hdr rec_2_x_hdr;
1034         void *hdrp;
1035         size_t rec_size;
1036         struct netmonrec_2_1_trlr rec_2_x_trlr;
1037         size_t hdr_size;
1038         struct netmon_atm_hdr atm_hdr;
1039         int atm_hdrsize;
1040         gint64  secs;
1041         gint32  nsecs;
1042
1043         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1044                 /*
1045                  * Is this network type supported?
1046                  */
1047                 if (phdr->pkt_encap < 0 ||
1048                     (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1049                     wtap_encap[phdr->pkt_encap] == -1) {
1050                         /*
1051                          * No.  Fail.
1052                          */
1053                         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
1054                         return FALSE;
1055                 }
1056
1057                 /*
1058                  * Fill in the trailer with the network type.
1059                  */
1060                 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1061         }
1062
1063         /*
1064          * Will the file offset of this frame fit in a 32-bit unsigned
1065          * integer?
1066          */
1067         if (netmon->no_more_room) {
1068                 /*
1069                  * No, so the file is too big for NetMon format to
1070                  * handle.
1071                  */
1072                 *err = EFBIG;
1073                 return FALSE;
1074         }
1075
1076         /*
1077          * NetMon files have a capture start time in the file header,
1078          * and have times relative to that in the packet headers;
1079          * pick the time of the first packet as the capture start
1080          * time.
1081          *
1082          * That time has millisecond resolution, so chop any
1083          * sub-millisecond part of the time stamp off.
1084          */
1085         if (!netmon->got_first_record_time) {
1086                 netmon->first_record_time.secs = phdr->ts.secs;
1087                 netmon->first_record_time.nsecs =
1088                     (phdr->ts.nsecs/1000000)*1000000;
1089                 netmon->got_first_record_time = TRUE;
1090         }
1091
1092         if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1093                 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1094         else
1095                 atm_hdrsize = 0;
1096         secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1097         nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1098         while (nsecs < 0) {
1099                 /*
1100                  * Propagate a borrow into the seconds.
1101                  * The seconds is a time_t, and can be < 0
1102                  * (unlikely, as neither UN*X nor DOS
1103                  * nor the original Mac System existed
1104                  * before January 1, 1970, 00:00:00 UTC),
1105                  * while the nanoseconds should be positive,
1106                  * as in "nanoseconds since the instant of time
1107                  * represented by the seconds".
1108                  *
1109                  * We do not want t to be negative, as, according
1110                  * to the C90 standard, "if either operand [of /
1111                  * or %] is negative, whether the result of the
1112                  * / operator is the largest integer less than or
1113                  * equal to the algebraic quotient or the smallest
1114                  * greater than or equal to the algebraic quotient
1115                  * is implementation-defined, as is the sign of
1116                  * the result of the % operator", and we want
1117                  * the result of the division and remainder
1118                  * operations to be the same on all platforms.
1119                  */
1120                 nsecs += 1000000000;
1121                 secs--;
1122         }
1123         switch (wdh->file_type) {
1124
1125         case WTAP_FILE_NETMON_1_x:
1126                 rec_1_x_hdr.ts_delta = htolel(secs*1000 + (nsecs + 500000)/1000000);
1127                 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
1128                 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
1129                 hdrp = &rec_1_x_hdr;
1130                 hdr_size = sizeof rec_1_x_hdr;
1131                 break;
1132
1133         case WTAP_FILE_NETMON_2_x:
1134                 rec_2_x_hdr.ts_delta = htolell(secs*1000000 + (nsecs + 500)/1000);
1135                 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
1136                 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
1137                 hdrp = &rec_2_x_hdr;
1138                 hdr_size = sizeof rec_2_x_hdr;
1139                 break;
1140
1141         default:
1142                 /* We should never get here - our open routine
1143                    should only get called for the types above. */
1144                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1145                 return FALSE;
1146         }
1147
1148         /*
1149          * Keep track of the record size, as we need to update
1150          * the current file offset.
1151          */
1152         rec_size = 0;
1153
1154         if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1155                 return FALSE;
1156         rec_size += hdr_size;
1157
1158         if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1159                 /*
1160                  * Write the ATM header.
1161                  * We supply all-zero destination and source addresses.
1162                  */
1163                 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1164                 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1165                 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1166                 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1167                 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1168                         return FALSE;
1169                 rec_size += sizeof atm_hdr;
1170         }
1171
1172         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1173                 return FALSE;
1174         rec_size += phdr->caplen;
1175
1176         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1177                 /*
1178                  * Write out the trailer.
1179                  */
1180                 if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1181                     sizeof rec_2_x_trlr, err))
1182                         return FALSE;
1183                 rec_size += sizeof rec_2_x_trlr;
1184         }
1185
1186         /*
1187          * Stash the file offset of this frame.
1188          */
1189         if (netmon->frame_table_size == 0) {
1190                 /*
1191                  * Haven't yet allocated the buffer for the frame table.
1192                  */
1193                 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1194                 netmon->frame_table_size = 1024;
1195         } else {
1196                 /*
1197                  * We've allocated it; are we at the end?
1198                  */
1199                 if (netmon->frame_table_index >= netmon->frame_table_size) {
1200                         /*
1201                          * Yes - double the size of the frame table.
1202                          */
1203                         netmon->frame_table_size *= 2;
1204                         netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1205                             netmon->frame_table_size * sizeof *netmon->frame_table);
1206                 }
1207         }
1208
1209         netmon->frame_table[netmon->frame_table_index] =
1210             htolel(netmon->frame_table_offset);
1211
1212         /*
1213          * Is this the last record we can write?
1214          * I.e., will the frame table offset of the next record not fit
1215          * in a 32-bit frame table offset entry?
1216          *
1217          * (We don't bother checking whether the number of frames
1218          * will fit in a 32-bit value, as, even if each record were
1219          * 1 byte, if there were more than 2^32-1 packets, the frame
1220          * table offset of at least one of those packets will be >
1221          * 2^32 - 1.)
1222          *
1223          * Note: this also catches the unlikely possibility that
1224          * the record itself is > 2^32 - 1 bytes long.
1225          */
1226         if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1227                 /*
1228                  * Yup, too big.
1229                  */
1230                 netmon->no_more_room = TRUE;
1231         }
1232         netmon->frame_table_index++;
1233         netmon->frame_table_offset += (guint32) rec_size;
1234
1235         return TRUE;
1236 }
1237
1238 /* Finish writing to a dump file.
1239    Returns TRUE on success, FALSE on failure. */
1240 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
1241 {
1242         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1243         size_t n_to_write;
1244         struct netmon_hdr file_hdr;
1245         const char *magicp;
1246         size_t magic_size;
1247         struct tm *tm;
1248
1249         /* Write out the frame table.  "netmon->frame_table_index" is
1250            the number of entries we've put into it. */
1251         n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1252         if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1253                 return FALSE;
1254
1255         /* Now go fix up the file header. */
1256         if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1257                 return FALSE;
1258         memset(&file_hdr, '\0', sizeof file_hdr);
1259         switch (wdh->file_type) {
1260
1261         case WTAP_FILE_NETMON_1_x:
1262                 magicp = netmon_1_x_magic;
1263                 magic_size = sizeof netmon_1_x_magic;
1264                 /* NetMon file version, for 1.x, is 1.1 */
1265                 file_hdr.ver_major = 1;
1266                 file_hdr.ver_minor = 1;
1267                 break;
1268
1269         case WTAP_FILE_NETMON_2_x:
1270                 magicp = netmon_2_x_magic;
1271                 magic_size = sizeof netmon_2_x_magic;
1272                 /*
1273                  * NetMon file version, for 2.x, is 2.0;
1274                  * for 3.0, it's 2.1.
1275                  *
1276                  * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1277                  * we need version 2.1.
1278                  *
1279                  * XXX - version 2.3 supports UTC time stamps; when
1280                  * should we use it?  According to the file format
1281                  * documentation, NetMon 3.3 "cannot properly
1282                  * interpret" the UTC timestamp information; does
1283                  * that mean it ignores it and uses the local-time
1284                  * start time and time deltas, or mishandles them?
1285                  * Also, NetMon 3.1 and earlier can't read version
1286                  * 2.2, much less version 2.3.
1287                  */
1288                 file_hdr.ver_major = 2;
1289                 file_hdr.ver_minor =
1290                     (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1291                 break;
1292
1293         default:
1294                 /* We should never get here - our open routine
1295                    should only get called for the types above. */
1296                 if (err != NULL)
1297                         *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1298                 return FALSE;
1299         }
1300         if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1301                 return FALSE;
1302
1303         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1304                 /*
1305                  * We're writing NetMon 2.1 format, so the media
1306                  * type in the file header is irrelevant.  Set it
1307                  * to 1, just as Network Monitor does.
1308                  */
1309                 file_hdr.network = htoles(1);
1310         } else
1311                 file_hdr.network = htoles(wtap_encap[wdh->encap]);
1312         tm = localtime(&netmon->first_record_time.secs);
1313         if (tm != NULL) {
1314                 file_hdr.ts_year  = htoles(1900 + tm->tm_year);
1315                 file_hdr.ts_month = htoles(tm->tm_mon + 1);
1316                 file_hdr.ts_dow   = htoles(tm->tm_wday);
1317                 file_hdr.ts_day   = htoles(tm->tm_mday);
1318                 file_hdr.ts_hour  = htoles(tm->tm_hour);
1319                 file_hdr.ts_min   = htoles(tm->tm_min);
1320                 file_hdr.ts_sec   = htoles(tm->tm_sec);
1321         } else {
1322                 file_hdr.ts_year  = htoles(1900 + 0);
1323                 file_hdr.ts_month = htoles(0 + 1);
1324                 file_hdr.ts_dow   = htoles(0);
1325                 file_hdr.ts_day   = htoles(0);
1326                 file_hdr.ts_hour  = htoles(0);
1327                 file_hdr.ts_min   = htoles(0);
1328                 file_hdr.ts_sec   = htoles(0);
1329         }
1330         file_hdr.ts_msec = htoles(netmon->first_record_time.nsecs/1000000);
1331         file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
1332         file_hdr.frametablelength =
1333             htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
1334         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1335                 return FALSE;
1336
1337         return TRUE;
1338 }