3 * $Id: netmon.c,v 1.54 2002/05/04 10:00:18 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"
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
38 * ftp://ftp.microsoft.com/developr/drg/cifs/cifs/Bhfile.zip
40 * contains "STRUCT.H", which declares the typedef CAPTUREFILE_HEADER
41 * for the header of a Microsoft Network Monitor capture file.
44 /* Capture file header, *including* magic number, is padded to 128 bytes. */
45 #define CAPTUREFILE_HEADER_SIZE 128
47 /* Magic number in Network Monitor 1.x files. */
48 static const char netmon_1_x_magic[] = {
52 /* Magic number in Network Monitor 2.x files. */
53 static const char netmon_2_x_magic[] = {
57 /* Network Monitor file header (minus magic number). */
59 guint8 ver_minor; /* minor version number */
60 guint8 ver_major; /* major version number */
61 guint16 network; /* network type */
62 guint16 ts_year; /* year of capture start */
63 guint16 ts_month; /* month of capture start (January = 1) */
64 guint16 ts_dow; /* day of week of capture start (Sun = 0) */
65 guint16 ts_day; /* day of month of capture start */
66 guint16 ts_hour; /* hour of capture start */
67 guint16 ts_min; /* minute of capture start */
68 guint16 ts_sec; /* second of capture start */
69 guint16 ts_msec; /* millisecond of capture start */
70 guint32 frametableoffset; /* frame index table offset */
71 guint32 frametablelength; /* frame index table size */
72 guint32 userdataoffset; /* user data offset */
73 guint32 userdatalength; /* user data size */
74 guint32 commentdataoffset; /* comment data offset */
75 guint32 commentdatalength; /* comment data size */
76 guint32 statisticsoffset; /* offset to statistics structure */
77 guint32 statisticslength; /* length of statistics structure */
78 guint32 networkinfooffset; /* offset to network info structure */
79 guint32 networkinfolength; /* length of network info structure */
82 /* Network Monitor 1.x record header; not defined in STRUCT.H, but deduced by
83 * looking at capture files. */
84 struct netmonrec_1_x_hdr {
85 guint32 ts_delta; /* time stamp - msecs since start of capture */
86 guint16 orig_len; /* actual length of packet */
87 guint16 incl_len; /* number of octets captured in file */
90 /* Network Monitor 2.x record header; not defined in STRUCT.H, but deduced by
91 * looking at capture files. */
92 struct netmonrec_2_x_hdr {
93 guint32 ts_delta_lo; /* time stamp - usecs since start of capture */
94 guint32 ts_delta_hi; /* time stamp - usecs since start of capture */
95 guint32 orig_len; /* actual length of packet */
96 guint32 incl_len; /* number of octets captured in file */
100 * The link-layer header on ATM packets.
102 struct netmon_atm_hdr {
103 guint8 dest[6]; /* "Destination address" - what is it? */
104 guint8 src[6]; /* "Source address" - what is it? */
105 guint16 vpi; /* VPI */
106 guint16 vci; /* VCI */
109 static gboolean netmon_read(wtap *wth, int *err, long *data_offset);
110 static gboolean netmon_seek_read(wtap *wth, long seek_off,
111 union wtap_pseudo_header *pseudo_header, u_char *pd, int length, int *err);
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, u_char *pd, int length,
116 static void netmon_close(wtap *wth);
117 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
118 const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err);
119 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err);
121 int netmon_open(wtap *wth, int *err)
124 char magic[sizeof netmon_1_x_magic];
125 struct netmon_hdr hdr;
127 static const int netmon_encap[] = {
130 WTAP_ENCAP_TOKEN_RING,
131 WTAP_ENCAP_FDDI_BITSWAPPED,
132 WTAP_ENCAP_ATM_SNIFFER, /* NDIS WAN - this is what's used for ATM */
133 WTAP_ENCAP_UNKNOWN, /* NDIS LocalTalk */
134 WTAP_ENCAP_UNKNOWN, /* NDIS "DIX" - should not occur */
135 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET raw */
136 WTAP_ENCAP_UNKNOWN, /* NDIS ARCNET 878.2 */
137 WTAP_ENCAP_UNKNOWN, /* NDIS ATM (no, this is NOT used for ATM) */
138 WTAP_ENCAP_UNKNOWN, /* NDIS Wireless WAN */
139 WTAP_ENCAP_UNKNOWN /* NDIS IrDA */
141 #define NUM_NETMON_ENCAPS (sizeof netmon_encap / sizeof netmon_encap[0])
143 int frame_table_offset;
144 guint32 frame_table_length;
145 guint32 frame_table_size;
146 guint32 *frame_table;
147 #ifdef WORDS_BIGENDIAN
151 /* Read in the string that should be at the start of a Network
153 errno = WTAP_ERR_CANT_READ;
154 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
155 if (bytes_read != sizeof magic) {
156 *err = file_error(wth->fh);
162 if (memcmp(magic, netmon_1_x_magic, sizeof netmon_1_x_magic) != 0
163 && memcmp(magic, netmon_2_x_magic, sizeof netmon_1_x_magic) != 0) {
167 /* Read the rest of the header. */
168 errno = WTAP_ERR_CANT_READ;
169 bytes_read = file_read(&hdr, 1, sizeof hdr, wth->fh);
170 if (bytes_read != sizeof hdr) {
171 *err = file_error(wth->fh);
177 switch (hdr.ver_major) {
180 file_type = WTAP_FILE_NETMON_1_x;
184 file_type = WTAP_FILE_NETMON_2_x;
188 g_message("netmon: major version %u unsupported", hdr.ver_major);
189 *err = WTAP_ERR_UNSUPPORTED;
193 hdr.network = pletohs(&hdr.network);
194 if (hdr.network >= NUM_NETMON_ENCAPS
195 || netmon_encap[hdr.network] == WTAP_ENCAP_UNKNOWN) {
196 g_message("netmon: network type %u unknown or unsupported",
198 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
202 /* This is a netmon file */
203 wth->file_type = file_type;
204 wth->capture.netmon = g_malloc(sizeof(netmon_t));
205 wth->subtype_read = netmon_read;
206 wth->subtype_seek_read = netmon_seek_read;
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) == -1) {
271 *err = file_error(wth->fh);
272 g_free(wth->capture.netmon);
275 frame_table = g_malloc(frame_table_length);
276 errno = WTAP_ERR_CANT_READ;
277 bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
278 if ((guint32)bytes_read != frame_table_length) {
279 *err = file_error(wth->fh);
281 *err = WTAP_ERR_SHORT_READ;
284 wth->capture.netmon->frame_table_size = frame_table_size;
285 wth->capture.netmon->frame_table = frame_table;
287 #ifdef WORDS_BIGENDIAN
289 * OK, now byte-swap the frame table.
291 for (i = 0; i < frame_table_size; i++)
292 frame_table[i] = pletohl(&frame_table[i]);
295 /* Set up to start reading at the first frame. */
296 wth->capture.netmon->current_frame = 0;
301 /* Read the next packet */
302 static gboolean netmon_read(wtap *wth, int *err, long *data_offset)
304 netmon_t *netmon = wth->capture.netmon;
305 guint32 packet_size = 0;
306 guint32 orig_size = 0;
309 struct netmonrec_1_x_hdr hdr_1_x;
310 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) == -1) {
336 *err = file_error(wth->fh);
340 netmon->current_frame++;
342 /* Read record header. */
343 switch (netmon->version_major) {
346 hdr_size = sizeof (struct netmonrec_1_x_hdr);
350 hdr_size = sizeof (struct netmonrec_2_x_hdr);
353 errno = WTAP_ERR_CANT_READ;
355 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
356 if (bytes_read != hdr_size) {
357 *err = file_error(wth->fh);
358 if (*err == 0 && bytes_read != 0) {
359 *err = WTAP_ERR_SHORT_READ;
363 wth->data_offset += hdr_size;
365 switch (netmon->version_major) {
368 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
369 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
373 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
374 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
377 if (packet_size > WTAP_MAX_PACKET_SIZE) {
379 * Probably a corrupt capture file; don't blow up trying
380 * to allocate space for an immensely-large packet.
382 g_message("netmon: File has %u-byte packet, bigger than maximum of %u",
383 packet_size, WTAP_MAX_PACKET_SIZE);
384 *err = WTAP_ERR_BAD_RECORD;
388 *data_offset = wth->data_offset;
391 * If this is an ATM packet, the first
392 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
393 * source addresses (6 bytes - MAC addresses of some sort?)
394 * and the VPI and VCI; read them and generate the pseudo-header
397 if (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER) {
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 buffer_assure_space(wth->frame_buffer, packet_size);
421 if (!netmon_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
423 return FALSE; /* Read error */
424 wth->data_offset += packet_size;
426 t = (double)netmon->start_usecs;
427 switch (netmon->version_major) {
430 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
434 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
435 + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
438 secs = (time_t)(t/1000000);
439 usecs = (guint32)(t - secs*1000000);
440 wth->phdr.ts.tv_sec = netmon->start_secs + secs;
441 wth->phdr.ts.tv_usec = usecs;
442 wth->phdr.caplen = packet_size;
443 wth->phdr.len = orig_size;
444 wth->phdr.pkt_encap = wth->file_encap;
450 netmon_seek_read(wtap *wth, long seek_off,
451 union wtap_pseudo_header *pseudo_header, u_char *pd, int length, int *err)
453 if (file_seek(wth->random_fh, seek_off, SEEK_SET) == -1) {
454 *err = file_error(wth->random_fh);
458 if (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER) {
459 if (!netmon_read_atm_pseudoheader(wth->random_fh, pseudo_header,
467 * Read the packet data.
469 return netmon_read_rec_data(wth->random_fh, pd, length, err);
473 netmon_read_atm_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
476 struct netmon_atm_hdr atm_phdr;
480 errno = WTAP_ERR_CANT_READ;
481 bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
482 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
483 *err = file_error(fh);
485 *err = WTAP_ERR_SHORT_READ;
489 vpi = ntohs(atm_phdr.vpi);
490 vci = ntohs(atm_phdr.vci);
493 * Assume it's AAL5, unless it's VPI 0 and VCI 5, in which case
494 * assume it's AAL_SIGNALLING; we know nothing more about it.
496 if (vpi == 0 && vci == 5)
497 pseudo_header->atm.aal = AAL_SIGNALLING;
499 pseudo_header->atm.aal = AAL_5;
500 pseudo_header->atm.type = TRAF_UNKNOWN;
501 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
503 pseudo_header->atm.vpi = vpi;
504 pseudo_header->atm.vci = vci;
506 /* We don't have this information */
507 pseudo_header->atm.channel = 0;
508 pseudo_header->atm.cells = 0;
509 pseudo_header->atm.aal5t_u2u = 0;
510 pseudo_header->atm.aal5t_len = 0;
511 pseudo_header->atm.aal5t_chksum = 0;
517 netmon_read_rec_data(FILE_T fh, u_char *pd, int length, int *err)
521 errno = WTAP_ERR_CANT_READ;
522 bytes_read = file_read(pd, 1, length, fh);
524 if (bytes_read != length) {
525 *err = file_error(fh);
527 *err = WTAP_ERR_SHORT_READ;
534 netmon_close(wtap *wth)
536 if (wth->capture.netmon->frame_table != NULL)
537 g_free(wth->capture.netmon->frame_table);
538 g_free(wth->capture.netmon);
541 static const int wtap_encap[] = {
542 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
543 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
544 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
545 -1, /* WTAP_ENCAP_SLIP -> unsupported */
546 -1, /* WTAP_ENCAP_PPP -> unsupported */
547 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
548 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
549 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
550 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
551 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
552 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
553 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
554 4, /* WTAP_ENCAP_ATM_SNIFFER -> NDIS WAN (*NOT* ATM!) */
555 -1 /* WTAP_ENCAP_NULL -> unsupported */
557 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
559 /* Returns 0 if we could write the specified encapsulation type,
560 an error indication otherwise. */
561 int netmon_dump_can_write_encap(int encap)
563 /* Per-packet encapsulations aren't supported. */
564 if (encap == WTAP_ENCAP_PER_PACKET)
565 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
567 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
568 return WTAP_ERR_UNSUPPORTED_ENCAP;
573 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
575 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
577 /* This is a netmon file */
578 wdh->subtype_write = netmon_dump;
579 wdh->subtype_close = netmon_dump_close;
581 /* We can't fill in all the fields in the file header, as we
582 haven't yet written any packets. As we'll have to rewrite
583 the header when we've written out all the packets, we just
584 skip over the header for now. */
585 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
590 wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
591 wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
592 wdh->dump.netmon->got_first_record_time = FALSE;
593 wdh->dump.netmon->frame_table = NULL;
594 wdh->dump.netmon->frame_table_index = 0;
595 wdh->dump.netmon->frame_table_size = 0;
600 /* Write a record for a packet to a dump file.
601 Returns TRUE on success, FALSE on failure. */
602 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
603 const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
605 netmon_dump_t *netmon = wdh->dump.netmon;
606 struct netmonrec_1_x_hdr rec_1_x_hdr;
607 struct netmonrec_2_x_hdr rec_2_x_hdr;
612 guint32 time_low, time_high;
613 struct netmon_atm_hdr atm_hdr;
616 /* NetMon files have a capture start time in the file header,
617 and have times relative to that in the packet headers;
618 pick the time of the first packet as the capture start
620 if (!netmon->got_first_record_time) {
621 netmon->first_record_time = phdr->ts;
622 netmon->got_first_record_time = TRUE;
625 if (wdh->encap == WTAP_ENCAP_ATM_SNIFFER)
626 atm_hdrsize = sizeof (struct netmon_atm_hdr);
629 switch (wdh->file_type) {
631 case WTAP_FILE_NETMON_1_x:
632 rec_1_x_hdr.ts_delta = htolel(
633 (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000
634 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec + 500)/1000);
635 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
636 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
637 hdrp = (char *)&rec_1_x_hdr;
638 hdr_size = sizeof rec_1_x_hdr;
641 case WTAP_FILE_NETMON_2_x:
643 * Unfortunately, not all the platforms on which we run
644 * support 64-bit integral types, even though most do
645 * (even on 32-bit processors), so we do it in floating
648 t = (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000000.0
649 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec);
650 time_high = t/4294967296.0;
651 time_low = t - (time_high*4294967296.0);
652 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
653 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
654 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
655 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
656 hdrp = (char *)&rec_2_x_hdr;
657 hdr_size = sizeof rec_2_x_hdr;
661 /* We should never get here - our open routine
662 should only get called for the types above. */
663 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
667 nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
668 if (nwritten != hdr_size) {
669 if (nwritten == 0 && ferror(wdh->fh))
672 *err = WTAP_ERR_SHORT_WRITE;
676 if (wdh->encap == WTAP_ENCAP_ATM_SNIFFER) {
678 * Write the ATM header.
679 * We supply all-zero destination and source addresses.
681 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
682 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
683 atm_hdr.vpi = htons(pseudo_header->atm.vpi);
684 atm_hdr.vci = htons(pseudo_header->atm.vci);
685 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
686 if (nwritten != sizeof atm_hdr) {
687 if (nwritten == 0 && ferror(wdh->fh))
690 *err = WTAP_ERR_SHORT_WRITE;
695 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
696 if (nwritten != phdr->caplen) {
697 if (nwritten == 0 && ferror(wdh->fh))
700 *err = WTAP_ERR_SHORT_WRITE;
705 * Stash the file offset of this frame.
707 if (netmon->frame_table_size == 0) {
709 * Haven't yet allocated the buffer for the frame table.
711 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
712 netmon->frame_table_size = 1024;
715 * We've allocated it; are we at the end?
717 if (netmon->frame_table_index >= netmon->frame_table_size) {
719 * Yes - double the size of the frame table.
721 netmon->frame_table_size *= 2;
722 netmon->frame_table = g_realloc(netmon->frame_table,
723 netmon->frame_table_size * sizeof *netmon->frame_table);
726 netmon->frame_table[netmon->frame_table_index] =
727 htolel(netmon->frame_table_offset);
728 netmon->frame_table_index++;
729 netmon->frame_table_offset += hdr_size + phdr->caplen + atm_hdrsize;
734 /* Finish writing to a dump file.
735 Returns TRUE on success, FALSE on failure. */
736 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
738 netmon_dump_t *netmon = wdh->dump.netmon;
741 struct netmon_hdr file_hdr;
746 /* Write out the frame table. "netmon->frame_table_index" is
747 the number of entries we've put into it. */
748 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
749 nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
750 if (nwritten != n_to_write) {
752 if (nwritten == 0 && ferror(wdh->fh))
755 *err = WTAP_ERR_SHORT_WRITE;
760 /* Now go fix up the file header. */
761 fseek(wdh->fh, 0, SEEK_SET);
762 memset(&file_hdr, '\0', sizeof file_hdr);
763 switch (wdh->file_type) {
765 case WTAP_FILE_NETMON_1_x:
766 magicp = netmon_1_x_magic;
767 magic_size = sizeof netmon_1_x_magic;
768 /* current NetMon version, for 1.x, is 1.1 */
769 file_hdr.ver_major = 1;
770 file_hdr.ver_minor = 1;
773 case WTAP_FILE_NETMON_2_x:
774 magicp = netmon_2_x_magic;
775 magic_size = sizeof netmon_2_x_magic;
776 /* current NetMon version, for 2.x, is 2.0 */
777 file_hdr.ver_major = 2;
778 file_hdr.ver_minor = 0;
782 /* We should never get here - our open routine
783 should only get called for the types above. */
785 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
788 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
789 if (nwritten != magic_size) {
791 if (nwritten == 0 && ferror(wdh->fh))
794 *err = WTAP_ERR_SHORT_WRITE;
799 file_hdr.network = htoles(wtap_encap[wdh->encap]);
800 tm = localtime(&netmon->first_record_time.tv_sec);
802 file_hdr.ts_year = htoles(1900 + tm->tm_year);
803 file_hdr.ts_month = htoles(tm->tm_mon + 1);
804 file_hdr.ts_dow = htoles(tm->tm_wday);
805 file_hdr.ts_day = htoles(tm->tm_mday);
806 file_hdr.ts_hour = htoles(tm->tm_hour);
807 file_hdr.ts_min = htoles(tm->tm_min);
808 file_hdr.ts_sec = htoles(tm->tm_sec);
810 file_hdr.ts_year = htoles(1900 + 0);
811 file_hdr.ts_month = htoles(0 + 1);
812 file_hdr.ts_dow = htoles(0);
813 file_hdr.ts_day = htoles(0);
814 file_hdr.ts_hour = htoles(0);
815 file_hdr.ts_min = htoles(0);
816 file_hdr.ts_sec = htoles(0);
818 file_hdr.ts_msec = htoles(netmon->first_record_time.tv_usec/1000);
819 /* XXX - what about rounding? */
820 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
821 file_hdr.frametablelength =
822 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
823 nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
824 if (nwritten != sizeof file_hdr) {
826 if (nwritten == 0 && ferror(wdh->fh))
829 *err = WTAP_ERR_SHORT_WRITE;