2 * File read and write routines for Visual Networks cap files.
3 * Copyright (c) 2001, Tom Nisbet tnisbet@visualnetworks.com
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 header, and for ATM captures, there is an additional atm packet header.
39 * The data follows the packet header. The last section is the packet index block.
40 * The index block contains one 4 octet pointer for each captured packet.
41 * The first packet index is (4 * num_pkts) octets from the end of the file
42 * and the last index is in the last four octets of the file.
44 * All integer and time values are stored in little-endian format, except for
45 * the ATM Packet Header, which is stored in network byte order.
50 * [ Packet Header 1 ] [(opt) ATM Packet Header] [ Data ]
52 * [ Packet Header n ] [(opt) ATM Packet Header] [ Data ]
55 * [ Index Block 1 ] ... [ Index Block n ]
58 /* Capture file header, INCLUDING the magic number, is 192 bytes. */
59 #define CAPTUREFILE_HEADER_SIZE 192
61 /* Magic number for Visual Networks traffic capture files. */
62 static const char visual_magic[] = {
67 /* Visual File Header (minus magic number). */
68 /* This structure is used to extract information */
69 struct visual_file_hdr
71 guint32 num_pkts; /* Number of packets in the file */
72 guint32 start_time; /* Capture start time in PC format */
73 guint16 media_type; /* IANA ifType of packet source */
74 guint16 max_length; /* Max allowable stored packet length */
75 guint16 file_flags; /* File type flags */
76 /* Bit 0 indicates indexes present */
77 guint16 file_version; /* Version number of this file format */
78 guint32 media_speed; /* ifSpeed of packet source in bits/sec. */
79 guint16 media_param; /* Media-specific extra parameter. */
80 char RESERVED_[102]; /* MUST BE ALL ZEROS FOR FUTURE COMPATABILITY */
81 char description[64]; /* File description (null terminated) */
85 /* Packet status bits */
88 #define PS_ERRORED 0x04
89 #define PS_1ST_AFTER_DROP 0x08
90 #define PS_APPROX_ORDER 0x10
92 #define PS_ABORTED 0x80
94 /* Visual Packet Header */
95 /* This structure is used to extract information */
98 guint32 ts_delta; /* Time stamp - msecs since start of capture */
99 guint16 orig_len; /* Actual length of packet */
100 guint16 incl_len; /* Number of octets captured in file */
101 guint32 status; /* Packet status flags (media specific) */
102 guint8 encap_hint; /* Encapsulation type hint */
103 guint8 encap_skip; /* Number of bytes to skip before decoding */
104 char RESERVED_[6]; /* RESERVED - must be zero */
107 /* Optional Visual ATM Packet Header */
108 /* This structure is used to extract information */
109 struct visual_atm_hdr
111 guint16 vpi; /* 4 bits of zeros; 12 bits of ATM VPI */
112 guint16 vci; /* ATM VCI */
113 guint8 info; /* 4 bits version; 3 bits unused-zero; 1 bit direction */
114 guint8 category; /* indicates type of traffic. 4 bits of status + 4 bits of type */
115 guint16 cell_count; /* number of cells that make up this pdu */
116 guint32 data_length; /* PDU data length for AAL-5 PDUs, all others - cellcount * 48 */
117 guint32 ts_secs; /* seonds value of sysUpTime when the last cell of this PDU was captured */
118 guint32 ts_nsec; /* nanoseonds value of sysUpTime when the last cell of this PDU was captured */
122 /* visual_atm_hdr info bit definitions */
123 #define FROM_NETWORK 0x01
124 #define ATM_VER_MASK 0xf0 /* Not currently displayed */
126 /* visual_atm_hdr category definitions */
127 /* High nibble - not currently displayed */
128 #define VN_INCOMPLETE 0x40
129 #define VN_BAD_CRC 0x80
130 #define VN_CAT_STAT_MASK 0xf0
132 #define VN_UNKNOWN 0x00
135 #define VN_AAL34 0x03
141 #define VN_CAT_TYPE_MASK 0x0f
144 /* Additional information for reading Visual files */
145 struct visual_read_info
147 guint32 num_pkts; /* Number of pkts in the file */
148 guint32 current_pkt; /* Next packet to be read */
149 double start_time; /* Capture start time in microseconds */
153 /* Additional information for writing Visual files */
154 struct visual_write_info
156 unsigned start_time; /* Capture start time in seconds */
157 int index_table_index; /* Index of the next index entry */
158 int index_table_size; /* Allocated size of the index table */
159 guint32 * index_table; /* File offsets for the packets */
160 guint32 next_offset; /* Offset of next packet */
164 /* Local functions to handle file reads and writes */
165 static gboolean visual_read(wtap *wth, int *err, gchar **err_info,
166 gint64 *data_offset);
167 static void visual_close(wtap *wth);
168 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
169 union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
170 int *err, gchar **err_info);
171 static void visual_set_pseudo_header(int encap, struct visual_pkt_hdr *vpkt_hdr,
172 struct visual_atm_hdr *vatm_hdr, union wtap_pseudo_header *pseudo_header);
173 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
174 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
175 static gboolean visual_dump_close(wtap_dumper *wdh, int *err);
176 static void visual_dump_free(wtap_dumper *wdh);
179 /* Open a file for reading */
180 int visual_open(wtap *wth, int *err, gchar **err_info)
183 char magic[sizeof visual_magic];
184 struct visual_file_hdr vfile_hdr;
185 struct visual_read_info * visual;
188 /* Check the magic string at the start of the file */
189 errno = WTAP_ERR_CANT_READ;
190 bytes_read = file_read(magic, 1, sizeof magic, wth->fh);
191 if (bytes_read != sizeof magic)
193 *err = file_error(wth->fh);
198 if (memcmp(magic, visual_magic, sizeof visual_magic) != 0)
203 /* Read the rest of the file header. */
204 errno = WTAP_ERR_CANT_READ;
205 bytes_read = file_read(&vfile_hdr, 1, sizeof vfile_hdr, wth->fh);
206 if (bytes_read != sizeof vfile_hdr)
208 *err = file_error(wth->fh);
214 /* Verify the file version is known */
215 vfile_hdr.file_version = pletohs(&vfile_hdr.file_version);
216 if (vfile_hdr.file_version != 1)
218 *err = WTAP_ERR_UNSUPPORTED;
219 *err_info = g_strdup_printf("visual: file version %u unsupported", vfile_hdr.file_version);
223 /* Translate the encapsulation type; these values are SNMP ifType
224 values, as found in http://www.iana.org/assignments/smi-numbers.
226 Note that a file with media type 22 ("propPointToPointSerial") may
227 contain Cisco HDLC or PPP over HDLC. This will get sorted out after
228 the first packet is read.
230 XXX - should we use WTAP_ENCAP_PER_PACKET for that? */
231 switch (pletohs(&vfile_hdr.media_type))
233 case 6: /* ethernet-csmacd */
234 encap = WTAP_ENCAP_ETHERNET;
237 case 9: /* IEEE802.5 */
238 encap = WTAP_ENCAP_TOKEN_RING;
242 encap = WTAP_ENCAP_LAPB;
245 case 22: /* propPointToPointSerial */
247 encap = WTAP_ENCAP_CHDLC_WITH_PHDR;
250 case 32: /* frame-relay */
251 encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
255 encap = WTAP_ENCAP_ATM_PDUS;
259 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
260 *err_info = g_strdup_printf("visual: network type %u unknown or unsupported",
261 vfile_hdr.media_type);
265 /* Fill in the wiretap struct with data from the file header */
266 wth->file_type = WTAP_FILE_VISUAL_NETWORKS;
267 wth->file_encap = encap;
268 wth->snapshot_length = pletohs(&vfile_hdr.max_length);
270 /* Save the pointer to the beginning of the packet data so
271 that the later seek_reads work correctly. */
272 wth->data_offset = CAPTUREFILE_HEADER_SIZE;
274 /* Set up the pointers to the handlers for this file type */
275 wth->subtype_read = visual_read;
276 wth->subtype_seek_read = visual_seek_read;
277 wth->subtype_close = visual_close;
278 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
280 /* Add Visual-specific information to the wiretap struct for later use. */
281 visual = g_malloc(sizeof(struct visual_read_info));
282 wth->capture.generic = visual;
283 visual->num_pkts = pletohl(&vfile_hdr.num_pkts);
284 visual->start_time = ((double) pletohl(&vfile_hdr.start_time)) * 1000000;
285 visual->current_pkt = 1;
291 /* Read the next available packet from the file. This is called
292 in a loop to sequentially read the entire file one time. After
293 the file has been read once, any Future access to the packets is
294 done through seek_read. */
295 static gboolean visual_read(wtap *wth, int *err, gchar **err_info,
298 struct visual_read_info *visual = wth->capture.generic;
299 guint32 packet_size = 0;
301 struct visual_pkt_hdr vpkt_hdr;
302 struct visual_atm_hdr vatm_hdr;
303 int phdr_size = sizeof(vpkt_hdr);
304 int ahdr_size = sizeof(vatm_hdr);
309 /* Check for the end of the packet data. Note that a check for file EOF
310 will not work because there are index values stored after the last
312 if (visual->current_pkt > visual->num_pkts)
314 *err = 0; /* it's just an EOF, not an error */
317 visual->current_pkt++;
319 /* Read the packet header. */
320 errno = WTAP_ERR_CANT_READ;
321 bytes_read = file_read(&vpkt_hdr, 1, phdr_size, wth->fh);
322 if (bytes_read != phdr_size)
324 *err = file_error(wth->fh);
325 if (*err == 0 && bytes_read != 0)
327 *err = WTAP_ERR_SHORT_READ;
331 wth->data_offset += phdr_size;
333 /* Get the included length of data. This includes extra headers + payload */
334 packet_size = pletohs(&vpkt_hdr.incl_len);
336 /* Check for additional ATM packet header */
337 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
339 /* Read the atm packet header. */
340 errno = WTAP_ERR_CANT_READ;
341 bytes_read = file_read(&vatm_hdr, 1, ahdr_size, wth->fh);
342 if (bytes_read != ahdr_size)
344 *err = file_error(wth->fh);
345 if (*err == 0 && bytes_read != 0)
347 *err = WTAP_ERR_SHORT_READ;
351 wth->data_offset += ahdr_size;
353 /* Remove ATM header from length of included bytes in capture, as
354 this header was appended by the processor doing the packet reassembly,
355 and was not transmitted across the wire */
356 packet_size -= ahdr_size;
359 /* Read the packet data. */
360 if (packet_size > WTAP_MAX_PACKET_SIZE)
362 /* Probably a corrupt capture file; don't blow up trying
363 to allocate space for an immensely-large packet. */
364 *err = WTAP_ERR_BAD_RECORD;
365 *err_info = g_strdup_printf("visual: File has %u-byte packet, bigger than maximum of %u",
366 packet_size, WTAP_MAX_PACKET_SIZE);
369 buffer_assure_space(wth->frame_buffer, packet_size);
370 *data_offset = wth->data_offset;
371 errno = WTAP_ERR_CANT_READ;
372 bytes_read = file_read(buffer_start_ptr(wth->frame_buffer), 1,
373 packet_size, wth->fh);
375 if (bytes_read != (int) packet_size)
377 *err = file_error(wth->fh);
379 *err = WTAP_ERR_SHORT_READ;
382 wth->data_offset += packet_size;
384 /* Set the packet time and length. */
385 t = visual->start_time;
386 t += ((double)pletohl(&vpkt_hdr.ts_delta))*1000;
387 secs = (time_t)(t/1000000);
388 usecs = (guint32)(t - secs*1000000);
389 wth->phdr.ts.secs = secs;
390 wth->phdr.ts.nsecs = usecs * 1000;
392 /* Most visual capture types include FCS checks in the original length value, but
393 * but don't include the FCS as part of the payload or captured length.
394 * This causes the RTP audio payload save to fail since then captured len != orig len.
395 * Adjusting the original length to remove the FCS bytes we counted based
396 * on the file encapsualtion type.
398 * Only downside to this fix is throughput calculations will be slightly lower
399 * as they won't include the FCS bytes.
402 wth->phdr.caplen = packet_size;
403 wth->phdr.len = pletohs(&vpkt_hdr.orig_len);
405 switch (wth->file_encap)
407 case WTAP_ENCAP_ETHERNET:
411 case WTAP_ENCAP_FRELAY_WITH_PHDR:
412 case WTAP_ENCAP_CHDLC_WITH_PHDR:
413 case WTAP_ENCAP_LAPB:
417 /* ATM original length doesn't include any FCS. Do nothing. */
418 case WTAP_ENCAP_ATM_PDUS:
419 /* Not sure about token ring. Just leaving alone for now. */
420 case WTAP_ENCAP_TOKEN_RING:
426 if (wth->phdr.len < wth->phdr.caplen)
428 wth->phdr.len = wth->phdr.caplen;
431 /* Set the pseudo_header. */
432 visual_set_pseudo_header(wth->file_encap, &vpkt_hdr, &vatm_hdr, &wth->pseudo_header);
434 /* Fill in the encapsulation. Visual files have a media type in the
435 file header and an encapsulation type in each packet header. Files
436 with a media type of HDLC can be either Cisco EtherType or PPP.
438 The encapsulation hint values we've seen are:
440 2 - seen in an Ethernet capture
441 13 - seen in a PPP capture; possibly also seen in Cisco HDLC
443 14 - seen in a PPP capture; probably seen only for PPP */
444 if (wth->file_encap == WTAP_ENCAP_CHDLC_WITH_PHDR)
446 /* If PPP is specified in the encap hint, then use that */
447 if (vpkt_hdr.encap_hint == 14)
449 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
453 /* Otherwise, we need to examine the first two octets to
454 try to determine the encapsulation. */
455 guint8 *buf = buffer_start_ptr(wth->frame_buffer);
456 if ((0xff == buf[0]) && (0x03 == buf[1]))
458 /* It is actually PPP */
459 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
467 /* Close a file opened for reading. */
468 static void visual_close(wtap *wth)
470 /* Free the info allocated by a Visual file reader. */
471 if (wth->capture.generic)
472 g_free(wth->capture.generic);
473 wth->capture.generic = 0;
477 /* Read packet data for random access.
478 This gets the packet data and rebuilds the pseudo header so that
479 the direction flag works. */
480 static gboolean visual_seek_read (wtap *wth, gint64 seek_off,
481 union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
482 int *err, gchar **err_info _U_)
484 struct visual_pkt_hdr vpkt_hdr;
485 struct visual_atm_hdr vatm_hdr;
486 int phdr_size = sizeof(vpkt_hdr);
487 int ahdr_size = sizeof(vatm_hdr);
491 /* Get the size of the visual packet header to skip */
492 header_size = sizeof(struct visual_pkt_hdr);
494 /* If ATM capture, need to skip over visual ATM packet header too */
495 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
497 header_size += (int)sizeof(struct visual_atm_hdr);
500 /* Seek to the packet header */
501 if (file_seek(wth->random_fh, seek_off - header_size,
502 SEEK_SET, err) == -1)
505 /* Read the packet header to get the status flags. */
506 errno = WTAP_ERR_CANT_READ;
507 bytes_read = file_read(&vpkt_hdr, 1, phdr_size, wth->random_fh);
508 if (bytes_read != phdr_size) {
509 *err = file_error(wth->random_fh);
511 *err = WTAP_ERR_SHORT_READ;
515 /* Check for additional ATM packet header */
516 if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
518 /* Read the atm packet header */
519 errno = WTAP_ERR_CANT_READ;
520 bytes_read = file_read(&vatm_hdr, 1, ahdr_size, wth->random_fh);
521 if (bytes_read != ahdr_size)
523 *err = file_error(wth->fh);
524 if (*err == 0 && bytes_read != 0)
526 *err = WTAP_ERR_SHORT_READ;
532 /* Read the packet data. */
533 errno = WTAP_ERR_CANT_READ;
534 bytes_read = file_read(pd, sizeof(guint8), len, wth->random_fh);
535 if (bytes_read != len) {
537 *err = WTAP_ERR_SHORT_READ;
541 /* Set the pseudo_header. */
542 visual_set_pseudo_header(wth->file_encap, &vpkt_hdr, &vatm_hdr, pseudo_header);
547 static void visual_set_pseudo_header(int encap, struct visual_pkt_hdr *vpkt_hdr,
548 struct visual_atm_hdr *vatm_hdr, union wtap_pseudo_header *pseudo_header)
550 guint32 packet_status;
552 /* Set status flags. The only status currently supported for all
553 encapsulations is direction. This either goes in the p2p or the
554 X.25 pseudo header. It would probably be better to move this up
556 packet_status = pletohl(&vpkt_hdr->status);
559 case WTAP_ENCAP_ETHERNET:
560 /* XXX - is there an FCS in the frame? */
561 pseudo_header->eth.fcs_len = -1;
564 case WTAP_ENCAP_CHDLC_WITH_PHDR:
565 case WTAP_ENCAP_PPP_WITH_PHDR:
566 pseudo_header->p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
569 case WTAP_ENCAP_FRELAY_WITH_PHDR:
570 case WTAP_ENCAP_LAPB:
571 pseudo_header->x25.flags =
572 (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
575 case WTAP_ENCAP_ATM_PDUS:
577 pseudo_header->atm.type = TRAF_UNKNOWN;
578 pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
579 pseudo_header->atm.aal5t_len = 0;
581 /* Next two items not supported. Defaulting to zero */
582 pseudo_header->atm.aal5t_u2u = 0;
583 pseudo_header->atm.aal5t_chksum = 0;
585 /* Flags appear only to convey that packet is a raw cell. Set to 0 */
586 pseudo_header->atm.flags = 0;
588 /* Not supported. Defaulting to zero */
589 pseudo_header->atm.aal2_cid = 0;
591 switch(vatm_hdr->category & VN_CAT_TYPE_MASK )
594 pseudo_header->atm.aal = AAL_1;
598 pseudo_header->atm.aal = AAL_2;
602 pseudo_header->atm.aal = AAL_3_4;
606 pseudo_header->atm.aal = AAL_5;
607 pseudo_header->atm.type = TRAF_LLCMX;
608 pseudo_header->atm.aal5t_len = pntohl(&vatm_hdr->data_length);
612 /* Marking next 3 as OAM versus unknown */
616 pseudo_header->atm.aal = AAL_OAMCELL;
621 pseudo_header->atm.aal = AAL_UNKNOWN;
625 pseudo_header->atm.vpi = pntohs(&vatm_hdr->vpi) & 0x0FFF;
626 pseudo_header->atm.vci = pntohs(&vatm_hdr->vci);
627 pseudo_header->atm.cells = pntohs(&vatm_hdr->cell_count);
629 /* Using bit value of 1 (DCE -> DTE) to indicate From Network */
630 pseudo_header->atm.channel = vatm_hdr->info & FROM_NETWORK;
636 /* Check for media types that may be written in Visual file format.
637 Returns 0 if the specified encapsulation type is supported,
638 an error indication otherwise. */
639 int visual_dump_can_write_encap(int encap)
641 /* Per-packet encapsulations aren't supported. */
642 if (encap == WTAP_ENCAP_PER_PACKET)
643 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
645 /* Check for supported encapsulation types */
648 case WTAP_ENCAP_ETHERNET:
649 case WTAP_ENCAP_TOKEN_RING:
650 case WTAP_ENCAP_LAPB:
651 case WTAP_ENCAP_CHDLC_WITH_PHDR:
652 case WTAP_ENCAP_FRELAY_WITH_PHDR:
654 case WTAP_ENCAP_PPP_WITH_PHDR:
658 return WTAP_ERR_UNSUPPORTED_ENCAP;
662 /* Open a file for writing.
663 Returns TRUE on success, FALSE on failure; sets "*err" to an
664 error code on failure */
665 gboolean visual_dump_open(wtap_dumper *wdh, gboolean cant_seek, int *err)
667 struct visual_write_info *visual;
669 /* We can't fill in some fields in the header until all the packets
670 have been written, so we can't write to a pipe. */
672 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
676 /* Set the write routines for a visual file. */
677 wdh->subtype_write = visual_dump;
678 wdh->subtype_close = visual_dump_close;
680 /* Create a struct to hold file information for the duration
682 visual = g_malloc(sizeof(struct visual_write_info));
683 wdh->dump.opaque = visual;
684 visual->index_table_index = 0;
685 visual->index_table_size = 1024;
686 visual->index_table = 0;
687 visual->next_offset = CAPTUREFILE_HEADER_SIZE;
689 /* All of the fields in the file header aren't known yet so
690 just skip over it for now. It will be created after all
691 of the packets have been written. */
692 if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
701 /* Write a packet to a Visual dump file.
702 Returns TRUE on success, FALSE on failure. */
703 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
704 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
706 struct visual_write_info * visual = wdh->dump.opaque;
707 struct visual_pkt_hdr vpkt_hdr;
708 size_t hdr_size = sizeof vpkt_hdr;
711 guint32 packet_status;
713 /* If the visual structure was never allocated then nothing useful
718 /* Zero out unused and reserved fields in the packet header. */
719 memset(&vpkt_hdr, 0, hdr_size);
721 /* Visual UpTime capture files have a capture start time in the
722 file header. Each packet has a capture time (in msec) relative
723 to the file start time. Use the time of the first packet as the
725 if (visual->index_table_index == 0)
727 /* This is the first packet. Save its start time as the file time. */
728 visual->start_time = (guint32) phdr->ts.secs;
730 /* Initialize the index table */
731 visual->index_table = g_malloc(1024 * sizeof *visual->index_table);
732 visual->index_table_size = 1024;
735 /* Calculate milliseconds since capture start. */
736 delta_msec = phdr->ts.nsecs / 1000000;
737 delta_msec += ( (guint32) phdr->ts.secs - visual->start_time) * 1000;
738 vpkt_hdr.ts_delta = htolel(delta_msec);
740 /* Fill in the length fields. */
741 vpkt_hdr.orig_len = htoles(phdr->len);
742 vpkt_hdr.incl_len = htoles(phdr->caplen);
744 /* Fill in the encapsulation hint for the file's media type. */
747 case WTAP_ENCAP_ETHERNET: /* Ethernet */
748 vpkt_hdr.encap_hint = 2;
750 case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
751 vpkt_hdr.encap_hint = 3;
753 case WTAP_ENCAP_PPP: /* PPP */
754 case WTAP_ENCAP_PPP_WITH_PHDR:
755 vpkt_hdr.encap_hint = 14;
757 case WTAP_ENCAP_CHDLC_WITH_PHDR: /* HDLC Router */
758 vpkt_hdr.encap_hint = 13;
760 case WTAP_ENCAP_FRELAY_WITH_PHDR: /* Frame Relay Auto-detect */
761 vpkt_hdr.encap_hint = 12;
763 case WTAP_ENCAP_LAPB: /* Unknown */
765 vpkt_hdr.encap_hint = 1;
769 /* Set status flags. The only status currently supported for all
770 encapsulations is direction. This either goes in the p2p or the
771 X.25 pseudo header. It would probably be better to move this up
776 case WTAP_ENCAP_CHDLC_WITH_PHDR:
777 packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
780 case WTAP_ENCAP_FRELAY_WITH_PHDR:
781 case WTAP_ENCAP_LAPB:
783 ((pseudo_header->x25.flags & FROM_DCE) ? 0x00 : PS_SENT);
786 vpkt_hdr.status = htolel(packet_status);
788 /* Write the packet header. */
789 nwritten = fwrite(&vpkt_hdr, 1, hdr_size, wdh->fh);
790 if (nwritten != hdr_size)
792 if (nwritten == 0 && ferror(wdh->fh))
795 *err = WTAP_ERR_SHORT_WRITE;
799 /* Write the packet data */
800 nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh);
801 if (nwritten != phdr->caplen)
803 if (nwritten == 0 && ferror(wdh->fh))
806 *err = WTAP_ERR_SHORT_WRITE;
810 /* Store the frame offset in the index table. */
811 if (visual->index_table_index >= visual->index_table_size)
813 /* End of table reached. Reallocate with a larger size */
814 visual->index_table_size *= 2;
815 visual->index_table = g_realloc(visual->index_table,
816 visual->index_table_size * sizeof *visual->index_table);
818 visual->index_table[visual->index_table_index] = htolel(visual->next_offset);
820 /* Update the table index and offset for the next frame. */
821 visual->index_table_index++;
822 visual->next_offset += (guint32) hdr_size + phdr->caplen;
828 /* Finish writing to a dump file.
829 Returns TRUE on success, FALSE on failure. */
830 static gboolean visual_dump_close(wtap_dumper *wdh, int *err)
832 struct visual_write_info * visual = wdh->dump.opaque;
835 struct visual_file_hdr vfile_hdr;
839 /* If the visual structure was never allocated then nothing useful
844 /* Write out the frame table at the end of the file. */
845 if (visual->index_table)
847 /* Write the index table to the file. */
848 n_to_write = visual->index_table_index * sizeof *visual->index_table;
849 nwritten = fwrite(visual->index_table, 1, n_to_write, wdh->fh);
850 if (nwritten != n_to_write)
854 if (nwritten == 0 && ferror(wdh->fh))
857 *err = WTAP_ERR_SHORT_WRITE;
859 visual_dump_free(wdh);
864 /* Write the magic number at the start of the file. */
865 fseek(wdh->fh, 0, SEEK_SET);
866 magicp = visual_magic;
867 magic_size = sizeof visual_magic;
868 nwritten = fwrite(magicp, 1, magic_size, wdh->fh);
869 if (nwritten != magic_size)
873 if (nwritten == 0 && ferror(wdh->fh))
876 *err = WTAP_ERR_SHORT_WRITE;
878 visual_dump_free(wdh);
882 /* Initialize the file header with zeroes for the reserved fields. */
883 memset(&vfile_hdr, '\0', sizeof vfile_hdr);
884 vfile_hdr.num_pkts = htolel(visual->index_table_index);
885 vfile_hdr.start_time = htolel(visual->start_time);
886 vfile_hdr.max_length = htoles(65535);
887 vfile_hdr.file_flags = htoles(1); /* indexes are present */
888 vfile_hdr.file_version = htoles(1);
889 g_strlcpy(vfile_hdr.description, "Wireshark file", 64);
891 /* Translate the encapsulation type */
894 case WTAP_ENCAP_ETHERNET:
895 vfile_hdr.media_type = htoles(6);
898 case WTAP_ENCAP_TOKEN_RING:
899 vfile_hdr.media_type = htoles(9);
902 case WTAP_ENCAP_LAPB:
903 vfile_hdr.media_type = htoles(16);
906 case WTAP_ENCAP_PPP: /* PPP is differentiated from CHDLC in PktHdr */
907 case WTAP_ENCAP_PPP_WITH_PHDR:
908 case WTAP_ENCAP_CHDLC_WITH_PHDR:
909 vfile_hdr.media_type = htoles(22);
912 case WTAP_ENCAP_FRELAY_WITH_PHDR:
913 vfile_hdr.media_type = htoles(32);
917 /* Write the file header following the magic bytes. */
918 nwritten = fwrite(&vfile_hdr, 1, sizeof vfile_hdr, wdh->fh);
919 if (nwritten != sizeof vfile_hdr)
923 if (nwritten == 0 && ferror(wdh->fh))
926 *err = WTAP_ERR_SHORT_WRITE;
928 visual_dump_free(wdh);
932 /* Deallocate the file write data */
933 visual_dump_free(wdh);
938 /* Free the memory allocated by a visual file writer. */
939 static void visual_dump_free(wtap_dumper *wdh)
941 struct visual_write_info * visual = wdh->dump.opaque;
945 /* Free the index table memory. */
946 if (visual->index_table)
947 g_free(visual->index_table);
949 /* Free the write file info struct. */
951 wdh->dump.opaque = 0;