6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
29 #include "file_wrappers.h"
32 #include "pcap-encap.h"
37 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
39 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
40 * for the header of a Microsoft Network Monitor capture file.
43 /* Capture file header, *including* magic number, is padded to 128 bytes. */
44 #define CAPTUREFILE_HEADER_SIZE 128
46 /* Magic number in Network Monitor 1.x files. */
47 static const char netmon_1_x_magic[] = {
51 /* Magic number in Network Monitor 2.x files. */
52 static const char netmon_2_x_magic[] = {
56 /* Network Monitor file header (minus magic number). */
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 */
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 */
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 */
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.
103 * Some fields are multi-byte integers, but they're not aligned on their
104 * natural boundaries.
106 struct netmonrec_2_1_trlr {
107 guint8 network[2]; /* network type for this packet */
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 */
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 */
123 * The link-layer header on ATM packets.
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 */
135 guint8 version_major;
136 guint8 version_minor;
137 guint32 *frame_table;
138 guint32 frame_table_size;
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?
148 static const int netmon_encap[] = {
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, but format 2.x uses it for IP-over-IEEE 1394 */
155 WTAP_ENCAP_IEEE802_11_NETMON_RADIO,
156 /* NDIS "DIX", but format 2.x uses it for 802.11 */
157 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET raw, but format 2.x uses it for "Tunneling interfaces" */
158 WTAP_ENCAP_RAW_IP, /* NDIS ARCNET 878.2, but format 2.x uses it for "Wireless WAN" */
159 WTAP_ENCAP_RAW_IP, /* NDIS ATM (no, this is NOT used for ATM); format 2.x uses it for "Raw IP Frames" */
160 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
161 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
163 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
166 * Special link-layer types.
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
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, guint8 *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, gchar **err_info);
183 static gboolean netmon_read_rec_data(FILE_T fh, guint8 *pd, int length,
184 int *err, gchar **err_info);
185 static int netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err,
187 static void netmon_sequential_close(wtap *wth);
188 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
189 const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err);
190 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
192 int netmon_open(wtap *wth, int *err, gchar **err_info)
195 char magic[sizeof netmon_1_x_magic];
196 struct netmon_hdr hdr;
199 int frame_table_offset;
200 guint32 frame_table_length;
201 guint32 frame_table_size;
202 guint32 *frame_table;
203 #ifdef WORDS_BIGENDIAN
208 /* Read in the string that should be at the start of a Network
210 errno = WTAP_ERR_CANT_READ;
211 bytes_read = file_read(magic, sizeof magic, wth->fh);
212 if (bytes_read != sizeof magic) {
213 *err = file_error(wth->fh, err_info);
219 if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
220 && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
224 /* Read the rest of the header. */
225 errno = WTAP_ERR_CANT_READ;
226 bytes_read = file_read(&hdr, sizeof hdr, wth->fh);
227 if (bytes_read != sizeof hdr) {
228 *err = file_error(wth->fh, err_info);
234 switch (hdr.ver_major) {
237 file_type = WTAP_FILE_NETMON_1_x;
241 file_type = WTAP_FILE_NETMON_2_x;
245 *err = WTAP_ERR_UNSUPPORTED;
246 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
250 hdr.network = pletohs(&hdr.network);
251 if (hdr.network >= NUM_NETMON_ENCAPS
252 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
253 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
254 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
259 /* This is a netmon file */
260 wth->file_type = file_type;
261 netmon = (netmon_t *)g_malloc(sizeof(netmon_t));
262 wth->priv = (void *)netmon;
263 wth->subtype_read = netmon_read;
264 wth->subtype_seek_read = netmon_seek_read;
265 wth->subtype_sequential_close = netmon_sequential_close;
267 /* NetMon capture file formats v2.1+ use per-packet encapsulation types. NetMon 3 sets the value in
268 * the header to 1 (Ethernet) for backwards compability. */
269 if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
270 wth->file_encap = WTAP_ENCAP_PER_PACKET;
272 wth->file_encap = netmon_encap[hdr.network];
274 wth->snapshot_length = 0; /* not available in header */
276 * Convert the time stamp to a "time_t" and a number of
279 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
280 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
281 tm.tm_mday = pletohs(&hdr.ts_day);
282 tm.tm_hour = pletohs(&hdr.ts_hour);
283 tm.tm_min = pletohs(&hdr.ts_min);
284 tm.tm_sec = pletohs(&hdr.ts_sec);
286 netmon->start_secs = mktime(&tm);
288 * XXX - what if "secs" is -1? Unlikely, but if the capture was
289 * done in a time zone that switches between standard and summer
290 * time sometime other than when we do, and thus the time was one
291 * that doesn't exist here because a switch from standard to summer
292 * time zips over it, it could happen.
294 * On the other hand, if the capture was done in a different time
295 * zone, this won't work right anyway; unfortunately, the time
296 * zone isn't stored in the capture file (why the hell didn't
297 * they stuff a FILETIME, which is the number of 100-nanosecond
298 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
299 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
301 netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
303 netmon->version_major = hdr.ver_major;
304 netmon->version_minor = hdr.ver_minor;
307 * Get the offset of the frame index table.
309 frame_table_offset = pletohl(&hdr.frametableoffset);
312 * It appears that some NetMon 2.x files don't have the
313 * first packet starting exactly 128 bytes into the file.
315 * Furthermore, it also appears that there are "holes" in
316 * the file, i.e. frame N+1 doesn't always follow immediately
319 * Therefore, we must read the frame table, and use the offsets
320 * in it as the offsets of the frames.
322 frame_table_length = pletohl(&hdr.frametablelength);
323 frame_table_size = frame_table_length / (guint32)sizeof (guint32);
324 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
325 *err = WTAP_ERR_UNSUPPORTED;
326 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
331 if (frame_table_size == 0) {
332 *err = WTAP_ERR_UNSUPPORTED;
333 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
338 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
342 frame_table = g_malloc(frame_table_length);
343 errno = WTAP_ERR_CANT_READ;
344 bytes_read = file_read(frame_table, frame_table_length, wth->fh);
345 if ((guint32)bytes_read != frame_table_length) {
346 *err = file_error(wth->fh, err_info);
348 *err = WTAP_ERR_SHORT_READ;
353 netmon->frame_table_size = frame_table_size;
354 netmon->frame_table = frame_table;
356 #ifdef WORDS_BIGENDIAN
358 * OK, now byte-swap the frame table.
360 for (i = 0; i < frame_table_size; i++)
361 frame_table[i] = pletohl(&frame_table[i]);
364 /* Set up to start reading at the first frame. */
365 netmon->current_frame = 0;
366 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
372 netmon_trailer_size(netmon_t *netmon)
374 if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
375 netmon->version_major > 2) {
376 if (netmon->version_major > 2) {
378 * Asssume 2.3 format, for now.
380 return sizeof (struct netmonrec_2_3_trlr);
382 switch (netmon->version_minor) {
385 return sizeof (struct netmonrec_2_1_trlr);
388 return sizeof (struct netmonrec_2_2_trlr);
391 return sizeof (struct netmonrec_2_3_trlr);
395 return 0; /* no trailer */
399 netmon_set_pseudo_header_info(int pkt_encap,
400 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length)
404 case WTAP_ENCAP_ATM_PDUS:
406 * Attempt to guess from the packet data, the VPI, and
407 * the VCIinformation about the type of traffic.
409 atm_guess_traffic_type(pd, length, pseudo_header);
412 case WTAP_ENCAP_ETHERNET:
414 * We assume there's no FCS in this frame.
416 pseudo_header->eth.fcs_len = 0;
419 case WTAP_ENCAP_IEEE802_11_NETMON_RADIO:
421 * It appears to be the case that management
422 * frames have an FCS and data frames don't;
423 * I'm not sure about control frames. An
424 * "FCS length" of -2 means "NetMon weirdness".
426 pseudo_header->ieee_802_11.fcs_len = -2;
431 /* Read the next packet */
432 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
435 netmon_t *netmon = (netmon_t *)wth->priv;
436 guint32 packet_size = 0;
437 guint32 orig_size = 0;
440 struct netmonrec_1_x_hdr hdr_1_x;
441 struct netmonrec_2_x_hdr hdr_2_x;
447 gint64 delta = 0; /* signed - frame times can be before the nominal start */
453 /* Have we reached the end of the packet data? */
454 if (netmon->current_frame >= netmon->frame_table_size) {
455 /* Yes. We won't need the frame table any more;
457 g_free(netmon->frame_table);
458 netmon->frame_table = NULL;
459 *err = 0; /* it's just an EOF, not an error */
463 /* Seek to the beginning of the current record, if we're
464 not there already (seeking to the current position
465 may still cause a seek and a read of the underlying file,
466 so we don't want to do it unconditionally).
468 Yes, the current record could be before the previous
469 record. At least some captures put the trailer record
470 with statistics as the first physical record in the
471 file, but set the frame table up so it's the last
472 record in sequence. */
473 rec_offset = netmon->frame_table[netmon->current_frame];
474 if (wth->data_offset != rec_offset) {
475 wth->data_offset = rec_offset;
476 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
479 netmon->current_frame++;
481 /* Read record header. */
482 switch (netmon->version_major) {
485 hdr_size = sizeof (struct netmonrec_1_x_hdr);
489 hdr_size = sizeof (struct netmonrec_2_x_hdr);
492 errno = WTAP_ERR_CANT_READ;
494 bytes_read = file_read(&hdr, hdr_size, wth->fh);
495 if (bytes_read != hdr_size) {
496 *err = file_error(wth->fh, err_info);
497 if (*err == 0 && bytes_read != 0) {
498 *err = WTAP_ERR_SHORT_READ;
502 wth->data_offset += hdr_size;
504 switch (netmon->version_major) {
507 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
508 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
512 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
513 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
516 if (packet_size > WTAP_MAX_PACKET_SIZE) {
518 * Probably a corrupt capture file; don't blow up trying
519 * to allocate space for an immensely-large packet.
521 *err = WTAP_ERR_BAD_RECORD;
522 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
523 packet_size, WTAP_MAX_PACKET_SIZE);
527 *data_offset = wth->data_offset;
530 * If this is an ATM packet, the first
531 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
532 * source addresses (6 bytes - MAC addresses of some sort?)
533 * and the VPI and VCI; read them and generate the pseudo-header
536 switch (wth->file_encap) {
538 case WTAP_ENCAP_ATM_PDUS:
539 if (packet_size < sizeof (struct netmon_atm_hdr)) {
541 * Uh-oh, the packet isn't big enough to even
542 * have a pseudo-header.
544 *err = WTAP_ERR_BAD_RECORD;
545 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
549 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
551 return FALSE; /* Read error */
554 * Don't count the pseudo-header as part of the packet.
556 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
557 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
558 wth->data_offset += sizeof (struct netmon_atm_hdr);
565 buffer_assure_space(wth->frame_buffer, packet_size);
566 data_ptr = buffer_start_ptr(wth->frame_buffer);
567 if (!netmon_read_rec_data(wth->fh, data_ptr, packet_size, err,
569 return FALSE; /* Read error */
570 wth->data_offset += packet_size;
572 t = (double)netmon->start_usecs;
573 switch (netmon->version_major) {
577 * According to Paul Long, this offset is unsigned.
578 * It's 32 bits, so the maximum value will fit in
579 * a gint64 such as delta, even after multiplying
582 * pletohl() returns a guint32; we cast it to gint64
583 * before multiplying, so that the product doesn't
584 * overflow a guint32.
586 delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
590 delta = pletohl(&hdr.hdr_2_x.ts_delta_lo)
591 | (((guint64)pletohl(&hdr.hdr_2_x.ts_delta_hi)) << 32);
595 secs = (time_t)(t/1000000);
596 usecs = (guint32)(t - (double)secs*1000000);
597 wth->phdr.ts.secs = netmon->start_secs + secs;
598 wth->phdr.ts.nsecs = usecs * 1000;
599 wth->phdr.caplen = packet_size;
600 wth->phdr.len = orig_size;
603 * For version 2.1 and later, there's additional information
604 * after the frame data.
606 trlr_size = (int)netmon_trailer_size(netmon);
607 if (trlr_size != 0) {
611 wth->phdr.pkt_encap = netmon_read_rec_trailer(wth->fh,
612 trlr_size, err, err_info);
613 if (wth->phdr.pkt_encap == -1)
614 return FALSE; /* error */
615 wth->data_offset += trlr_size;
616 if (wth->phdr.pkt_encap == 0)
618 netmon_set_pseudo_header_info(wth->phdr.pkt_encap,
619 &wth->pseudo_header, data_ptr, packet_size);
621 netmon_set_pseudo_header_info(wth->file_encap,
622 &wth->pseudo_header, data_ptr, packet_size);
629 netmon_seek_read(wtap *wth, gint64 seek_off,
630 union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
631 int *err, gchar **err_info)
633 netmon_t *netmon = (netmon_t *)wth->priv;
637 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
640 switch (wth->file_encap) {
642 case WTAP_ENCAP_ATM_PDUS:
643 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
652 * Read the packet data.
654 if (!netmon_read_rec_data(wth->random_fh, pd, length, err, err_info))
658 * For version 2.1 and later, there's additional information
659 * after the frame data.
661 trlr_size = (int)netmon_trailer_size(netmon);
662 if (trlr_size != 0) {
666 pkt_encap = netmon_read_rec_trailer(wth->random_fh,
667 trlr_size, err, err_info);
669 return FALSE; /* error */
670 if (pkt_encap == 0) {
672 * This should not happen.
674 *err = WTAP_ERR_BAD_RECORD;
675 *err_info = g_strdup("netmon: saw metadata in netmon_seek_read");
678 netmon_set_pseudo_header_info(pkt_encap, pseudo_header,
681 netmon_set_pseudo_header_info(wth->file_encap, pseudo_header,
689 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
690 int *err, gchar **err_info)
692 struct netmon_atm_hdr atm_phdr;
696 errno = WTAP_ERR_CANT_READ;
697 bytes_read = file_read(&atm_phdr, sizeof (struct netmon_atm_hdr), fh);
698 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
699 *err = file_error(fh, err_info);
701 *err = WTAP_ERR_SHORT_READ;
705 vpi = g_ntohs(atm_phdr.vpi);
706 vci = g_ntohs(atm_phdr.vci);
708 pseudo_header->atm.vpi = vpi;
709 pseudo_header->atm.vci = vci;
711 /* We don't have this information */
712 pseudo_header->atm.flags = 0;
713 pseudo_header->atm.channel = 0;
714 pseudo_header->atm.cells = 0;
715 pseudo_header->atm.aal5t_u2u = 0;
716 pseudo_header->atm.aal5t_len = 0;
717 pseudo_header->atm.aal5t_chksum = 0;
723 netmon_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
728 errno = WTAP_ERR_CANT_READ;
729 bytes_read = file_read(pd, length, fh);
731 if (bytes_read != length) {
732 *err = file_error(fh, err_info);
734 *err = WTAP_ERR_SHORT_READ;
741 * Read a record trailer.
742 * On success, returns the packet encapsulation type.
743 * On error, returns -1 (which is WTAP_ENCAP_PER_PACKET, but we'd
744 * never return that on success).
745 * For metadata packets, returns 0 (which is WTAP_ENCAP_UNKNOWN, but
746 * we'd never return that on success).
749 netmon_read_rec_trailer(FILE_T fh, int trlr_size, int *err, gchar **err_info)
753 struct netmonrec_2_1_trlr trlr_2_1;
754 struct netmonrec_2_2_trlr trlr_2_2;
755 struct netmonrec_2_3_trlr trlr_2_3;
760 errno = WTAP_ERR_CANT_READ;
761 bytes_read = file_read(&trlr, trlr_size, fh);
762 if (bytes_read != trlr_size) {
763 *err = file_error(fh, err_info);
764 if (*err == 0 && bytes_read != 0) {
765 *err = WTAP_ERR_SHORT_READ;
767 return -1; /* error */
770 network = pletohs(trlr.trlr_2_1.network);
771 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
773 * Converted pcap file - the LINKTYPE_ value
774 * is the network value with 0xF000 masked off.
777 pkt_encap = wtap_pcap_encap_to_wtap_encap(network);
778 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
779 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
780 *err_info = g_strdup_printf("netmon: converted pcap network type %u unknown or unsupported",
782 return -1; /* error */
784 } else if (network < NUM_NETMON_ENCAPS) {
786 * Regular NetMon encapsulation.
788 pkt_encap = netmon_encap[network];
789 if (pkt_encap == WTAP_ENCAP_UNKNOWN) {
790 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
791 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
793 return -1; /* error */
797 * Special packet type for metadata.
801 case NETMON_NET_NETEVENT:
802 case NETMON_NET_NETWORK_INFO_EX:
803 case NETMON_NET_PAYLOAD_HEADER:
804 case NETMON_NET_NETWORK_INFO:
805 case NETMON_NET_DNS_CACHE:
806 case NETMON_NET_NETMON_FILTER:
808 * Just ignore those record types, for
809 * now. Tell our caller to read the next
815 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
816 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
818 return -1; /* error */
822 return pkt_encap; /* success */
825 /* Throw away the frame table used by the sequential I/O stream. */
827 netmon_sequential_close(wtap *wth)
829 netmon_t *netmon = (netmon_t *)wth->priv;
831 if (netmon->frame_table != NULL) {
832 g_free(netmon->frame_table);
833 netmon->frame_table = NULL;
838 gboolean got_first_record_time;
839 struct wtap_nstime first_record_time;
840 guint32 frame_table_offset;
841 guint32 *frame_table;
842 guint frame_table_index;
843 guint frame_table_size;
846 static const int wtap_encap[] = {
847 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
848 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
849 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
850 -1, /* WTAP_ENCAP_SLIP -> unsupported */
851 -1, /* WTAP_ENCAP_PPP -> unsupported */
852 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
853 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
854 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
855 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
856 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
857 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
858 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
859 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
860 -1 /* WTAP_ENCAP_NULL -> unsupported */
862 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
864 /* Returns 0 if we could write the specified encapsulation type,
865 an error indication otherwise. */
866 int netmon_dump_can_write_encap(int encap)
868 /* Per-packet encapsulations aren't supported. */
869 if (encap == WTAP_ENCAP_PER_PACKET)
870 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
872 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
873 return WTAP_ERR_UNSUPPORTED_ENCAP;
878 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
880 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
882 netmon_dump_t *netmon;
884 /* We can't fill in all the fields in the file header, as we
885 haven't yet written any packets. As we'll have to rewrite
886 the header when we've written out all the packets, we just
887 skip over the header for now. */
888 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
893 wdh->subtype_write = netmon_dump;
894 wdh->subtype_close = netmon_dump_close;
896 netmon = (netmon_dump_t *)g_malloc(sizeof(netmon_dump_t));
897 wdh->priv = (void *)netmon;
898 netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
899 netmon->got_first_record_time = FALSE;
900 netmon->frame_table = NULL;
901 netmon->frame_table_index = 0;
902 netmon->frame_table_size = 0;
907 /* Write a record for a packet to a dump file.
908 Returns TRUE on success, FALSE on failure. */
909 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
910 const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
912 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
913 struct netmonrec_1_x_hdr rec_1_x_hdr;
914 struct netmonrec_2_x_hdr rec_2_x_hdr;
918 guint32 time_low, time_high;
919 struct netmon_atm_hdr atm_hdr;
922 /* NetMon files have a capture start time in the file header,
923 and have times relative to that in the packet headers;
924 pick the time of the first packet as the capture start
926 if (!netmon->got_first_record_time) {
927 netmon->first_record_time = phdr->ts;
928 netmon->got_first_record_time = TRUE;
931 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
932 atm_hdrsize = sizeof (struct netmon_atm_hdr);
935 switch (wdh->file_type) {
937 case WTAP_FILE_NETMON_1_x:
938 rec_1_x_hdr.ts_delta = htolel(
939 (phdr->ts.secs - netmon->first_record_time.secs)*1000
940 + (phdr->ts.nsecs - netmon->first_record_time.nsecs + 500000)/1000000);
941 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
942 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
943 hdrp = (char *)&rec_1_x_hdr;
944 hdr_size = sizeof rec_1_x_hdr;
947 case WTAP_FILE_NETMON_2_x:
949 * Unfortunately, not all the platforms on which we run
950 * support 64-bit integral types, even though most do
951 * (even on 32-bit processors), so we do it in floating
954 t = (phdr->ts.secs - netmon->first_record_time.secs)*1000000.0
955 + (phdr->ts.nsecs - netmon->first_record_time.nsecs) / 1000;
956 time_high = (guint32) (t/4294967296.0);
957 time_low = (guint32) (t - (time_high*4294967296.0));
958 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
959 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
960 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
961 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
962 hdrp = (char *)&rec_2_x_hdr;
963 hdr_size = sizeof rec_2_x_hdr;
967 /* We should never get here - our open routine
968 should only get called for the types above. */
969 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
973 if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
976 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
978 * Write the ATM header.
979 * We supply all-zero destination and source addresses.
981 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
982 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
983 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
984 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
985 if (!wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr, err))
989 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
993 * Stash the file offset of this frame.
995 if (netmon->frame_table_size == 0) {
997 * Haven't yet allocated the buffer for the frame table.
999 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
1000 netmon->frame_table_size = 1024;
1003 * We've allocated it; are we at the end?
1005 if (netmon->frame_table_index >= netmon->frame_table_size) {
1007 * Yes - double the size of the frame table.
1009 netmon->frame_table_size *= 2;
1010 netmon->frame_table = g_realloc(netmon->frame_table,
1011 netmon->frame_table_size * sizeof *netmon->frame_table);
1014 netmon->frame_table[netmon->frame_table_index] =
1015 htolel(netmon->frame_table_offset);
1016 netmon->frame_table_index++;
1017 netmon->frame_table_offset += (int) hdr_size + phdr->caplen + atm_hdrsize;
1022 /* Finish writing to a dump file.
1023 Returns TRUE on success, FALSE on failure. */
1024 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
1026 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
1028 struct netmon_hdr file_hdr;
1033 /* Write out the frame table. "netmon->frame_table_index" is
1034 the number of entries we've put into it. */
1035 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
1036 if (!wtap_dump_file_write(wdh, netmon->frame_table, n_to_write, err))
1039 /* Now go fix up the file header. */
1040 fseek(wdh->fh, 0, SEEK_SET);
1041 memset(&file_hdr, '\0', sizeof file_hdr);
1042 switch (wdh->file_type) {
1044 case WTAP_FILE_NETMON_1_x:
1045 magicp = netmon_1_x_magic;
1046 magic_size = sizeof netmon_1_x_magic;
1047 /* NetMon file version, for 1.x, is 1.1 */
1048 file_hdr.ver_major = 1;
1049 file_hdr.ver_minor = 1;
1052 case WTAP_FILE_NETMON_2_x:
1053 magicp = netmon_2_x_magic;
1054 magic_size = sizeof netmon_2_x_magic;
1056 * NetMon file version, for 2.x, is 2.0;
1057 * for 3.0, it's 2.1.
1059 file_hdr.ver_major = 2;
1060 file_hdr.ver_minor = 0;
1064 /* We should never get here - our open routine
1065 should only get called for the types above. */
1067 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1070 if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
1073 file_hdr.network = htoles(wtap_encap[wdh->encap]);
1074 tm = localtime(&netmon->first_record_time.secs);
1076 file_hdr.ts_year = htoles(1900 + tm->tm_year);
1077 file_hdr.ts_month = htoles(tm->tm_mon + 1);
1078 file_hdr.ts_dow = htoles(tm->tm_wday);
1079 file_hdr.ts_day = htoles(tm->tm_mday);
1080 file_hdr.ts_hour = htoles(tm->tm_hour);
1081 file_hdr.ts_min = htoles(tm->tm_min);
1082 file_hdr.ts_sec = htoles(tm->tm_sec);
1084 file_hdr.ts_year = htoles(1900 + 0);
1085 file_hdr.ts_month = htoles(0 + 1);
1086 file_hdr.ts_dow = htoles(0);
1087 file_hdr.ts_day = htoles(0);
1088 file_hdr.ts_hour = htoles(0);
1089 file_hdr.ts_min = htoles(0);
1090 file_hdr.ts_sec = htoles(0);
1092 file_hdr.ts_msec = htoles(netmon->first_record_time.nsecs/1000000);
1093 /* XXX - what about rounding? */
1094 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
1095 file_hdr.frametablelength =
1096 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
1097 if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))