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