2 * File read and write routines for Visual Networks cap files.
3 * Copyright (c) 2001, Tom Nisbet tnisbet@visualnetworks.com
5 * $Id: visual.c,v 1.11 2002/08/28 20:30:45 jmayer Exp $
8 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include "file_wrappers.h"
36 * A Visual Networks traffic capture file contains three sections. The
37 * first is a 192 octet file header. This is followed by the captured
38 * packet headers and data. The last section is the packet index block.
39 * The index block contains one 4 octet pointer for each captured packet.
40 * The first packet index is (4 * num_pkts) octets from the end of the file
41 * and the last index is in the last four octets of the file.
43 * All integer and time values are stored in little-endian format.
46 /* Capture file header, INCLUDING the magic number, is 192 bytes. */
47 #define CAPTUREFILE_HEADER_SIZE 192
49 /* Magic number for Visual Networks traffic capture files. */
50 static const char visual_magic[] = {
55 /* Visual file header (minus magic number). */
56 struct visual_file_hdr
58 guint32 num_pkts; /* Number of packets in the file */
59 guint32 start_time; /* Capture start time in PC format */
60 guint16 media_type; /* IANA ifType of packet source */
61 guint16 max_length; /* Max allowable stored packet length */
62 guint16 file_flags; /* File type flags */
63 /* Bit 0 indicates indexes present */
64 guint16 file_version; /* Version number of this file format */
65 guint32 media_speed; /* ifSpeed of packet source in bits/sec. */
66 guint16 media_param; /* Media-specific extra parameter. */
67 char RESERVED_[102]; /* MUST BE ALL ZEROS FOR FUTURE COMPATABILITY */
68 char description[64]; /* File description (null terminated) */
72 /* Packet status bits */
75 #define PS_ERRORED 0x04
76 #define PS_1ST_AFTER_DROP 0x08
77 #define PS_APPROX_ORDER 0x10
79 #define PS_ABORTED 0x80
81 /* Visual packet header */
84 guint32 ts_delta; /* Time stamp - msecs since start of capture */
85 guint16 orig_len; /* Actual length of packet */
86 guint16 incl_len; /* Number of octets captured in file */
87 guint32 status; /* Packet status flags (media specific) */
88 guint8 encap_hint; /* Encapsulation type hint */
89 guint8 encap_skip; /* Number of bytes to skip before decoding */
90 char RESERVED_[6]; /* RESERVED - must be zero */
94 /* Additional information for reading Visual files */
95 struct visual_read_info
97 guint32 num_pkts; /* Number of pkts in the file */
98 guint32 current_pkt; /* Next packet to be read */
99 double start_time; /* Capture start time in microseconds */
103 /* Additional information for writing Visual files */
104 struct visual_write_info
106 unsigned start_time; /* Capture start time in seconds */
107 int index_table_index; /* Index of the next index entry */
108 int index_table_size; /* Allocated size of the index table */
109 guint32 * index_table; /* File offsets for the packets */
110 guint32 next_offset; /* Offset of next packet */
114 /* Local functions to handle file reads and writes */
115 static gboolean visual_read(wtap *wth, int *err, long *data_offset);
116 static void visual_close(wtap *wth);
117 static gboolean visual_seek_read(wtap *wth, long seek_off,
118 union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
120 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
121 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
122 static gboolean visual_dump_close(wtap_dumper *wdh, int *err);
123 static void visual_dump_free(wtap_dumper *wdh);
126 /* Open a file for reading */
127 int visual_open(wtap *wth, int *err)
130 char magic[sizeof visual_magic];
131 struct visual_file_hdr vfile_hdr;
132 struct visual_read_info * visual;
135 /* Check the magic string at the start of the file */
136 errno = WTAP_ERR_CANT_READ;
137 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
138 if (bytes_read != sizeof magic)
140 *err = file_error(wth->fh);
145 if (memcmp(magic, visual_magic, sizeof visual_magic) != 0)
150 /* Read the rest of the file header. */
151 errno = WTAP_ERR_CANT_READ;
152 bytes_read = file_read(&vfile_hdr, 1, sizeof vfile_hdr, wth->fh);
153 if (bytes_read != sizeof vfile_hdr)
155 *err = file_error(wth->fh);
161 /* Verify the file version is known */
162 vfile_hdr.file_version = pletohs(&vfile_hdr.file_version);
163 if (vfile_hdr.file_version != 1)
165 g_message("visual: file version %u unsupported", vfile_hdr.file_version);
166 *err = WTAP_ERR_UNSUPPORTED;
170 /* Translate the encapsulation type. Note that a file with media
171 type 22 may contain Cisco HDLC or PPP over HDLC. This will
172 get sorted out after the first packet is read. */
173 switch (pletohs(&vfile_hdr.media_type))
175 case 6: encap = WTAP_ENCAP_ETHERNET; break;
176 case 9: encap = WTAP_ENCAP_TOKEN_RING; break;
177 case 16: encap = WTAP_ENCAP_LAPB; break;
178 case 22: encap = WTAP_ENCAP_CHDLC; break;
179 case 32: encap = WTAP_ENCAP_FRELAY; break;
181 g_message("visual: network type %u unknown or unsupported",
182 vfile_hdr.media_type);
183 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
187 /* Fill in the wiretap struct with data from the file header */
188 wth->file_type = WTAP_FILE_VISUAL_NETWORKS;
189 wth->file_encap = encap;
190 wth->snapshot_length = pletohs(&vfile_hdr.max_length);
192 /* Save the pointer to the beginning of the packet data so
193 that the later seek_reads work correctly. */
194 wth->data_offset = CAPTUREFILE_HEADER_SIZE;
196 /* Set up the pointers to the handlers for this file type */
197 wth->subtype_read = visual_read;
198 wth->subtype_seek_read = visual_seek_read;
199 wth->subtype_close = visual_close;
201 /* Add Visual-specific information to the wiretap struct for later use. */
202 visual = g_malloc(sizeof(struct visual_read_info));
203 wth->capture.generic = visual;
204 visual->num_pkts = pletohl(&vfile_hdr.num_pkts);
205 visual->start_time = ((double) pletohl(&vfile_hdr.start_time)) * 1000000;
206 visual->current_pkt = 1;
212 /* Read the next available packet from the file. This is called
213 in a loop to sequentially read the entire file one time. After
214 the file has been read once, any Future access to the packets is
215 done through seek_read. */
216 static gboolean visual_read(wtap *wth, int *err, long *data_offset)
218 struct visual_read_info *visual = wth->capture.generic;
219 guint32 packet_size = 0;
220 guint32 packet_status;
222 struct visual_pkt_hdr vpkt_hdr;
223 int phdr_size = sizeof(vpkt_hdr);
228 /* Check for the end of the packet data. Note that a check for file EOF
229 will not work because there are index values stored after the last
231 if (visual->current_pkt > visual->num_pkts)
233 *err = 0; /* it's just an EOF, not an error */
236 visual->current_pkt++;
238 /* Read the packet header. */
239 errno = WTAP_ERR_CANT_READ;
240 bytes_read = file_read(&vpkt_hdr, 1, phdr_size, wth->fh);
241 if (bytes_read != phdr_size)
243 *err = file_error(wth->fh);
244 if (*err == 0 && bytes_read != 0)
246 *err = WTAP_ERR_SHORT_READ;
250 wth->data_offset += phdr_size;
252 /* Read the packet data. */
253 packet_size = pletohs(&vpkt_hdr.incl_len);
254 if (packet_size > WTAP_MAX_PACKET_SIZE)
256 /* Probably a corrupt capture file; don't blow up trying
257 to allocate space for an immensely-large packet. */
258 g_message("visual: File has %u-byte packet, bigger than maximum of %u",
259 packet_size, WTAP_MAX_PACKET_SIZE);
260 *err = WTAP_ERR_BAD_RECORD;
263 buffer_assure_space(wth->frame_buffer, packet_size);
264 *data_offset = wth->data_offset;
265 errno = WTAP_ERR_CANT_READ;
266 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
267 packet_size, wth->fh);
269 if (bytes_read != (int) packet_size)
271 *err = file_error(wth->fh);
273 *err = WTAP_ERR_SHORT_READ;
276 wth->data_offset += packet_size;
278 /* Set the packet time and length. */
279 t = visual->start_time;
280 t += ((double)pletohl(&vpkt_hdr.ts_delta))*1000;
281 secs = (time_t)(t/1000000);
282 usecs = (guint32)(t - secs*1000000);
283 wth->phdr.ts.tv_sec = secs;
284 wth->phdr.ts.tv_usec = usecs;
285 wth->phdr.caplen = packet_size;
286 wth->phdr.len = pletohs(&vpkt_hdr.orig_len);
288 /* Set status flags. The only status currently supported for all
289 encapsulations is direction. This either goes in the p2p or the
290 X.25 pseudo header. It would probably be better to move this up
292 packet_status = pletohl(&vpkt_hdr.status);
293 switch (wth->file_encap)
295 case WTAP_ENCAP_CHDLC:
296 case WTAP_ENCAP_PPP_WITH_PHDR:
297 wth->pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
300 case WTAP_ENCAP_FRELAY:
301 case WTAP_ENCAP_LAPB:
302 wth->pseudo_header.x25.flags =
303 (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
307 /* Fill in the encapsulation. Visual files have a media type in the
308 file header and an encapsulation type in each packet header. Files
309 with a media type of HDLC can be either Cisco EtherType or PPP. */
310 if ((wth->file_encap == WTAP_ENCAP_CHDLC) && (vpkt_hdr.encap_hint == 14))
311 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
313 wth->phdr.pkt_encap = wth->file_encap;
319 /* Close a file opened for reading. */
320 static void visual_close(wtap *wth)
322 /* Free the info allocated by a Visual file reader. */
323 if (wth->capture.generic)
324 g_free(wth->capture.generic);
325 wth->capture.generic = 0;
329 /* Read packet data for random access.
330 This gets the packet data and rebuilds the pseudo header so that
331 the direction flag works. */
332 static gboolean visual_seek_read (wtap *wth, long seek_off,
333 union wtap_pseudo_header *pseudo_header, guint8 *pd, int len, int *err)
335 struct visual_pkt_hdr vpkt_hdr;
336 int phdr_size = sizeof(vpkt_hdr);
337 guint32 packet_status;
340 /* Seek to the packet header */
341 if (file_seek(wth->random_fh, seek_off - sizeof(struct visual_pkt_hdr),
342 SEEK_SET, err) == -1)
345 /* Read the packet header to get the status flags. */
346 errno = WTAP_ERR_CANT_READ;
347 bytes_read = file_read(&vpkt_hdr, 1, phdr_size, wth->random_fh);
348 if (bytes_read != phdr_size) {
349 *err = file_error(wth->random_fh);
351 *err = WTAP_ERR_SHORT_READ;
355 /* Read the packet data. */
356 errno = WTAP_ERR_CANT_READ;
357 bytes_read = file_read(pd, sizeof(guint8), len, wth->random_fh);
358 if (bytes_read != len) {
360 *err = WTAP_ERR_SHORT_READ;
364 /* Set status flags. The only status currently supported for all
365 encapsulations is direction. This either goes in the p2p or the
366 X.25 pseudo header. It would probably be better to move this up
368 packet_status = pletohl(&vpkt_hdr.status);
369 switch (wth->file_encap)
371 case WTAP_ENCAP_CHDLC:
372 case WTAP_ENCAP_PPP_WITH_PHDR:
373 pseudo_header->p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
376 case WTAP_ENCAP_FRELAY:
377 case WTAP_ENCAP_LAPB:
378 pseudo_header->x25.flags = (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
386 /* Check for media types that may be written in Visual file format.
387 Returns 0 if the specified encapsulation type is supported,
388 an error indication otherwise. */
389 int visual_dump_can_write_encap(int encap)
391 /* Per-packet encapsulations aren't supported. */
392 if (encap == WTAP_ENCAP_PER_PACKET)
393 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
395 /* Check for supported encapsulation types */
398 case WTAP_ENCAP_ETHERNET:
399 case WTAP_ENCAP_TOKEN_RING:
400 case WTAP_ENCAP_LAPB:
401 case WTAP_ENCAP_CHDLC:
402 case WTAP_ENCAP_FRELAY:
404 case WTAP_ENCAP_PPP_WITH_PHDR:
408 return WTAP_ERR_UNSUPPORTED_ENCAP;
412 /* Open a file for writing.
413 Returns TRUE on success, FALSE on failure; sets "*err" to an
414 error code on failure */
415 gboolean visual_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
417 struct visual_write_info *visual;
419 /* We can't fill in some fields in the header until all the packets
420 have been written, so we can't write to a pipe. */
422 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
426 /* Set the write routines for a visual file. */
427 wdh->subtype_write = visual_dump;
428 wdh->subtype_close = visual_dump_close;
430 /* Create a struct to hold file information for the duration
432 visual = g_malloc(sizeof(struct visual_write_info));
433 wdh->dump.opaque = visual;
434 visual->index_table_index = 0;
435 visual->index_table_size = 1024;
436 visual->index_table = 0;
437 visual->next_offset = CAPTUREFILE_HEADER_SIZE;
439 /* All of the fields in the file header aren't known yet so
440 just skip over it for now. It will be created after all
441 of the packets have been written. */
442 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
451 /* Write a packet to a Visual dump file.
452 Returns TRUE on success, FALSE on failure. */
453 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
454 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
456 struct visual_write_info * visual = wdh->dump.opaque;
457 struct visual_pkt_hdr vpkt_hdr;
458 size_t hdr_size = sizeof vpkt_hdr;
461 guint32 packet_status;
463 /* If the visual structure was never allocated then nothing useful
468 /* Zero out unused and reserved fields in the packet header. */
469 memset(&vpkt_hdr, 0, hdr_size);
471 /* Visual UpTime capture files have a capture start time in the
472 file header. Each packet has a capture time (in msec) relative
473 to the file start time. Use the time of the first packet as the
475 if (visual->index_table_index == 0)
477 /* This is the first packet. Save its start time as the file time. */
478 visual->start_time = phdr->ts.tv_sec;
480 /* Initialize the index table */
481 visual->index_table = g_malloc(1024 * sizeof *visual->index_table);
482 visual->index_table_size = 1024;
485 /* Calculate milliseconds since capture start. */
486 delta_msec = phdr->ts.tv_usec / 1000;
487 delta_msec += (phdr->ts.tv_sec - visual->start_time) * 1000;
488 vpkt_hdr.ts_delta = htolel(delta_msec);
490 /* Fill in the length fields. */
491 vpkt_hdr.orig_len = htoles(phdr->len);
492 vpkt_hdr.incl_len = htoles(phdr->caplen);
494 /* Fill in the encapsulation hint for the file's media type. */
497 case WTAP_ENCAP_ETHERNET: /* Ethernet */
498 vpkt_hdr.encap_hint = 2;
500 case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
501 vpkt_hdr.encap_hint = 3;
503 case WTAP_ENCAP_PPP: /* PPP */
504 case WTAP_ENCAP_PPP_WITH_PHDR:
505 vpkt_hdr.encap_hint = 14;
507 case WTAP_ENCAP_CHDLC: /* HDLC Router */
508 vpkt_hdr.encap_hint = 13;
510 case WTAP_ENCAP_FRELAY: /* Frame Relay Auto-detect */
511 vpkt_hdr.encap_hint = 12;
513 case WTAP_ENCAP_LAPB: /* Unknown */
515 vpkt_hdr.encap_hint = 1;
519 /* Set status flags. The only status currently supported for all
520 encapsulations is direction. This either goes in the p2p or the
521 X.25 pseudo header. It would probably be better to move this up
526 case WTAP_ENCAP_CHDLC:
527 packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
530 case WTAP_ENCAP_FRELAY:
531 case WTAP_ENCAP_LAPB:
533 ((pseudo_header->x25.flags & FROM_DCE) ? 0x00 : PS_SENT);
536 vpkt_hdr.status = htolel(packet_status);
538 /* Write the packet header. */
539 nwritten = fwrite(&vpkt_hdr, 1, hdr_size, wdh->fh);
540 if (nwritten != hdr_size)
542 if (nwritten == 0 && ferror(wdh->fh))
545 *err = WTAP_ERR_SHORT_WRITE;
549 /* Write the packet data */
550 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
551 if (nwritten != phdr->caplen)
553 if (nwritten == 0 && ferror(wdh->fh))
556 *err = WTAP_ERR_SHORT_WRITE;
560 /* Store the frame offset in the index table. */
561 if (visual->index_table_index >= visual->index_table_size)
563 /* End of table reached. Reallocate with a larger size */
564 visual->index_table_size *= 2;
565 visual->index_table = g_realloc(visual->index_table,
566 visual->index_table_size * sizeof *visual->index_table);
568 visual->index_table[visual->index_table_index] = htolel(visual->next_offset);
570 /* Update the table index and offset for the next frame. */
571 visual->index_table_index++;
572 visual->next_offset += hdr_size + phdr->caplen;
578 /* Finish writing to a dump file.
579 Returns TRUE on success, FALSE on failure. */
580 static gboolean visual_dump_close(wtap_dumper *wdh, int *err)
582 struct visual_write_info * visual = wdh->dump.opaque;
585 struct visual_file_hdr vfile_hdr;
589 /* If the visual structure was never allocated then nothing useful
594 /* Write out the frame table at the end of the file. */
595 if (visual->index_table)
597 /* Write the index table to the file. */
598 n_to_write = visual->index_table_index * sizeof *visual->index_table;
599 nwritten = fwrite(visual->index_table, 1, n_to_write, wdh->fh);
600 if (nwritten != n_to_write)
604 if (nwritten == 0 && ferror(wdh->fh))
607 *err = WTAP_ERR_SHORT_WRITE;
609 visual_dump_free(wdh);
614 /* Write the magic number at the start of the file. */
615 fseek(wdh->fh, 0, SEEK_SET);
616 magicp = visual_magic;
617 magic_size = sizeof visual_magic;
618 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
619 if (nwritten != magic_size)
623 if (nwritten == 0 && ferror(wdh->fh))
626 *err = WTAP_ERR_SHORT_WRITE;
628 visual_dump_free(wdh);
632 /* Initialize the file header with zeroes for the reserved fields. */
633 memset(&vfile_hdr, '\0', sizeof vfile_hdr);
634 vfile_hdr.num_pkts = htolel(visual->index_table_index);
635 vfile_hdr.start_time = htolel(visual->start_time);
636 vfile_hdr.max_length = htoles(65535);
637 vfile_hdr.file_flags = htoles(1); /* indexes are present */
638 vfile_hdr.file_version = htoles(1);
639 strcpy(vfile_hdr.description, "Ethereal file");
641 /* Translate the encapsulation type */
644 case WTAP_ENCAP_ETHERNET: vfile_hdr.media_type = htoles(6); break;
645 case WTAP_ENCAP_TOKEN_RING: vfile_hdr.media_type = htoles(9); break;
646 case WTAP_ENCAP_LAPB: vfile_hdr.media_type = htoles(16); break;
647 case WTAP_ENCAP_PPP: /* PPP is differentiated from CHDLC in PktHdr */
648 case WTAP_ENCAP_PPP_WITH_PHDR:
649 case WTAP_ENCAP_CHDLC: vfile_hdr.media_type = htoles(22); break;
650 case WTAP_ENCAP_FRELAY: vfile_hdr.media_type = htoles(32); break;
653 /* Write the file header following the magic bytes. */
654 nwritten = fwrite(&vfile_hdr, 1, sizeof vfile_hdr, wdh->fh);
655 if (nwritten != sizeof vfile_hdr)
659 if (nwritten == 0 && ferror(wdh->fh))
662 *err = WTAP_ERR_SHORT_WRITE;
664 visual_dump_free(wdh);
668 /* Deallocate the file write data */
669 visual_dump_free(wdh);
674 /* Free the memory allocated by a visual file writer. */
675 static void visual_dump_free(wtap_dumper *wdh)
677 struct visual_write_info * visual = wdh->dump.opaque;
681 /* Free the index table memory. */
682 if (visual->index_table)
683 g_free(visual->index_table);
685 /* Free the write file info struct. */
687 wdh->dump.opaque = 0;