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;
210 wth->file_encap = netmon_encap[hdr.network];
211 wth->snapshot_length = 0; /* not available in header */
213 * Convert the time stamp to a "time_t" and a number of
216 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
217 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
218 tm.tm_mday = pletohs(&hdr.ts_day);
219 tm.tm_hour = pletohs(&hdr.ts_hour);
220 tm.tm_min = pletohs(&hdr.ts_min);
221 tm.tm_sec = pletohs(&hdr.ts_sec);
223 wth->capture.netmon->start_secs = mktime(&tm);
225 * XXX - what if "secs" is -1? Unlikely, but if the capture was
226 * done in a time zone that switches between standard and summer
227 * time sometime other than when we do, and thus the time was one
228 * that doesn't exist here because a switch from standard to summer
229 * time zips over it, it could happen.
231 * On the other hand, if the capture was done in a different time
232 * zone, this won't work right anyway; unfortunately, the time
233 * zone isn't stored in the capture file (why the hell didn't
234 * they stuff a FILETIME, which is the number of 100-nanosecond
235 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
236 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
238 wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
240 wth->capture.netmon->version_major = hdr.ver_major;
243 * Get the offset of the frame index table.
245 frame_table_offset = pletohl(&hdr.frametableoffset);
248 * It appears that some NetMon 2.x files don't have the
249 * first packet starting exactly 128 bytes into the file.
251 * Furthermore, it also appears that there are "holes" in
252 * the file, i.e. frame N+1 doesn't always follow immediately
255 * Therefore, we must read the frame table, and use the offsets
256 * in it as the offsets of the frames.
258 frame_table_length = pletohl(&hdr.frametablelength);
259 frame_table_size = frame_table_length / sizeof (guint32);
260 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
261 *err = WTAP_ERR_UNSUPPORTED;
262 *err_info = g_strdup_printf("netmon: frame table length is %u, which is not a multiple of the size of an entry",
264 g_free(wth->capture.netmon);
267 if (frame_table_size == 0) {
268 *err = WTAP_ERR_UNSUPPORTED;
269 *err_info = g_strdup_printf("netmon: frame table length is %u, which means it's less than one entry in size",
271 g_free(wth->capture.netmon);
274 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
275 g_free(wth->capture.netmon);
278 frame_table = g_malloc(frame_table_length);
279 errno = WTAP_ERR_CANT_READ;
280 bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
281 if ((guint32)bytes_read != frame_table_length) {
282 *err = file_error(wth->fh);
284 *err = WTAP_ERR_SHORT_READ;
286 g_free(wth->capture.netmon);
289 wth->capture.netmon->frame_table_size = frame_table_size;
290 wth->capture.netmon->frame_table = frame_table;
292 #ifdef WORDS_BIGENDIAN
294 * OK, now byte-swap the frame table.
296 for (i = 0; i < frame_table_size; i++)
297 frame_table[i] = pletohl(&frame_table[i]);
300 /* Set up to start reading at the first frame. */
301 wth->capture.netmon->current_frame = 0;
302 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
307 /* Read the next packet */
308 static gboolean netmon_read(wtap *wth, int *err, gchar **err_info,
311 netmon_t *netmon = wth->capture.netmon;
312 guint32 packet_size = 0;
313 guint32 orig_size = 0;
316 struct netmonrec_1_x_hdr hdr_1_x;
317 struct netmonrec_2_x_hdr hdr_2_x;
326 /* Have we reached the end of the packet data? */
327 if (netmon->current_frame >= netmon->frame_table_size) {
328 /* Yes. We won't need the frame table any more;
330 g_free(wth->capture.netmon->frame_table);
331 wth->capture.netmon->frame_table = NULL;
332 *err = 0; /* it's just an EOF, not an error */
336 /* Seek to the beginning of the current record, if we're
337 not there already (seeking to the current position
338 may still cause a seek and a read of the underlying file,
339 so we don't want to do it unconditionally). */
340 rec_offset = netmon->frame_table[netmon->current_frame];
341 if (wth->data_offset != rec_offset) {
342 wth->data_offset = rec_offset;
343 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
346 netmon->current_frame++;
348 /* Read record header. */
349 switch (netmon->version_major) {
352 hdr_size = sizeof (struct netmonrec_1_x_hdr);
356 hdr_size = sizeof (struct netmonrec_2_x_hdr);
359 errno = WTAP_ERR_CANT_READ;
361 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
362 if (bytes_read != hdr_size) {
363 *err = file_error(wth->fh);
364 if (*err == 0 && bytes_read != 0) {
365 *err = WTAP_ERR_SHORT_READ;
369 wth->data_offset += hdr_size;
371 switch (netmon->version_major) {
374 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
375 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
379 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
380 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
383 if (packet_size > WTAP_MAX_PACKET_SIZE) {
385 * Probably a corrupt capture file; don't blow up trying
386 * to allocate space for an immensely-large packet.
388 *err = WTAP_ERR_BAD_RECORD;
389 *err_info = g_strdup_printf("netmon: File has %u-byte packet, bigger than maximum of %u",
390 packet_size, WTAP_MAX_PACKET_SIZE);
394 *data_offset = wth->data_offset;
397 * If this is an ATM packet, the first
398 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
399 * source addresses (6 bytes - MAC addresses of some sort?)
400 * and the VPI and VCI; read them and generate the pseudo-header
403 switch (wth->file_encap) {
405 case WTAP_ENCAP_ATM_PDUS:
406 if (packet_size < sizeof (struct netmon_atm_hdr)) {
408 * Uh-oh, the packet isn't big enough to even
409 * have a pseudo-header.
411 *err = WTAP_ERR_BAD_RECORD;
412 *err_info = g_strdup_printf("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header\n",
416 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
418 return FALSE; /* Read error */
421 * Don't count the pseudo-header as part of the packet.
423 orig_size -= sizeof (struct netmon_atm_hdr);
424 packet_size -= sizeof (struct netmon_atm_hdr);
425 wth->data_offset += sizeof (struct netmon_atm_hdr);
428 case WTAP_ENCAP_ETHERNET:
430 * We assume there's no FCS in this frame.
432 wth->pseudo_header.eth.fcs_len = 0;
436 buffer_assure_space(wth->frame_buffer, packet_size);
437 data_ptr = buffer_start_ptr(wth->frame_buffer);
438 if (!netmon_read_rec_data(wth->fh, data_ptr, packet_size, err))
439 return FALSE; /* Read error */
440 wth->data_offset += packet_size;
442 t = (double)netmon->start_usecs;
443 switch (netmon->version_major) {
446 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
450 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
451 + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
454 secs = (time_t)(t/1000000);
455 usecs = (guint32)(t - (double)secs*1000000);
456 wth->phdr.ts.secs = netmon->start_secs + secs;
457 wth->phdr.ts.nsecs = usecs * 1000;
458 wth->phdr.caplen = packet_size;
459 wth->phdr.len = orig_size;
462 * Attempt to guess from the packet data, the VPI, and the VCI
463 * information about the type of traffic.
465 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS) {
466 atm_guess_traffic_type(data_ptr, packet_size,
467 &wth->pseudo_header);
474 netmon_seek_read(wtap *wth, gint64 seek_off,
475 union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
476 int *err, gchar **err_info _U_)
478 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
481 switch (wth->file_encap) {
483 case WTAP_ENCAP_ATM_PDUS:
484 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
491 case WTAP_ENCAP_ETHERNET:
493 * We assume there's no FCS in this frame.
495 pseudo_header->eth.fcs_len = 0;
500 * Read the packet data.
502 if (!netmon_read_rec_data(wth->random_fh, pd, length, err))
506 * Attempt to guess from the packet data, the VPI, and the VCI
507 * information about the type of traffic.
509 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
510 atm_guess_traffic_type(pd, length, pseudo_header);
516 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
519 struct netmon_atm_hdr atm_phdr;
523 errno = WTAP_ERR_CANT_READ;
524 bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
525 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
526 *err = file_error(fh);
528 *err = WTAP_ERR_SHORT_READ;
532 vpi = g_ntohs(atm_phdr.vpi);
533 vci = g_ntohs(atm_phdr.vci);
535 pseudo_header->atm.vpi = vpi;
536 pseudo_header->atm.vci = vci;
538 /* We don't have this information */
539 pseudo_header->atm.flags = 0;
540 pseudo_header->atm.channel = 0;
541 pseudo_header->atm.cells = 0;
542 pseudo_header->atm.aal5t_u2u = 0;
543 pseudo_header->atm.aal5t_len = 0;
544 pseudo_header->atm.aal5t_chksum = 0;
550 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
554 errno = WTAP_ERR_CANT_READ;
555 bytes_read = file_read(pd, 1, length, fh);
557 if (bytes_read != length) {
558 *err = file_error(fh);
560 *err = WTAP_ERR_SHORT_READ;
566 /* Throw away the frame table used by the sequential I/O stream. */
568 netmon_sequential_close(wtap *wth)
570 if (wth->capture.netmon->frame_table != NULL) {
571 g_free(wth->capture.netmon->frame_table);
572 wth->capture.netmon->frame_table = NULL;
576 /* Close stuff used by the random I/O stream, if any, and free up any
577 private data structures. (If there's a "sequential_close" routine
578 for a capture file type, it'll be called before the "close" routine
579 is called, so we don't have to free the frame table here.) */
581 netmon_close(wtap *wth)
583 g_free(wth->capture.netmon);
586 static const int wtap_encap[] = {
587 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
588 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
589 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
590 -1, /* WTAP_ENCAP_SLIP -> unsupported */
591 -1, /* WTAP_ENCAP_PPP -> unsupported */
592 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
593 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
594 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
595 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
596 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
597 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
598 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
599 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
600 -1 /* WTAP_ENCAP_NULL -> unsupported */
602 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
604 /* Returns 0 if we could write the specified encapsulation type,
605 an error indication otherwise. */
606 int netmon_dump_can_write_encap(int encap)
608 /* Per-packet encapsulations aren't supported. */
609 if (encap == WTAP_ENCAP_PER_PACKET)
610 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
612 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
613 return WTAP_ERR_UNSUPPORTED_ENCAP;
618 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
620 gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
622 /* This is a NetMon file. We can't fill in some fields in the
623 header until all the packets have been written, so we can't
626 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
630 /* We can't fill in all the fields in the file header, as we
631 haven't yet written any packets. As we'll have to rewrite
632 the header when we've written out all the packets, we just
633 skip over the header for now. */
634 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
639 wdh->subtype_write = netmon_dump;
640 wdh->subtype_close = netmon_dump_close;
642 wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
643 wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
644 wdh->dump.netmon->got_first_record_time = FALSE;
645 wdh->dump.netmon->frame_table = NULL;
646 wdh->dump.netmon->frame_table_index = 0;
647 wdh->dump.netmon->frame_table_size = 0;
652 /* Write a record for a packet to a dump file.
653 Returns TRUE on success, FALSE on failure. */
654 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
655 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
657 netmon_dump_t *netmon = wdh->dump.netmon;
658 struct netmonrec_1_x_hdr rec_1_x_hdr;
659 struct netmonrec_2_x_hdr rec_2_x_hdr;
664 guint32 time_low, time_high;
665 struct netmon_atm_hdr atm_hdr;
668 /* NetMon files have a capture start time in the file header,
669 and have times relative to that in the packet headers;
670 pick the time of the first packet as the capture start
672 if (!netmon->got_first_record_time) {
673 netmon->first_record_time = phdr->ts;
674 netmon->got_first_record_time = TRUE;
677 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
678 atm_hdrsize = sizeof (struct netmon_atm_hdr);
681 switch (wdh->file_type) {
683 case WTAP_FILE_NETMON_1_x:
684 rec_1_x_hdr.ts_delta = htolel(
685 (phdr->ts.secs - netmon->first_record_time.secs)*1000
686 + (phdr->ts.nsecs - netmon->first_record_time.nsecs + 500000)/1000000);
687 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
688 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
689 hdrp = (char *)&rec_1_x_hdr;
690 hdr_size = sizeof rec_1_x_hdr;
693 case WTAP_FILE_NETMON_2_x:
695 * Unfortunately, not all the platforms on which we run
696 * support 64-bit integral types, even though most do
697 * (even on 32-bit processors), so we do it in floating
700 t = (phdr->ts.secs - netmon->first_record_time.secs)*1000000.0
701 + (phdr->ts.nsecs - netmon->first_record_time.nsecs) / 1000;
702 time_high = (guint32) (t/4294967296.0);
703 time_low = (guint32) (t - (time_high*4294967296.0));
704 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
705 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
706 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
707 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
708 hdrp = (char *)&rec_2_x_hdr;
709 hdr_size = sizeof rec_2_x_hdr;
713 /* We should never get here - our open routine
714 should only get called for the types above. */
715 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
719 nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
720 if (nwritten != hdr_size) {
721 if (nwritten == 0 && ferror(wdh->fh))
724 *err = WTAP_ERR_SHORT_WRITE;
728 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
730 * Write the ATM header.
731 * We supply all-zero destination and source addresses.
733 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
734 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
735 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
736 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
737 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
738 if (nwritten != sizeof atm_hdr) {
739 if (nwritten == 0 && ferror(wdh->fh))
742 *err = WTAP_ERR_SHORT_WRITE;
747 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
748 if (nwritten != phdr->caplen) {
749 if (nwritten == 0 && ferror(wdh->fh))
752 *err = WTAP_ERR_SHORT_WRITE;
757 * Stash the file offset of this frame.
759 if (netmon->frame_table_size == 0) {
761 * Haven't yet allocated the buffer for the frame table.
763 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
764 netmon->frame_table_size = 1024;
767 * We've allocated it; are we at the end?
769 if (netmon->frame_table_index >= netmon->frame_table_size) {
771 * Yes - double the size of the frame table.
773 netmon->frame_table_size *= 2;
774 netmon->frame_table = g_realloc(netmon->frame_table,
775 netmon->frame_table_size * sizeof *netmon->frame_table);
778 netmon->frame_table[netmon->frame_table_index] =
779 htolel(netmon->frame_table_offset);
780 netmon->frame_table_index++;
781 netmon->frame_table_offset += hdr_size + phdr->caplen + atm_hdrsize;
786 /* Finish writing to a dump file.
787 Returns TRUE on success, FALSE on failure. */
788 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
790 netmon_dump_t *netmon = wdh->dump.netmon;
793 struct netmon_hdr file_hdr;
798 /* Write out the frame table. "netmon->frame_table_index" is
799 the number of entries we've put into it. */
800 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
801 nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
802 if (nwritten != n_to_write) {
804 if (nwritten == 0 && ferror(wdh->fh))
807 *err = WTAP_ERR_SHORT_WRITE;
812 /* Now go fix up the file header. */
813 fseek(wdh->fh, 0, SEEK_SET);
814 memset(&file_hdr, '\0', sizeof file_hdr);
815 switch (wdh->file_type) {
817 case WTAP_FILE_NETMON_1_x:
818 magicp = netmon_1_x_magic;
819 magic_size = sizeof netmon_1_x_magic;
820 /* NetMon file version, for 1.x, is 1.1 */
821 file_hdr.ver_major = 1;
822 file_hdr.ver_minor = 1;
825 case WTAP_FILE_NETMON_2_x:
826 magicp = netmon_2_x_magic;
827 magic_size = sizeof netmon_2_x_magic;
829 * NetMon file version, for 2.x, is 2.0;
832 file_hdr.ver_major = 2;
833 file_hdr.ver_minor = 0;
837 /* We should never get here - our open routine
838 should only get called for the types above. */
840 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
843 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
844 if (nwritten != magic_size) {
846 if (nwritten == 0 && ferror(wdh->fh))
849 *err = WTAP_ERR_SHORT_WRITE;
854 file_hdr.network = htoles(wtap_encap[wdh->encap]);
855 tm = localtime(&netmon->first_record_time.secs);
857 file_hdr.ts_year = htoles(1900 + tm->tm_year);
858 file_hdr.ts_month = htoles(tm->tm_mon + 1);
859 file_hdr.ts_dow = htoles(tm->tm_wday);
860 file_hdr.ts_day = htoles(tm->tm_mday);
861 file_hdr.ts_hour = htoles(tm->tm_hour);
862 file_hdr.ts_min = htoles(tm->tm_min);
863 file_hdr.ts_sec = htoles(tm->tm_sec);
865 file_hdr.ts_year = htoles(1900 + 0);
866 file_hdr.ts_month = htoles(0 + 1);
867 file_hdr.ts_dow = htoles(0);
868 file_hdr.ts_day = htoles(0);
869 file_hdr.ts_hour = htoles(0);
870 file_hdr.ts_min = htoles(0);
871 file_hdr.ts_sec = htoles(0);
873 file_hdr.ts_msec = htoles(netmon->first_record_time.nsecs/1000000);
874 /* XXX - what about rounding? */
875 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
876 file_hdr.frametablelength =
877 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
878 nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
879 if (nwritten != sizeof file_hdr) {
881 if (nwritten == 0 && ferror(wdh->fh))
884 *err = WTAP_ERR_SHORT_WRITE;