wtap: Make default_filter static
[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) {
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);
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                                 return RETRY;
693
694                         case NETMON_NET_NETWORK_INFO_EX:
695                                 /*
696                                  * List of adapters on which the capture
697                                  * was done.
698                                  */
699                                 return RETRY;
700
701                         case NETMON_NET_PAYLOAD_HEADER:
702                                 /*
703                                  * Header for a fake frame constructed
704                                  * by reassembly.
705                                  */
706                                 return RETRY;
707
708                         case NETMON_NET_NETWORK_INFO:
709                                 /*
710                                  * List of adapters on which the capture
711                                  * was done.
712                                  */
713                                 return RETRY;
714
715                         case NETMON_NET_DNS_CACHE:
716                                 /*
717                                  * List of resolved IP addresses.
718                                  */
719                                 return RETRY;
720
721                         case NETMON_NET_NETMON_FILTER:
722                                 /*
723                                  * NetMon capture or display filter
724                                  * string.
725                                  */
726                                 return RETRY;
727
728                         default:
729                                 *err = WTAP_ERR_UNSUPPORTED;
730                                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
731                                     network);
732                                 return FAILURE;
733                         }
734                 }
735
736                 phdr->pkt_encap = pkt_encap;
737                 if (netmon->version_major > 2 || netmon->version_minor > 2) {
738                         guint64 d;
739
740                         d = pletoh64(trlr.trlr_2_3.utc_timestamp);
741
742                         /*
743                          * Get the time as seconds and nanoseconds.
744                          * and overwrite the time stamp obtained
745                          * from the record header.
746                          */
747                         if (!filetime_to_nstime(&phdr->ts, d)) {
748                                 *err = WTAP_ERR_BAD_FILE;
749                                 *err_info = g_strdup("netmon: time stamp outside supported range");
750                                 return FAILURE;
751                         }
752                 }
753         }
754
755         netmon_set_pseudo_header_info(phdr, buf);
756         return SUCCESS;
757 }
758
759 /* Read the next packet */
760 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
761     gint64 *data_offset)
762 {
763         netmon_t *netmon = (netmon_t *)wth->priv;
764         gint64  rec_offset;
765
766         for (;;) {
767                 /* Have we reached the end of the packet data? */
768                 if (netmon->current_frame >= netmon->frame_table_size) {
769                         /* Yes.  We won't need the frame table any more;
770                            free it. */
771                         g_free(netmon->frame_table);
772                         netmon->frame_table = NULL;
773                         *err = 0;       /* it's just an EOF, not an error */
774                         return FALSE;
775                 }
776
777                 /* Seek to the beginning of the current record, if we're
778                    not there already (seeking to the current position
779                    may still cause a seek and a read of the underlying file,
780                    so we don't want to do it unconditionally).
781
782                    Yes, the current record could be before the previous
783                    record.  At least some captures put the trailer record
784                    with statistics as the first physical record in the
785                    file, but set the frame table up so it's the last
786                    record in sequence. */
787                 rec_offset = netmon->frame_table[netmon->current_frame];
788                 if (file_tell(wth->fh) != rec_offset) {
789                         if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
790                                 return FALSE;
791                 }
792                 netmon->current_frame++;
793
794                 *data_offset = file_tell(wth->fh);
795
796                 switch (netmon_process_record(wth, wth->fh, &wth->phdr,
797                     wth->frame_buffer, err, err_info)) {
798
799                 case RETRY:
800                         continue;
801
802                 case SUCCESS:
803                         return TRUE;
804
805                 case FAILURE:
806                         return FALSE;
807                 }
808         }
809 }
810
811 static gboolean
812 netmon_seek_read(wtap *wth, gint64 seek_off,
813     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
814 {
815         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
816                 return FALSE;
817
818         switch (netmon_process_record(wth, wth->random_fh, phdr, buf, err,
819             err_info)) {
820
821         default:
822                 /*
823                  * This should not happen.
824                  */
825                 *err = WTAP_ERR_BAD_FILE;
826                 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
827                 return FALSE;
828
829         case SUCCESS:
830                 return TRUE;
831
832         case FAILURE:
833                 return FALSE;
834         }
835 }
836
837 static gboolean
838 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
839     int *err, gchar **err_info)
840 {
841         struct netmon_atm_hdr atm_phdr;
842         guint16 vpi, vci;
843
844         if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
845             err, err_info))
846                 return FALSE;
847
848         vpi = g_ntohs(atm_phdr.vpi);
849         vci = g_ntohs(atm_phdr.vci);
850
851         pseudo_header->atm.vpi = vpi;
852         pseudo_header->atm.vci = vci;
853
854         /* We don't have this information */
855         pseudo_header->atm.flags = 0;
856         pseudo_header->atm.channel = 0;
857         pseudo_header->atm.cells = 0;
858         pseudo_header->atm.aal5t_u2u = 0;
859         pseudo_header->atm.aal5t_len = 0;
860         pseudo_header->atm.aal5t_chksum = 0;
861
862         return TRUE;
863 }
864
865 /* Throw away the frame table used by the sequential I/O stream. */
866 static void
867 netmon_sequential_close(wtap *wth)
868 {
869         netmon_t *netmon = (netmon_t *)wth->priv;
870
871         if (netmon->frame_table != NULL) {
872                 g_free(netmon->frame_table);
873                 netmon->frame_table = NULL;
874         }
875 }
876
877 typedef struct {
878         gboolean got_first_record_time;
879         nstime_t first_record_time;
880         guint32 frame_table_offset;
881         guint32 *frame_table;
882         guint   frame_table_index;
883         guint   frame_table_size;
884         gboolean no_more_room;          /* TRUE if no more records can be written */
885 } netmon_dump_t;
886
887 static const int wtap_encap[] = {
888         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
889         1,              /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
890         2,              /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
891         -1,             /* WTAP_ENCAP_SLIP -> unsupported */
892         -1,             /* WTAP_ENCAP_PPP -> unsupported */
893         3,              /* WTAP_ENCAP_FDDI -> NDIS FDDI */
894         3,              /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
895         -1,             /* WTAP_ENCAP_RAW_IP -> unsupported */
896         -1,             /* WTAP_ENCAP_ARCNET -> unsupported */
897         -1,             /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
898         -1,             /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
899         -1,             /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
900         -1,             /* WTAP_ENCAP_LAPB -> unsupported*/
901         4,              /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
902 };
903 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
904
905 /* Returns 0 if we could write the specified encapsulation type,
906    an error indication otherwise. */
907 int netmon_dump_can_write_encap_1_x(int encap)
908 {
909         /*
910          * Per-packet encapsulations are *not* supported in NetMon 1.x
911          * format.
912          */
913         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
914                 return WTAP_ERR_UNWRITABLE_ENCAP;
915
916         return 0;
917 }
918
919 int netmon_dump_can_write_encap_2_x(int encap)
920 {
921         /*
922          * Per-packet encapsulations are supported in NetMon 2.1
923          * format.
924          */
925         if (encap == WTAP_ENCAP_PER_PACKET)
926                 return 0;
927
928         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
929                 return WTAP_ERR_UNWRITABLE_ENCAP;
930
931         return 0;
932 }
933
934 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
935    failure */
936 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
937 {
938         netmon_dump_t *netmon;
939
940         /* We can't fill in all the fields in the file header, as we
941            haven't yet written any packets.  As we'll have to rewrite
942            the header when we've written out all the packets, we just
943            skip over the header for now. */
944         if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
945                 return FALSE;
946
947         wdh->subtype_write = netmon_dump;
948         wdh->subtype_finish = netmon_dump_finish;
949
950         netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
951         wdh->priv = (void *)netmon;
952         netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
953         netmon->got_first_record_time = FALSE;
954         netmon->frame_table = NULL;
955         netmon->frame_table_index = 0;
956         netmon->frame_table_size = 0;
957         netmon->no_more_room = FALSE;
958
959         return TRUE;
960 }
961
962 /* Write a record for a packet to a dump file.
963    Returns TRUE on success, FALSE on failure. */
964 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
965     const guint8 *pd, int *err, gchar **err_info _U_)
966 {
967         const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
968         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
969         struct netmonrec_1_x_hdr rec_1_x_hdr;
970         struct netmonrec_2_x_hdr rec_2_x_hdr;
971         void *hdrp;
972         size_t rec_size;
973         struct netmonrec_2_1_trlr rec_2_x_trlr;
974         size_t hdr_size;
975         struct netmon_atm_hdr atm_hdr;
976         int atm_hdrsize;
977         gint64  secs;
978         gint32  nsecs;
979
980         /* We can only write packet records. */
981         if (phdr->rec_type != REC_TYPE_PACKET) {
982                 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
983                 return FALSE;
984         }
985
986         switch (wdh->file_type_subtype) {
987
988         case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
989                 /*
990                  * The length fields are 16-bit, so there's a hard limit
991                  * of 65535.
992                  */
993                 if (phdr->caplen > 65535) {
994                         *err = WTAP_ERR_PACKET_TOO_LARGE;
995                         return FALSE;
996                 }
997                 break;
998
999         case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1000                 /* Don't write anything we're not willing to read. */
1001                 if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
1002                         *err = WTAP_ERR_PACKET_TOO_LARGE;
1003                         return FALSE;
1004                 }
1005                 break;
1006
1007         default:
1008                 /* We should never get here - our open routine
1009                    should only get called for the types above. */
1010                 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1011                 return FALSE;
1012         }
1013
1014         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1015                 /*
1016                  * Is this network type supported?
1017                  */
1018                 if (phdr->pkt_encap < 0 ||
1019                     (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1020                     wtap_encap[phdr->pkt_encap] == -1) {
1021                         /*
1022                          * No.  Fail.
1023                          */
1024                         *err = WTAP_ERR_UNWRITABLE_ENCAP;
1025                         return FALSE;
1026                 }
1027
1028                 /*
1029                  * Fill in the trailer with the network type.
1030                  */
1031                 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1032         }
1033
1034         /*
1035          * Will the file offset of this frame fit in a 32-bit unsigned
1036          * integer?
1037          */
1038         if (netmon->no_more_room) {
1039                 /*
1040                  * No, so the file is too big for NetMon format to
1041                  * handle.
1042                  */
1043                 *err = EFBIG;
1044                 return FALSE;
1045         }
1046
1047         /*
1048          * NetMon files have a capture start time in the file header,
1049          * and have times relative to that in the packet headers;
1050          * pick the time of the first packet as the capture start
1051          * time.
1052          *
1053          * That time has millisecond resolution, so chop any
1054          * sub-millisecond part of the time stamp off.
1055          */
1056         if (!netmon->got_first_record_time) {
1057                 netmon->first_record_time.secs = phdr->ts.secs;
1058                 netmon->first_record_time.nsecs =
1059                     (phdr->ts.nsecs/1000000)*1000000;
1060                 netmon->got_first_record_time = TRUE;
1061         }
1062
1063         if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1064                 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1065         else
1066                 atm_hdrsize = 0;
1067         secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1068         nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1069         while (nsecs < 0) {
1070                 /*
1071                  * Propagate a borrow into the seconds.
1072                  * The seconds is a time_t, and can be < 0
1073                  * (unlikely, as neither UN*X nor DOS
1074                  * nor the original Mac System existed
1075                  * before January 1, 1970, 00:00:00 UTC),
1076                  * while the nanoseconds should be positive,
1077                  * as in "nanoseconds since the instant of time
1078                  * represented by the seconds".
1079                  *
1080                  * We do not want t to be negative, as, according
1081                  * to the C90 standard, "if either operand [of /
1082                  * or %] is negative, whether the result of the
1083                  * / operator is the largest integer less than or
1084                  * equal to the algebraic quotient or the smallest
1085                  * greater than or equal to the algebraic quotient
1086                  * is implementation-defined, as is the sign of
1087                  * the result of the % operator", and we want
1088                  * the result of the division and remainder
1089                  * operations to be the same on all platforms.
1090                  */
1091                 nsecs += 1000000000;
1092                 secs--;
1093         }
1094         switch (wdh->file_type_subtype) {
1095
1096         case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1097                 rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1098                 rec_1_x_hdr.orig_len = GUINT16_TO_LE(phdr->len + atm_hdrsize);
1099                 rec_1_x_hdr.incl_len = GUINT16_TO_LE(phdr->caplen + atm_hdrsize);
1100                 hdrp = &rec_1_x_hdr;
1101                 hdr_size = sizeof rec_1_x_hdr;
1102                 break;
1103
1104         case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1105                 rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1106                 rec_2_x_hdr.orig_len = GUINT32_TO_LE(phdr->len + atm_hdrsize);
1107                 rec_2_x_hdr.incl_len = GUINT32_TO_LE(phdr->caplen + atm_hdrsize);
1108                 hdrp = &rec_2_x_hdr;
1109                 hdr_size = sizeof rec_2_x_hdr;
1110                 break;
1111
1112         default:
1113                 /* We should never get here - our open routine
1114                    should only get called for the types above. */
1115                 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1116                 return FALSE;
1117         }
1118
1119         /*
1120          * Keep track of the record size, as we need to update
1121          * the current file offset.
1122          */
1123         rec_size = 0;
1124
1125         if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1126                 return FALSE;
1127         rec_size += hdr_size;
1128
1129         if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1130                 /*
1131                  * Write the ATM header.
1132                  * We supply all-zero destination and source addresses.
1133                  */
1134                 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1135                 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1136                 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1137                 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1138                 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1139                         return FALSE;
1140                 rec_size += sizeof atm_hdr;
1141         }
1142
1143         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1144                 return FALSE;
1145         rec_size += phdr->caplen;
1146
1147         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1148                 /*
1149                  * Write out the trailer.
1150                  */
1151                 if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1152                     sizeof rec_2_x_trlr, err))
1153                         return FALSE;
1154                 rec_size += sizeof rec_2_x_trlr;
1155         }
1156
1157         /*
1158          * Stash the file offset of this frame.
1159          */
1160         if (netmon->frame_table_size == 0) {
1161                 /*
1162                  * Haven't yet allocated the buffer for the frame table.
1163                  */
1164                 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1165                 netmon->frame_table_size = 1024;
1166         } else {
1167                 /*
1168                  * We've allocated it; are we at the end?
1169                  */
1170                 if (netmon->frame_table_index >= netmon->frame_table_size) {
1171                         /*
1172                          * Yes - double the size of the frame table.
1173                          */
1174                         netmon->frame_table_size *= 2;
1175                         netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1176                             netmon->frame_table_size * sizeof *netmon->frame_table);
1177                 }
1178         }
1179
1180         netmon->frame_table[netmon->frame_table_index] =
1181             GUINT32_TO_LE(netmon->frame_table_offset);
1182
1183         /*
1184          * Is this the last record we can write?
1185          * I.e., will the frame table offset of the next record not fit
1186          * in a 32-bit frame table offset entry?
1187          *
1188          * (We don't bother checking whether the number of frames
1189          * will fit in a 32-bit value, as, even if each record were
1190          * 1 byte, if there were more than 2^32-1 packets, the frame
1191          * table offset of at least one of those packets will be >
1192          * 2^32 - 1.)
1193          *
1194          * Note: this also catches the unlikely possibility that
1195          * the record itself is > 2^32 - 1 bytes long.
1196          */
1197         if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1198                 /*
1199                  * Yup, too big.
1200                  */
1201                 netmon->no_more_room = TRUE;
1202         }
1203         netmon->frame_table_index++;
1204         netmon->frame_table_offset += (guint32) rec_size;
1205
1206         return TRUE;
1207 }
1208
1209 /* Finish writing to a dump file.
1210    Returns TRUE on success, FALSE on failure. */
1211 static gboolean netmon_dump_finish(wtap_dumper *wdh, int *err)
1212 {
1213         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1214         size_t n_to_write;
1215         struct netmon_hdr file_hdr;
1216         const char *magicp;
1217         size_t magic_size;
1218         struct tm *tm;
1219
1220         /* Write out the frame table.  "netmon->frame_table_index" is
1221            the number of entries we've put into it. */
1222         n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1223         if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1224                 return FALSE;
1225
1226         /* Now go fix up the file header. */
1227         if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1228                 return FALSE;
1229         memset(&file_hdr, '\0', sizeof file_hdr);
1230         switch (wdh->file_type_subtype) {
1231
1232         case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1233                 magicp = netmon_1_x_magic;
1234                 magic_size = sizeof netmon_1_x_magic;
1235                 /* NetMon file version, for 1.x, is 1.1 */
1236                 file_hdr.ver_major = 1;
1237                 file_hdr.ver_minor = 1;
1238                 break;
1239
1240         case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1241                 magicp = netmon_2_x_magic;
1242                 magic_size = sizeof netmon_2_x_magic;
1243                 /*
1244                  * NetMon file version, for 2.x, is 2.0;
1245                  * for 3.0, it's 2.1.
1246                  *
1247                  * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1248                  * we need version 2.1.
1249                  *
1250                  * XXX - version 2.3 supports UTC time stamps; when
1251                  * should we use it?  According to the file format
1252                  * documentation, NetMon 3.3 "cannot properly
1253                  * interpret" the UTC timestamp information; does
1254                  * that mean it ignores it and uses the local-time
1255                  * start time and time deltas, or mishandles them?
1256                  * Also, NetMon 3.1 and earlier can't read version
1257                  * 2.2, much less version 2.3.
1258                  */
1259                 file_hdr.ver_major = 2;
1260                 file_hdr.ver_minor =
1261                     (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1262                 break;
1263
1264         default:
1265                 /* We should never get here - our open routine
1266                    should only get called for the types above. */
1267                 if (err != NULL)
1268                         *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1269                 return FALSE;
1270         }
1271         if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1272                 return FALSE;
1273
1274         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1275                 /*
1276                  * We're writing NetMon 2.1 format, so the media
1277                  * type in the file header is irrelevant.  Set it
1278                  * to 1, just as Network Monitor does.
1279                  */
1280                 file_hdr.network = GUINT16_TO_LE(1);
1281         } else
1282                 file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->encap]);
1283         tm = localtime(&netmon->first_record_time.secs);
1284         if (tm != NULL) {
1285                 file_hdr.ts_year  = GUINT16_TO_LE(1900 + tm->tm_year);
1286                 file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1287                 file_hdr.ts_dow   = GUINT16_TO_LE(tm->tm_wday);
1288                 file_hdr.ts_day   = GUINT16_TO_LE(tm->tm_mday);
1289                 file_hdr.ts_hour  = GUINT16_TO_LE(tm->tm_hour);
1290                 file_hdr.ts_min   = GUINT16_TO_LE(tm->tm_min);
1291                 file_hdr.ts_sec   = GUINT16_TO_LE(tm->tm_sec);
1292         } else {
1293                 file_hdr.ts_year  = GUINT16_TO_LE(1900 + 0);
1294                 file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1295                 file_hdr.ts_dow   = GUINT16_TO_LE(0);
1296                 file_hdr.ts_day   = GUINT16_TO_LE(0);
1297                 file_hdr.ts_hour  = GUINT16_TO_LE(0);
1298                 file_hdr.ts_min   = GUINT16_TO_LE(0);
1299                 file_hdr.ts_sec   = GUINT16_TO_LE(0);
1300         }
1301         file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1302         file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1303         file_hdr.frametablelength =
1304             GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1305         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1306                 return FALSE;
1307
1308         return TRUE;
1309 }
1310
1311 /*
1312  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1313  *
1314  * Local variables:
1315  * c-basic-offset: 8
1316  * tab-width: 8
1317  * indent-tabs-mode: t
1318  * End:
1319  *
1320  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1321  * :indentSize=8:tabSize=8:noTabs=false:
1322  */