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 */
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 */
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, 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,
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);
190 int netmon_open(wtap *wth, int *err, gchar **err_info)
193 char magic[sizeof netmon_1_x_magic];
194 struct netmon_hdr hdr;
197 int frame_table_offset;
198 guint32 frame_table_length;
199 guint32 frame_table_size;
200 guint32 *frame_table;
201 #ifdef WORDS_BIGENDIAN
206 /* Read in the string that should be at the start of a Network
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);
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) {
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);
232 switch (hdr.ver_major) {
235 file_type = WTAP_FILE_NETMON_1_x;
239 file_type = WTAP_FILE_NETMON_2_x;
243 *err = WTAP_ERR_UNSUPPORTED;
244 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
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",
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;
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;
270 wth->file_encap = netmon_encap[hdr.network];
272 wth->snapshot_length = 0; /* not available in header */
274 * Convert the time stamp to a "time_t" and a number of
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);
284 netmon->start_secs = mktime(&tm);
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.
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?).
299 netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
301 netmon->version_major = hdr.ver_major;
302 netmon->version_minor = hdr.ver_minor;
305 * Get the offset of the frame index table.
307 frame_table_offset = pletohl(&hdr.frametableoffset);
310 * It appears that some NetMon 2.x files don't have the
311 * first packet starting exactly 128 bytes into the file.
313 * Furthermore, it also appears that there are "holes" in
314 * the file, i.e. frame N+1 doesn't always follow immediately
317 * Therefore, we must read the frame table, and use the offsets
318 * in it as the offsets of the frames.
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",
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",
336 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
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);
346 *err = WTAP_ERR_SHORT_READ;
351 netmon->frame_table_size = frame_table_size;
352 netmon->frame_table = frame_table;
354 #ifdef WORDS_BIGENDIAN
356 * OK, now byte-swap the frame table.
358 for (i = 0; i < frame_table_size; i++)
359 frame_table[i] = pletohl(&frame_table[i]);
362 /* Set up to start reading at the first frame. */
363 netmon->current_frame = 0;
364 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
369 /* Read the next packet */
370 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
373 netmon_t *netmon = (netmon_t *)wth->priv;
374 guint32 packet_size = 0;
375 guint32 orig_size = 0;
378 struct netmonrec_1_x_hdr hdr_1_x;
379 struct netmonrec_2_x_hdr hdr_2_x;
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;
390 gint64 delta = 0; /* signed - frame times can be before the nominal start */
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;
401 g_free(netmon->frame_table);
402 netmon->frame_table = NULL;
403 *err = 0; /* it's just an EOF, not an error */
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).
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)
423 netmon->current_frame++;
425 /* Read record header. */
426 switch (netmon->version_major) {
429 hdr_size = sizeof (struct netmonrec_1_x_hdr);
433 hdr_size = sizeof (struct netmonrec_2_x_hdr);
436 errno = WTAP_ERR_CANT_READ;
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;
446 wth->data_offset += hdr_size;
448 switch (netmon->version_major) {
451 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
452 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
456 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
457 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
460 if (packet_size > WTAP_MAX_PACKET_SIZE) {
462 * Probably a corrupt capture file; don't blow up trying
463 * to allocate space for an immensely-large packet.
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);
471 *data_offset = wth->data_offset;
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
480 switch (wth->file_encap) {
482 case WTAP_ENCAP_ATM_PDUS:
483 if (packet_size < sizeof (struct netmon_atm_hdr)) {
485 * Uh-oh, the packet isn't big enough to even
486 * have a pseudo-header.
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",
493 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
495 return FALSE; /* Read error */
498 * Don't count the pseudo-header as part of the packet.
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);
505 case WTAP_ENCAP_ETHERNET:
507 * We assume there's no FCS in this frame.
509 wth->pseudo_header.eth.fcs_len = 0;
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;
519 t = (double)netmon->start_usecs;
520 switch (netmon->version_major) {
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
529 * pletohl() returns a guint32; we cast it to gint64
530 * before multiplying, so that the product doesn't
531 * overflow a guint32.
533 delta = ((gint64)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
537 delta = pletohl(&hdr.hdr_2_x.ts_delta_lo)
538 | (((guint64)pletohl(&hdr.hdr_2_x.ts_delta_hi)) << 32);
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;
550 * Attempt to guess from the packet data, the VPI, and the VCI
551 * information about the type of traffic.
553 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS) {
554 atm_guess_traffic_type(data_ptr, packet_size,
555 &wth->pseudo_header);
559 * For version 2.1 and later, there's additional information
560 * after the frame data.
562 if ((netmon->version_major == 2 && netmon->version_minor >= 1) ||
563 netmon->version_major > 2) {
564 if (netmon->version_major > 2) {
566 * Asssume 2.3 format, for now.
568 trlr_size = sizeof (struct netmonrec_2_3_trlr);
570 switch (netmon->version_minor) {
573 trlr_size = sizeof (struct netmonrec_2_1_trlr);
577 trlr_size = sizeof (struct netmonrec_2_2_trlr);
581 trlr_size = sizeof (struct netmonrec_2_3_trlr);
585 errno = WTAP_ERR_CANT_READ;
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;
595 wth->data_offset += trlr_size;
597 network = pletohs(trlr.trlr_2_1.network);
598 if ((network & 0xF000) == NETMON_NET_PCAP_BASE) {
600 * Converted pcap file - the LINKTYPE_ value
601 * is the network value with 0xF000 masked off.
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",
612 } else if (network < NUM_NETMON_ENCAPS) {
614 * Regular NetMon encapsulation.
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",
625 * Special packet type for metadata.
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:
636 * Just ignore those record types, for
637 * now. Read the next record.
642 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
643 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
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_)
658 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
661 switch (wth->file_encap) {
663 case WTAP_ENCAP_ATM_PDUS:
664 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
671 case WTAP_ENCAP_ETHERNET:
673 * We assume there's no FCS in this frame.
675 pseudo_header->eth.fcs_len = 0;
680 * Read the packet data.
682 if (!netmon_read_rec_data(wth->random_fh, pd, length, err))
686 * Attempt to guess from the packet data, the VPI, and the VCI
687 * information about the type of traffic.
689 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
690 atm_guess_traffic_type(pd, length, pseudo_header);
696 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
699 struct netmon_atm_hdr atm_phdr;
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);
708 *err = WTAP_ERR_SHORT_READ;
712 vpi = g_ntohs(atm_phdr.vpi);
713 vci = g_ntohs(atm_phdr.vci);
715 pseudo_header->atm.vpi = vpi;
716 pseudo_header->atm.vci = vci;
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;
730 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
734 errno = WTAP_ERR_CANT_READ;
735 bytes_read = file_read(pd, length, fh);
737 if (bytes_read != length) {
738 *err = file_error(fh);
740 *err = WTAP_ERR_SHORT_READ;
746 /* Throw away the frame table used by the sequential I/O stream. */
748 netmon_sequential_close(wtap *wth)
750 netmon_t *netmon = (netmon_t *)wth->priv;
752 if (netmon->frame_table != NULL) {
753 g_free(netmon->frame_table);
754 netmon->frame_table = NULL;
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;
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 */
783 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
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)
789 /* Per-packet encapsulations aren't supported. */
790 if (encap == WTAP_ENCAP_PER_PACKET)
791 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
793 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
794 return WTAP_ERR_UNSUPPORTED_ENCAP;
799 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
801 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
803 netmon_dump_t *netmon;
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) {
814 wdh->subtype_write = netmon_dump;
815 wdh->subtype_close = netmon_dump_close;
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;
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)
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;
839 guint32 time_low, time_high;
840 struct netmon_atm_hdr atm_hdr;
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
847 if (!netmon->got_first_record_time) {
848 netmon->first_record_time = phdr->ts;
849 netmon->got_first_record_time = TRUE;
852 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
853 atm_hdrsize = sizeof (struct netmon_atm_hdr);
856 switch (wdh->file_type) {
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;
868 case WTAP_FILE_NETMON_2_x:
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
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;
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;
894 if (!wtap_dump_file_write(wdh, hdrp, hdr_size, err))
897 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
899 * Write the ATM header.
900 * We supply all-zero destination and source addresses.
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))
910 if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
914 * Stash the file offset of this frame.
916 if (netmon->frame_table_size == 0) {
918 * Haven't yet allocated the buffer for the frame table.
920 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
921 netmon->frame_table_size = 1024;
924 * We've allocated it; are we at the end?
926 if (netmon->frame_table_index >= netmon->frame_table_size) {
928 * Yes - double the size of the frame table.
930 netmon->frame_table_size *= 2;
931 netmon->frame_table = g_realloc(netmon->frame_table,
932 netmon->frame_table_size * sizeof *netmon->frame_table);
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;
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)
947 netmon_dump_t *netmon = (netmon_dump_t *)wdh->priv;
949 struct netmon_hdr file_hdr;
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))
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) {
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;
973 case WTAP_FILE_NETMON_2_x:
974 magicp = netmon_2_x_magic;
975 magic_size = sizeof netmon_2_x_magic;
977 * NetMon file version, for 2.x, is 2.0;
980 file_hdr.ver_major = 2;
981 file_hdr.ver_minor = 0;
985 /* We should never get here - our open routine
986 should only get called for the types above. */
988 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
991 if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
994 file_hdr.network = htoles(wtap_encap[wdh->encap]);
995 tm = localtime(&netmon->first_record_time.secs);
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);
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);
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))