3 * $Id: netmon.c,v 1.46 2002/01/25 09:44:52 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 int netmon_seek_read(wtap *wth, long seek_off,
111 union wtap_pseudo_header *pseudo_header, u_char *pd, int length);
112 static int netmon_read_atm_pseudoheader(FILE_T fh,
113 union wtap_pseudo_header *pseudo_header, int *err);
114 static int netmon_read_rec_data(FILE_T fh, u_char *pd, int length, int *err);
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 u_char *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_SNIFFER, /* 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_close = netmon_close;
207 wth->file_encap = netmon_encap[hdr.network];
208 wth->snapshot_length = 16384; /* XXX - not available in header */
210 * Convert the time stamp to a "time_t" and a number of
213 tm.tm_year = pletohs(&hdr.ts_year) - 1900;
214 tm.tm_mon = pletohs(&hdr.ts_month) - 1;
215 tm.tm_mday = pletohs(&hdr.ts_day);
216 tm.tm_hour = pletohs(&hdr.ts_hour);
217 tm.tm_min = pletohs(&hdr.ts_min);
218 tm.tm_sec = pletohs(&hdr.ts_sec);
220 wth->capture.netmon->start_secs = mktime(&tm);
222 * XXX - what if "secs" is -1? Unlikely, but if the capture was
223 * done in a time zone that switches between standard and summer
224 * time sometime other than when we do, and thus the time was one
225 * that doesn't exist here because a switch from standard to summer
226 * time zips over it, it could happen.
228 * On the other hand, if the capture was done in a different time
229 * zone, this won't work right anyway; unfortunately, the time
230 * zone isn't stored in the capture file (why the hell didn't
231 * they stuff a FILETIME, which is the number of 100-nanosecond
232 * intervals since 1601-01-01 00:00:00 "UTC", there, instead
233 * of stuffing a SYSTEMTIME, which is time-zone-dependent, there?).
235 wth->capture.netmon->start_usecs = pletohs(&hdr.ts_msec)*1000;
237 wth->capture.netmon->version_major = hdr.ver_major;
240 * Get the offset of the frame index table.
242 frame_table_offset = pletohl(&hdr.frametableoffset);
245 * It appears that some NetMon 2.x files don't have the
246 * first packet starting exactly 128 bytes into the file.
248 * Furthermore, it also appears that there are "holes" in
249 * the file, i.e. frame N+1 doesn't always follow immediately
252 * Therefore, we must read the frame table, and use the offsets
253 * in it as the offsets of the frames.
255 frame_table_length = pletohl(&hdr.frametablelength);
256 frame_table_size = frame_table_length / sizeof (guint32);
257 if ((frame_table_size * sizeof (guint32)) != frame_table_length) {
258 g_message("netmon: frame table length is %u, which is not a multiple of the size of an entry",
260 *err = WTAP_ERR_UNSUPPORTED;
263 if (frame_table_size == 0) {
264 g_message("netmon: frame table length is %u, which means it's less than one entry in size",
266 *err = WTAP_ERR_UNSUPPORTED;
269 frame_table = g_malloc(frame_table_length);
270 errno = WTAP_ERR_CANT_READ;
271 file_seek(wth->fh, frame_table_offset, SEEK_SET);
272 bytes_read = file_read(frame_table, 1, frame_table_length, wth->fh);
273 if ((guint32)bytes_read != frame_table_length) {
274 *err = file_error(wth->fh);
276 *err = WTAP_ERR_SHORT_READ;
279 wth->capture.netmon->frame_table_size = frame_table_size;
280 wth->capture.netmon->frame_table = frame_table;
282 #ifdef WORDS_BIGENDIAN
284 * OK, now byte-swap the frame table.
286 for (i = 0; i < frame_table_size; i++)
287 frame_table[i] = pletohl(&frame_table[i]);
290 /* Set up to start reading at the first frame. */
291 wth->capture.netmon->current_frame = 0;
296 /* Read the next packet */
297 static gboolean netmon_read(wtap *wth, int *err, long *data_offset)
299 netmon_t *netmon = wth->capture.netmon;
300 guint32 packet_size = 0;
301 guint32 orig_size = 0;
304 struct netmonrec_1_x_hdr hdr_1_x;
305 struct netmonrec_2_x_hdr hdr_2_x;
313 /* Have we reached the end of the packet data? */
314 if (netmon->current_frame >= netmon->frame_table_size) {
315 /* Yes. We won't need the frame table any more;
317 g_free(wth->capture.netmon->frame_table);
318 wth->capture.netmon->frame_table = NULL;
319 *err = 0; /* it's just an EOF, not an error */
323 /* Seek to the beginning of the current record, if we're
324 not there already (seeking to the current position
325 may still cause a seek and a read of the underlying file,
326 so we don't want to do it unconditionally). */
327 rec_offset = netmon->frame_table[netmon->current_frame];
328 if (wth->data_offset != rec_offset) {
329 wth->data_offset = rec_offset;
330 file_seek(wth->fh, wth->data_offset, SEEK_SET);
332 netmon->current_frame++;
334 /* Read record header. */
335 switch (netmon->version_major) {
338 hdr_size = sizeof (struct netmonrec_1_x_hdr);
342 hdr_size = sizeof (struct netmonrec_2_x_hdr);
345 errno = WTAP_ERR_CANT_READ;
347 bytes_read = file_read(&hdr, 1, hdr_size, wth->fh);
348 if (bytes_read != hdr_size) {
349 *err = file_error(wth->fh);
350 if (*err == 0 && bytes_read != 0) {
351 *err = WTAP_ERR_SHORT_READ;
355 wth->data_offset += hdr_size;
357 switch (netmon->version_major) {
360 orig_size = pletohs(&hdr.hdr_1_x.orig_len);
361 packet_size = pletohs(&hdr.hdr_1_x.incl_len);
365 orig_size = pletohl(&hdr.hdr_2_x.orig_len);
366 packet_size = pletohl(&hdr.hdr_2_x.incl_len);
369 if (packet_size > WTAP_MAX_PACKET_SIZE) {
371 * Probably a corrupt capture file; don't blow up trying
372 * to allocate space for an immensely-large packet.
374 g_message("netmon: File has %u-byte packet, bigger than maximum of %u",
375 packet_size, WTAP_MAX_PACKET_SIZE);
376 *err = WTAP_ERR_BAD_RECORD;
380 *data_offset = wth->data_offset;
383 * If this is an ATM packet, the first
384 * "sizeof (struct netmon_atm_hdr)" bytes have destination and
385 * source addresses (6 bytes - MAC addresses of some sort?)
386 * and the VPI and VCI; read them and generate the pseudo-header
389 if (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER) {
390 if (packet_size < sizeof (struct netmon_atm_hdr)) {
392 * Uh-oh, the packet isn't big enough to even
393 * have a pseudo-header.
395 g_message("netmon: atmsnoop file has a %u-byte packet, too small to have even an ATM pseudo-header\n",
397 *err = WTAP_ERR_BAD_RECORD;
400 if (netmon_read_atm_pseudoheader(wth->fh, &wth->pseudo_header,
402 return FALSE; /* Read error */
405 * Don't count the pseudo-header as part of the packet.
407 orig_size -= sizeof (struct netmon_atm_hdr);
408 packet_size -= sizeof (struct netmon_atm_hdr);
409 wth->data_offset += sizeof (struct netmon_atm_hdr);
412 buffer_assure_space(wth->frame_buffer, packet_size);
413 if (netmon_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
414 packet_size, err) < 0)
415 return FALSE; /* Read error */
416 wth->data_offset += packet_size;
418 t = (double)netmon->start_usecs;
419 switch (netmon->version_major) {
422 t += ((double)pletohl(&hdr.hdr_1_x.ts_delta))*1000;
426 t += (double)pletohl(&hdr.hdr_2_x.ts_delta_lo)
427 + (double)pletohl(&hdr.hdr_2_x.ts_delta_hi)*4294967296.0;
430 secs = (time_t)(t/1000000);
431 usecs = (guint32)(t - secs*1000000);
432 wth->phdr.ts.tv_sec = netmon->start_secs + secs;
433 wth->phdr.ts.tv_usec = usecs;
434 wth->phdr.caplen = packet_size;
435 wth->phdr.len = orig_size;
436 wth->phdr.pkt_encap = wth->file_encap;
442 netmon_seek_read(wtap *wth, long seek_off,
443 union wtap_pseudo_header *pseudo_header, u_char *pd, int length)
446 int err; /* XXX - return this */
448 file_seek(wth->random_fh, seek_off, SEEK_SET);
450 if (wth->file_encap == WTAP_ENCAP_ATM_SNIFFER) {
451 ret = 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;
472 errno = WTAP_ERR_CANT_READ;
473 bytes_read = file_read(&atm_phdr, 1, sizeof (struct netmon_atm_hdr), fh);
474 if (bytes_read != sizeof (struct netmon_atm_hdr)) {
475 *err = file_error(fh);
477 *err = WTAP_ERR_SHORT_READ;
481 pseudo_header->ngsniffer_atm.Vpi = ntohs(atm_phdr.vpi);
482 pseudo_header->ngsniffer_atm.Vci = ntohs(atm_phdr.vci);
484 /* We don't have this information */
485 pseudo_header->ngsniffer_atm.channel = 0;
486 pseudo_header->ngsniffer_atm.cells = 0;
487 pseudo_header->ngsniffer_atm.aal5t_u2u = 0;
488 pseudo_header->ngsniffer_atm.aal5t_len = 0;
489 pseudo_header->ngsniffer_atm.aal5t_chksum = 0;
492 * Assume it's AAL5; we know nothing more about it.
494 pseudo_header->ngsniffer_atm.AppTrafType = ATT_AAL5|ATT_HL_UNKNOWN;
495 pseudo_header->ngsniffer_atm.AppHLType = AHLT_UNKNOWN;
501 netmon_read_rec_data(FILE_T fh, u_char *pd, int length, int *err)
505 errno = WTAP_ERR_CANT_READ;
506 bytes_read = file_read(pd, 1, length, fh);
508 if (bytes_read != length) {
509 *err = file_error(fh);
511 *err = WTAP_ERR_SHORT_READ;
518 netmon_close(wtap *wth)
520 if (wth->capture.netmon->frame_table != NULL)
521 g_free(wth->capture.netmon->frame_table);
522 g_free(wth->capture.netmon);
525 static const int wtap_encap[] = {
526 -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */
527 1, /* WTAP_ENCAP_ETHERNET -> NDIS Ethernet */
528 2, /* WTAP_ENCAP_TOKEN_RING -> NDIS Token Ring */
529 -1, /* WTAP_ENCAP_SLIP -> unsupported */
530 -1, /* WTAP_ENCAP_PPP -> unsupported */
531 3, /* WTAP_ENCAP_FDDI -> NDIS FDDI */
532 3, /* WTAP_ENCAP_FDDI_BITSWAPPED -> NDIS FDDI */
533 -1, /* WTAP_ENCAP_RAW_IP -> unsupported */
534 -1, /* WTAP_ENCAP_ARCNET -> unsupported */
535 -1, /* WTAP_ENCAP_ATM_RFC1483 -> unsupported */
536 -1, /* WTAP_ENCAP_LINUX_ATM_CLIP -> unsupported */
537 -1, /* WTAP_ENCAP_LAPB -> unsupported*/
538 4, /* WTAP_ENCAP_ATM_SNIFFER -> NDIS WAN (*NOT* ATM!) */
539 -1 /* WTAP_ENCAP_NULL -> unsupported */
541 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
543 /* Returns 0 if we could write the specified encapsulation type,
544 an error indication otherwise. */
545 int netmon_dump_can_write_encap(int filetype, int encap)
547 /* Per-packet encapsulations aren't supported. */
548 if (encap == WTAP_ENCAP_PER_PACKET)
549 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
551 if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
552 return WTAP_ERR_UNSUPPORTED_ENCAP;
557 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
559 gboolean netmon_dump_open(wtap_dumper *wdh, int *err)
561 /* This is a netmon file */
562 wdh->subtype_write = netmon_dump;
563 wdh->subtype_close = netmon_dump_close;
565 /* We can't fill in all the fields in the file header, as we
566 haven't yet written any packets. As we'll have to rewrite
567 the header when we've written out all the packets, we just
568 skip over the header for now. */
569 fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET);
571 wdh->dump.netmon = g_malloc(sizeof(netmon_dump_t));
572 wdh->dump.netmon->frame_table_offset = CAPTUREFILE_HEADER_SIZE;
573 wdh->dump.netmon->got_first_record_time = FALSE;
574 wdh->dump.netmon->frame_table = NULL;
575 wdh->dump.netmon->frame_table_index = 0;
576 wdh->dump.netmon->frame_table_size = 0;
581 /* Write a record for a packet to a dump file.
582 Returns TRUE on success, FALSE on failure. */
583 static gboolean netmon_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
584 const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
586 netmon_dump_t *netmon = wdh->dump.netmon;
587 struct netmonrec_1_x_hdr rec_1_x_hdr;
588 struct netmonrec_2_x_hdr rec_2_x_hdr;
593 guint32 time_low, time_high;
594 struct netmon_atm_hdr atm_hdr;
597 /* NetMon files have a capture start time in the file header,
598 and have times relative to that in the packet headers;
599 pick the time of the first packet as the capture start
601 if (!netmon->got_first_record_time) {
602 netmon->first_record_time = phdr->ts;
603 netmon->got_first_record_time = TRUE;
606 if (wdh->encap == WTAP_ENCAP_ATM_SNIFFER)
607 atm_hdrsize = 6+6+2+2;
610 switch (wdh->file_type) {
612 case WTAP_FILE_NETMON_1_x:
613 rec_1_x_hdr.ts_delta = htolel(
614 (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000
615 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec + 500)/1000);
616 rec_1_x_hdr.orig_len = htoles(phdr->len + atm_hdrsize);
617 rec_1_x_hdr.incl_len = htoles(phdr->caplen + atm_hdrsize);
618 hdrp = (char *)&rec_1_x_hdr;
619 hdr_size = sizeof rec_1_x_hdr;
622 case WTAP_FILE_NETMON_2_x:
624 * Unfortunately, not all the platforms on which we run
625 * support 64-bit integral types, even though most do
626 * (even on 32-bit processors), so we do it in floating
629 t = (phdr->ts.tv_sec - netmon->first_record_time.tv_sec)*1000000.0
630 + (phdr->ts.tv_usec - netmon->first_record_time.tv_usec);
631 time_high = t/4294967296.0;
632 time_low = t - (time_high*4294967296.0);
633 rec_2_x_hdr.ts_delta_lo = htolel(time_low);
634 rec_2_x_hdr.ts_delta_hi = htolel(time_high);
635 rec_2_x_hdr.orig_len = htolel(phdr->len + atm_hdrsize);
636 rec_2_x_hdr.incl_len = htolel(phdr->caplen + atm_hdrsize);
637 hdrp = (char *)&rec_2_x_hdr;
638 hdr_size = sizeof rec_2_x_hdr;
642 /* We should never get here - our open routine
643 should only get called for the types above. */
644 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
648 nwritten = fwrite(hdrp, 1, hdr_size, wdh->fh);
649 if (nwritten != hdr_size) {
650 if (nwritten == 0 && ferror(wdh->fh))
653 *err = WTAP_ERR_SHORT_WRITE;
657 if (wdh->encap == WTAP_ENCAP_ATM_SNIFFER) {
659 * Write the ATM header.
660 * We supply all-zero destination and source addresses.
662 memset(&atm_hdr.dest, 0, sizeof atm_hdr.dest);
663 memset(&atm_hdr.src, 0, sizeof atm_hdr.src);
664 atm_hdr.vpi = htons(pseudo_header->ngsniffer_atm.Vpi);
665 atm_hdr.vci = htons(pseudo_header->ngsniffer_atm.Vci);
666 nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh);
667 if (nwritten != sizeof atm_hdr) {
668 if (nwritten == 0 && ferror(wdh->fh))
671 *err = WTAP_ERR_SHORT_WRITE;
676 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
677 if (nwritten != phdr->caplen) {
678 if (nwritten == 0 && ferror(wdh->fh))
681 *err = WTAP_ERR_SHORT_WRITE;
686 * Stash the file offset of this frame.
688 if (netmon->frame_table_size == 0) {
690 * Haven't yet allocated the buffer for the frame table.
692 netmon->frame_table = g_malloc(1024 * sizeof *netmon->frame_table);
693 netmon->frame_table_size = 1024;
696 * We've allocated it; are we at the end?
698 if (netmon->frame_table_index >= netmon->frame_table_size) {
700 * Yes - double the size of the frame table.
702 netmon->frame_table_size *= 2;
703 netmon->frame_table = g_realloc(netmon->frame_table,
704 netmon->frame_table_size * sizeof *netmon->frame_table);
707 netmon->frame_table[netmon->frame_table_index] =
708 htolel(netmon->frame_table_offset);
709 netmon->frame_table_index++;
710 netmon->frame_table_offset += hdr_size + phdr->caplen + atm_hdrsize;
715 /* Finish writing to a dump file.
716 Returns TRUE on success, FALSE on failure. */
717 static gboolean netmon_dump_close(wtap_dumper *wdh, int *err)
719 netmon_dump_t *netmon = wdh->dump.netmon;
722 struct netmon_hdr file_hdr;
727 /* Write out the frame table. "netmon->frame_table_index" is
728 the number of entries we've put into it. */
729 n_to_write = netmon->frame_table_index * sizeof *netmon->frame_table;
730 nwritten = fwrite(netmon->frame_table, 1, n_to_write, wdh->fh);
731 if (nwritten != n_to_write) {
732 if (nwritten == 0 && ferror(wdh->fh))
735 *err = WTAP_ERR_SHORT_WRITE;
739 /* Now go fix up the file header. */
740 fseek(wdh->fh, 0, SEEK_SET);
741 memset(&file_hdr, '\0', sizeof file_hdr);
742 switch (wdh->file_type) {
744 case WTAP_FILE_NETMON_1_x:
745 magicp = netmon_1_x_magic;
746 magic_size = sizeof netmon_1_x_magic;
747 /* current NetMon version, for 1.x, is 1.1 */
748 file_hdr.ver_major = 1;
749 file_hdr.ver_minor = 1;
752 case WTAP_FILE_NETMON_2_x:
753 magicp = netmon_2_x_magic;
754 magic_size = sizeof netmon_2_x_magic;
755 /* current NetMon version, for 2.x, is 2.0 */
756 file_hdr.ver_major = 2;
757 file_hdr.ver_minor = 0;
761 /* We should never get here - our open routine
762 should only get called for the types above. */
763 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
766 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
767 if (nwritten != magic_size) {
768 if (nwritten == 0 && ferror(wdh->fh))
771 *err = WTAP_ERR_SHORT_WRITE;
775 file_hdr.network = htoles(wtap_encap[wdh->encap]);
776 tm = localtime(&netmon->first_record_time.tv_sec);
778 file_hdr.ts_year = htoles(1900 + tm->tm_year);
779 file_hdr.ts_month = htoles(tm->tm_mon + 1);
780 file_hdr.ts_dow = htoles(tm->tm_wday);
781 file_hdr.ts_day = htoles(tm->tm_mday);
782 file_hdr.ts_hour = htoles(tm->tm_hour);
783 file_hdr.ts_min = htoles(tm->tm_min);
784 file_hdr.ts_sec = htoles(tm->tm_sec);
786 file_hdr.ts_year = htoles(1900 + 0);
787 file_hdr.ts_month = htoles(0 + 1);
788 file_hdr.ts_dow = htoles(0);
789 file_hdr.ts_day = htoles(0);
790 file_hdr.ts_hour = htoles(0);
791 file_hdr.ts_min = htoles(0);
792 file_hdr.ts_sec = htoles(0);
794 file_hdr.ts_msec = htoles(netmon->first_record_time.tv_usec/1000);
795 /* XXX - what about rounding? */
796 file_hdr.frametableoffset = htolel(netmon->frame_table_offset);
797 file_hdr.frametablelength =
798 htolel(netmon->frame_table_index * sizeof *netmon->frame_table);
799 nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh);
800 if (nwritten != sizeof file_hdr) {
801 if (nwritten == 0 && ferror(wdh->fh))
804 *err = WTAP_ERR_SHORT_WRITE;