1 /* visual.c
2  * File read and write routines for Visual Networks cap files.
3  * Copyright (c) 2001, Tom Nisbet  tnisbet@visualnetworks.com
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "config.h"
12 #include <errno.h>
13 #include <string.h>
14 #include "wtap-int.h"
15 #include "file_wrappers.h"
16 #include "visual.h"
17 
18 /*
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.
26  *
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.
29  *
30  * [ File Header ]
31  *
32  *
33  * [ Packet Header 1 ] [(opt) ATM Packet Header] [ Data ]
34  * ...
35  * [ Packet Header n ] [(opt) ATM Packet Header] [ Data ]
36  *
37  *
38  * [ Index Block 1 ] ... [ Index Block n ]
39  */
40 
41 /* Capture file header, INCLUDING the magic number, is 192 bytes. */
42 #define CAPTUREFILE_HEADER_SIZE 192
43 
44 /* Magic number for Visual Networks traffic capture files. */
45 static const char visual_magic[] = {
46     5, 'V', 'N', 'F'
47 };
48 
49 
50 /* Visual File Header (minus magic number). */
51 /* This structure is used to extract information */
52 struct visual_file_hdr
53 {
54     guint32 num_pkts;           /* Number of packets in the file */
55     guint32 start_time;         /* Capture start time in PC format */
56     guint16 media_type;         /* IANA ifType of packet source */
57     guint16 max_length;         /* Max allowable stored packet length */
58     guint16 file_flags;         /* File type flags */
59                                 /*   Bit 0 indicates indexes present */
60     guint16 file_version;       /* Version number of this file format */
61     guint32 media_speed;        /* ifSpeed of packet source in bits/sec. */
62     guint16 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) */
65 };
66 
67 
68 /* Packet status bits */
69 #define PS_LONG             0x01
70 #define PS_SHORT            0x02
71 #define PS_ERRORED          0x04
72 #define PS_1ST_AFTER_DROP   0x08
73 #define PS_APPROX_ORDER     0x10
74 #define PS_SENT             0x40
75 #define PS_ABORTED          0x80
76 
77 /* Visual Packet Header */
78 /* This structure is used to extract information */
79 struct visual_pkt_hdr
80 {
81     guint32 ts_delta;           /* Time stamp - msecs since start of capture */
82     guint16 orig_len;           /* Actual length of packet */
83     guint16 incl_len;           /* Number of octets captured in file */
84     guint32 status;             /* Packet status flags (media specific) */
85     guint8  encap_hint;         /* Encapsulation type hint */
86     guint8  encap_skip;         /* Number of bytes to skip before decoding */
87     char    RESERVED_[6];       /* RESERVED - must be zero */
88 };
89 
90 /* Optional Visual ATM Packet Header */
91 /* This structure is used to extract information */
92 struct visual_atm_hdr
93 {
94    guint16 vpi;           /* 4 bits of zeros; 12 bits of ATM VPI */
95    guint16 vci;           /* ATM VCI */
96    guint8  info;          /* 4 bits version; 3 bits unused-zero; 1 bit direction */
97    guint8  category;      /* indicates type of traffic. 4 bits of status + 4 bits of type */
98    guint16 cell_count;    /* number of cells that make up this pdu */
99    guint32 data_length;   /* PDU data length for AAL-5 PDUs, all others - cellcount * 48 */
100    guint32 ts_secs;       /* seonds value of sysUpTime when the last cell of this PDU was captured */
101    guint32 ts_nsec;       /* nanoseonds value of sysUpTime when the last cell of this PDU was captured */
102 
103 };
104 
105 /* visual_atm_hdr info bit definitions */
106 #define FROM_NETWORK       0x01
107 #define ATM_VER_MASK       0xf0  /* Not currently displayed */
108 
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
114 /* Low nibble */
115 #define VN_UNKNOWN         0x00
116 #define VN_AAL1            0x01
117 #define VN_AAL2            0x02
118 #define VN_AAL34           0x03
119 #define VN_O191            0x04
120 #define VN_AAL5            0x05
121 #define VN_OAM             0x0a
122 #define VN_RM              0x0b
123 #define VN_IDLE            0x0c
124 #define VN_CAT_TYPE_MASK   0x0f
125 
126 
127 /* Additional information for reading Visual files */
128 struct visual_read_info
129 {
130     guint32 num_pkts;           /* Number of pkts in the file */
131     guint32 current_pkt;        /* Next packet to be read */
132     time_t  start_time;         /* Capture start time in seconds */
133 };
134 
135 
136 /* Additional information for writing Visual files */
137 struct visual_write_info
138 {
139     time_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     guint32 * index_table;      /* File offsets for the packets */
143     guint32 next_offset;        /* Offset of next packet */
144 };
145 
146 
147 /* Local functions to handle file reads and writes */
148 static gboolean visual_read(wtap *wth, wtap_rec *rec, Buffer *buf,
149     int *err, gchar **err_info, gint64 *data_offset);
150 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
151     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
152 static gboolean visual_read_packet(wtap *wth, FILE_T fh,
153     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
154 static gboolean visual_dump(wtap_dumper *wdh, const wtap_rec *rec,
155     const guint8 *pd, int *err, gchar **err_info);
156 static gboolean visual_dump_finish(wtap_dumper *wdh, int *err,
157     gchar **err_info);
158 static void visual_dump_free(wtap_dumper *wdh);
159 
160 static int visual_file_type_subtype = -1;
161 
162 void register_visual(void);
163 
164 
165 /* Open a file for reading */
visual_open(wtap * wth,int * err,gchar ** err_info)166 wtap_open_return_val visual_open(wtap *wth, int *err, gchar **err_info)
167 {
168     char magic[sizeof visual_magic];
169     struct visual_file_hdr vfile_hdr;
170     struct visual_read_info * visual;
171     int encap;
172 
173     /* Check the magic string at the start of the file */
174     if (!wtap_read_bytes(wth->fh, magic, sizeof magic, err, err_info))
175     {
176         if (*err != WTAP_ERR_SHORT_READ)
177             return WTAP_OPEN_ERROR;
178         return WTAP_OPEN_NOT_MINE;
179     }
180     if (memcmp(magic, visual_magic, sizeof visual_magic) != 0)
181     {
182         return WTAP_OPEN_NOT_MINE;
183     }
184 
185     /* Read the rest of the file header. */
186     if (!wtap_read_bytes(wth->fh, &vfile_hdr, sizeof vfile_hdr, err, err_info))
187     {
188         return WTAP_OPEN_ERROR;
189     }
190 
191     /* Verify the file version is known */
192     vfile_hdr.file_version = pletoh16(&vfile_hdr.file_version);
193     if (vfile_hdr.file_version != 1)
194     {
195         *err = WTAP_ERR_UNSUPPORTED;
196         *err_info = g_strdup_printf("visual: file version %u unsupported", vfile_hdr.file_version);
197         return WTAP_OPEN_ERROR;
198     }
199 
200     /* Translate the encapsulation type; these values are SNMP ifType
201        values, as found in https://www.iana.org/assignments/smi-numbers.
202 
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.
206 
207        XXX - should we use WTAP_ENCAP_PER_PACKET for that? */
208     switch (pletoh16(&vfile_hdr.media_type))
209     {
210     case  6:    /* ethernet-csmacd */
211         encap = WTAP_ENCAP_ETHERNET;
212         break;
213 
214     case  9:    /* IEEE802.5 */
215         encap = WTAP_ENCAP_TOKEN_RING;
216         break;
217 
218     case 16:    /* lapb */
219         encap = WTAP_ENCAP_LAPB;
220         break;
221 
222     case 22:    /* propPointToPointSerial */
223     case 118:   /* HDLC */
224         encap = WTAP_ENCAP_CHDLC_WITH_PHDR;
225         break;
226 
227     case 32:    /* frame-relay */
228         encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
229         break;
230 
231     case 37:    /* ATM */
232        encap = WTAP_ENCAP_ATM_PDUS;
233        break;
234 
235     default:
236         *err = WTAP_ERR_UNSUPPORTED;
237         *err_info = g_strdup_printf("visual: network type %u unknown or unsupported",
238                                      vfile_hdr.media_type);
239         return WTAP_OPEN_ERROR;
240     }
241 
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);
246 
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;
251 
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;
258 
259     /*
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.
264      */
265     wtap_add_generated_idb(wth);
266 
267     return WTAP_OPEN_MINE;
268 }
269 
270 
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. */
visual_read(wtap * wth,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info,gint64 * data_offset)275 static gboolean visual_read(wtap *wth, wtap_rec *rec, Buffer *buf,
276     int *err, gchar **err_info, gint64 *data_offset)
277 {
278     struct visual_read_info *visual = (struct visual_read_info *)wth->priv;
279 
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
282        packet's data. */
283     if (visual->current_pkt > visual->num_pkts)
284     {
285         *err = 0;   /* it's just an EOF, not an error */
286         return FALSE;
287     }
288     visual->current_pkt++;
289 
290     *data_offset = file_tell(wth->fh);
291 
292     return visual_read_packet(wth, wth->fh, rec, buf, err, err_info);
293 }
294 
295 /* Read packet header and data for random access. */
visual_seek_read(wtap * wth,gint64 seek_off,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)296 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
297     wtap_rec *rec, Buffer *buf, int *err, gchar **err_info)
298 {
299     /* Seek to the packet header */
300     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
301         return FALSE;
302 
303     /* Read the packet. */
304     if (!visual_read_packet(wth, wth->random_fh, rec, buf, err, err_info)) {
305         if (*err == 0)
306             *err = WTAP_ERR_SHORT_READ;
307         return FALSE;
308     }
309     return TRUE;
310 }
311 
312 static gboolean
visual_read_packet(wtap * wth,FILE_T fh,wtap_rec * rec,Buffer * buf,int * err,gchar ** err_info)313 visual_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
314         Buffer *buf, int *err, gchar **err_info)
315 {
316     struct visual_read_info *visual = (struct visual_read_info *)wth->priv;
317     struct visual_pkt_hdr vpkt_hdr;
318     guint32 packet_size;
319     struct visual_atm_hdr vatm_hdr;
320     guint32 relmsecs;
321     guint32 packet_status;
322     guint8 *pd;
323 
324     /* Read the packet header. */
325     if (!wtap_read_bytes_or_eof(fh, &vpkt_hdr, (unsigned int)sizeof vpkt_hdr, err, err_info))
326     {
327         return FALSE;
328     }
329 
330     /* Get the included length of data. This includes extra headers + payload */
331     packet_size = pletoh16(&vpkt_hdr.incl_len);
332 
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;
336 
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;
341 
342     rec->rec_header.packet_header.len = pletoh16(&vpkt_hdr.orig_len);
343 
344     packet_status = pletoh32(&vpkt_hdr.status);
345 
346     /* Do encapsulation-specific processing.
347 
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.
354 
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.
360 
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
364        into the phdr. */
365     switch (wth->file_encap)
366     {
367     case WTAP_ENCAP_ETHERNET:
368         /* Ethernet has a 4-byte FCS. */
369         if (rec->rec_header.packet_header.len < 4)
370         {
371             *err = WTAP_ERR_BAD_FILE;
372             *err_info = g_strdup_printf("visual: Ethernet packet has %u-byte original packet, less than the FCS length",
373                         rec->rec_header.packet_header.len);
374             return FALSE;
375         }
376         rec->rec_header.packet_header.len -= 4;
377 
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;
381         break;
382 
383     case WTAP_ENCAP_CHDLC_WITH_PHDR:
384         /* This has a 2-byte FCS. */
385         if (rec->rec_header.packet_header.len < 2)
386         {
387             *err = WTAP_ERR_BAD_FILE;
388             *err_info = g_strdup_printf("visual: Cisco HDLC packet has %u-byte original packet, less than the FCS length",
389                         rec->rec_header.packet_header.len);
390             return FALSE;
391         }
392         rec->rec_header.packet_header.len -= 2;
393 
394         rec->rec_header.packet_header.pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
395         break;
396 
397     case WTAP_ENCAP_PPP_WITH_PHDR:
398         /* No FCS.
399            XXX - true?  Note that PPP can negotiate no FCS, a 2-byte FCS,
400            or a 4-byte FCS. */
401         rec->rec_header.packet_header.pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
402         break;
403 
404     case WTAP_ENCAP_FRELAY_WITH_PHDR:
405         /* This has a 2-byte FCS. */
406         if (rec->rec_header.packet_header.len < 2)
407         {
408             *err = WTAP_ERR_BAD_FILE;
409             *err_info = g_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
410                         rec->rec_header.packet_header.len);
411             return FALSE;
412         }
413         rec->rec_header.packet_header.len -= 2;
414 
415         rec->rec_header.packet_header.pseudo_header.dte_dce.flags =
416             (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
417         break;
418 
419     case WTAP_ENCAP_LAPB:
420         /* This has a 2-byte FCS. */
421         if (rec->rec_header.packet_header.len < 2)
422         {
423             *err = WTAP_ERR_BAD_FILE;
424             *err_info = g_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
425                         rec->rec_header.packet_header.len);
426             return FALSE;
427         }
428         rec->rec_header.packet_header.len -= 2;
429 
430         rec->rec_header.packet_header.pseudo_header.dte_dce.flags =
431             (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
432         break;
433 
434     case WTAP_ENCAP_ATM_PDUS:
435         /* ATM original length doesn't include any FCS. Do nothing to
436            the packet length.
437 
438            ATM packets have an additional packet header; read and
439            process it. */
440         if (!wtap_read_bytes(fh, &vatm_hdr, (unsigned int)sizeof vatm_hdr, err, err_info))
441         {
442             return FALSE;
443         }
444 
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 -= (guint32)sizeof vatm_hdr;
449 
450         /* Set defaults */
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;
454 
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;
458 
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;
461 
462         /* Not supported. Defaulting to zero */
463         rec->rec_header.packet_header.pseudo_header.atm.aal2_cid = 0;
464 
465         switch(vatm_hdr.category & VN_CAT_TYPE_MASK )
466         {
467         case VN_AAL1:
468             rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_1;
469             break;
470 
471         case VN_AAL2:
472             rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_2;
473             break;
474 
475         case VN_AAL34:
476             rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_3_4;
477             break;
478 
479         case VN_AAL5:
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);
483             break;
484 
485         case VN_OAM:
486         /* Marking next 3 as OAM versus unknown */
487         case VN_O191:
488         case VN_IDLE:
489         case VN_RM:
490             rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_OAMCELL;
491             break;
492 
493         case VN_UNKNOWN:
494         default:
495             rec->rec_header.packet_header.pseudo_header.atm.aal = AAL_UNKNOWN;
496             break;
497         }
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);
501 
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;
504         break;
505 
506     /* Not sure about token ring. Just leaving alone for now. */
507     case WTAP_ENCAP_TOKEN_RING:
508     default:
509         break;
510     }
511 
512     rec->rec_header.packet_header.caplen = packet_size;
513 
514     /* Check for too-large packet. */
515     if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD)
516     {
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 = g_strdup_printf("visual: File has %u-byte packet, bigger than maximum of %u",
521             packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
522         return FALSE;
523     }
524 
525     /* Read the packet data */
526     if (!wtap_read_packet_bytes(fh, buf, packet_size, err, err_info))
527         return FALSE;
528 
529     if (wth->file_encap == WTAP_ENCAP_CHDLC_WITH_PHDR)
530     {
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.
534 
535            The encapsulation hint values we've seen are:
536 
537              2 - seen in an Ethernet capture
538              13 - seen in a PPP capture; possibly also seen in Cisco HDLC
539                   captures
540              14 - seen in a PPP capture; probably seen only for PPP.
541 
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);
548 
549         /* If PPP is specified in the encap hint, then use that */
550         if (vpkt_hdr.encap_hint == 14)
551         {
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]))
556             {
557                 /* It is actually LLC encapsulated PPP */
558                 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_ATM_RFC1483;
559             }
560             else
561             {
562                 /* It is actually PPP */
563                 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
564             }
565         }
566         else
567         {
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]))
571             {
572                 /* It is actually PPP */
573                 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
574             }
575         }
576     }
577 
578     return TRUE;
579 }
580 
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. */
visual_dump_can_write_encap(int encap)584 static int visual_dump_can_write_encap(int encap)
585 {
586     /* Per-packet encapsulations aren't supported. */
587     if (encap == WTAP_ENCAP_PER_PACKET)
588         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
589 
590     /* Check for supported encapsulation types */
591     switch (encap)
592     {
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:
598     case WTAP_ENCAP_PPP:
599     case WTAP_ENCAP_PPP_WITH_PHDR:
600         return 0;
601     }
602 
603     return WTAP_ERR_UNWRITABLE_ENCAP;
604 }
605 
606 
607 /* Open a file for writing.
608    Returns TRUE on success, FALSE on failure; sets "*err" to an
609    error code on failure */
visual_dump_open(wtap_dumper * wdh,int * err,gchar ** err_info _U_)610 static gboolean visual_dump_open(wtap_dumper *wdh, int *err, gchar **err_info _U_)
611 {
612     struct visual_write_info *visual;
613 
614     /* Set the write routines for a visual file. */
615     wdh->subtype_write = visual_dump;
616     wdh->subtype_finish = visual_dump_finish;
617 
618     /* Create a struct to hold file information for the duration
619        of the write */
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;
626 
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)
631         return FALSE;
632 
633     return TRUE;
634 }
635 
636 
637 /* Write a packet to a Visual dump file.
638    Returns TRUE on success, FALSE on failure. */
visual_dump(wtap_dumper * wdh,const wtap_rec * rec,const guint8 * pd,int * err,gchar ** err_info _U_)639 static gboolean visual_dump(wtap_dumper *wdh, const wtap_rec *rec,
640     const guint8 *pd, int *err, gchar **err_info _U_)
641 {
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;
646     guint delta_msec;
647     guint32 packet_status;
648 
649     /* We can only write packet records. */
650     if (rec->rec_type != REC_TYPE_PACKET) {
651         *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
652         return FALSE;
653     }
654 
655     /*
656      * Make sure this packet doesn't have a link-layer type that
657      * differs from the one for the file.
658      */
659     if (wdh->encap != rec->rec_header.packet_header.pkt_encap) {
660         *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
661         return FALSE;
662     }
663 
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;
667         return FALSE;
668     }
669 
670     /* If the visual structure was never allocated then nothing useful
671        can be done. */
672     if (visual == 0)
673         return FALSE;
674 
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
678        file start time. */
679     if (visual->index_table_index == 0)
680     {
681         /* This is the first packet.  Save its start time as the file time. */
682         visual->start_time = rec->ts.secs;
683 
684         /* Initialize the index table */
685         visual->index_table = (guint32 *)g_malloc(1024 * sizeof *visual->index_table);
686         visual->index_table_size = 1024;
687     }
688 
689     /* Calculate milliseconds since capture start. */
690     delta_msec = rec->ts.nsecs / 1000000;
691     delta_msec += (guint32)((rec->ts.secs - visual->start_time) * 1000);
692     vpkt_hdr.ts_delta = GUINT32_TO_LE(delta_msec);
693 
694     /* Fill in the length fields. */
695     vpkt_hdr.orig_len = GUINT16_TO_LE(rec->rec_header.packet_header.len);
696     vpkt_hdr.incl_len = GUINT16_TO_LE(rec->rec_header.packet_header.caplen);
697 
698     /* Fill in the encapsulation hint for the file's media type. */
699     switch (wdh->encap)
700     {
701     case WTAP_ENCAP_ETHERNET:   /* Ethernet */
702         vpkt_hdr.encap_hint = 2;
703         break;
704     case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
705         vpkt_hdr.encap_hint = 3;
706         break;
707     case WTAP_ENCAP_PPP:        /* PPP */
708     case WTAP_ENCAP_PPP_WITH_PHDR:
709         vpkt_hdr.encap_hint = 14;
710         break;
711     case WTAP_ENCAP_CHDLC_WITH_PHDR:      /* HDLC Router */
712         vpkt_hdr.encap_hint = 13;
713         break;
714     case WTAP_ENCAP_FRELAY_WITH_PHDR:     /* Frame Relay Auto-detect */
715         vpkt_hdr.encap_hint = 12;
716         break;
717     case WTAP_ENCAP_LAPB:       /* Unknown */
718     default:
719         vpkt_hdr.encap_hint = 1;
720         break;
721     }
722 
723     /* Set status flags.  The only status currently supported for all
724        encapsulations is direction.  This either goes in the p2p or the
725        X.25 pseudo header.  It would probably be better to move this up
726        into the phdr. */
727     packet_status = 0;
728     switch (wdh->encap)
729     {
730     case WTAP_ENCAP_CHDLC_WITH_PHDR:
731         packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
732         break;
733 
734     case WTAP_ENCAP_FRELAY_WITH_PHDR:
735     case WTAP_ENCAP_LAPB:
736         packet_status |=
737             ((pseudo_header->dte_dce.flags & FROM_DCE) ? 0x00 : PS_SENT);
738         break;
739     }
740     vpkt_hdr.status = GUINT32_TO_LE(packet_status);
741 
742     /* Write the packet header. */
743     if (!wtap_dump_file_write(wdh, &vpkt_hdr, hdr_size, err))
744         return FALSE;
745 
746     /* Write the packet data */
747     if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
748         return FALSE;
749 
750     /* Store the frame offset in the index table. */
751     if (visual->index_table_index >= visual->index_table_size)
752     {
753         /* End of table reached.  Reallocate with a larger size */
754         visual->index_table_size *= 2;
755         visual->index_table = (guint32 *)g_realloc(visual->index_table,
756             visual->index_table_size * sizeof *visual->index_table);
757     }
758     visual->index_table[visual->index_table_index] = GUINT32_TO_LE(visual->next_offset);
759 
760     /* Update the table index and offset for the next frame. */
761     visual->index_table_index++;
762     visual->next_offset += (guint32) hdr_size + rec->rec_header.packet_header.caplen;
763 
764     return TRUE;
765 }
766 
767 
768 /* Finish writing to a dump file.
769    Returns TRUE on success, FALSE on failure. */
visual_dump_finish(wtap_dumper * wdh,int * err,gchar ** err_info _U_)770 static gboolean visual_dump_finish(wtap_dumper *wdh, int *err,
771     gchar **err_info _U_)
772 {
773     struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
774     size_t n_to_write;
775     struct visual_file_hdr vfile_hdr = {0};
776     const char *magicp;
777     size_t magic_size;
778 
779     /* If the visual structure was never allocated then nothing useful
780        can be done. */
781     if (visual == 0)
782         return FALSE;
783 
784     /* Write out the frame table at the end of the file. */
785     if (visual->index_table)
786     {
787         /* Write the index table to the file. */
788         n_to_write = visual->index_table_index * sizeof *visual->index_table;
789         if (!wtap_dump_file_write(wdh, visual->index_table, n_to_write, err))
790         {
791             visual_dump_free(wdh);
792             return FALSE;
793         }
794     }
795 
796     /* Write the magic number at the start of the file. */
797     if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
798         return FALSE;
799     magicp = visual_magic;
800     magic_size = sizeof visual_magic;
801     if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
802     {
803         visual_dump_free(wdh);
804         return FALSE;
805     }
806 
807     vfile_hdr.num_pkts = GUINT32_TO_LE(visual->index_table_index);
808     vfile_hdr.start_time = GUINT32_TO_LE(visual->start_time);
809     vfile_hdr.max_length = GUINT16_TO_LE(65535);
810     vfile_hdr.file_flags = GUINT16_TO_LE(1);  /* indexes are present */
811     vfile_hdr.file_version = GUINT16_TO_LE(1);
812     (void) g_strlcpy(vfile_hdr.description, "Wireshark file", 64);
813 
814     /* Translate the encapsulation type */
815     switch (wdh->encap)
816     {
817     case WTAP_ENCAP_ETHERNET:
818         vfile_hdr.media_type = GUINT16_TO_LE(6);
819         break;
820 
821     case WTAP_ENCAP_TOKEN_RING:
822         vfile_hdr.media_type = GUINT16_TO_LE(9);
823         break;
824 
825     case WTAP_ENCAP_LAPB:
826         vfile_hdr.media_type = GUINT16_TO_LE(16);
827         break;
828 
829     case WTAP_ENCAP_PPP:        /* PPP is differentiated from CHDLC in PktHdr */
830     case WTAP_ENCAP_PPP_WITH_PHDR:
831     case WTAP_ENCAP_CHDLC_WITH_PHDR:
832         vfile_hdr.media_type = GUINT16_TO_LE(22);
833         break;
834 
835     case WTAP_ENCAP_FRELAY_WITH_PHDR:
836         vfile_hdr.media_type = GUINT16_TO_LE(32);
837         break;
838     }
839 
840     /* Write the file header following the magic bytes. */
841     if (!wtap_dump_file_write(wdh, &vfile_hdr, sizeof vfile_hdr, err))
842     {
843         visual_dump_free(wdh);
844         return FALSE;
845     }
846 
847     /* Deallocate the file write data */
848     visual_dump_free(wdh);
849     return TRUE;
850 }
851 
852 
853 /* Free the memory allocated by a visual file writer. */
visual_dump_free(wtap_dumper * wdh)854 static void visual_dump_free(wtap_dumper *wdh)
855 {
856     struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
857 
858     if (visual)
859     {
860         /* Free the index table memory. */
861         g_free(visual->index_table);
862     }
863 }
864 
865 static const struct supported_block_type visual_blocks_supported[] = {
866     /*
867      * We support packet blocks, with no comments or other options.
868      */
869     { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
870 };
871 
872 static const struct file_type_subtype_info visual_info = {
873     "Visual Networks traffic capture", "visual", NULL, NULL,
874     TRUE, BLOCKS_SUPPORTED(visual_blocks_supported),
875     visual_dump_can_write_encap, visual_dump_open, NULL
876 };
877 
register_visual(void)878 void register_visual(void)
879 {
880     visual_file_type_subtype = wtap_register_file_type_subtype(&visual_info);
881 
882     /*
883      * Register name for backwards compatibility with the
884      * wtap_filetypes table in Lua.
885      */
886     wtap_register_backwards_compatibility_lua_name("VISUAL_NETWORKS",
887                                                    visual_file_type_subtype);
888 }
889 
890 /*
891  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
892  *
893  * Local variables:
894  * c-basic-offset: 4
895  * tab-width: 8
896  * indent-tabs-mode: nil
897  * End:
898  *
899  * vi: set shiftwidth=4 tabstop=8 expandtab:
900  * :indentSize=4:tabSize=8:noTabs=true:
901  */
902