2 * File read and write routines for Visual Networks cap files.
3 * Copyright (c) 2001, Tom Nisbet tnisbet@visualnetworks.com
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include "file_wrappers.h"
19 * A Visual Networks traffic capture file contains three sections. The
20 * first is a 192 octet file header. This is followed by the captured
21 * packet header, and for ATM captures, there is an additional atm packet header.
22 * The data follows the packet header. The last section is the packet index block.
23 * The index block contains one 4 octet pointer for each captured packet.
24 * The first packet index is (4 * num_pkts) octets from the end of the file
25 * and the last index is in the last four octets of the file.
27 * All integer and time values are stored in little-endian format, except for
28 * the ATM Packet Header, which is stored in network byte order.
33 * [ Packet Header 1 ] [(opt) ATM Packet Header] [ Data ]
35 * [ Packet Header n ] [(opt) ATM Packet Header] [ Data ]
38 * [ Index Block 1 ] ... [ Index Block n ]
41 /* Capture file header, INCLUDING the magic number, is 192 bytes. */
42 #define CAPTUREFILE_HEADER_SIZE 192
44 /* Magic number for Visual Networks traffic capture files. */
45 static const char visual_magic
[] = {
50 /* Visual File Header (minus magic number). */
51 /* This structure is used to extract information */
52 struct visual_file_hdr
54 uint32_t num_pkts
; /* Number of packets in the file */
55 uint32_t start_time
; /* Capture start time in PC format */
56 uint16_t media_type
; /* IANA ifType of packet source */
57 uint16_t max_length
; /* Max allowable stored packet length */
58 uint16_t file_flags
; /* File type flags */
59 /* Bit 0 indicates indexes present */
60 uint16_t file_version
; /* Version number of this file format */
61 uint32_t media_speed
; /* ifSpeed of packet source in bits/sec. */
62 uint16_t media_param
; /* Media-specific extra parameter. */
63 char RESERVED_
[102]; /* MUST BE ALL ZEROS FOR FUTURE COMPATIBILITY */
64 char description
[64]; /* File description (null terminated) */
68 /* Packet status bits */
71 #define PS_ERRORED 0x04
72 #define PS_1ST_AFTER_DROP 0x08
73 #define PS_APPROX_ORDER 0x10
75 #define PS_ABORTED 0x80
77 /* Visual Packet Header */
78 /* This structure is used to extract information */
81 uint32_t ts_delta
; /* Time stamp - msecs since start of capture */
82 uint16_t orig_len
; /* Actual length of packet */
83 uint16_t incl_len
; /* Number of octets captured in file */
84 uint32_t status
; /* Packet status flags (media specific) */
85 uint8_t encap_hint
; /* Encapsulation type hint */
86 uint8_t encap_skip
; /* Number of bytes to skip before decoding */
87 char RESERVED_
[6]; /* RESERVED - must be zero */
90 /* Optional Visual ATM Packet Header */
91 /* This structure is used to extract information */
94 uint16_t vpi
; /* 4 bits of zeros; 12 bits of ATM VPI */
95 uint16_t vci
; /* ATM VCI */
96 uint8_t info
; /* 4 bits version; 3 bits unused-zero; 1 bit direction */
97 uint8_t category
; /* indicates type of traffic. 4 bits of status + 4 bits of type */
98 uint16_t cell_count
; /* number of cells that make up this pdu */
99 uint32_t data_length
; /* PDU data length for AAL-5 PDUs, all others - cellcount * 48 */
100 uint32_t ts_secs
; /* seconds value of sysUpTime when the last cell of this PDU was captured */
101 uint32_t ts_nsec
; /* nanoseconds value of sysUpTime when the last cell of this PDU was captured */
105 /* visual_atm_hdr info bit definitions */
106 #define FROM_NETWORK 0x01
107 #define ATM_VER_MASK 0xf0 /* Not currently displayed */
109 /* visual_atm_hdr category definitions */
110 /* High nibble - not currently displayed */
111 #define VN_INCOMPLETE 0x40
112 #define VN_BAD_CRC 0x80
113 #define VN_CAT_STAT_MASK 0xf0
115 #define VN_UNKNOWN 0x00
118 #define VN_AAL34 0x03
124 #define VN_CAT_TYPE_MASK 0x0f
127 /* Additional information for reading Visual files */
128 struct visual_read_info
130 uint32_t num_pkts
; /* Number of pkts in the file */
131 uint32_t current_pkt
; /* Next packet to be read */
132 time_t start_time
; /* Capture start time in seconds */
136 /* Additional information for writing Visual files */
137 struct visual_write_info
139 uint32_t start_time
; /* Capture start time in seconds */
140 int index_table_index
; /* Index of the next index entry */
141 int index_table_size
; /* Allocated size of the index table */
142 uint32_t * index_table
; /* File offsets for the packets */
143 uint32_t next_offset
; /* Offset of next packet */
147 /* Local functions to handle file reads and writes */
148 static bool visual_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
149 int *err
, char **err_info
, int64_t *data_offset
);
150 static bool visual_seek_read(wtap
*wth
, int64_t seek_off
,
151 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
);
152 static bool visual_read_packet(wtap
*wth
, FILE_T fh
,
153 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
);
154 static bool visual_dump(wtap_dumper
*wdh
, const wtap_rec
*rec
,
155 const uint8_t *pd
, int *err
, char **err_info
);
156 static bool visual_dump_finish(wtap_dumper
*wdh
, int *err
,
158 static void visual_dump_free(wtap_dumper
*wdh
);
160 static int visual_file_type_subtype
= -1;
162 void register_visual(void);
165 /* Open a file for reading */
166 wtap_open_return_val
visual_open(wtap
*wth
, int *err
, char **err_info
)
168 char magic
[sizeof visual_magic
];
169 struct visual_file_hdr vfile_hdr
;
170 struct visual_read_info
* visual
;
173 /* Check the magic string at the start of the file */
174 if (!wtap_read_bytes(wth
->fh
, magic
, sizeof magic
, err
, err_info
))
176 if (*err
!= WTAP_ERR_SHORT_READ
)
177 return WTAP_OPEN_ERROR
;
178 return WTAP_OPEN_NOT_MINE
;
180 if (memcmp(magic
, visual_magic
, sizeof visual_magic
) != 0)
182 return WTAP_OPEN_NOT_MINE
;
185 /* Read the rest of the file header. */
186 if (!wtap_read_bytes(wth
->fh
, &vfile_hdr
, sizeof vfile_hdr
, err
, err_info
))
188 return WTAP_OPEN_ERROR
;
191 /* Verify the file version is known */
192 vfile_hdr
.file_version
= pletoh16(&vfile_hdr
.file_version
);
193 if (vfile_hdr
.file_version
!= 1)
195 *err
= WTAP_ERR_UNSUPPORTED
;
196 *err_info
= ws_strdup_printf("visual: file version %u unsupported", vfile_hdr
.file_version
);
197 return WTAP_OPEN_ERROR
;
200 /* Translate the encapsulation type; these values are SNMP ifType
201 values, as found in https://www.iana.org/assignments/smi-numbers.
203 Note that a file with media type 22 ("propPointToPointSerial") may
204 contain Cisco HDLC or PPP over HDLC. This will get sorted out after
205 the first packet is read.
207 XXX - should we use WTAP_ENCAP_PER_PACKET for that? */
208 switch (pletoh16(&vfile_hdr
.media_type
))
210 case 6: /* ethernet-csmacd */
211 encap
= WTAP_ENCAP_ETHERNET
;
214 case 9: /* IEEE802.5 */
215 encap
= WTAP_ENCAP_TOKEN_RING
;
219 encap
= WTAP_ENCAP_LAPB
;
222 case 22: /* propPointToPointSerial */
224 encap
= WTAP_ENCAP_CHDLC_WITH_PHDR
;
227 case 32: /* frame-relay */
228 encap
= WTAP_ENCAP_FRELAY_WITH_PHDR
;
232 encap
= WTAP_ENCAP_ATM_PDUS
;
236 *err
= WTAP_ERR_UNSUPPORTED
;
237 *err_info
= ws_strdup_printf("visual: network type %u unknown or unsupported",
238 vfile_hdr
.media_type
);
239 return WTAP_OPEN_ERROR
;
242 /* Fill in the wiretap struct with data from the file header */
243 wth
->file_type_subtype
= visual_file_type_subtype
;
244 wth
->file_encap
= encap
;
245 wth
->snapshot_length
= pletoh16(&vfile_hdr
.max_length
);
247 /* Set up the pointers to the handlers for this file type */
248 wth
->subtype_read
= visual_read
;
249 wth
->subtype_seek_read
= visual_seek_read
;
250 wth
->file_tsprec
= WTAP_TSPREC_MSEC
;
252 /* Add Visual-specific information to the wiretap struct for later use. */
253 visual
= g_new(struct visual_read_info
, 1);
254 wth
->priv
= (void *)visual
;
255 visual
->num_pkts
= pletoh32(&vfile_hdr
.num_pkts
);
256 visual
->start_time
= pletoh32(&vfile_hdr
.start_time
);
257 visual
->current_pkt
= 1;
260 * Add an IDB; we don't know how many interfaces were
261 * involved, so we just say one interface, about which
262 * we only know the link-layer type, snapshot length,
263 * and time stamp resolution.
265 wtap_add_generated_idb(wth
);
267 return WTAP_OPEN_MINE
;
271 /* Read the next available packet from the file. This is called
272 in a loop to sequentially read the entire file one time. After
273 the file has been read once, any Future access to the packets is
274 done through seek_read. */
275 static bool visual_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
276 int *err
, char **err_info
, int64_t *data_offset
)
278 struct visual_read_info
*visual
= (struct visual_read_info
*)wth
->priv
;
280 /* Check for the end of the packet data. Note that a check for file EOF
281 will not work because there are index values stored after the last
283 if (visual
->current_pkt
> visual
->num_pkts
)
285 *err
= 0; /* it's just an EOF, not an error */
288 visual
->current_pkt
++;
290 *data_offset
= file_tell(wth
->fh
);
292 return visual_read_packet(wth
, wth
->fh
, rec
, buf
, err
, err_info
);
295 /* Read packet header and data for random access. */
296 static bool visual_seek_read(wtap
*wth
, int64_t seek_off
,
297 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
)
299 /* Seek to the packet header */
300 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
303 /* Read the packet. */
304 if (!visual_read_packet(wth
, wth
->random_fh
, rec
, buf
, err
, err_info
)) {
306 *err
= WTAP_ERR_SHORT_READ
;
313 visual_read_packet(wtap
*wth
, FILE_T fh
, wtap_rec
*rec
,
314 Buffer
*buf
, int *err
, char **err_info
)
316 struct visual_read_info
*visual
= (struct visual_read_info
*)wth
->priv
;
317 struct visual_pkt_hdr vpkt_hdr
;
318 uint32_t packet_size
;
319 struct visual_atm_hdr vatm_hdr
;
321 uint32_t packet_status
;
324 /* Read the packet header. */
325 if (!wtap_read_bytes_or_eof(fh
, &vpkt_hdr
, (unsigned int)sizeof vpkt_hdr
, err
, err_info
))
330 /* Get the included length of data. This includes extra headers + payload */
331 packet_size
= pletoh16(&vpkt_hdr
.incl_len
);
333 rec
->rec_type
= REC_TYPE_PACKET
;
334 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
335 rec
->presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
337 /* Set the packet time and length. */
338 relmsecs
= pletoh32(&vpkt_hdr
.ts_delta
);
339 rec
->ts
.secs
= visual
->start_time
+ relmsecs
/1000;
340 rec
->ts
.nsecs
= (relmsecs
% 1000)*1000000;
342 rec
->rec_header
.packet_header
.len
= pletoh16(&vpkt_hdr
.orig_len
);
344 packet_status
= pletoh32(&vpkt_hdr
.status
);
346 /* Do encapsulation-specific processing.
348 Most Visual capture types include the FCS in the original length
349 value, but don't include the FCS as part of the payload or captured
350 length. This is different from the model used in most other capture
351 file formats, including pcap and pcapng in cases where the FCS isn't
352 captured (which are the typical cases), and causes the RTP audio
353 payload save to fail since then captured len != orig len.
355 We adjust the original length to remove the FCS bytes we counted based
356 on the file encapsualtion type. The only downside to this fix is
357 throughput calculations will be slightly lower as it won't include
358 the FCS bytes. However, as noted, that problem also exists with
359 other capture formats.
361 We also set status flags. The only status currently supported for
362 all encapsulations is direction. This either goes in the p2p or the
363 X.25 pseudo header. It would probably be better to move this up
365 switch (wth
->file_encap
)
367 case WTAP_ENCAP_ETHERNET
:
368 /* Ethernet has a 4-byte FCS. */
369 if (rec
->rec_header
.packet_header
.len
< 4)
371 *err
= WTAP_ERR_BAD_FILE
;
372 *err_info
= ws_strdup_printf("visual: Ethernet packet has %u-byte original packet, less than the FCS length",
373 rec
->rec_header
.packet_header
.len
);
376 rec
->rec_header
.packet_header
.len
-= 4;
378 /* XXX - the above implies that there's never an FCS; should this
379 set the FCS length to 0? */
380 rec
->rec_header
.packet_header
.pseudo_header
.eth
.fcs_len
= -1;
383 case WTAP_ENCAP_CHDLC_WITH_PHDR
:
384 /* This has a 2-byte FCS. */
385 if (rec
->rec_header
.packet_header
.len
< 2)
387 *err
= WTAP_ERR_BAD_FILE
;
388 *err_info
= ws_strdup_printf("visual: Cisco HDLC packet has %u-byte original packet, less than the FCS length",
389 rec
->rec_header
.packet_header
.len
);
392 rec
->rec_header
.packet_header
.len
-= 2;
394 rec
->rec_header
.packet_header
.pseudo_header
.p2p
.sent
= (packet_status
& PS_SENT
) ? true : false;
397 case WTAP_ENCAP_PPP_WITH_PHDR
:
399 XXX - true? Note that PPP can negotiate no FCS, a 2-byte FCS,
401 rec
->rec_header
.packet_header
.pseudo_header
.p2p
.sent
= (packet_status
& PS_SENT
) ? true : false;
404 case WTAP_ENCAP_FRELAY_WITH_PHDR
:
405 /* This has a 2-byte FCS. */
406 if (rec
->rec_header
.packet_header
.len
< 2)
408 *err
= WTAP_ERR_BAD_FILE
;
409 *err_info
= ws_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
410 rec
->rec_header
.packet_header
.len
);
413 rec
->rec_header
.packet_header
.len
-= 2;
415 rec
->rec_header
.packet_header
.pseudo_header
.dte_dce
.flags
=
416 (packet_status
& PS_SENT
) ? 0x00 : FROM_DCE
;
419 case WTAP_ENCAP_LAPB
:
420 /* This has a 2-byte FCS. */
421 if (rec
->rec_header
.packet_header
.len
< 2)
423 *err
= WTAP_ERR_BAD_FILE
;
424 *err_info
= ws_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
425 rec
->rec_header
.packet_header
.len
);
428 rec
->rec_header
.packet_header
.len
-= 2;
430 rec
->rec_header
.packet_header
.pseudo_header
.dte_dce
.flags
=
431 (packet_status
& PS_SENT
) ? 0x00 : FROM_DCE
;
434 case WTAP_ENCAP_ATM_PDUS
:
435 /* ATM original length doesn't include any FCS. Do nothing to
438 ATM packets have an additional packet header; read and
440 if (!wtap_read_bytes(fh
, &vatm_hdr
, (unsigned int)sizeof vatm_hdr
, err
, err_info
))
445 /* Remove ATM header from length of included bytes in capture, as
446 this header was appended by the processor doing the packet
447 reassembly, and was not transmitted across the wire */
448 packet_size
-= (uint32_t)sizeof vatm_hdr
;
451 rec
->rec_header
.packet_header
.pseudo_header
.atm
.type
= TRAF_UNKNOWN
;
452 rec
->rec_header
.packet_header
.pseudo_header
.atm
.subtype
= TRAF_ST_UNKNOWN
;
453 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal5t_len
= 0;
455 /* Next two items not supported. Defaulting to zero */
456 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal5t_u2u
= 0;
457 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal5t_chksum
= 0;
459 /* Flags appear only to convey that packet is a raw cell. Set to 0 */
460 rec
->rec_header
.packet_header
.pseudo_header
.atm
.flags
= 0;
462 /* Not supported. Defaulting to zero */
463 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal2_cid
= 0;
465 switch(vatm_hdr
.category
& VN_CAT_TYPE_MASK
)
468 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal
= AAL_1
;
472 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal
= AAL_2
;
476 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal
= AAL_3_4
;
480 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal
= AAL_5
;
481 rec
->rec_header
.packet_header
.pseudo_header
.atm
.type
= TRAF_LLCMX
;
482 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal5t_len
= pntoh32(&vatm_hdr
.data_length
);
486 /* Marking next 3 as OAM versus unknown */
490 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal
= AAL_OAMCELL
;
495 rec
->rec_header
.packet_header
.pseudo_header
.atm
.aal
= AAL_UNKNOWN
;
498 rec
->rec_header
.packet_header
.pseudo_header
.atm
.vpi
= pntoh16(&vatm_hdr
.vpi
) & 0x0FFF;
499 rec
->rec_header
.packet_header
.pseudo_header
.atm
.vci
= pntoh16(&vatm_hdr
.vci
);
500 rec
->rec_header
.packet_header
.pseudo_header
.atm
.cells
= pntoh16(&vatm_hdr
.cell_count
);
502 /* Using bit value of 1 (DCE -> DTE) to indicate From Network */
503 rec
->rec_header
.packet_header
.pseudo_header
.atm
.channel
= vatm_hdr
.info
& FROM_NETWORK
;
506 /* Not sure about token ring. Just leaving alone for now. */
507 case WTAP_ENCAP_TOKEN_RING
:
512 rec
->rec_header
.packet_header
.caplen
= packet_size
;
514 /* Check for too-large packet. */
515 if (packet_size
> WTAP_MAX_PACKET_SIZE_STANDARD
)
517 /* Probably a corrupt capture file; don't blow up trying
518 to allocate space for an immensely-large packet. */
519 *err
= WTAP_ERR_BAD_FILE
;
520 *err_info
= ws_strdup_printf("visual: File has %u-byte packet, bigger than maximum of %u",
521 packet_size
, WTAP_MAX_PACKET_SIZE_STANDARD
);
525 /* Read the packet data */
526 if (!wtap_read_packet_bytes(fh
, buf
, packet_size
, err
, err_info
))
529 if (wth
->file_encap
== WTAP_ENCAP_CHDLC_WITH_PHDR
)
531 /* Fill in the encapsulation. Visual files have a media type in the
532 file header and an encapsulation type in each packet header. Files
533 with a media type of HDLC can be either Cisco EtherType or PPP.
535 The encapsulation hint values we've seen are:
537 2 - seen in an Ethernet capture
538 13 - seen in a PPP capture; possibly also seen in Cisco HDLC
540 14 - seen in a PPP capture; probably seen only for PPP.
542 According to bug 2005, the collection probe can be configured
543 for PPP, in which case the encapsulation hint is 14, or can
544 be configured for auto-detect, in which case the encapsulation
545 hint is 13, and the encapsulation must be guessed from the
546 packet contents. Auto-detect is the default. */
547 pd
= ws_buffer_start_ptr(buf
);
549 /* If PPP is specified in the encap hint, then use that */
550 if (vpkt_hdr
.encap_hint
== 14)
552 /* But first we need to examine the first three octets to
553 try to determine the proper encapsulation, see RFC 2364. */
554 if (packet_size
>= 3 &&
555 (0xfe == pd
[0]) && (0xfe == pd
[1]) && (0x03 == pd
[2]))
557 /* It is actually LLC encapsulated PPP */
558 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_ATM_RFC1483
;
562 /* It is actually PPP */
563 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_PPP_WITH_PHDR
;
568 /* Otherwise, we need to examine the first two octets to
569 try to determine the encapsulation. */
570 if (packet_size
>= 2 && (0xff == pd
[0]) && (0x03 == pd
[1]))
572 /* It is actually PPP */
573 rec
->rec_header
.packet_header
.pkt_encap
= WTAP_ENCAP_PPP_WITH_PHDR
;
581 /* Check for media types that may be written in Visual file format.
582 Returns 0 if the specified encapsulation type is supported,
583 an error indication otherwise. */
584 static int visual_dump_can_write_encap(int encap
)
586 /* Per-packet encapsulations aren't supported. */
587 if (encap
== WTAP_ENCAP_PER_PACKET
)
588 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED
;
590 /* Check for supported encapsulation types */
593 case WTAP_ENCAP_ETHERNET
:
594 case WTAP_ENCAP_TOKEN_RING
:
595 case WTAP_ENCAP_LAPB
:
596 case WTAP_ENCAP_CHDLC_WITH_PHDR
:
597 case WTAP_ENCAP_FRELAY_WITH_PHDR
:
599 case WTAP_ENCAP_PPP_WITH_PHDR
:
603 return WTAP_ERR_UNWRITABLE_ENCAP
;
607 /* Open a file for writing.
608 Returns true on success, false on failure; sets "*err" to an
609 error code on failure */
610 static bool visual_dump_open(wtap_dumper
*wdh
, int *err
, char **err_info _U_
)
612 struct visual_write_info
*visual
;
614 /* Set the write routines for a visual file. */
615 wdh
->subtype_write
= visual_dump
;
616 wdh
->subtype_finish
= visual_dump_finish
;
618 /* Create a struct to hold file information for the duration
620 visual
= g_new(struct visual_write_info
, 1);
621 wdh
->priv
= (void *)visual
;
622 visual
->index_table_index
= 0;
623 visual
->index_table_size
= 1024;
624 visual
->index_table
= 0;
625 visual
->next_offset
= CAPTUREFILE_HEADER_SIZE
;
627 /* All of the fields in the file header aren't known yet so
628 just skip over it for now. It will be created after all
629 of the packets have been written. */
630 if (wtap_dump_file_seek(wdh
, CAPTUREFILE_HEADER_SIZE
, SEEK_SET
, err
) == -1)
637 /* Write a packet to a Visual dump file.
638 Returns true on success, false on failure. */
639 static bool visual_dump(wtap_dumper
*wdh
, const wtap_rec
*rec
,
640 const uint8_t *pd
, int *err
, char **err_info _U_
)
642 const union wtap_pseudo_header
*pseudo_header
= &rec
->rec_header
.packet_header
.pseudo_header
;
643 struct visual_write_info
* visual
= (struct visual_write_info
*)wdh
->priv
;
644 struct visual_pkt_hdr vpkt_hdr
= {0};
645 size_t hdr_size
= sizeof vpkt_hdr
;
647 uint32_t packet_status
;
649 /* We can only write packet records. */
650 if (rec
->rec_type
!= REC_TYPE_PACKET
) {
651 *err
= WTAP_ERR_UNWRITABLE_REC_TYPE
;
656 * Make sure this packet doesn't have a link-layer type that
657 * differs from the one for the file.
659 if (wdh
->file_encap
!= rec
->rec_header
.packet_header
.pkt_encap
) {
660 *err
= WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED
;
664 /* Don't write anything we're not willing to read. */
665 if (rec
->rec_header
.packet_header
.caplen
> WTAP_MAX_PACKET_SIZE_STANDARD
) {
666 *err
= WTAP_ERR_PACKET_TOO_LARGE
;
670 /* If the visual structure was never allocated then nothing useful
675 /* Visual UpTime capture files have a capture start time in the
676 file header. Each packet has a capture time (in msec) relative
677 to the file start time. Use the time of the first packet as the
679 if (visual
->index_table_index
== 0)
682 * This is the first packet. Save its start time as the file time.
684 * XXX - is the start time signed, or unsigned? If it's signed,
685 * in which case we should check against INT32_MIN and INT32_MAX
686 * and make start_time a int32_t.
688 if (rec
->ts
.secs
< 0 || rec
->ts
.secs
> WTAP_NSTIME_32BIT_SECS_MAX
) {
689 *err
= WTAP_ERR_TIME_STAMP_NOT_SUPPORTED
;
692 visual
->start_time
= (uint32_t)rec
->ts
.secs
;
694 /* Initialize the index table */
695 visual
->index_table
= (uint32_t *)g_malloc(1024 * sizeof *visual
->index_table
);
696 visual
->index_table_size
= 1024;
699 /* Calculate milliseconds since capture start. */
700 delta_msec
= rec
->ts
.nsecs
/ 1000000;
701 delta_msec
+= (uint32_t)((rec
->ts
.secs
- visual
->start_time
) * 1000);
702 vpkt_hdr
.ts_delta
= GUINT32_TO_LE(delta_msec
);
704 /* Fill in the length fields. */
705 vpkt_hdr
.orig_len
= GUINT16_TO_LE(rec
->rec_header
.packet_header
.len
);
706 vpkt_hdr
.incl_len
= GUINT16_TO_LE(rec
->rec_header
.packet_header
.caplen
);
708 /* Fill in the encapsulation hint for the file's media type. */
709 switch (wdh
->file_encap
)
711 case WTAP_ENCAP_ETHERNET
: /* Ethernet */
712 vpkt_hdr
.encap_hint
= 2;
714 case WTAP_ENCAP_TOKEN_RING
: /* Token Ring */
715 vpkt_hdr
.encap_hint
= 3;
717 case WTAP_ENCAP_PPP
: /* PPP */
718 case WTAP_ENCAP_PPP_WITH_PHDR
:
719 vpkt_hdr
.encap_hint
= 14;
721 case WTAP_ENCAP_CHDLC_WITH_PHDR
: /* HDLC Router */
722 vpkt_hdr
.encap_hint
= 13;
724 case WTAP_ENCAP_FRELAY_WITH_PHDR
: /* Frame Relay Auto-detect */
725 vpkt_hdr
.encap_hint
= 12;
727 case WTAP_ENCAP_LAPB
: /* Unknown */
729 vpkt_hdr
.encap_hint
= 1;
733 /* Set status flags. The only status currently supported for all
734 encapsulations is direction. This either goes in the p2p or the
735 X.25 pseudo header. It would probably be better to move this up
738 switch (wdh
->file_encap
)
740 case WTAP_ENCAP_CHDLC_WITH_PHDR
:
741 packet_status
|= (pseudo_header
->p2p
.sent
? PS_SENT
: 0x00);
744 case WTAP_ENCAP_FRELAY_WITH_PHDR
:
745 case WTAP_ENCAP_LAPB
:
747 ((pseudo_header
->dte_dce
.flags
& FROM_DCE
) ? 0x00 : PS_SENT
);
750 vpkt_hdr
.status
= GUINT32_TO_LE(packet_status
);
752 /* Write the packet header. */
753 if (!wtap_dump_file_write(wdh
, &vpkt_hdr
, hdr_size
, err
))
756 /* Write the packet data */
757 if (!wtap_dump_file_write(wdh
, pd
, rec
->rec_header
.packet_header
.caplen
, err
))
760 /* Store the frame offset in the index table. */
761 if (visual
->index_table_index
>= visual
->index_table_size
)
763 /* End of table reached. Reallocate with a larger size */
764 visual
->index_table_size
*= 2;
765 visual
->index_table
= (uint32_t *)g_realloc(visual
->index_table
,
766 visual
->index_table_size
* sizeof *visual
->index_table
);
768 visual
->index_table
[visual
->index_table_index
] = GUINT32_TO_LE(visual
->next_offset
);
770 /* Update the table index and offset for the next frame. */
771 visual
->index_table_index
++;
772 visual
->next_offset
+= (uint32_t) hdr_size
+ rec
->rec_header
.packet_header
.caplen
;
778 /* Finish writing to a dump file.
779 Returns true on success, false on failure. */
780 static bool visual_dump_finish(wtap_dumper
*wdh
, int *err
,
783 struct visual_write_info
* visual
= (struct visual_write_info
*)wdh
->priv
;
785 struct visual_file_hdr vfile_hdr
= {0};
789 /* If the visual structure was never allocated then nothing useful
794 /* Write out the frame table at the end of the file. */
795 if (visual
->index_table
)
797 /* Write the index table to the file. */
798 n_to_write
= visual
->index_table_index
* sizeof *visual
->index_table
;
799 if (!wtap_dump_file_write(wdh
, visual
->index_table
, n_to_write
, err
))
801 visual_dump_free(wdh
);
806 /* Write the magic number at the start of the file. */
807 if (wtap_dump_file_seek(wdh
, 0, SEEK_SET
, err
) == -1)
809 magicp
= visual_magic
;
810 magic_size
= sizeof visual_magic
;
811 if (!wtap_dump_file_write(wdh
, magicp
, magic_size
, err
))
813 visual_dump_free(wdh
);
817 vfile_hdr
.num_pkts
= GUINT32_TO_LE(visual
->index_table_index
);
818 vfile_hdr
.start_time
= GUINT32_TO_LE(visual
->start_time
);
819 vfile_hdr
.max_length
= GUINT16_TO_LE(65535);
820 vfile_hdr
.file_flags
= GUINT16_TO_LE(1); /* indexes are present */
821 vfile_hdr
.file_version
= GUINT16_TO_LE(1);
822 (void) g_strlcpy(vfile_hdr
.description
, "Wireshark file", 64);
824 /* Translate the encapsulation type */
825 switch (wdh
->file_encap
)
827 case WTAP_ENCAP_ETHERNET
:
828 vfile_hdr
.media_type
= GUINT16_TO_LE(6);
831 case WTAP_ENCAP_TOKEN_RING
:
832 vfile_hdr
.media_type
= GUINT16_TO_LE(9);
835 case WTAP_ENCAP_LAPB
:
836 vfile_hdr
.media_type
= GUINT16_TO_LE(16);
839 case WTAP_ENCAP_PPP
: /* PPP is differentiated from CHDLC in PktHdr */
840 case WTAP_ENCAP_PPP_WITH_PHDR
:
841 case WTAP_ENCAP_CHDLC_WITH_PHDR
:
842 vfile_hdr
.media_type
= GUINT16_TO_LE(22);
845 case WTAP_ENCAP_FRELAY_WITH_PHDR
:
846 vfile_hdr
.media_type
= GUINT16_TO_LE(32);
850 /* Write the file header following the magic bytes. */
851 if (!wtap_dump_file_write(wdh
, &vfile_hdr
, sizeof vfile_hdr
, err
))
853 visual_dump_free(wdh
);
857 /* Deallocate the file write data */
858 visual_dump_free(wdh
);
863 /* Free the memory allocated by a visual file writer. */
864 static void visual_dump_free(wtap_dumper
*wdh
)
866 struct visual_write_info
* visual
= (struct visual_write_info
*)wdh
->priv
;
870 /* Free the index table memory. */
871 g_free(visual
->index_table
);
875 static const struct supported_block_type visual_blocks_supported
[] = {
877 * We support packet blocks, with no comments or other options.
879 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
882 static const struct file_type_subtype_info visual_info
= {
883 "Visual Networks traffic capture", "visual", NULL
, NULL
,
884 true, BLOCKS_SUPPORTED(visual_blocks_supported
),
885 visual_dump_can_write_encap
, visual_dump_open
, NULL
888 void register_visual(void)
890 visual_file_type_subtype
= wtap_register_file_type_subtype(&visual_info
);
893 * Register name for backwards compatibility with the
894 * wtap_filetypes table in Lua.
896 wtap_register_backwards_compatibility_lua_name("VISUAL_NETWORKS",
897 visual_file_type_subtype
);
901 * Editor modelines - https://www.wireshark.org/tools/modelines.html
906 * indent-tabs-mode: nil
909 * vi: set shiftwidth=4 tabstop=8 expandtab:
910 * :indentSize=4:tabSize=8:noTabs=true: