9a4ad1e9990bb9413d77a23a13cb4db8254d2a7c
[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_close(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                 phdr->pseudo_header.ieee_802_11.presence_flags = 0; /* radio data is in the packet data */
432                 phdr->pseudo_header.ieee_802_11.fcs_len = -2;
433                 phdr->pseudo_header.ieee_802_11.decrypted = FALSE;
434                 break;
435         }
436 }
437
438 typedef enum {
439         SUCCESS,
440         FAILURE,
441         RETRY
442 } process_record_retval;
443
444 /*
445  * Number of seconds between the UN*X epoch (January 1, 1970, 00:00:00 GMT)
446  * and the Windows NT epoch (January 1, 1601, 00:00:00 "GMT").
447  */
448 #define TIME_FIXUP_CONSTANT G_GUINT64_CONSTANT(11644473600)
449
450 #ifndef TIME_T_MIN
451 #define TIME_T_MIN ((time_t) ((time_t)0 < (time_t) -1 ? (time_t) 0 \
452                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
453 #endif
454 #ifndef TIME_T_MAX
455 #define TIME_T_MAX ((time_t) (~ (time_t) 0 - TIME_T_MIN))
456 #endif
457
458 static process_record_retval
459 netmon_process_record(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
460     Buffer *buf, int *err, gchar **err_info)
461 {
462         netmon_t *netmon = (netmon_t *)wth->priv;
463         int     hdr_size = 0;
464         union {
465                 struct netmonrec_1_x_hdr hdr_1_x;
466                 struct netmonrec_2_x_hdr hdr_2_x;
467         }       hdr;
468         gint64  delta = 0;      /* signed - frame times can be before the nominal start */
469         gint64  t;
470         time_t  secs;
471         int     nsecs;
472         guint32 packet_size = 0;
473         guint32 orig_size = 0;
474         int     trlr_size;
475         union {
476                 struct netmonrec_2_1_trlr trlr_2_1;
477                 struct netmonrec_2_2_trlr trlr_2_2;
478                 struct netmonrec_2_3_trlr trlr_2_3;
479         }       trlr;
480         guint16 network;
481         int     pkt_encap;
482
483         /* Read record header. */
484         switch (netmon->version_major) {
485
486         case 1:
487                 hdr_size = sizeof (struct netmonrec_1_x_hdr);
488                 break;
489
490         case 2:
491                 hdr_size = sizeof (struct netmonrec_2_x_hdr);
492                 break;
493         }
494         if (!wtap_read_bytes_or_eof(fh, &hdr, hdr_size, err, err_info))
495                 return FAILURE;
496
497         switch (netmon->version_major) {
498
499         case 1:
500                 orig_size = pletoh16(&hdr.hdr_1_x.orig_len);
501                 packet_size = pletoh16(&hdr.hdr_1_x.incl_len);
502                 break;
503
504         case 2:
505                 orig_size = pletoh32(&hdr.hdr_2_x.orig_len);
506                 packet_size = pletoh32(&hdr.hdr_2_x.incl_len);
507                 break;
508         }
509         if (packet_size > WTAP_MAX_PACKET_SIZE) {
510                 /*
511                  * Probably a corrupt capture file; don't blow up trying
512                  * to allocate space for an immensely-large packet.
513                  */
514                 *err = WTAP_ERR_BAD_FILE;
515                 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
516                     packet_size, WTAP_MAX_PACKET_SIZE);
517                 return FAILURE;
518         }
519
520         phdr->rec_type = REC_TYPE_PACKET;
521
522         /*
523          * If this is an ATM packet, the first
524          * "sizeof (struct netmon_atm_hdr)" bytes have destination and
525          * source addresses (6 bytes - MAC addresses of some sort?)
526          * and the VPI and VCI; read them and generate the pseudo-header
527          * from them.
528          */
529         switch (wth->file_encap) {
530
531         case WTAP_ENCAP_ATM_PDUS:
532                 if (packet_size < sizeof (struct netmon_atm_hdr)) {
533                         /*
534                          * Uh-oh, the packet isn't big enough to even
535                          * have a pseudo-header.
536                          */
537                         *err = WTAP_ERR_BAD_FILE;
538                         *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
539                             packet_size);
540                         return FAILURE;
541                 }
542                 if (!netmon_read_atm_pseudoheader(fh, &phdr->pseudo_header,
543                     err, err_info))
544                         return FAILURE; /* Read error */
545
546                 /*
547                  * Don't count the pseudo-header as part of the packet.
548                  */
549                 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
550                 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
551                 break;
552
553         default:
554                 break;
555         }
556
557         switch (netmon->version_major) {
558
559         case 1:
560                 /*
561                  * According to Paul Long, this offset is unsigned.
562                  * It's 32 bits, so the maximum value will fit in
563                  * a gint64 such as delta, even after multiplying
564                  * it by 1000000.
565                  *
566                  * pletoh32() returns a guint32; we cast it to gint64
567                  * before multiplying, so that the product doesn't
568                  * overflow a guint32.
569                  */
570                 delta = ((gint64)pletoh32(&hdr.hdr_1_x.ts_delta))*1000000;
571                 break;
572
573         case 2:
574                 /*
575                  * OK, this is weird.  Microsoft's documentation
576                  * says this is in microseconds and is a 64-bit
577                  * unsigned number, but it can be negative; they
578                  * say what appears to amount to "treat it as an
579                  * unsigned number, multiply it by 10, and then
580                  * interpret the resulting 64-bit quantity as a
581                  * signed number".  That operation can turn a
582                  * value with the uppermost bit 0 to a value with
583                  * the uppermost bit 1, hence turning a large
584                  * positive number-of-microseconds into a small
585                  * negative number-of-100-nanosecond-increments.
586                  */
587                 delta = pletoh64(&hdr.hdr_2_x.ts_delta)*10;
588
589                 /*
590                  * OK, it's now a signed value in 100-nanosecond
591                  * units.  Now convert it to nanosecond units.
592                  */
593                 delta *= 100;
594                 break;
595         }
596         secs = 0;
597         t = netmon->start_nsecs + delta;
598         while (t < 0) {
599                 /*
600                  * Propagate a borrow into the seconds.
601                  * The seconds is a time_t, and can be < 0
602                  * (unlikely, as Windows didn't exist before
603                  * January 1, 1970, 00:00:00 UTC), while the
604                  * nanoseconds should be positive, as in
605                  * "nanoseconds since the instant of time
606                  * represented by the seconds".
607                  *
608                  * We do not want t to be negative, as, according
609                  * to the C90 standard, "if either operand [of /
610                  * or %] is negative, whether the result of the
611                  * / operator is the largest integer less than or
612                  * equal to the algebraic quotient or the smallest
613                  * greater than or equal to the algebraic quotient
614                  * is implementation-defined, as is the sign of
615                  * the result of the % operator", and we want
616                  * the result of the division and remainder
617                  * operations to be the same on all platforms.
618                  */
619                 t += 1000000000;
620                 secs--;
621         }
622         secs += (time_t)(t/1000000000);
623         nsecs = (int)(t%1000000000);
624         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
625         phdr->ts.secs = netmon->start_secs + secs;
626         phdr->ts.nsecs = nsecs;
627         phdr->caplen = packet_size;
628         phdr->len = orig_size;
629
630         /*
631          * Read the packet data.
632          */
633         if (!wtap_read_packet_bytes(fh, buf, phdr->caplen, err, err_info))
634                 return FAILURE;
635
636         /*
637          * For version 2.1 and later, there's additional information
638          * after the frame data.
639          */
640         if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
641             netmon->version_major > 2) {
642                 if (netmon->version_major > 2) {
643                         /*
644                          * Asssume 2.3 format, for now.
645                          */
646                         trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
647                 } else {
648                         switch (netmon->version_minor) {
649
650                         case 1:
651                                 trlr_size = (int)sizeof (struct netmonrec_2_1_trlr);
652                                 break;
653
654                         case 2:
655                                 trlr_size = (int)sizeof (struct netmonrec_2_2_trlr);
656                                 break;
657
658                         default:
659                                 trlr_size = (int)sizeof (struct netmonrec_2_3_trlr);
660                                 break;
661                         }
662                 }
663
664                 if (!wtap_read_bytes(fh, &trlr, trlr_size, err, err_info))
665                         return FAILURE;
666
667                 network = pletoh16(trlr.trlr_2_1.network);
668                 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
669                         /*
670                          * Converted pcap file - the LINKTYPE_ value
671                          * is the network value with 0xF000 masked off.
672                          */
673                         network &= 0x0FFF;
674                         pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
675                         if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
676                                 *err = WTAP_ERR_UNSUPPORTED;
677                                 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
678                                     network);
679                                 return FAILURE;
680                         }
681                 } else if (network < NUM_NETMON_ENCAPS) {
682                         /*
683                          * Regular NetMon encapsulation.
684                          */
685                         pkt_encap = netmon_encap[network];
686                         if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
687                                 *err = WTAP_ERR_UNSUPPORTED;
688                                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
689                                     network);
690                                 return FAILURE;
691                         }
692                 } else {
693                         /*
694                          * Special packet type for metadata.
695                          */
696                         switch (network) {
697
698                         case NETMON_NET_NETEVENT:
699                                 /*
700                                  * Event Tracing event.
701                                  *
702                                  * http://msdn.microsoft.com/en-us/library/aa363759(VS.85).aspx
703                                  */
704                                 return RETRY;
705
706                         case NETMON_NET_NETWORK_INFO_EX:
707                                 /*
708                                  * List of adapters on which the capture
709                                  * was done.
710                                  */
711                                 return RETRY;
712
713                         case NETMON_NET_PAYLOAD_HEADER:
714                                 /*
715                                  * Header for a fake frame constructed
716                                  * by reassembly.
717                                  */
718                                 return RETRY;
719
720                         case NETMON_NET_NETWORK_INFO:
721                                 /*
722                                  * List of adapters on which the capture
723                                  * was done.
724                                  */
725                                 return RETRY;
726
727                         case NETMON_NET_DNS_CACHE:
728                                 /*
729                                  * List of resolved IP addresses.
730                                  */
731                                 return RETRY;
732
733                         case NETMON_NET_NETMON_FILTER:
734                                 /*
735                                  * NetMon capture or display filter
736                                  * string.
737                                  */
738                                 return RETRY;
739
740                         default:
741                                 *err = WTAP_ERR_UNSUPPORTED;
742                                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
743                                     network);
744                                 return FAILURE;
745                         }
746                 }
747
748                 phdr->pkt_encap = pkt_encap;
749                 if (netmon->version_major > 2 || netmon->version_minor > 2) {
750                         /*
751                          * This code is based on the Samba code:
752                          *
753                          *      Unix SMB/Netbios implementation.
754                          *      Version 1.9.
755                          *      time handling functions
756                          *      Copyright (C) Andrew Tridgell 1992-1998
757                          */
758                         guint64 d;
759                         gint64 utcsecs;
760                         /* The next two lines are a fix needed for the
761                             broken SCO compiler. JRA. */
762                         time_t l_time_min = TIME_T_MIN;
763                         time_t l_time_max = TIME_T_MAX;
764
765                         d = pletoh64(trlr.trlr_2_3.utc_timestamp);
766
767                         /* Split into seconds and nanoseconds. */
768                         utcsecs = d / 10000000;
769                         nsecs = (int)((d % 10000000)*100);
770
771                         /* Now adjust the seconds. */
772                         utcsecs -= TIME_FIXUP_CONSTANT;
773
774                         if (!(l_time_min <= secs && secs <= l_time_max)) {
775                                 *err = WTAP_ERR_BAD_FILE;
776                                 *err_info = g_strdup_printf("netmon: time stamp outside supported range");
777                                 return FAILURE;
778                         }
779
780                         /*
781                          * Get the time as seconds and nanoseconds.
782                          * and overwrite the time stamp obtained
783                          * from the record header.
784                          */
785                         phdr->ts.secs = (time_t) utcsecs;
786                         phdr->ts.nsecs = nsecs;
787                 }
788         }
789
790         netmon_set_pseudo_header_info(phdr, buf);
791         return SUCCESS;
792 }
793
794 /* Read the next packet */
795 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
796     gint64 *data_offset)
797 {
798         netmon_t *netmon = (netmon_t *)wth->priv;
799         gint64  rec_offset;
800
801         for (;;) {
802                 /* Have we reached the end of the packet data? */
803                 if (netmon->current_frame >= netmon->frame_table_size) {
804                         /* Yes.  We won't need the frame table any more;
805                            free it. */
806                         g_free(netmon->frame_table);
807                         netmon->frame_table = NULL;
808                         *err = 0;       /* it's just an EOF, not an error */
809                         return FALSE;
810                 }
811
812                 /* Seek to the beginning of the current record, if we're
813                    not there already (seeking to the current position
814                    may still cause a seek and a read of the underlying file,
815                    so we don't want to do it unconditionally).
816
817                    Yes, the current record could be before the previous
818                    record.  At least some captures put the trailer record
819                    with statistics as the first physical record in the
820                    file, but set the frame table up so it's the last
821                    record in sequence. */
822                 rec_offset = netmon->frame_table[netmon->current_frame];
823                 if (file_tell(wth->fh) != rec_offset) {
824                         if (file_seek(wth->fh, rec_offset, SEEK_SET, err) == -1)
825                                 return FALSE;
826                 }
827                 netmon->current_frame++;
828
829                 *data_offset = file_tell(wth->fh);
830
831                 switch (netmon_process_record(wth, wth->fh, &wth->phdr,
832                     wth->frame_buffer, err, err_info)) {
833
834                 case RETRY:
835                         continue;
836
837                 case SUCCESS:
838                         return TRUE;
839
840                 case FAILURE:
841                         return FALSE;
842                 }
843         }
844 }
845
846 static gboolean
847 netmon_seek_read(wtap *wth, gint64 seek_off,
848     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
849 {
850         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
851                 return FALSE;
852
853         switch (netmon_process_record(wth, wth->random_fh, phdr, buf, err,
854             err_info)) {
855
856         default:
857                 /*
858                  * This should not happen.
859                  */
860                 *err = WTAP_ERR_BAD_FILE;
861                 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
862                 return FALSE;
863
864         case SUCCESS:
865                 return TRUE;
866
867         case FAILURE:
868                 return FALSE;
869         }
870 }
871
872 static gboolean
873 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
874     int *err, gchar **err_info)
875 {
876         struct netmon_atm_hdr atm_phdr;
877         guint16 vpi, vci;
878
879         if (!wtap_read_bytes(fh, &atm_phdr, sizeof (struct netmon_atm_hdr),
880             err, err_info))
881                 return FALSE;
882
883         vpi = g_ntohs(atm_phdr.vpi);
884         vci = g_ntohs(atm_phdr.vci);
885
886         pseudo_header->atm.vpi = vpi;
887         pseudo_header->atm.vci = vci;
888
889         /* We don't have this information */
890         pseudo_header->atm.flags = 0;
891         pseudo_header->atm.channel = 0;
892         pseudo_header->atm.cells = 0;
893         pseudo_header->atm.aal5t_u2u = 0;
894         pseudo_header->atm.aal5t_len = 0;
895         pseudo_header->atm.aal5t_chksum = 0;
896
897         return TRUE;
898 }
899
900 /* Throw away the frame table used by the sequential I/O stream. */
901 static void
902 netmon_sequential_close(wtap *wth)
903 {
904         netmon_t *netmon = (netmon_t *)wth->priv;
905
906         if (netmon->frame_table != NULL) {
907                 g_free(netmon->frame_table);
908                 netmon->frame_table = NULL;
909         }
910 }
911
912 typedef struct {
913         gboolean got_first_record_time;
914         nstime_t first_record_time;
915         guint32 frame_table_offset;
916         guint32 *frame_table;
917         guint   frame_table_index;
918         guint   frame_table_size;
919         gboolean no_more_room;          /* TRUE if no more records can be written */
920 } netmon_dump_t;
921
922 static const int wtap_encap[] = {
923         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
924         1,              /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
925         2,              /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
926         -1,             /* WTAP_ENCAP_SLIP -> unsupported */
927         -1,             /* WTAP_ENCAP_PPP -> unsupported */
928         3,              /* WTAP_ENCAP_FDDI -> NDIS FDDI */
929         3,              /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
930         -1,             /* WTAP_ENCAP_RAW_IP -> unsupported */
931         -1,             /* WTAP_ENCAP_ARCNET -> unsupported */
932         -1,             /* WTAP_ENCAP_ARCNET_LINUX -> unsupported */
933         -1,             /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
934         -1,             /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
935         -1,             /* WTAP_ENCAP_LAPB -> unsupported*/
936         4,              /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
937 };
938 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
939
940 /* Returns 0 if we could write the specified encapsulation type,
941    an error indication otherwise. */
942 int netmon_dump_can_write_encap_1_x(int encap)
943 {
944         /*
945          * Per-packet encapsulations are *not* supported in NetMon 1.x
946          * format.
947          */
948         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
949                 return WTAP_ERR_UNWRITABLE_ENCAP;
950
951         return 0;
952 }
953
954 int netmon_dump_can_write_encap_2_x(int encap)
955 {
956         /*
957          * Per-packet encapsulations are supported in NetMon 2.1
958          * format.
959          */
960         if (encap == WTAP_ENCAP_PER_PACKET)
961                 return 0;
962
963         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
964                 return WTAP_ERR_UNWRITABLE_ENCAP;
965
966         return 0;
967 }
968
969 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
970    failure */
971 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
972 {
973         netmon_dump_t *netmon;
974
975         /* We can't fill in all the fields in the file header, as we
976            haven't yet written any packets.  As we'll have to rewrite
977            the header when we've written out all the packets, we just
978            skip over the header for now. */
979         if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
980                 return FALSE;
981
982         wdh->subtype_write = netmon_dump;
983         wdh->subtype_close = netmon_dump_close;
984
985         netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
986         wdh->priv = (void *)netmon;
987         netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
988         netmon->got_first_record_time = FALSE;
989         netmon->frame_table = NULL;
990         netmon->frame_table_index = 0;
991         netmon->frame_table_size = 0;
992         netmon->no_more_room = FALSE;
993
994         return TRUE;
995 }
996
997 /* Write a record for a packet to a dump file.
998    Returns TRUE on success, FALSE on failure. */
999 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1000     const guint8 *pd, int *err, gchar **err_info _U_)
1001 {
1002         const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
1003         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1004         struct netmonrec_1_x_hdr rec_1_x_hdr;
1005         struct netmonrec_2_x_hdr rec_2_x_hdr;
1006         void *hdrp;
1007         size_t rec_size;
1008         struct netmonrec_2_1_trlr rec_2_x_trlr;
1009         size_t hdr_size;
1010         struct netmon_atm_hdr atm_hdr;
1011         int atm_hdrsize;
1012         gint64  secs;
1013         gint32  nsecs;
1014
1015         /* We can only write packet records. */
1016         if (phdr->rec_type != REC_TYPE_PACKET) {
1017                 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
1018                 return FALSE;
1019         }
1020
1021         switch (wdh->file_type_subtype) {
1022
1023         case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1024                 /*
1025                  * The length fields are 16-bit, so there's a hard limit
1026                  * of 65535.
1027                  */
1028                 if (phdr->caplen > 65535) {
1029                         *err = WTAP_ERR_PACKET_TOO_LARGE;
1030                         return FALSE;
1031                 }
1032                 break;
1033
1034         case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1035                 /* Don't write anything we're not willing to read. */
1036                 if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
1037                         *err = WTAP_ERR_PACKET_TOO_LARGE;
1038                         return FALSE;
1039                 }
1040                 break;
1041
1042         default:
1043                 /* We should never get here - our open routine
1044                    should only get called for the types above. */
1045                 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1046                 return FALSE;
1047         }
1048
1049         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1050                 /*
1051                  * Is this network type supported?
1052                  */
1053                 if (phdr->pkt_encap < 0 ||
1054                     (unsigned) phdr->pkt_encap >= NUM_WTAP_ENCAPS ||
1055                     wtap_encap[phdr->pkt_encap] == -1) {
1056                         /*
1057                          * No.  Fail.
1058                          */
1059                         *err = WTAP_ERR_UNWRITABLE_ENCAP;
1060                         return FALSE;
1061                 }
1062
1063                 /*
1064                  * Fill in the trailer with the network type.
1065                  */
1066                 phtoles(rec_2_x_trlr.network, wtap_encap[phdr->pkt_encap]);
1067         }
1068
1069         /*
1070          * Will the file offset of this frame fit in a 32-bit unsigned
1071          * integer?
1072          */
1073         if (netmon->no_more_room) {
1074                 /*
1075                  * No, so the file is too big for NetMon format to
1076                  * handle.
1077                  */
1078                 *err = EFBIG;
1079                 return FALSE;
1080         }
1081
1082         /*
1083          * NetMon files have a capture start time in the file header,
1084          * and have times relative to that in the packet headers;
1085          * pick the time of the first packet as the capture start
1086          * time.
1087          *
1088          * That time has millisecond resolution, so chop any
1089          * sub-millisecond part of the time stamp off.
1090          */
1091         if (!netmon->got_first_record_time) {
1092                 netmon->first_record_time.secs = phdr->ts.secs;
1093                 netmon->first_record_time.nsecs =
1094                     (phdr->ts.nsecs/1000000)*1000000;
1095                 netmon->got_first_record_time = TRUE;
1096         }
1097
1098         if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
1099                 atm_hdrsize = sizeof (struct netmon_atm_hdr);
1100         else
1101                 atm_hdrsize = 0;
1102         secs = (gint64)(phdr->ts.secs - netmon->first_record_time.secs);
1103         nsecs = phdr->ts.nsecs - netmon->first_record_time.nsecs;
1104         while (nsecs < 0) {
1105                 /*
1106                  * Propagate a borrow into the seconds.
1107                  * The seconds is a time_t, and can be < 0
1108                  * (unlikely, as neither UN*X nor DOS
1109                  * nor the original Mac System existed
1110                  * before January 1, 1970, 00:00:00 UTC),
1111                  * while the nanoseconds should be positive,
1112                  * as in "nanoseconds since the instant of time
1113                  * represented by the seconds".
1114                  *
1115                  * We do not want t to be negative, as, according
1116                  * to the C90 standard, "if either operand [of /
1117                  * or %] is negative, whether the result of the
1118                  * / operator is the largest integer less than or
1119                  * equal to the algebraic quotient or the smallest
1120                  * greater than or equal to the algebraic quotient
1121                  * is implementation-defined, as is the sign of
1122                  * the result of the % operator", and we want
1123                  * the result of the division and remainder
1124                  * operations to be the same on all platforms.
1125                  */
1126                 nsecs += 1000000000;
1127                 secs--;
1128         }
1129         switch (wdh->file_type_subtype) {
1130
1131         case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1132                 rec_1_x_hdr.ts_delta = GUINT32_TO_LE(secs*1000 + (nsecs + 500000)/1000000);
1133                 rec_1_x_hdr.orig_len = GUINT16_TO_LE(phdr->len + atm_hdrsize);
1134                 rec_1_x_hdr.incl_len = GUINT16_TO_LE(phdr->caplen + atm_hdrsize);
1135                 hdrp = &rec_1_x_hdr;
1136                 hdr_size = sizeof rec_1_x_hdr;
1137                 break;
1138
1139         case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1140                 rec_2_x_hdr.ts_delta = GUINT64_TO_LE(secs*1000000 + (nsecs + 500)/1000);
1141                 rec_2_x_hdr.orig_len = GUINT32_TO_LE(phdr->len + atm_hdrsize);
1142                 rec_2_x_hdr.incl_len = GUINT32_TO_LE(phdr->caplen + atm_hdrsize);
1143                 hdrp = &rec_2_x_hdr;
1144                 hdr_size = sizeof rec_2_x_hdr;
1145                 break;
1146
1147         default:
1148                 /* We should never get here - our open routine
1149                    should only get called for the types above. */
1150                 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1151                 return FALSE;
1152         }
1153
1154         /*
1155          * Keep track of the record size, as we need to update
1156          * the current file offset.
1157          */
1158         rec_size = 0;
1159
1160         if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
1161                 return FALSE;
1162         rec_size += hdr_size;
1163
1164         if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
1165                 /*
1166                  * Write the ATM header.
1167                  * We supply all-zero destination and source addresses.
1168                  */
1169                 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
1170                 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
1171                 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
1172                 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
1173                 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
1174                         return FALSE;
1175                 rec_size += sizeof atm_hdr;
1176         }
1177
1178         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
1179                 return FALSE;
1180         rec_size += phdr->caplen;
1181
1182         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1183                 /*
1184                  * Write out the trailer.
1185                  */
1186                 if (!wtap_dump_file_write(wdh, &rec_2_x_trlr,
1187                     sizeof rec_2_x_trlr, err))
1188                         return FALSE;
1189                 rec_size += sizeof rec_2_x_trlr;
1190         }
1191
1192         /*
1193          * Stash the file offset of this frame.
1194          */
1195         if (netmon->frame_table_size == 0) {
1196                 /*
1197                  * Haven't yet allocated the buffer for the frame table.
1198                  */
1199                 netmon->frame_table = (guint32 *)g_malloc(1024 * sizeof *netmon->frame_table);
1200                 netmon->frame_table_size = 1024;
1201         } else {
1202                 /*
1203                  * We've allocated it; are we at the end?
1204                  */
1205                 if (netmon->frame_table_index >= netmon->frame_table_size) {
1206                         /*
1207                          * Yes - double the size of the frame table.
1208                          */
1209                         netmon->frame_table_size *= 2;
1210                         netmon->frame_table = (guint32 *)g_realloc(netmon->frame_table,
1211                             netmon->frame_table_size * sizeof *netmon->frame_table);
1212                 }
1213         }
1214
1215         netmon->frame_table[netmon->frame_table_index] =
1216             GUINT32_TO_LE(netmon->frame_table_offset);
1217
1218         /*
1219          * Is this the last record we can write?
1220          * I.e., will the frame table offset of the next record not fit
1221          * in a 32-bit frame table offset entry?
1222          *
1223          * (We don't bother checking whether the number of frames
1224          * will fit in a 32-bit value, as, even if each record were
1225          * 1 byte, if there were more than 2^32-1 packets, the frame
1226          * table offset of at least one of those packets will be >
1227          * 2^32 - 1.)
1228          *
1229          * Note: this also catches the unlikely possibility that
1230          * the record itself is > 2^32 - 1 bytes long.
1231          */
1232         if ((guint64)netmon->frame_table_offset + rec_size > G_MAXUINT32) {
1233                 /*
1234                  * Yup, too big.
1235                  */
1236                 netmon->no_more_room = TRUE;
1237         }
1238         netmon->frame_table_index++;
1239         netmon->frame_table_offset += (guint32) rec_size;
1240
1241         return TRUE;
1242 }
1243
1244 /* Finish writing to a dump file.
1245    Returns TRUE on success, FALSE on failure. */
1246 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
1247 {
1248         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1249         size_t n_to_write;
1250         struct netmon_hdr file_hdr;
1251         const char *magicp;
1252         size_t magic_size;
1253         struct tm *tm;
1254
1255         /* Write out the frame table.  "netmon->frame_table_index" is
1256            the number of entries we've put into it. */
1257         n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1258         if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1259                 return FALSE;
1260
1261         /* Now go fix up the file header. */
1262         if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
1263                 return FALSE;
1264         memset(&file_hdr, '\0', sizeof file_hdr);
1265         switch (wdh->file_type_subtype) {
1266
1267         case WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x:
1268                 magicp = netmon_1_x_magic;
1269                 magic_size = sizeof netmon_1_x_magic;
1270                 /* NetMon file version, for 1.x, is 1.1 */
1271                 file_hdr.ver_major = 1;
1272                 file_hdr.ver_minor = 1;
1273                 break;
1274
1275         case WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x:
1276                 magicp = netmon_2_x_magic;
1277                 magic_size = sizeof netmon_2_x_magic;
1278                 /*
1279                  * NetMon file version, for 2.x, is 2.0;
1280                  * for 3.0, it's 2.1.
1281                  *
1282                  * If the file encapsulation is WTAP_ENCAP_PER_PACKET,
1283                  * we need version 2.1.
1284                  *
1285                  * XXX - version 2.3 supports UTC time stamps; when
1286                  * should we use it?  According to the file format
1287                  * documentation, NetMon 3.3 "cannot properly
1288                  * interpret" the UTC timestamp information; does
1289                  * that mean it ignores it and uses the local-time
1290                  * start time and time deltas, or mishandles them?
1291                  * Also, NetMon 3.1 and earlier can't read version
1292                  * 2.2, much less version 2.3.
1293                  */
1294                 file_hdr.ver_major = 2;
1295                 file_hdr.ver_minor =
1296                     (wdh->encap == WTAP_ENCAP_PER_PACKET) ? 1 : 0;
1297                 break;
1298
1299         default:
1300                 /* We should never get here - our open routine
1301                    should only get called for the types above. */
1302                 if (err != NULL)
1303                         *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
1304                 return FALSE;
1305         }
1306         if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1307                 return FALSE;
1308
1309         if (wdh->encap == WTAP_ENCAP_PER_PACKET) {
1310                 /*
1311                  * We're writing NetMon 2.1 format, so the media
1312                  * type in the file header is irrelevant.  Set it
1313                  * to 1, just as Network Monitor does.
1314                  */
1315                 file_hdr.network = GUINT16_TO_LE(1);
1316         } else
1317                 file_hdr.network = GUINT16_TO_LE(wtap_encap[wdh->encap]);
1318         tm = localtime(&netmon->first_record_time.secs);
1319         if (tm != NULL) {
1320                 file_hdr.ts_year  = GUINT16_TO_LE(1900 + tm->tm_year);
1321                 file_hdr.ts_month = GUINT16_TO_LE(tm->tm_mon + 1);
1322                 file_hdr.ts_dow   = GUINT16_TO_LE(tm->tm_wday);
1323                 file_hdr.ts_day   = GUINT16_TO_LE(tm->tm_mday);
1324                 file_hdr.ts_hour  = GUINT16_TO_LE(tm->tm_hour);
1325                 file_hdr.ts_min   = GUINT16_TO_LE(tm->tm_min);
1326                 file_hdr.ts_sec   = GUINT16_TO_LE(tm->tm_sec);
1327         } else {
1328                 file_hdr.ts_year  = GUINT16_TO_LE(1900 + 0);
1329                 file_hdr.ts_month = GUINT16_TO_LE(0 + 1);
1330                 file_hdr.ts_dow   = GUINT16_TO_LE(0);
1331                 file_hdr.ts_day   = GUINT16_TO_LE(0);
1332                 file_hdr.ts_hour  = GUINT16_TO_LE(0);
1333                 file_hdr.ts_min   = GUINT16_TO_LE(0);
1334                 file_hdr.ts_sec   = GUINT16_TO_LE(0);
1335         }
1336         file_hdr.ts_msec = GUINT16_TO_LE(netmon->first_record_time.nsecs/1000000);
1337         file_hdr.frametableoffset = GUINT32_TO_LE(netmon->frame_table_offset);
1338         file_hdr.frametablelength =
1339             GUINT32_TO_LE(netmon->frame_table_index * sizeof *netmon->frame_table);
1340         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1341                 return FALSE;
1342
1343         return TRUE;
1344 }
1345
1346 /*
1347  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1348  *
1349  * Local variables:
1350  * c-basic-offset: 8
1351  * tab-width: 8
1352  * indent-tabs-mode: t
1353  * End:
1354  *
1355  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1356  * :indentSize=8:tabSize=8:noTabs=false:
1357  */