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"
36 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
38 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
39 * for the header of a Microsoft Network Monitor capture file.
42 /* Capture file header, *including* magic number, is padded to 128 bytes. */
43 #define CAPTUREFILE_HEADER_SIZE 128
45 /* Magic number in Network Monitor 1.x files. */
46 static const char netmon_1_x_magic[] = {
50 /* Magic number in Network Monitor 2.x files. */
51 static const char netmon_2_x_magic[] = {
55 /* Network Monitor file header (minus magic number). */
57 guint8 ver_minor; /* minor version number */
58 guint8 ver_major; /* major version number */
59 guint16 network; /* network type */
60 guint16 ts_year; /* year of capture start */
61 guint16 ts_month; /* month of capture start (January = 1) */
62 guint16 ts_dow; /* day of week of capture start (Sun = 0) */
63 guint16 ts_day; /* day of month of capture start */
64 guint16 ts_hour; /* hour of capture start */
65 guint16 ts_min; /* minute of capture start */
66 guint16 ts_sec; /* second of capture start */
67 guint16 ts_msec; /* millisecond of capture start */
68 guint32 frametableoffset; /* frame index table offset */
69 guint32 frametablelength; /* frame index table size */
70 guint32 userdataoffset; /* user data offset */
71 guint32 userdatalength; /* user data size */
72 guint32 commentdataoffset; /* comment data offset */
73 guint32 commentdatalength; /* comment data size */
74 guint32 statisticsoffset; /* offset to statistics structure */
75 guint32 statisticslength; /* length of statistics structure */
76 guint32 networkinfooffset; /* offset to network info structure */
77 guint32 networkinfolength; /* length of network info structure */
80 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
81 * looking at capture files. */
82 struct netmonrec_1_x_hdr {
83 guint32 ts_delta; /* time stamp - msecs since start of capture */
84 guint16 orig_len; /* actual length of packet */
85 guint16 incl_len; /* number of octets captured in file */
88 /* Network Monitor 2.x record header; not defined in STRUCT.H, but deduced by
89 * looking at capture files. */
90 struct netmonrec_2_x_hdr {
91 guint32 ts_delta_lo; /* time stamp - usecs since start of capture */
92 guint32 ts_delta_hi; /* time stamp - usecs since start of capture */
93 guint32 orig_len; /* actual length of packet */
94 guint32 incl_len; /* number of octets captured in file */
98 * The link-layer header on ATM packets.
100 struct netmon_atm_hdr {
101 guint8 dest[6]; /* "Destination address" - what is it? */
102 guint8 src[6]; /* "Source address" - what is it? */
103 guint16 vpi; /* VPI */
104 guint16 vci; /* VCI */
107 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
108 gint64 *data_offset);
109 static gboolean netmon_seek_read(wtap *wth, gint64 seek_off,
110 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
111 int *err, gchar **err_info);
112 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
113 union wtap_pseudo_header *pseudo_header, int *err);
114 static gboolean netmon_read_rec_data(FILE_T fh, guchar *pd, int length,
116 static void netmon_sequential_close(wtap *wth);
117 static void netmon_close(wtap *wth);
118 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
119 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
120 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
122 int netmon_open(wtap *wth, int *err, gchar **err_info)
125 char magic[sizeof netmon_1_x_magic];
126 struct netmon_hdr hdr;
128 static const int netmon_encap[] = {
131 WTAP_ENCAP_TOKEN_RING,
132 WTAP_ENCAP_FDDI_BITSWAPPED,
133 WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
134 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk */
135 WTAP_ENCAP_UNKNOWN, /* NDIS "DIX" - should not occur */
136 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET raw */
137 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET 878.2 */
138 WTAP_ENCAP_UNKNOWN, /* NDIS ATM (no, this is NOT used for ATM) */
139 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
140 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
142 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
144 int frame_table_offset;
145 guint32 frame_table_length;
146 guint32 frame_table_size;
147 guint32 *frame_table;
148 #ifdef WORDS_BIGENDIAN
152 /* Read in the string that should be at the start of a Network
154 errno = WTAP_ERR_CANT_READ;
155 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
156 if (bytes_read != sizeof magic) {
157 *err = file_error(wth->fh);
163 if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
164 && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
168 /* Read the rest of the header. */
169 errno = WTAP_ERR_CANT_READ;
170 bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
171 if (bytes_read != sizeof hdr) {
172 *err = file_error(wth->fh);
178 switch (hdr.ver_major) {
181 file_type = WTAP_FILE_NETMON_1_x;
185 file_type = WTAP_FILE_NETMON_2_x;
189 *err = WTAP_ERR_UNSUPPORTED;
190 *err_info = g_strdup_printf("netmon: major version %u unsupported", hdr.ver_major);
194 hdr.network = pletohs(&hdr.network);
195 if (hdr.network >= NUM_NETMON_ENCAPS
196 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
197 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
198 *err_info = g_strdup_printf("netmon: network type %u unknown or unsupported",
203 /* This is a netmon file */
204 wth->file_type = file_type;
205 wth->capture.netmon = g_malloc(sizeof(netmon_t));
206 wth->subtype_read = netmon_read;
207 wth->subtype_seek_read = netmon_seek_read;
208 wth->subtype_sequential_close = netmon_sequential_close;
209 wth->subtype_close = netmon_close;
211 /* NetMon capture file formats v2.1+ use per-packet encapsulation types. NetMon 3 sets the value in
212 * the header to 1 (Ethernet) for backwards compability. */
213 /* XXX - It would be better if we could set this to WTAP_ENCAP_PER_PACKET and show a message for
214 * that, but the wtap_read() routine asserts on that value to catch errors. */
215 if((hdr.ver_major == 2 && hdr.ver_minor >= 1) || hdr.ver_major > 2)
216 wth->file_encap = WTAP_ENCAP_UNKNOWN;
218 wth->file_encap = netmon_encap[hdr.network];
220 wth->snapshot_length = 0; /* not available in header */
222 * Convert the time stamp to a "time_t" and a number of
225 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
226 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
227 tm.tm_mday = pletohs(&hdr.ts_day);
228 tm.tm_hour = pletohs(&hdr.ts_hour);
229 tm.tm_min = pletohs(&hdr.ts_min);
230 tm.tm_sec = pletohs(&hdr.ts_sec);
232 wth->capture.netmon->start_secs = mktime(&tm);
234 * XXX - what if "secs" is -1? Unlikely, but if the capture was
235 * done in a time zone that switches between standard and summer
236 * time sometime other than when we do, and thus the time was one
237 * that doesn't exist here because a switch from standard to summer
238 * time zips over it, it could happen.
240 * On the other hand, if the capture was done in a different time
241 * zone, this won't work right anyway; unfortunately, the time
242 * zone isn't stored in the capture file (why the hell didn't
243 * they stuff a FILETIME, which is the number of 100-nanosecond
244 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
245 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
247 wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
249 wth->capture.netmon->version_major = hdr.ver_major;
252 * Get the offset of the frame index table.
254 frame_table_offset = pletohl(&hdr.frametableoffset);
257 * It appears that some NetMon 2.x files don't have the
258 * first packet starting exactly 128 bytes into the file.
260 * Furthermore, it also appears that there are "holes" in
261 * the file, i.e. frame N+1 doesn't always follow immediately
264 * Therefore, we must read the frame table, and use the offsets
265 * in it as the offsets of the frames.
267 frame_table_length = pletohl(&hdr.frametablelength);
268 frame_table_size = frame_table_length / (guint32)sizeof (guint32);
269 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
270 *err = WTAP_ERR_UNSUPPORTED;
271 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
273 g_free(wth->capture.netmon);
276 if (frame_table_size == 0) {
277 *err = WTAP_ERR_UNSUPPORTED;
278 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
280 g_free(wth->capture.netmon);
283 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
284 g_free(wth->capture.netmon);
287 frame_table = g_malloc(frame_table_length);
288 errno = WTAP_ERR_CANT_READ;
289 bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
290 if ((guint32)bytes_read != frame_table_length) {
291 *err = file_error(wth->fh);
293 *err = WTAP_ERR_SHORT_READ;
295 g_free(wth->capture.netmon);
298 wth->capture.netmon->frame_table_size = frame_table_size;
299 wth->capture.netmon->frame_table = frame_table;
301 #ifdef WORDS_BIGENDIAN
303 * OK, now byte-swap the frame table.
305 for (i = 0; i < frame_table_size; i++)
306 frame_table[i] = pletohl(&frame_table[i]);
309 /* Set up to start reading at the first frame. */
310 wth->capture.netmon->current_frame = 0;
311 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
316 /* Read the next packet */
317 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
320 netmon_t *netmon = wth->capture.netmon;
321 guint32 packet_size = 0;
322 guint32 orig_size = 0;
325 struct netmonrec_1_x_hdr hdr_1_x;
326 struct netmonrec_2_x_hdr hdr_2_x;
335 /* Have we reached the end of the packet data? */
336 if (netmon->current_frame >= netmon->frame_table_size) {
337 /* Yes. We won't need the frame table any more;
339 g_free(wth->capture.netmon->frame_table);
340 wth->capture.netmon->frame_table = NULL;
341 *err = 0; /* it's just an EOF, not an error */
345 /* Seek to the beginning of the current record, if we're
346 not there already (seeking to the current position
347 may still cause a seek and a read of the underlying file,
348 so we don't want to do it unconditionally). */
349 rec_offset = netmon->frame_table[netmon->current_frame];
350 if (wth->data_offset != rec_offset) {
351 wth->data_offset = rec_offset;
352 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
355 netmon->current_frame++;
357 /* Read record header. */
358 switch (netmon->version_major) {
361 hdr_size = sizeof (struct netmonrec_1_x_hdr);
365 hdr_size = sizeof (struct netmonrec_2_x_hdr);
368 errno = WTAP_ERR_CANT_READ;
370 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
371 if (bytes_read != hdr_size) {
372 *err = file_error(wth->fh);
373 if (*err == 0 && bytes_read != 0) {
374 *err = WTAP_ERR_SHORT_READ;
378 wth->data_offset += hdr_size;
380 switch (netmon->version_major) {
383 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
384 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
388 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
389 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
392 if (packet_size > WTAP_MAX_PACKET_SIZE) {
394 * Probably a corrupt capture file; don't blow up trying
395 * to allocate space for an immensely-large packet.
397 *err = WTAP_ERR_BAD_RECORD;
398 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
399 packet_size, WTAP_MAX_PACKET_SIZE);
403 *data_offset = wth->data_offset;
406 * If this is an ATM packet, the first
407 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
408 * source addresses (6 bytes - MAC addresses of some sort?)
409 * and the VPI and VCI; read them and generate the pseudo-header
412 switch (wth->file_encap) {
414 case WTAP_ENCAP_ATM_PDUS:
415 if (packet_size < sizeof (struct netmon_atm_hdr)) {
417 * Uh-oh, the packet isn't big enough to even
418 * have a pseudo-header.
420 *err = WTAP_ERR_BAD_RECORD;
421 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header",
425 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
427 return FALSE; /* Read error */
430 * Don't count the pseudo-header as part of the packet.
432 orig_size -= (guint)sizeof (struct netmon_atm_hdr);
433 packet_size -= (guint)sizeof (struct netmon_atm_hdr);
434 wth->data_offset += sizeof (struct netmon_atm_hdr);
437 case WTAP_ENCAP_ETHERNET:
439 * We assume there's no FCS in this frame.
441 wth->pseudo_header.eth.fcs_len = 0;
445 buffer_assure_space(wth->frame_buffer, packet_size);
446 data_ptr = buffer_start_ptr(wth->frame_buffer);
447 if (!netmon_read_rec_data(wth->fh, data_ptr, packet_size, err))
448 return FALSE; /* Read error */
449 wth->data_offset += packet_size;
451 t = (double)netmon->start_usecs;
452 switch (netmon->version_major) {
455 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
459 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
460 + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
463 secs = (time_t)(t/1000000);
464 usecs = (guint32)(t - (double)secs*1000000);
465 wth->phdr.ts.secs = netmon->start_secs + secs;
466 wth->phdr.ts.nsecs = usecs * 1000;
467 wth->phdr.caplen = packet_size;
468 wth->phdr.len = orig_size;
471 * Attempt to guess from the packet data, the VPI, and the VCI
472 * information about the type of traffic.
474 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS) {
475 atm_guess_traffic_type(data_ptr, packet_size,
476 &wth->pseudo_header);
483 netmon_seek_read(wtap *wth, gint64 seek_off,
484 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
485 int *err, gchar **err_info _U_)
487 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
490 switch (wth->file_encap) {
492 case WTAP_ENCAP_ATM_PDUS:
493 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
500 case WTAP_ENCAP_ETHERNET:
502 * We assume there's no FCS in this frame.
504 pseudo_header->eth.fcs_len = 0;
509 * Read the packet data.
511 if (!netmon_read_rec_data(wth->random_fh, pd, length, err))
515 * Attempt to guess from the packet data, the VPI, and the VCI
516 * information about the type of traffic.
518 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
519 atm_guess_traffic_type(pd, length, pseudo_header);
525 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
528 struct netmon_atm_hdr atm_phdr;
532 errno = WTAP_ERR_CANT_READ;
533 bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
534 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
535 *err = file_error(fh);
537 *err = WTAP_ERR_SHORT_READ;
541 vpi = g_ntohs(atm_phdr.vpi);
542 vci = g_ntohs(atm_phdr.vci);
544 pseudo_header->atm.vpi = vpi;
545 pseudo_header->atm.vci = vci;
547 /* We don't have this information */
548 pseudo_header->atm.flags = 0;
549 pseudo_header->atm.channel = 0;
550 pseudo_header->atm.cells = 0;
551 pseudo_header->atm.aal5t_u2u = 0;
552 pseudo_header->atm.aal5t_len = 0;
553 pseudo_header->atm.aal5t_chksum = 0;
559 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
563 errno = WTAP_ERR_CANT_READ;
564 bytes_read = file_read(pd, 1, length, fh);
566 if (bytes_read != length) {
567 *err = file_error(fh);
569 *err = WTAP_ERR_SHORT_READ;
575 /* Throw away the frame table used by the sequential I/O stream. */
577 netmon_sequential_close(wtap *wth)
579 if (wth->capture.netmon->frame_table != NULL) {
580 g_free(wth->capture.netmon->frame_table);
581 wth->capture.netmon->frame_table = NULL;
585 /* Close stuff used by the random I/O stream, if any, and free up any
586 private data structures. (If there's a "sequential_close" routine
587 for a capture file type, it'll be called before the "close" routine
588 is called, so we don't have to free the frame table here.) */
590 netmon_close(wtap *wth)
592 g_free(wth->capture.netmon);
595 static const int wtap_encap[] = {
596 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
597 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
598 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
599 -1, /* WTAP_ENCAP_SLIP -> unsupported */
600 -1, /* WTAP_ENCAP_PPP -> unsupported */
601 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
602 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
603 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
604 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
605 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
606 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
607 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
608 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
609 -1 /* WTAP_ENCAP_NULL -> unsupported */
611 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
613 /* Returns 0 if we could write the specified encapsulation type,
614 an error indication otherwise. */
615 int netmon_dump_can_write_encap(int encap)
617 /* Per-packet encapsulations aren't supported. */
618 if (encap == WTAP_ENCAP_PER_PACKET)
619 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
621 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
622 return WTAP_ERR_UNSUPPORTED_ENCAP;
627 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
629 gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
631 /* This is a NetMon file. We can't fill in some fields in the
632 header until all the packets have been written, so we can't
635 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
639 /* We can't fill in all the fields in the file header, as we
640 haven't yet written any packets. As we'll have to rewrite
641 the header when we've written out all the packets, we just
642 skip over the header for now. */
643 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
648 wdh->subtype_write = netmon_dump;
649 wdh->subtype_close = netmon_dump_close;
651 wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
652 wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
653 wdh->dump.netmon->got_first_record_time = FALSE;
654 wdh->dump.netmon->frame_table = NULL;
655 wdh->dump.netmon->frame_table_index = 0;
656 wdh->dump.netmon->frame_table_size = 0;
661 /* Write a record for a packet to a dump file.
662 Returns TRUE on success, FALSE on failure. */
663 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
664 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
666 netmon_dump_t *netmon = wdh->dump.netmon;
667 struct netmonrec_1_x_hdr rec_1_x_hdr;
668 struct netmonrec_2_x_hdr rec_2_x_hdr;
673 guint32 time_low, time_high;
674 struct netmon_atm_hdr atm_hdr;
677 /* NetMon files have a capture start time in the file header,
678 and have times relative to that in the packet headers;
679 pick the time of the first packet as the capture start
681 if (!netmon->got_first_record_time) {
682 netmon->first_record_time = phdr->ts;
683 netmon->got_first_record_time = TRUE;
686 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
687 atm_hdrsize = sizeof (struct netmon_atm_hdr);
690 switch (wdh->file_type) {
692 case WTAP_FILE_NETMON_1_x:
693 rec_1_x_hdr.ts_delta = htolel(
694 (phdr->ts.secs - netmon->first_record_time.secs)*1000
695 + (phdr->ts.nsecs - netmon->first_record_time.nsecs + 500000)/1000000);
696 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
697 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
698 hdrp = (char *)&rec_1_x_hdr;
699 hdr_size = sizeof rec_1_x_hdr;
702 case WTAP_FILE_NETMON_2_x:
704 * Unfortunately, not all the platforms on which we run
705 * support 64-bit integral types, even though most do
706 * (even on 32-bit processors), so we do it in floating
709 t = (phdr->ts.secs - netmon->first_record_time.secs)*1000000.0
710 + (phdr->ts.nsecs - netmon->first_record_time.nsecs) / 1000;
711 time_high = (guint32) (t/4294967296.0);
712 time_low = (guint32) (t - (time_high*4294967296.0));
713 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
714 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
715 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
716 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
717 hdrp = (char *)&rec_2_x_hdr;
718 hdr_size = sizeof rec_2_x_hdr;
722 /* We should never get here - our open routine
723 should only get called for the types above. */
724 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
728 nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
729 if (nwritten != hdr_size) {
730 if (nwritten == 0 && ferror(wdh->fh))
733 *err = WTAP_ERR_SHORT_WRITE;
737 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
739 * Write the ATM header.
740 * We supply all-zero destination and source addresses.
742 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
743 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
744 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
745 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
746 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
747 if (nwritten != sizeof atm_hdr) {
748 if (nwritten == 0 && ferror(wdh->fh))
751 *err = WTAP_ERR_SHORT_WRITE;
756 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
757 if (nwritten != phdr->caplen) {
758 if (nwritten == 0 && ferror(wdh->fh))
761 *err = WTAP_ERR_SHORT_WRITE;
766 * Stash the file offset of this frame.
768 if (netmon->frame_table_size == 0) {
770 * Haven't yet allocated the buffer for the frame table.
772 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
773 netmon->frame_table_size = 1024;
776 * We've allocated it; are we at the end?
778 if (netmon->frame_table_index >= netmon->frame_table_size) {
780 * Yes - double the size of the frame table.
782 netmon->frame_table_size *= 2;
783 netmon->frame_table = g_realloc(netmon->frame_table,
784 netmon->frame_table_size * sizeof *netmon->frame_table);
787 netmon->frame_table[netmon->frame_table_index] =
788 htolel(netmon->frame_table_offset);
789 netmon->frame_table_index++;
790 netmon->frame_table_offset += (int) hdr_size + phdr->caplen + atm_hdrsize;
795 /* Finish writing to a dump file.
796 Returns TRUE on success, FALSE on failure. */
797 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
799 netmon_dump_t *netmon = wdh->dump.netmon;
802 struct netmon_hdr file_hdr;
807 /* Write out the frame table. "netmon->frame_table_index" is
808 the number of entries we've put into it. */
809 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
810 nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
811 if (nwritten != n_to_write) {
813 if (nwritten == 0 && ferror(wdh->fh))
816 *err = WTAP_ERR_SHORT_WRITE;
821 /* Now go fix up the file header. */
822 fseek(wdh->fh, 0, SEEK_SET);
823 memset(&file_hdr, '\0', sizeof file_hdr);
824 switch (wdh->file_type) {
826 case WTAP_FILE_NETMON_1_x:
827 magicp = netmon_1_x_magic;
828 magic_size = sizeof netmon_1_x_magic;
829 /* NetMon file version, for 1.x, is 1.1 */
830 file_hdr.ver_major = 1;
831 file_hdr.ver_minor = 1;
834 case WTAP_FILE_NETMON_2_x:
835 magicp = netmon_2_x_magic;
836 magic_size = sizeof netmon_2_x_magic;
838 * NetMon file version, for 2.x, is 2.0;
841 file_hdr.ver_major = 2;
842 file_hdr.ver_minor = 0;
846 /* We should never get here - our open routine
847 should only get called for the types above. */
849 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
852 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
853 if (nwritten != magic_size) {
855 if (nwritten == 0 && ferror(wdh->fh))
858 *err = WTAP_ERR_SHORT_WRITE;
863 file_hdr.network = htoles(wtap_encap[wdh->encap]);
864 tm = localtime(&netmon->first_record_time.secs);
866 file_hdr.ts_year = htoles(1900 + tm->tm_year);
867 file_hdr.ts_month = htoles(tm->tm_mon + 1);
868 file_hdr.ts_dow = htoles(tm->tm_wday);
869 file_hdr.ts_day = htoles(tm->tm_mday);
870 file_hdr.ts_hour = htoles(tm->tm_hour);
871 file_hdr.ts_min = htoles(tm->tm_min);
872 file_hdr.ts_sec = htoles(tm->tm_sec);
874 file_hdr.ts_year = htoles(1900 + 0);
875 file_hdr.ts_month = htoles(0 + 1);
876 file_hdr.ts_dow = htoles(0);
877 file_hdr.ts_day = htoles(0);
878 file_hdr.ts_hour = htoles(0);
879 file_hdr.ts_min = htoles(0);
880 file_hdr.ts_sec = htoles(0);
882 file_hdr.ts_msec = htoles(netmon->first_record_time.nsecs/1000000);
883 /* XXX - what about rounding? */
884 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
885 file_hdr.frametablelength =
886 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
887 nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
888 if (nwritten != sizeof file_hdr) {
890 if (nwritten == 0 && ferror(wdh->fh))
893 *err = WTAP_ERR_SHORT_WRITE;