3 * $Id: netmon.c,v 1.67 2003/12/23 00:15:02 ulfl 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"
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, long *data_offset);
108 static gboolean netmon_seek_read(wtap *wth, long seek_off,
109 union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err);
110 static gboolean netmon_read_atm_pseudoheader(FILE_T fh,
111 union wtap_pseudo_header *pseudo_header, int *err);
112 static gboolean netmon_read_rec_data(FILE_T fh, guchar *pd, int length,
114 static void netmon_sequential_close(wtap *wth);
115 static void netmon_close(wtap *wth);
116 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
117 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
118 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
120 int netmon_open(wtap *wth, int *err)
123 char magic[sizeof netmon_1_x_magic];
124 struct netmon_hdr hdr;
126 static const int netmon_encap[] = {
129 WTAP_ENCAP_TOKEN_RING,
130 WTAP_ENCAP_FDDI_BITSWAPPED,
131 WTAP_ENCAP_ATM_PDUS, /* NDIS WAN - this is what's used for ATM */
132 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk */
133 WTAP_ENCAP_UNKNOWN, /* NDIS "DIX" - should not occur */
134 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET raw */
135 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET 878.2 */
136 WTAP_ENCAP_UNKNOWN, /* NDIS ATM (no, this is NOT used for ATM) */
137 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
138 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
140 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
142 int frame_table_offset;
143 guint32 frame_table_length;
144 guint32 frame_table_size;
145 guint32 *frame_table;
146 #ifdef WORDS_BIGENDIAN
150 /* Read in the string that should be at the start of a Network
152 errno = WTAP_ERR_CANT_READ;
153 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
154 if (bytes_read != sizeof magic) {
155 *err = file_error(wth->fh);
161 if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
162 && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
166 /* Read the rest of the header. */
167 errno = WTAP_ERR_CANT_READ;
168 bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
169 if (bytes_read != sizeof hdr) {
170 *err = file_error(wth->fh);
176 switch (hdr.ver_major) {
179 file_type = WTAP_FILE_NETMON_1_x;
183 file_type = WTAP_FILE_NETMON_2_x;
187 g_message("netmon: major version %u unsupported", hdr.ver_major);
188 *err = WTAP_ERR_UNSUPPORTED;
192 hdr.network = pletohs(&hdr.network);
193 if (hdr.network >= NUM_NETMON_ENCAPS
194 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
195 g_message("netmon: network type %u unknown or unsupported",
197 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
201 /* This is a netmon file */
202 wth->file_type = file_type;
203 wth->capture.netmon = g_malloc(sizeof(netmon_t));
204 wth->subtype_read = netmon_read;
205 wth->subtype_seek_read = netmon_seek_read;
206 wth->subtype_sequential_close = netmon_sequential_close;
207 wth->subtype_close = netmon_close;
208 wth->file_encap = netmon_encap[hdr.network];
209 wth->snapshot_length = 0; /* not available in header */
211 * Convert the time stamp to a "time_t" and a number of
214 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
215 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
216 tm.tm_mday = pletohs(&hdr.ts_day);
217 tm.tm_hour = pletohs(&hdr.ts_hour);
218 tm.tm_min = pletohs(&hdr.ts_min);
219 tm.tm_sec = pletohs(&hdr.ts_sec);
221 wth->capture.netmon->start_secs = mktime(&tm);
223 * XXX - what if "secs" is -1? Unlikely, but if the capture was
224 * done in a time zone that switches between standard and summer
225 * time sometime other than when we do, and thus the time was one
226 * that doesn't exist here because a switch from standard to summer
227 * time zips over it, it could happen.
229 * On the other hand, if the capture was done in a different time
230 * zone, this won't work right anyway; unfortunately, the time
231 * zone isn't stored in the capture file (why the hell didn't
232 * they stuff a FILETIME, which is the number of 100-nanosecond
233 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
234 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
236 wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
238 wth->capture.netmon->version_major = hdr.ver_major;
241 * Get the offset of the frame index table.
243 frame_table_offset = pletohl(&hdr.frametableoffset);
246 * It appears that some NetMon 2.x files don't have the
247 * first packet starting exactly 128 bytes into the file.
249 * Furthermore, it also appears that there are "holes" in
250 * the file, i.e. frame N+1 doesn't always follow immediately
253 * Therefore, we must read the frame table, and use the offsets
254 * in it as the offsets of the frames.
256 frame_table_length = pletohl(&hdr.frametablelength);
257 frame_table_size = frame_table_length / sizeof (guint32);
258 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
259 g_message("netmon: frame table length is %u, which is not a multiple of the size of an entry",
261 *err = WTAP_ERR_UNSUPPORTED;
264 if (frame_table_size == 0) {
265 g_message("netmon: frame table length is %u, which means it's less than one entry in size",
267 *err = WTAP_ERR_UNSUPPORTED;
270 if (file_seek(wth->fh, frame_table_offset, SEEK_SET, err) == -1) {
271 g_free(wth->capture.netmon);
274 frame_table = g_malloc(frame_table_length);
275 errno = WTAP_ERR_CANT_READ;
276 bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
277 if ((guint32)bytes_read != frame_table_length) {
278 *err = file_error(wth->fh);
280 *err = WTAP_ERR_SHORT_READ;
283 wth->capture.netmon->frame_table_size = frame_table_size;
284 wth->capture.netmon->frame_table = frame_table;
286 #ifdef WORDS_BIGENDIAN
288 * OK, now byte-swap the frame table.
290 for (i = 0; i < frame_table_size; i++)
291 frame_table[i] = pletohl(&frame_table[i]);
294 /* Set up to start reading at the first frame. */
295 wth->capture.netmon->current_frame = 0;
300 /* Read the next packet */
301 static gboolean netmon_read(wtap *wth, int *err, long *data_offset)
303 netmon_t *netmon = wth->capture.netmon;
304 guint32 packet_size = 0;
305 guint32 orig_size = 0;
308 struct netmonrec_1_x_hdr hdr_1_x;
309 struct netmonrec_2_x_hdr hdr_2_x;
318 /* Have we reached the end of the packet data? */
319 if (netmon->current_frame >= netmon->frame_table_size) {
320 /* Yes. We won't need the frame table any more;
322 g_free(wth->capture.netmon->frame_table);
323 wth->capture.netmon->frame_table = NULL;
324 *err = 0; /* it's just an EOF, not an error */
328 /* Seek to the beginning of the current record, if we're
329 not there already (seeking to the current position
330 may still cause a seek and a read of the underlying file,
331 so we don't want to do it unconditionally). */
332 rec_offset = netmon->frame_table[netmon->current_frame];
333 if (wth->data_offset != rec_offset) {
334 wth->data_offset = rec_offset;
335 if (file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1)
338 netmon->current_frame++;
340 /* Read record header. */
341 switch (netmon->version_major) {
344 hdr_size = sizeof (struct netmonrec_1_x_hdr);
348 hdr_size = sizeof (struct netmonrec_2_x_hdr);
351 errno = WTAP_ERR_CANT_READ;
353 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
354 if (bytes_read != hdr_size) {
355 *err = file_error(wth->fh);
356 if (*err == 0 && bytes_read != 0) {
357 *err = WTAP_ERR_SHORT_READ;
361 wth->data_offset += hdr_size;
363 switch (netmon->version_major) {
366 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
367 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
371 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
372 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
375 if (packet_size > WTAP_MAX_PACKET_SIZE) {
377 * Probably a corrupt capture file; don't blow up trying
378 * to allocate space for an immensely-large packet.
380 g_message("netmon: File has %u-byte packet, bigger than maximum of %u",
381 packet_size, WTAP_MAX_PACKET_SIZE);
382 *err = WTAP_ERR_BAD_RECORD;
386 *data_offset = wth->data_offset;
389 * If this is an ATM packet, the first
390 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
391 * source addresses (6 bytes - MAC addresses of some sort?)
392 * and the VPI and VCI; read them and generate the pseudo-header
395 switch (wth->file_encap) {
397 case WTAP_ENCAP_ATM_PDUS:
398 if (packet_size < sizeof (struct netmon_atm_hdr)) {
400 * Uh-oh, the packet isn't big enough to even
401 * have a pseudo-header.
403 g_message("netmon: ATM file has a %u-byte packet, too small to have even an ATM pseudo-header\n",
405 *err = WTAP_ERR_BAD_RECORD;
408 if (!netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
410 return FALSE; /* Read error */
413 * Don't count the pseudo-header as part of the packet.
415 orig_size -= sizeof (struct netmon_atm_hdr);
416 packet_size -= sizeof (struct netmon_atm_hdr);
417 wth->data_offset += sizeof (struct netmon_atm_hdr);
420 case WTAP_ENCAP_ETHERNET:
422 * We assume there's no FCS in this frame.
424 wth->pseudo_header.eth.fcs_len = 0;
428 buffer_assure_space(wth->frame_buffer, packet_size);
429 data_ptr = buffer_start_ptr(wth->frame_buffer);
430 if (!netmon_read_rec_data(wth->fh, data_ptr, packet_size, err))
431 return FALSE; /* Read error */
432 wth->data_offset += packet_size;
434 t = (double)netmon->start_usecs;
435 switch (netmon->version_major) {
438 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
442 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
443 + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
446 secs = (time_t)(t/1000000);
447 usecs = (guint32)(t - (double)secs*1000000);
448 wth->phdr.ts.tv_sec = netmon->start_secs + secs;
449 wth->phdr.ts.tv_usec = usecs;
450 wth->phdr.caplen = packet_size;
451 wth->phdr.len = orig_size;
452 wth->phdr.pkt_encap = wth->file_encap;
455 * Attempt to guess from the packet data, the VPI, and the VCI
456 * information about the type of traffic.
458 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS) {
459 atm_guess_traffic_type(data_ptr, packet_size,
460 &wth->pseudo_header);
467 netmon_seek_read(wtap *wth, long seek_off,
468 union wtap_pseudo_header *pseudo_header, guchar *pd, int length, int *err)
470 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
473 switch (wth->file_encap) {
475 case WTAP_ENCAP_ATM_PDUS:
476 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
483 case WTAP_ENCAP_ETHERNET:
485 * We assume there's no FCS in this frame.
487 pseudo_header->eth.fcs_len = 0;
492 * Read the packet data.
494 if (!netmon_read_rec_data(wth->random_fh, pd, length, err))
498 * Attempt to guess from the packet data, the VPI, and the VCI
499 * information about the type of traffic.
501 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
502 atm_guess_traffic_type(pd, length, pseudo_header);
508 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
511 struct netmon_atm_hdr atm_phdr;
515 errno = WTAP_ERR_CANT_READ;
516 bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
517 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
518 *err = file_error(fh);
520 *err = WTAP_ERR_SHORT_READ;
524 vpi = g_ntohs(atm_phdr.vpi);
525 vci = g_ntohs(atm_phdr.vci);
527 pseudo_header->atm.vpi = vpi;
528 pseudo_header->atm.vci = vci;
530 /* We don't have this information */
531 pseudo_header->atm.flags = 0;
532 pseudo_header->atm.channel = 0;
533 pseudo_header->atm.cells = 0;
534 pseudo_header->atm.aal5t_u2u = 0;
535 pseudo_header->atm.aal5t_len = 0;
536 pseudo_header->atm.aal5t_chksum = 0;
542 netmon_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
546 errno = WTAP_ERR_CANT_READ;
547 bytes_read = file_read(pd, 1, length, fh);
549 if (bytes_read != length) {
550 *err = file_error(fh);
552 *err = WTAP_ERR_SHORT_READ;
558 /* Throw away the frame table used by the sequential I/O stream. */
560 netmon_sequential_close(wtap *wth)
562 if (wth->capture.netmon->frame_table != NULL) {
563 g_free(wth->capture.netmon->frame_table);
564 wth->capture.netmon->frame_table = NULL;
568 /* Close stuff used by the random I/O stream, if any, and free up any
569 private data structures. (If there's a "sequential_close" routine
570 for a capture file type, it'll be called before the "close" routine
571 is called, so we don't have to free the frame table here.) */
573 netmon_close(wtap *wth)
575 g_free(wth->capture.netmon);
578 static const int wtap_encap[] = {
579 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
580 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
581 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
582 -1, /* WTAP_ENCAP_SLIP -> unsupported */
583 -1, /* WTAP_ENCAP_PPP -> unsupported */
584 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
585 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
586 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
587 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
588 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
589 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
590 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
591 4, /* WTAP_ENCAP_ATM_PDUS -> NDIS WAN (*NOT* ATM!) */
592 -1 /* WTAP_ENCAP_NULL -> unsupported */
594 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
596 /* Returns 0 if we could write the specified encapsulation type,
597 an error indication otherwise. */
598 int netmon_dump_can_write_encap(int encap)
600 /* Per-packet encapsulations aren't supported. */
601 if (encap == WTAP_ENCAP_PER_PACKET)
602 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
604 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
605 return WTAP_ERR_UNSUPPORTED_ENCAP;
610 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
612 gboolean netmon_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
614 /* This is a NetMon file. We can't fill in some fields in the
615 header until all the packets have been written, so we can't
618 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
622 /* We can't fill in all the fields in the file header, as we
623 haven't yet written any packets. As we'll have to rewrite
624 the header when we've written out all the packets, we just
625 skip over the header for now. */
626 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
631 wdh->subtype_write = netmon_dump;
632 wdh->subtype_close = netmon_dump_close;
634 wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
635 wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
636 wdh->dump.netmon->got_first_record_time = FALSE;
637 wdh->dump.netmon->frame_table = NULL;
638 wdh->dump.netmon->frame_table_index = 0;
639 wdh->dump.netmon->frame_table_size = 0;
644 /* Write a record for a packet to a dump file.
645 Returns TRUE on success, FALSE on failure. */
646 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
647 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
649 netmon_dump_t *netmon = wdh->dump.netmon;
650 struct netmonrec_1_x_hdr rec_1_x_hdr;
651 struct netmonrec_2_x_hdr rec_2_x_hdr;
656 guint32 time_low, time_high;
657 struct netmon_atm_hdr atm_hdr;
660 /* NetMon files have a capture start time in the file header,
661 and have times relative to that in the packet headers;
662 pick the time of the first packet as the capture start
664 if (!netmon->got_first_record_time) {
665 netmon->first_record_time = phdr->ts;
666 netmon->got_first_record_time = TRUE;
669 if (wdh->encap == WTAP_ENCAP_ATM_PDUS)
670 atm_hdrsize = sizeof (struct netmon_atm_hdr);
673 switch (wdh->file_type) {
675 case WTAP_FILE_NETMON_1_x:
676 rec_1_x_hdr.ts_delta = htolel(
677 (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000
678 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec + 500)/1000);
679 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
680 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
681 hdrp = (char *)&rec_1_x_hdr;
682 hdr_size = sizeof rec_1_x_hdr;
685 case WTAP_FILE_NETMON_2_x:
687 * Unfortunately, not all the platforms on which we run
688 * support 64-bit integral types, even though most do
689 * (even on 32-bit processors), so we do it in floating
692 t = (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000000.0
693 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec);
694 time_high = (guint32) (t/4294967296.0);
695 time_low = (guint32) (t - (time_high*4294967296.0));
696 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
697 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
698 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
699 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
700 hdrp = (char *)&rec_2_x_hdr;
701 hdr_size = sizeof rec_2_x_hdr;
705 /* We should never get here - our open routine
706 should only get called for the types above. */
707 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
711 nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
712 if (nwritten != hdr_size) {
713 if (nwritten == 0 && ferror(wdh->fh))
716 *err = WTAP_ERR_SHORT_WRITE;
720 if (wdh->encap == WTAP_ENCAP_ATM_PDUS) {
722 * Write the ATM header.
723 * We supply all-zero destination and source addresses.
725 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
726 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
727 atm_hdr.vpi = g_htons(pseudo_header->atm.vpi);
728 atm_hdr.vci = g_htons(pseudo_header->atm.vci);
729 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
730 if (nwritten != sizeof atm_hdr) {
731 if (nwritten == 0 && ferror(wdh->fh))
734 *err = WTAP_ERR_SHORT_WRITE;
739 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
740 if (nwritten != phdr->caplen) {
741 if (nwritten == 0 && ferror(wdh->fh))
744 *err = WTAP_ERR_SHORT_WRITE;
749 * Stash the file offset of this frame.
751 if (netmon->frame_table_size == 0) {
753 * Haven't yet allocated the buffer for the frame table.
755 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
756 netmon->frame_table_size = 1024;
759 * We've allocated it; are we at the end?
761 if (netmon->frame_table_index >= netmon->frame_table_size) {
763 * Yes - double the size of the frame table.
765 netmon->frame_table_size *= 2;
766 netmon->frame_table = g_realloc(netmon->frame_table,
767 netmon->frame_table_size * sizeof *netmon->frame_table);
770 netmon->frame_table[netmon->frame_table_index] =
771 htolel(netmon->frame_table_offset);
772 netmon->frame_table_index++;
773 netmon->frame_table_offset += hdr_size + phdr->caplen + atm_hdrsize;
778 /* Finish writing to a dump file.
779 Returns TRUE on success, FALSE on failure. */
780 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
782 netmon_dump_t *netmon = wdh->dump.netmon;
785 struct netmon_hdr file_hdr;
790 /* Write out the frame table. "netmon->frame_table_index" is
791 the number of entries we've put into it. */
792 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
793 nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
794 if (nwritten != n_to_write) {
796 if (nwritten == 0 && ferror(wdh->fh))
799 *err = WTAP_ERR_SHORT_WRITE;
804 /* Now go fix up the file header. */
805 fseek(wdh->fh, 0, SEEK_SET);
806 memset(&file_hdr, '\0', sizeof file_hdr);
807 switch (wdh->file_type) {
809 case WTAP_FILE_NETMON_1_x:
810 magicp = netmon_1_x_magic;
811 magic_size = sizeof netmon_1_x_magic;
812 /* current NetMon version, for 1.x, is 1.1 */
813 file_hdr.ver_major = 1;
814 file_hdr.ver_minor = 1;
817 case WTAP_FILE_NETMON_2_x:
818 magicp = netmon_2_x_magic;
819 magic_size = sizeof netmon_2_x_magic;
820 /* current NetMon version, for 2.x, is 2.0 */
821 file_hdr.ver_major = 2;
822 file_hdr.ver_minor = 0;
826 /* We should never get here - our open routine
827 should only get called for the types above. */
829 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
832 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
833 if (nwritten != magic_size) {
835 if (nwritten == 0 && ferror(wdh->fh))
838 *err = WTAP_ERR_SHORT_WRITE;
843 file_hdr.network = htoles(wtap_encap[wdh->encap]);
844 tm = localtime(&netmon->first_record_time.tv_sec);
846 file_hdr.ts_year = htoles(1900 + tm->tm_year);
847 file_hdr.ts_month = htoles(tm->tm_mon + 1);
848 file_hdr.ts_dow = htoles(tm->tm_wday);
849 file_hdr.ts_day = htoles(tm->tm_mday);
850 file_hdr.ts_hour = htoles(tm->tm_hour);
851 file_hdr.ts_min = htoles(tm->tm_min);
852 file_hdr.ts_sec = htoles(tm->tm_sec);
854 file_hdr.ts_year = htoles(1900 + 0);
855 file_hdr.ts_month = htoles(0 + 1);
856 file_hdr.ts_dow = htoles(0);
857 file_hdr.ts_day = htoles(0);
858 file_hdr.ts_hour = htoles(0);
859 file_hdr.ts_min = htoles(0);
860 file_hdr.ts_sec = htoles(0);
862 file_hdr.ts_msec = htoles(netmon->first_record_time.tv_usec/1000);
863 /* XXX - what about rounding? */
864 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
865 file_hdr.frametablelength =
866 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
867 nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
868 if (nwritten != sizeof file_hdr) {
870 if (nwritten == 0 && ferror(wdh->fh))
873 *err = WTAP_ERR_SHORT_WRITE;