"This file format can't be written to a pipe" and "this file format
[obnox/wireshark/wip.git] / wiretap / netmon.c
1 /* netmon.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <errno.h>
27 #include <string.h>
28 #include "wtap-int.h"
29 #include "file_wrappers.h"
30 #include "buffer.h"
31 #include "atm.h"
32 #include "pcap-encap.h"
33 #include "netmon.h"
34
35 /* The file at
36  *
37  *      ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
38  *
39  * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
40  * for the header of a Microsoft Network Monitor capture file.
41  */
42
43 /* Capture file header, *including* magic number, is padded to 128 bytes. */
44 #define CAPTUREFILE_HEADER_SIZE 128
45
46 /* Magic number in Network Monitor 1.x files. */
47 static const char netmon_1_x_magic[] = {
48         'R', 'T', 'S', 'S'
49 };
50
51 /* Magic number in Network Monitor 2.x files. */
52 static const char netmon_2_x_magic[] = {
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 /* Network Monitor 2.x record header; not defined in STRUCT.H, but deduced by
90  * looking at capture files. */
91 struct netmonrec_2_x_hdr {
92         guint32 ts_delta_lo;    /* time stamp - usecs since start of capture */
93         guint32 ts_delta_hi;    /* time stamp - usecs since start of capture */
94         guint32 orig_len;       /* actual length of packet */
95         guint32 incl_len;       /* number of octets captured in file */
96 };
97
98 /*
99  * Network Monitor 2.1 and later record trailers; documented in the Network
100  * Monitor 3.x help files, for 3.3 and later, although they don't clearly
101  * state how the trailer format changes from version to version.
102  *
103  * Some fields are multi-byte integers, but they're not aligned on their
104  * natural boundaries.
105  */
106 struct netmonrec_2_1_trlr {
107         guint8 network[2];              /* network type for this packet */
108 };
109
110 struct netmonrec_2_2_trlr {
111         guint8 network[2];              /* network type for this packet */
112         guint8 process_info_index[4];   /* index into the process info table */
113 };
114
115 struct netmonrec_2_3_trlr {
116         guint8 network[2];              /* network type for this packet */
117         guint8 process_info_index[4];   /* index into the process info table */
118         guint8 utc_timestamp[8];        /* packet time stamp, as .1 us units since January 1, 1601, 00:00:00 UTC */
119         guint8 timezone_index;          /* index of time zone information */
120 };
121
122 /*
123  * The link-layer header on ATM packets.
124  */
125 struct netmon_atm_hdr {
126         guint8  dest[6];        /* "Destination address" - what is it? */
127         guint8  src[6];         /* "Source address" - what is it? */
128         guint16 vpi;            /* VPI */
129         guint16 vci;            /* VCI */
130 };
131
132 typedef struct {
133         time_t  start_secs;
134         guint32 start_usecs;
135         guint8  version_major;
136         guint8  version_minor;
137         guint32 *frame_table;
138         guint32 frame_table_size;
139         guint   current_frame;
140 } netmon_t;
141
142 /*
143  * XXX - at least in some NetMon 3.4 VPN captures, the per-packet
144  * link-layer type is 0, but the packets have Ethernet headers.
145  * We handle this by mapping 0 to WTAP_ENCAP_ETHERNET; should we,
146  * instead, use the per-file link-layer type?
147  */
148 static const int netmon_encap[] = {
149         WTAP_ENCAP_ETHERNET,
150         WTAP_ENCAP_ETHERNET,
151         WTAP_ENCAP_TOKEN_RING,
152         WTAP_ENCAP_FDDI_BITSWAPPED,
153         WTAP_ENCAP_ATM_PDUS,    /* NDIS WAN - this is what's used for ATM */
154         WTAP_ENCAP_UNKNOWN,     /* NDIS LocalTalk */
155         WTAP_ENCAP_IEEE802_11_NETMON_RADIO,
156                                 /* NDIS "DIX" - used for 802.11 */
157         WTAP_ENCAP_UNKNOWN,     /* NDIS ARCNET raw */
158         WTAP_ENCAP_UNKNOWN,     /* NDIS ARCNET 878.2 */
159         WTAP_ENCAP_UNKNOWN,     /* NDIS ATM (no, this is NOT used for ATM) */
160         WTAP_ENCAP_UNKNOWN,     /* NDIS Wireless WAN */
161         WTAP_ENCAP_UNKNOWN      /* NDIS IrDA */
162 };
163 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
164
165 /*
166  * Special link-layer types.
167  */
168 #define NETMON_NET_PCAP_BASE            0xE000
169 #define NETMON_NET_NETEVENT             0xFFE0
170 #define NETMON_NET_NETWORK_INFO_EX      0xFFFB
171 #define NETMON_NET_PAYLOAD_HEADER       0xFFFC
172 #define NETMON_NET_NETWORK_INFO         0xFFFD
173 #define NETMON_NET_DNS_CACHE            0xFFFE
174 #define NETMON_NET_NETMON_FILTER        0xFFFF
175
176 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
177     gint64 *data_offset);
178 static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
179     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
180     int *err, gchar **err_info);
181 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
182     union wtap_pseudo_header *pseudo_header, int *err);
183 static gboolean netmon_read_rec_data(FILE_T fh, guchar *pd, int length,
184     int *err);
185 static void netmon_sequential_close(wtap *wth);
186 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
187     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
188 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
189
190 int netmon_open(wtap *wth, int *err, gchar **err_info)
191 {
192         int bytes_read;
193         char magic[sizeof netmon_1_x_magic];
194         struct netmon_hdr hdr;
195         int file_type;
196         struct tm tm;
197         int frame_table_offset;
198         guint32 frame_table_length;
199         guint32 frame_table_size;
200         guint32 *frame_table;
201 #ifdef WORDS_BIGENDIAN
202         unsigned int i;
203 #endif
204         netmon_t *netmon;
205
206         /* Read in the string that should be at the start of a Network
207          * Monitor file */
208         errno = WTAP_ERR_CANT_READ;
209         bytes_read = file_read(magic, sizeof magic, wth->fh);
210         if (bytes_read != sizeof magic) {
211                 *err = file_error(wth->fh);
212                 if (*err != 0)
213                         return -1;
214                 return 0;
215         }
216
217         if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
218          && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
219                 return 0;
220         }
221
222         /* Read the rest of the header. */
223         errno = WTAP_ERR_CANT_READ;
224         bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
225         if (bytes_read != sizeof hdr) {
226                 *err = file_error(wth->fh);
227                 if (*err != 0)
228                         return -1;
229                 return 0;
230         }
231
232         switch (hdr.ver_major) {
233
234         case 1:
235                 file_type = WTAP_FILE_NETMON_1_x;
236                 break;
237
238         case 2:
239                 file_type = WTAP_FILE_NETMON_2_x;
240                 break;
241
242         default:
243                 *err = WTAP_ERR_UNSUPPORTED;
244                 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
245                 return -1;
246         }
247
248         hdr.network = pletohs(&hdr.network);
249         if (hdr.network >= NUM_NETMON_ENCAPS
250             || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
251                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
252                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
253                     hdr.network);
254                 return -1;
255         }
256
257         /* This is a netmon file */
258         wth->file_type = file_type;
259         netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
260         wth->priv = (void *)netmon;
261         wth->subtype_read = netmon_read;
262         wth->subtype_seek_read = netmon_seek_read;
263         wth->subtype_sequential_close = netmon_sequential_close;
264
265         /* NetMon capture file formats v2.1+ use per-packet encapsulation types.  NetMon 3 sets the value in
266          * the header to 1 (Ethernet) for backwards compability. */
267         if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
268                 wth->file_encap = WTAP_ENCAP_PER_PACKET;
269         else
270                 wth->file_encap = netmon_encap[hdr.network];
271
272         wth->snapshot_length = 0;       /* not available in header */
273         /*
274          * Convert the time stamp to a "time_t" and a number of
275          * milliseconds.
276          */
277         tm.tm_year = pletohs(&hdr.ts_year) - 1900;
278         tm.tm_mon = pletohs(&hdr.ts_month) - 1;
279         tm.tm_mday = pletohs(&hdr.ts_day);
280         tm.tm_hour = pletohs(&hdr.ts_hour);
281         tm.tm_min = pletohs(&hdr.ts_min);
282         tm.tm_sec = pletohs(&hdr.ts_sec);
283         tm.tm_isdst = -1;
284         netmon->start_secs = mktime(&tm);
285         /*
286          * XXX - what if "secs" is -1?  Unlikely, but if the capture was
287          * done in a time zone that switches between standard and summer
288          * time sometime other than when we do, and thus the time was one
289          * that doesn't exist here because a switch from standard to summer
290          * time zips over it, it could happen.
291          *
292          * On the other hand, if the capture was done in a different time
293          * zone, this won't work right anyway; unfortunately, the time
294          * zone isn't stored in the capture file (why the hell didn't
295          * they stuff a FILETIME, which is the number of 100-nanosecond
296          * intervals since 1601-01-01 00:00:00 "UTC", there, instead
297          * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
298          */
299         netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
300
301         netmon->version_major = hdr.ver_major;
302         netmon->version_minor = hdr.ver_minor;
303
304         /*
305          * Get the offset of the frame index table.
306          */
307         frame_table_offset = pletohl(&hdr.frametableoffset);
308
309         /*
310          * It appears that some NetMon 2.x files don't have the
311          * first packet starting exactly 128 bytes into the file.
312          *
313          * Furthermore, it also appears that there are "holes" in
314          * the file, i.e. frame N+1 doesn't always follow immediately
315          * after frame N.
316          *
317          * Therefore, we must read the frame table, and use the offsets
318          * in it as the offsets of the frames.
319          */
320         frame_table_length = pletohl(&hdr.frametablelength);
321         frame_table_size = frame_table_length / (guint32)sizeof (guint32);
322         if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
323                 *err = WTAP_ERR_UNSUPPORTED;
324                 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
325                     frame_table_length);
326                 g_free(netmon);
327                 return -1;
328         }
329         if (frame_table_size == 0) {
330                 *err = WTAP_ERR_UNSUPPORTED;
331                 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
332                     frame_table_length);
333                 g_free(netmon);
334                 return -1;
335         }
336         if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
337                 g_free(netmon);
338                 return -1;
339         }
340         frame_table = g_malloc(frame_table_length);
341         errno = WTAP_ERR_CANT_READ;
342         bytes_read = file_read(frame_table, frame_table_length, wth->fh);
343         if ((guint32)bytes_read != frame_table_length) {
344                 *err = file_error(wth->fh);
345                 if (*err == 0)
346                         *err = WTAP_ERR_SHORT_READ;
347                 g_free(frame_table);
348                 g_free(netmon);
349                 return -1;
350         }
351         netmon->frame_table_size = frame_table_size;
352         netmon->frame_table = frame_table;
353
354 #ifdef WORDS_BIGENDIAN
355         /*
356          * OK, now byte-swap the frame table.
357          */
358         for (i = 0; i < frame_table_size; i++)
359                 frame_table[i] = pletohl(&frame_table[i]);
360 #endif
361
362         /* Set up to start reading at the first frame. */
363         netmon->current_frame = 0;
364         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
365
366         return 1;
367 }
368
369 /* Read the next packet */
370 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
371     gint64 *data_offset)
372 {
373         netmon_t *netmon = (netmon_t *)wth->priv;
374         guint32 packet_size = 0;
375         guint32 orig_size = 0;
376         int     bytes_read;
377         union {
378                 struct netmonrec_1_x_hdr hdr_1_x;
379                 struct netmonrec_2_x_hdr hdr_2_x;
380         }       hdr;
381         union {
382                 struct netmonrec_2_1_trlr trlr_2_1;
383                 struct netmonrec_2_2_trlr trlr_2_2;
384                 struct netmonrec_2_3_trlr trlr_2_3;
385         }       trlr;
386         int     hdr_size = 0;
387         int     trlr_size = 0;
388         int     rec_offset;
389         guint8  *data_ptr;
390         gint64  delta = 0;      /* signed - frame times can be before the nominal start */
391         time_t  secs;
392         guint32 usecs;
393         double  t;
394         guint16 network;
395
396 again:
397         /* Have we reached the end of the packet data? */
398         if (netmon->current_frame >= netmon->frame_table_size) {
399                 /* Yes.  We won't need the frame table any more;
400                    free it. */
401                 g_free(netmon->frame_table);
402                 netmon->frame_table = NULL;
403                 *err = 0;       /* it's just an EOF, not an error */
404                 return FALSE;
405         }
406
407         /* Seek to the beginning of the current record, if we're
408            not there already (seeking to the current position
409            may still cause a seek and a read of the underlying file,
410            so we don't want to do it unconditionally).
411
412            Yes, the current record could be before the previous
413            record.  At least some captures put the trailer record
414            with statistics as the first physical record in the
415            file, but set the frame table up so it's the last
416            record in sequence. */
417         rec_offset = netmon->frame_table[netmon->current_frame];
418         if (wth->data_offset != rec_offset) {
419                 wth->data_offset = rec_offset;
420                 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
421                         return FALSE;
422         }
423         netmon->current_frame++;
424
425         /* Read record header. */
426         switch (netmon->version_major) {
427
428         case 1:
429                 hdr_size = sizeof (struct netmonrec_1_x_hdr);
430                 break;
431
432         case 2:
433                 hdr_size = sizeof (struct netmonrec_2_x_hdr);
434                 break;
435         }
436         errno = WTAP_ERR_CANT_READ;
437
438         bytes_read = file_read(&hdr, hdr_size, wth->fh);
439         if (bytes_read != hdr_size) {
440                 *err = file_error(wth->fh);
441                 if (*err == 0 && bytes_read != 0) {
442                         *err = WTAP_ERR_SHORT_READ;
443                 }
444                 return FALSE;
445         }
446         wth->data_offset += hdr_size;
447
448         switch (netmon->version_major) {
449
450         case 1:
451                 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
452                 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
453                 break;
454
455         case 2:
456                 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
457                 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
458                 break;
459         }
460         if (packet_size > WTAP_MAX_PACKET_SIZE) {
461                 /*
462                  * Probably a corrupt capture file; don't blow up trying
463                  * to allocate space for an immensely-large packet.
464                  */
465                 *err = WTAP_ERR_BAD_RECORD;
466                 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
467                     packet_size, WTAP_MAX_PACKET_SIZE);
468                 return FALSE;
469         }
470
471         *data_offset = wth->data_offset;
472
473         /*
474          * If this is an ATM packet, the first
475          * "sizeof (struct netmon_atm_hdr)" bytes have destination and
476          * source addresses (6 bytes - MAC addresses of some sort?)
477          * and the VPI and VCI; read them and generate the pseudo-header
478          * from them.
479          */
480         switch (wth->file_encap) {
481
482         case WTAP_ENCAP_ATM_PDUS:
483                 if (packet_size < sizeof (struct netmon_atm_hdr)) {
484                         /*
485                          * Uh-oh, the packet isn't big enough to even
486                          * have a pseudo-header.
487                          */
488                         *err = WTAP_ERR_BAD_RECORD;
489                         *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
490                             packet_size);
491                         return FALSE;
492                 }
493                 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
494                     err))
495                         return FALSE;   /* Read error */
496
497                 /*
498                  * Don't count the pseudo-header as part of the packet.
499                  */
500                 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
501                 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
502                 wth->data_offset += sizeof (struct netmon_atm_hdr);
503                 break;
504
505         case WTAP_ENCAP_ETHERNET:
506                 /*
507                  * We assume there's no FCS in this frame.
508                  */
509                 wth->pseudo_header.eth.fcs_len = 0;
510                 break;
511         }
512
513         buffer_assure_space(wth->frame_buffer, packet_size);
514         data_ptr = buffer_start_ptr(wth->frame_buffer);
515         if (!netmon_read_rec_data(wth->fh, data_ptr, packet_size, err))
516                 return FALSE;   /* Read error */
517         wth->data_offset += packet_size;
518
519         t = (double)netmon->start_usecs;
520         switch (netmon->version_major) {
521
522         case 1:
523                 /*
524                  * According to Paul Long, this offset is unsigned.
525                  * It's 32 bits, so the maximum value will fit in
526                  * a gint64 such as delta, even after multiplying
527                  * it by 1000.
528                  *
529                  * pletohl() returns a guint32; we cast it to gint64
530                  * before multiplying, so that the product doesn't
531                  * overflow a guint32.
532                  */
533                 delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
534                 break;
535
536         case 2:
537                 delta = pletohl(&hdr.hdr_2_x.ts_delta_lo)
538                     | (((guint64)pletohl(&hdr.hdr_2_x.ts_delta_hi)) << 32);
539                 break;
540         }
541         t += (double)delta;
542         secs = (time_t)(t/1000000);
543         usecs = (guint32)(t - (double)secs*1000000);
544         wth->phdr.ts.secs = netmon->start_secs + secs;
545         wth->phdr.ts.nsecs = usecs * 1000;
546         wth->phdr.caplen = packet_size;
547         wth->phdr.len = orig_size;
548
549         /*
550          * Attempt to guess from the packet data, the VPI, and the VCI
551          * information about the type of traffic.
552          */
553         if (wth->file_encap == WTAP_ENCAP_ATM_PDUS) {
554                 atm_guess_traffic_type(data_ptr, packet_size,
555                     &wth->pseudo_header);
556         }
557
558         /*
559          * For version 2.1 and later, there's additional information
560          * after the frame data.
561          */
562         if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
563             netmon->version_major > 2) {
564                 if (netmon->version_major > 2) {
565                         /*
566                          * Asssume 2.3 format, for now.
567                          */
568                         trlr_size = sizeof (struct netmonrec_2_3_trlr);
569                 } else {
570                         switch (netmon->version_minor) {
571
572                         case 1:
573                                 trlr_size = sizeof (struct netmonrec_2_1_trlr);
574                                 break;
575
576                         case 2:
577                                 trlr_size = sizeof (struct netmonrec_2_2_trlr);
578                                 break;
579
580                         default:
581                                 trlr_size = sizeof (struct netmonrec_2_3_trlr);
582                                 break;
583                         }
584                 }
585                 errno = WTAP_ERR_CANT_READ;
586
587                 bytes_read = file_read(&trlr, trlr_size, wth->fh);
588                 if (bytes_read != trlr_size) {
589                         *err = file_error(wth->fh);
590                         if (*err == 0 && bytes_read != 0) {
591                                 *err = WTAP_ERR_SHORT_READ;
592                         }
593                         return FALSE;
594                 }
595                 wth->data_offset += trlr_size;
596
597                 network = pletohs(trlr.trlr_2_1.network);
598                 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
599                         /*
600                          * Converted pcap file - the LINKTYPE_ value
601                          * is the network value with 0xF000 masked off.
602                          */
603                         network &= 0x0FFF;
604                         wth->phdr.pkt_encap =
605                             wtap_pcap_encap_to_wtap_encap(network);
606                         if (wth->phdr.pkt_encap == WTAP_ENCAP_UNKNOWN) {
607                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
608                                 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
609                                     network);
610                                 return FALSE;
611                         }
612                 } else if (network < NUM_NETMON_ENCAPS) {
613                         /*
614                          * Regular NetMon encapsulation.
615                          */
616                         wth->phdr.pkt_encap = netmon_encap[network];
617                         if (wth->phdr.pkt_encap == WTAP_ENCAP_UNKNOWN) {
618                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
619                                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
620                                     network);
621                                 return FALSE;
622                         }
623                 } else {
624                         /*
625                          * Special packet type for metadata.
626                          */
627                         switch (network) {
628
629                         case NETMON_NET_NETEVENT:
630                         case NETMON_NET_NETWORK_INFO_EX:
631                         case NETMON_NET_PAYLOAD_HEADER:
632                         case NETMON_NET_NETWORK_INFO:
633                         case NETMON_NET_DNS_CACHE:
634                         case NETMON_NET_NETMON_FILTER:
635                                 /*
636                                  * Just ignore those record types, for
637                                  * now.  Read the next record.
638                                  */
639                                 goto again;
640
641                         default:
642                                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
643                                 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
644                                     network);
645                                 return FALSE;
646                         }
647                 }
648         }
649
650         return TRUE;
651 }
652
653 static gboolean
654 netmon_seek_read(wtap *wth, gint64 seek_off,
655     union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
656     int *err, gchar **err_info _U_)
657 {
658         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
659                 return FALSE;
660
661         switch (wth->file_encap) {
662
663         case WTAP_ENCAP_ATM_PDUS:
664                 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
665                     err)) {
666                         /* Read error */
667                         return FALSE;
668                 }
669                 break;
670
671         case WTAP_ENCAP_ETHERNET:
672                 /*
673                  * We assume there's no FCS in this frame.
674                  */
675                 pseudo_header->eth.fcs_len = 0;
676                 break;
677         }
678
679         /*
680          * Read the packet data.
681          */
682         if (!netmon_read_rec_data(wth->random_fh, pd, length, err))
683                 return FALSE;
684
685         /*
686          * Attempt to guess from the packet data, the VPI, and the VCI
687          * information about the type of traffic.
688          */
689         if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
690                 atm_guess_traffic_type(pd, length, pseudo_header);
691
692         return TRUE;
693 }
694
695 static gboolean
696 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
697     int *err)
698 {
699         struct netmon_atm_hdr atm_phdr;
700         int     bytes_read;
701         guint16 vpi, vci;
702
703         errno = WTAP_ERR_CANT_READ;
704         bytes_read = file_read(&atm_phdr, sizeof (struct netmon_atm_hdr), fh);
705         if (bytes_read != sizeof (struct netmon_atm_hdr)) {
706                 *err = file_error(fh);
707                 if (*err == 0)
708                         *err = WTAP_ERR_SHORT_READ;
709                 return FALSE;
710         }
711
712         vpi = g_ntohs(atm_phdr.vpi);
713         vci = g_ntohs(atm_phdr.vci);
714
715         pseudo_header->atm.vpi = vpi;
716         pseudo_header->atm.vci = vci;
717
718         /* We don't have this information */
719         pseudo_header->atm.flags = 0;
720         pseudo_header->atm.channel = 0;
721         pseudo_header->atm.cells = 0;
722         pseudo_header->atm.aal5t_u2u = 0;
723         pseudo_header->atm.aal5t_len = 0;
724         pseudo_header->atm.aal5t_chksum = 0;
725
726         return TRUE;
727 }
728
729 static gboolean
730 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
731 {
732         int     bytes_read;
733
734         errno = WTAP_ERR_CANT_READ;
735         bytes_read = file_read(pd, length, fh);
736
737         if (bytes_read != length) {
738                 *err = file_error(fh);
739                 if (*err == 0)
740                         *err = WTAP_ERR_SHORT_READ;
741                 return FALSE;
742         }
743         return TRUE;
744 }
745
746 /* Throw away the frame table used by the sequential I/O stream. */
747 static void
748 netmon_sequential_close(wtap *wth)
749 {
750         netmon_t *netmon = (netmon_t *)wth->priv;
751
752         if (netmon->frame_table != NULL) {
753                 g_free(netmon->frame_table);
754                 netmon->frame_table = NULL;
755         }
756 }
757
758 typedef struct {
759         gboolean got_first_record_time;
760         struct wtap_nstime first_record_time;
761         guint32 frame_table_offset;
762         guint32 *frame_table;
763         guint   frame_table_index;
764         guint   frame_table_size;
765 } netmon_dump_t;
766
767 static const int wtap_encap[] = {
768         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
769         1,              /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
770         2,              /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
771         -1,             /* WTAP_ENCAP_SLIP -> unsupported */
772         -1,             /* WTAP_ENCAP_PPP -> unsupported */
773         3,              /* WTAP_ENCAP_FDDI -> NDIS FDDI */
774         3,              /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
775         -1,             /* WTAP_ENCAP_RAW_IP -> unsupported */
776         -1,             /* WTAP_ENCAP_ARCNET -> unsupported */
777         -1,             /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
778         -1,             /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
779         -1,             /* WTAP_ENCAP_LAPB -> unsupported*/
780         4,              /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
781         -1              /* WTAP_ENCAP_NULL -> unsupported */
782 };
783 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
784
785 /* Returns 0 if we could write the specified encapsulation type,
786    an error indication otherwise. */
787 int netmon_dump_can_write_encap(int encap)
788 {
789         /* Per-packet encapsulations aren't supported. */
790         if (encap == WTAP_ENCAP_PER_PACKET)
791                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
792
793         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
794                 return WTAP_ERR_UNSUPPORTED_ENCAP;
795
796         return 0;
797 }
798
799 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
800    failure */
801 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
802 {
803         netmon_dump_t *netmon;
804
805         /* We can't fill in all the fields in the file header, as we
806            haven't yet written any packets.  As we'll have to rewrite
807            the header when we've written out all the packets, we just
808            skip over the header for now. */
809         if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
810                 *err = errno;
811                 return FALSE;
812         }
813
814         wdh->subtype_write = netmon_dump;
815         wdh->subtype_close = netmon_dump_close;
816
817         netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
818         wdh->priv = (void *)netmon;
819         netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
820         netmon->got_first_record_time = FALSE;
821         netmon->frame_table = NULL;
822         netmon->frame_table_index = 0;
823         netmon->frame_table_size = 0;
824
825         return TRUE;
826 }
827
828 /* Write a record for a packet to a dump file.
829    Returns TRUE on success, FALSE on failure. */
830 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
831     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
832 {
833         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
834         struct netmonrec_1_x_hdr rec_1_x_hdr;
835         struct netmonrec_2_x_hdr rec_2_x_hdr;
836         char *hdrp;
837         size_t hdr_size;
838         double t;
839         guint32 time_low, time_high;
840         struct netmon_atm_hdr atm_hdr;
841         int atm_hdrsize;
842
843         /* NetMon files have a capture start time in the file header,
844            and have times relative to that in the packet headers;
845            pick the time of the first packet as the capture start
846            time. */
847         if (!netmon->got_first_record_time) {
848                 netmon->first_record_time = phdr->ts;
849                 netmon->got_first_record_time = TRUE;
850         }
851
852         if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
853                 atm_hdrsize = sizeof (struct netmon_atm_hdr);
854         else
855                 atm_hdrsize = 0;
856         switch (wdh->file_type) {
857
858         case WTAP_FILE_NETMON_1_x:
859                 rec_1_x_hdr.ts_delta = htolel(
860                     (phdr->ts.secs - netmon->first_record_time.secs)*1000
861                   + (phdr->ts.nsecs - netmon->first_record_time.nsecs + 500000)/1000000);
862                 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
863                 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
864                 hdrp = (char *)&rec_1_x_hdr;
865                 hdr_size = sizeof rec_1_x_hdr;
866                 break;
867
868         case WTAP_FILE_NETMON_2_x:
869                 /*
870                  * Unfortunately, not all the platforms on which we run
871                  * support 64-bit integral types, even though most do
872                  * (even on 32-bit processors), so we do it in floating
873                  * point.
874                  */
875                 t = (phdr->ts.secs - netmon->first_record_time.secs)*1000000.0
876                   + (phdr->ts.nsecs - netmon->first_record_time.nsecs) / 1000;
877                 time_high = (guint32) (t/4294967296.0);
878                 time_low  = (guint32) (t - (time_high*4294967296.0));
879                 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
880                 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
881                 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
882                 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
883                 hdrp = (char *)&rec_2_x_hdr;
884                 hdr_size = sizeof rec_2_x_hdr;
885                 break;
886
887         default:
888                 /* We should never get here - our open routine
889                    should only get called for the types above. */
890                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
891                 return FALSE;
892         }
893
894         if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
895                 return FALSE;
896
897         if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
898                 /*
899                  * Write the ATM header.
900                  * We supply all-zero destination and source addresses.
901                  */
902                 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
903                 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
904                 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
905                 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
906                 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
907                         return FALSE;
908         }
909
910         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
911                 return FALSE;
912
913         /*
914          * Stash the file offset of this frame.
915          */
916         if (netmon->frame_table_size == 0) {
917                 /*
918                  * Haven't yet allocated the buffer for the frame table.
919                  */
920                 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
921                 netmon->frame_table_size = 1024;
922         } else {
923                 /*
924                  * We've allocated it; are we at the end?
925                  */
926                 if (netmon->frame_table_index >= netmon->frame_table_size) {
927                         /*
928                          * Yes - double the size of the frame table.
929                          */
930                         netmon->frame_table_size *= 2;
931                         netmon->frame_table = g_realloc(netmon->frame_table,
932                             netmon->frame_table_size * sizeof *netmon->frame_table);
933                 }
934         }
935         netmon->frame_table[netmon->frame_table_index] =
936             htolel(netmon->frame_table_offset);
937         netmon->frame_table_index++;
938         netmon->frame_table_offset += (int) hdr_size + phdr->caplen + atm_hdrsize;
939
940         return TRUE;
941 }
942
943 /* Finish writing to a dump file.
944    Returns TRUE on success, FALSE on failure. */
945 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
946 {
947         netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
948         size_t n_to_write;
949         struct netmon_hdr file_hdr;
950         const char *magicp;
951         size_t magic_size;
952         struct tm *tm;
953
954         /* Write out the frame table.  "netmon->frame_table_index" is
955            the number of entries we've put into it. */
956         n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
957         if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
958                 return FALSE;
959
960         /* Now go fix up the file header. */
961         fseek(wdh->fh, 0, SEEK_SET);
962         memset(&file_hdr, '\0', sizeof file_hdr);
963         switch (wdh->file_type) {
964
965         case WTAP_FILE_NETMON_1_x:
966                 magicp = netmon_1_x_magic;
967                 magic_size = sizeof netmon_1_x_magic;
968                 /* NetMon file version, for 1.x, is 1.1 */
969                 file_hdr.ver_major = 1;
970                 file_hdr.ver_minor = 1;
971                 break;
972
973         case WTAP_FILE_NETMON_2_x:
974                 magicp = netmon_2_x_magic;
975                 magic_size = sizeof netmon_2_x_magic;
976                 /*
977                  * NetMon file version, for 2.x, is 2.0;
978                  * for 3.0, it's 2.1.
979                  */
980                 file_hdr.ver_major = 2;
981                 file_hdr.ver_minor = 0;
982                 break;
983
984         default:
985                 /* We should never get here - our open routine
986                    should only get called for the types above. */
987                 if (err != NULL)
988                         *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
989                 return FALSE;
990         }
991         if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
992                 return FALSE;
993
994         file_hdr.network = htoles(wtap_encap[wdh->encap]);
995         tm = localtime(&netmon->first_record_time.secs);
996         if (tm != NULL) {
997                 file_hdr.ts_year  = htoles(1900 + tm->tm_year);
998                 file_hdr.ts_month = htoles(tm->tm_mon + 1);
999                 file_hdr.ts_dow   = htoles(tm->tm_wday);
1000                 file_hdr.ts_day   = htoles(tm->tm_mday);
1001                 file_hdr.ts_hour  = htoles(tm->tm_hour);
1002                 file_hdr.ts_min   = htoles(tm->tm_min);
1003                 file_hdr.ts_sec   = htoles(tm->tm_sec);
1004         } else {
1005                 file_hdr.ts_year  = htoles(1900 + 0);
1006                 file_hdr.ts_month = htoles(0 + 1);
1007                 file_hdr.ts_dow   = htoles(0);
1008                 file_hdr.ts_day   = htoles(0);
1009                 file_hdr.ts_hour  = htoles(0);
1010                 file_hdr.ts_min   = htoles(0);
1011                 file_hdr.ts_sec   = htoles(0);
1012         }
1013         file_hdr.ts_msec  = htoles(netmon->first_record_time.nsecs/1000000);
1014                 /* XXX - what about rounding? */
1015         file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
1016         file_hdr.frametablelength =
1017             htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
1018         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
1019                 return FALSE;
1020
1021         return TRUE;
1022 }