3 * $Id: netmon.c,v 1.58 2002/07/29 06:09:59 guy Exp $
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"
34 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
36 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
37 * for the header of a Microsoft Network Monitor capture file.
40 /* Capture file header, *including* magic number, is padded to 128 bytes. */
41 #define CAPTUREFILE_HEADER_SIZE 128
43 /* Magic number in Network Monitor 1.x files. */
44 static const char netmon_1_x_magic[] = {
48 /* Magic number in Network Monitor 2.x files. */
49 static const char netmon_2_x_magic[] = {
53 /* Network Monitor file header (minus magic number). */
55 guint8 ver_minor; /* minor version number */
56 guint8 ver_major; /* major version number */
57 guint16 network; /* network type */
58 guint16 ts_year; /* year of capture start */
59 guint16 ts_month; /* month of capture start (January = 1) */
60 guint16 ts_dow; /* day of week of capture start (Sun = 0) */
61 guint16 ts_day; /* day of month of capture start */
62 guint16 ts_hour; /* hour of capture start */
63 guint16 ts_min; /* minute of capture start */
64 guint16 ts_sec; /* second of capture start */
65 guint16 ts_msec; /* millisecond of capture start */
66 guint32 frametableoffset; /* frame index table offset */
67 guint32 frametablelength; /* frame index table size */
68 guint32 userdataoffset; /* user data offset */
69 guint32 userdatalength; /* user data size */
70 guint32 commentdataoffset; /* comment data offset */
71 guint32 commentdatalength; /* comment data size */
72 guint32 statisticsoffset; /* offset to statistics structure */
73 guint32 statisticslength; /* length of statistics structure */
74 guint32 networkinfooffset; /* offset to network info structure */
75 guint32 networkinfolength; /* length of network info structure */
78 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
79 * looking at capture files. */
80 struct netmonrec_1_x_hdr {
81 guint32 ts_delta; /* time stamp - msecs since start of capture */
82 guint16 orig_len; /* actual length of packet */
83 guint16 incl_len; /* number of octets captured in file */
86 /* Network Monitor 2.x record header; not defined in STRUCT.H, but deduced by
87 * looking at capture files. */
88 struct netmonrec_2_x_hdr {
89 guint32 ts_delta_lo; /* time stamp - usecs since start of capture */
90 guint32 ts_delta_hi; /* time stamp - usecs since start of capture */
91 guint32 orig_len; /* actual length of packet */
92 guint32 incl_len; /* number of octets captured in file */
96 * The link-layer header on ATM packets.
98 struct netmon_atm_hdr {
99 guint8 dest[6]; /* "Destination address" - what is it? */
100 guint8 src[6]; /* "Source address" - what is it? */
101 guint16 vpi; /* VPI */
102 guint16 vci; /* VCI */
105 static gboolean netmon_read(wtap *wth, int *err, long *data_offset);
106 static gboolean netmon_seek_read(wtap *wth, long seek_off,
107 union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err);
108 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
109 union wtap_pseudo_header *pseudo_header, int *err);
110 static gboolean netmon_read_rec_data(FILE_T fh, guchar *pd, int length,
112 static void netmon_sequential_close(wtap *wth);
113 static void netmon_close(wtap *wth);
114 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
115 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
116 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
118 int netmon_open(wtap *wth, int *err)
121 char magic[sizeof netmon_1_x_magic];
122 struct netmon_hdr hdr;
124 static const int netmon_encap[] = {
127 WTAP_ENCAP_TOKEN_RING,
128 WTAP_ENCAP_FDDI_BITSWAPPED,
129 WTAP_ENCAP_ATM_SNIFFER, /* NDIS WAN - this is what's used for ATM */
130 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk */
131 WTAP_ENCAP_UNKNOWN, /* NDIS "DIX" - should not occur */
132 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET raw */
133 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET 878.2 */
134 WTAP_ENCAP_UNKNOWN, /* NDIS ATM (no, this is NOT used for ATM) */
135 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
136 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
138 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
140 int frame_table_offset;
141 guint32 frame_table_length;
142 guint32 frame_table_size;
143 guint32 *frame_table;
144 #ifdef WORDS_BIGENDIAN
148 /* Read in the string that should be at the start of a Network
150 errno = WTAP_ERR_CANT_READ;
151 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
152 if (bytes_read != sizeof magic) {
153 *err = file_error(wth->fh);
159 if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
160 && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
164 /* Read the rest of the header. */
165 errno = WTAP_ERR_CANT_READ;
166 bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
167 if (bytes_read != sizeof hdr) {
168 *err = file_error(wth->fh);
174 switch (hdr.ver_major) {
177 file_type = WTAP_FILE_NETMON_1_x;
181 file_type = WTAP_FILE_NETMON_2_x;
185 g_message("netmon: major version %u unsupported", hdr.ver_major);
186 *err = WTAP_ERR_UNSUPPORTED;
190 hdr.network = pletohs(&hdr.network);
191 if (hdr.network >= NUM_NETMON_ENCAPS
192 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
193 g_message("netmon: network type %u unknown or unsupported",
195 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
199 /* This is a netmon file */
200 wth->file_type = file_type;
201 wth->capture.netmon = g_malloc(sizeof(netmon_t));
202 wth->subtype_read = netmon_read;
203 wth->subtype_seek_read = netmon_seek_read;
204 wth->subtype_sequential_close = netmon_sequential_close;
205 wth->subtype_close = netmon_close;
206 wth->file_encap = netmon_encap[hdr.network];
207 wth->snapshot_length = 0; /* not available in header */
209 * Convert the time stamp to a "time_t" and a number of
212 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
213 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
214 tm.tm_mday = pletohs(&hdr.ts_day);
215 tm.tm_hour = pletohs(&hdr.ts_hour);
216 tm.tm_min = pletohs(&hdr.ts_min);
217 tm.tm_sec = pletohs(&hdr.ts_sec);
219 wth->capture.netmon->start_secs = mktime(&tm);
221 * XXX - what if "secs" is -1? Unlikely, but if the capture was
222 * done in a time zone that switches between standard and summer
223 * time sometime other than when we do, and thus the time was one
224 * that doesn't exist here because a switch from standard to summer
225 * time zips over it, it could happen.
227 * On the other hand, if the capture was done in a different time
228 * zone, this won't work right anyway; unfortunately, the time
229 * zone isn't stored in the capture file (why the hell didn't
230 * they stuff a FILETIME, which is the number of 100-nanosecond
231 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
232 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
234 wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
236 wth->capture.netmon->version_major = hdr.ver_major;
239 * Get the offset of the frame index table.
241 frame_table_offset = pletohl(&hdr.frametableoffset);
244 * It appears that some NetMon 2.x files don't have the
245 * first packet starting exactly 128 bytes into the file.
247 * Furthermore, it also appears that there are "holes" in
248 * the file, i.e. frame N+1 doesn't always follow immediately
251 * Therefore, we must read the frame table, and use the offsets
252 * in it as the offsets of the frames.
254 frame_table_length = pletohl(&hdr.frametablelength);
255 frame_table_size = frame_table_length / sizeof (guint32);
256 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
257 g_message("netmon: frame table length is %u, which is not a multiple of the size of an entry",
259 *err = WTAP_ERR_UNSUPPORTED;
262 if (frame_table_size == 0) {
263 g_message("netmon: frame table length is %u, which means it's less than one entry in size",
265 *err = WTAP_ERR_UNSUPPORTED;
268 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
269 g_free(wth->capture.netmon);
272 frame_table = g_malloc(frame_table_length);
273 errno = WTAP_ERR_CANT_READ;
274 bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
275 if ((guint32)bytes_read != frame_table_length) {
276 *err = file_error(wth->fh);
278 *err = WTAP_ERR_SHORT_READ;
281 wth->capture.netmon->frame_table_size = frame_table_size;
282 wth->capture.netmon->frame_table = frame_table;
284 #ifdef WORDS_BIGENDIAN
286 * OK, now byte-swap the frame table.
288 for (i = 0; i < frame_table_size; i++)
289 frame_table[i] = pletohl(&frame_table[i]);
292 /* Set up to start reading at the first frame. */
293 wth->capture.netmon->current_frame = 0;
298 /* Read the next packet */
299 static gboolean netmon_read(wtap *wth, int *err, long *data_offset)
301 netmon_t *netmon = wth->capture.netmon;
302 guint32 packet_size = 0;
303 guint32 orig_size = 0;
306 struct netmonrec_1_x_hdr hdr_1_x;
307 struct netmonrec_2_x_hdr hdr_2_x;
315 /* Have we reached the end of the packet data? */
316 if (netmon->current_frame >= netmon->frame_table_size) {
317 /* Yes. We won't need the frame table any more;
319 g_free(wth->capture.netmon->frame_table);
320 wth->capture.netmon->frame_table = NULL;
321 *err = 0; /* it's just an EOF, not an error */
325 /* Seek to the beginning of the current record, if we're
326 not there already (seeking to the current position
327 may still cause a seek and a read of the underlying file,
328 so we don't want to do it unconditionally). */
329 rec_offset = netmon->frame_table[netmon->current_frame];
330 if (wth->data_offset != rec_offset) {
331 wth->data_offset = rec_offset;
332 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
335 netmon->current_frame++;
337 /* Read record header. */
338 switch (netmon->version_major) {
341 hdr_size = sizeof (struct netmonrec_1_x_hdr);
345 hdr_size = sizeof (struct netmonrec_2_x_hdr);
348 errno = WTAP_ERR_CANT_READ;
350 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
351 if (bytes_read != hdr_size) {
352 *err = file_error(wth->fh);
353 if (*err == 0 && bytes_read != 0) {
354 *err = WTAP_ERR_SHORT_READ;
358 wth->data_offset += hdr_size;
360 switch (netmon->version_major) {
363 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
364 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
368 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
369 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
372 if (packet_size > WTAP_MAX_PACKET_SIZE) {
374 * Probably a corrupt capture file; don't blow up trying
375 * to allocate space for an immensely-large packet.
377 g_message("netmon: File has %u-byte packet, bigger than maximum of %u",
378 packet_size, WTAP_MAX_PACKET_SIZE);
379 *err = WTAP_ERR_BAD_RECORD;
383 *data_offset = wth->data_offset;
386 * If this is an ATM packet, the first
387 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
388 * source addresses (6 bytes - MAC addresses of some sort?)
389 * and the VPI and VCI; read them and generate the pseudo-header
392 if (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER) {
393 if (packet_size < sizeof (struct netmon_atm_hdr)) {
395 * Uh-oh, the packet isn't big enough to even
396 * have a pseudo-header.
398 g_message("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header\n",
400 *err = WTAP_ERR_BAD_RECORD;
403 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
405 return FALSE; /* Read error */
408 * Don't count the pseudo-header as part of the packet.
410 orig_size -= sizeof (struct netmon_atm_hdr);
411 packet_size -= sizeof (struct netmon_atm_hdr);
412 wth->data_offset += sizeof (struct netmon_atm_hdr);
415 buffer_assure_space(wth->frame_buffer, packet_size);
416 if (!netmon_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
418 return FALSE; /* Read error */
419 wth->data_offset += packet_size;
421 t = (double)netmon->start_usecs;
422 switch (netmon->version_major) {
425 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
429 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
430 + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
433 secs = (time_t)(t/1000000);
434 usecs = (guint32)(t - secs*1000000);
435 wth->phdr.ts.tv_sec = netmon->start_secs + secs;
436 wth->phdr.ts.tv_usec = usecs;
437 wth->phdr.caplen = packet_size;
438 wth->phdr.len = orig_size;
439 wth->phdr.pkt_encap = wth->file_encap;
445 netmon_seek_read(wtap *wth, long seek_off,
446 union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err)
448 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
451 if (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER) {
452 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
460 * Read the packet data.
462 return netmon_read_rec_data(wth->random_fh, pd, length, err);
466 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
469 struct netmon_atm_hdr atm_phdr;
473 errno = WTAP_ERR_CANT_READ;
474 bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
475 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
476 *err = file_error(fh);
478 *err = WTAP_ERR_SHORT_READ;
482 vpi = g_ntohs(atm_phdr.vpi);
483 vci = g_ntohs(atm_phdr.vci);
486 * Assume it's AAL5, unless it's VPI 0 and VCI 5, in which case
487 * assume it's AAL_SIGNALLING; we know nothing more about it.
489 if (vpi == 0 && vci == 5)
490 pseudo_header->atm.aal = AAL_SIGNALLING;
492 pseudo_header->atm.aal = AAL_5;
493 pseudo_header->atm.type = TRAF_UNKNOWN;
494 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
496 pseudo_header->atm.vpi = vpi;
497 pseudo_header->atm.vci = vci;
499 /* We don't have this information */
500 pseudo_header->atm.channel = 0;
501 pseudo_header->atm.cells = 0;
502 pseudo_header->atm.aal5t_u2u = 0;
503 pseudo_header->atm.aal5t_len = 0;
504 pseudo_header->atm.aal5t_chksum = 0;
510 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
514 errno = WTAP_ERR_CANT_READ;
515 bytes_read = file_read(pd, 1, length, fh);
517 if (bytes_read != length) {
518 *err = file_error(fh);
520 *err = WTAP_ERR_SHORT_READ;
526 /* Throw away the frame table used by the sequential I/O stream. */
528 netmon_sequential_close(wtap *wth)
530 if (wth->capture.netmon->frame_table != NULL) {
531 g_free(wth->capture.netmon->frame_table);
532 wth->capture.netmon->frame_table = NULL;
536 /* Close stuff used by the random I/O stream, if any, and free up any
537 private data structures. (If there's a "sequential_close" routine
538 for a capture file type, it'll be called before the "close" routine
539 is called, so we don't have to free the frame table here.) */
541 netmon_close(wtap *wth)
543 g_free(wth->capture.netmon);
546 static const int wtap_encap[] = {
547 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
548 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
549 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
550 -1, /* WTAP_ENCAP_SLIP -> unsupported */
551 -1, /* WTAP_ENCAP_PPP -> unsupported */
552 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
553 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
554 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
555 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
556 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
557 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
558 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
559 4, /* WTAP_ENCAP_ATM_SNIFFER -> NDIS WAN (*NOT* ATM!) */
560 -1 /* WTAP_ENCAP_NULL -> unsupported */
562 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
564 /* Returns 0 if we could write the specified encapsulation type,
565 an error indication otherwise. */
566 int netmon_dump_can_write_encap(int encap)
568 /* Per-packet encapsulations aren't supported. */
569 if (encap == WTAP_ENCAP_PER_PACKET)
570 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
572 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
573 return WTAP_ERR_UNSUPPORTED_ENCAP;
578 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
580 gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
582 /* This is a NetMon file. We can't fill in some fields in the
583 header until all the packets have been written, so we can't
586 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
590 wdh->subtype_write = netmon_dump;
591 wdh->subtype_close = netmon_dump_close;
593 /* We can't fill in all the fields in the file header, as we
594 haven't yet written any packets. As we'll have to rewrite
595 the header when we've written out all the packets, we just
596 skip over the header for now. */
597 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
602 wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
603 wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
604 wdh->dump.netmon->got_first_record_time = FALSE;
605 wdh->dump.netmon->frame_table = NULL;
606 wdh->dump.netmon->frame_table_index = 0;
607 wdh->dump.netmon->frame_table_size = 0;
612 /* Write a record for a packet to a dump file.
613 Returns TRUE on success, FALSE on failure. */
614 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
615 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
617 netmon_dump_t *netmon = wdh->dump.netmon;
618 struct netmonrec_1_x_hdr rec_1_x_hdr;
619 struct netmonrec_2_x_hdr rec_2_x_hdr;
624 guint32 time_low, time_high;
625 struct netmon_atm_hdr atm_hdr;
628 /* NetMon files have a capture start time in the file header,
629 and have times relative to that in the packet headers;
630 pick the time of the first packet as the capture start
632 if (!netmon->got_first_record_time) {
633 netmon->first_record_time = phdr->ts;
634 netmon->got_first_record_time = TRUE;
637 if (wdh->encap == WTAP_ENCAP_ATM_SNIFFER)
638 atm_hdrsize = sizeof (struct netmon_atm_hdr);
641 switch (wdh->file_type) {
643 case WTAP_FILE_NETMON_1_x:
644 rec_1_x_hdr.ts_delta = htolel(
645 (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000
646 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec + 500)/1000);
647 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
648 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
649 hdrp = (char *)&rec_1_x_hdr;
650 hdr_size = sizeof rec_1_x_hdr;
653 case WTAP_FILE_NETMON_2_x:
655 * Unfortunately, not all the platforms on which we run
656 * support 64-bit integral types, even though most do
657 * (even on 32-bit processors), so we do it in floating
660 t = (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000000.0
661 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec);
662 time_high = t/4294967296.0;
663 time_low = t - (time_high*4294967296.0);
664 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
665 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
666 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
667 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
668 hdrp = (char *)&rec_2_x_hdr;
669 hdr_size = sizeof rec_2_x_hdr;
673 /* We should never get here - our open routine
674 should only get called for the types above. */
675 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
679 nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
680 if (nwritten != hdr_size) {
681 if (nwritten == 0 && ferror(wdh->fh))
684 *err = WTAP_ERR_SHORT_WRITE;
688 if (wdh->encap == WTAP_ENCAP_ATM_SNIFFER) {
690 * Write the ATM header.
691 * We supply all-zero destination and source addresses.
693 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
694 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
695 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
696 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
697 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
698 if (nwritten != sizeof atm_hdr) {
699 if (nwritten == 0 && ferror(wdh->fh))
702 *err = WTAP_ERR_SHORT_WRITE;
707 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
708 if (nwritten != phdr->caplen) {
709 if (nwritten == 0 && ferror(wdh->fh))
712 *err = WTAP_ERR_SHORT_WRITE;
717 * Stash the file offset of this frame.
719 if (netmon->frame_table_size == 0) {
721 * Haven't yet allocated the buffer for the frame table.
723 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
724 netmon->frame_table_size = 1024;
727 * We've allocated it; are we at the end?
729 if (netmon->frame_table_index >= netmon->frame_table_size) {
731 * Yes - double the size of the frame table.
733 netmon->frame_table_size *= 2;
734 netmon->frame_table = g_realloc(netmon->frame_table,
735 netmon->frame_table_size * sizeof *netmon->frame_table);
738 netmon->frame_table[netmon->frame_table_index] =
739 htolel(netmon->frame_table_offset);
740 netmon->frame_table_index++;
741 netmon->frame_table_offset += hdr_size + phdr->caplen + atm_hdrsize;
746 /* Finish writing to a dump file.
747 Returns TRUE on success, FALSE on failure. */
748 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
750 netmon_dump_t *netmon = wdh->dump.netmon;
753 struct netmon_hdr file_hdr;
758 /* Write out the frame table. "netmon->frame_table_index" is
759 the number of entries we've put into it. */
760 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
761 nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
762 if (nwritten != n_to_write) {
764 if (nwritten == 0 && ferror(wdh->fh))
767 *err = WTAP_ERR_SHORT_WRITE;
772 /* Now go fix up the file header. */
773 fseek(wdh->fh, 0, SEEK_SET);
774 memset(&file_hdr, '\0', sizeof file_hdr);
775 switch (wdh->file_type) {
777 case WTAP_FILE_NETMON_1_x:
778 magicp = netmon_1_x_magic;
779 magic_size = sizeof netmon_1_x_magic;
780 /* current NetMon version, for 1.x, is 1.1 */
781 file_hdr.ver_major = 1;
782 file_hdr.ver_minor = 1;
785 case WTAP_FILE_NETMON_2_x:
786 magicp = netmon_2_x_magic;
787 magic_size = sizeof netmon_2_x_magic;
788 /* current NetMon version, for 2.x, is 2.0 */
789 file_hdr.ver_major = 2;
790 file_hdr.ver_minor = 0;
794 /* We should never get here - our open routine
795 should only get called for the types above. */
797 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
800 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
801 if (nwritten != magic_size) {
803 if (nwritten == 0 && ferror(wdh->fh))
806 *err = WTAP_ERR_SHORT_WRITE;
811 file_hdr.network = htoles(wtap_encap[wdh->encap]);
812 tm = localtime(&netmon->first_record_time.tv_sec);
814 file_hdr.ts_year = htoles(1900 + tm->tm_year);
815 file_hdr.ts_month = htoles(tm->tm_mon + 1);
816 file_hdr.ts_dow = htoles(tm->tm_wday);
817 file_hdr.ts_day = htoles(tm->tm_mday);
818 file_hdr.ts_hour = htoles(tm->tm_hour);
819 file_hdr.ts_min = htoles(tm->tm_min);
820 file_hdr.ts_sec = htoles(tm->tm_sec);
822 file_hdr.ts_year = htoles(1900 + 0);
823 file_hdr.ts_month = htoles(0 + 1);
824 file_hdr.ts_dow = htoles(0);
825 file_hdr.ts_day = htoles(0);
826 file_hdr.ts_hour = htoles(0);
827 file_hdr.ts_min = htoles(0);
828 file_hdr.ts_sec = htoles(0);
830 file_hdr.ts_msec = htoles(netmon->first_record_time.tv_usec/1000);
831 /* XXX - what about rounding? */
832 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
833 file_hdr.frametablelength =
834 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
835 nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
836 if (nwritten != sizeof file_hdr) {
838 if (nwritten == 0 && ferror(wdh->fh))
841 *err = WTAP_ERR_SHORT_WRITE;