RtpAudioStream: Add a cast.
[metze/wireshark/wip.git] / wiretap / visual.c
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  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include <errno.h>
25 #include <string.h>
26 #include "wtap-int.h"
27 #include "file_wrappers.h"
28 #include "visual.h"
29
30 /*
31  * A Visual Networks traffic capture file contains three sections. The
32  * first is a 192 octet file header.  This is followed by the captured
33  * packet header, and for ATM captures, there is an additional atm packet header.
34  * The data follows the packet header. The last section is the packet index block.
35  * The index block contains one 4 octet pointer for each captured packet.
36  * The first packet index is (4 * num_pkts) octets from the end of the file
37  * and the last index is in the last four octets of the file.
38  *
39  * All integer and time values are stored in little-endian format, except for
40  *  the ATM Packet Header, which is stored in network byte order.
41  *
42  * [ File Header ]
43  *
44  *
45  * [ Packet Header 1 ] [(opt) ATM Packet Header] [ Data ]
46  * ...
47  * [ Packet Header n ] [(opt) ATM Packet Header] [ Data ]
48  *
49  *
50  * [ Index Block 1 ] ... [ Index Block n ]
51  */
52
53 /* Capture file header, INCLUDING the magic number, is 192 bytes. */
54 #define CAPTUREFILE_HEADER_SIZE 192
55
56 /* Magic number for Visual Networks traffic capture files. */
57 static const char visual_magic[] = {
58     5, 'V', 'N', 'F'
59 };
60
61
62 /* Visual File Header (minus magic number). */
63 /* This structure is used to extract information */
64 struct visual_file_hdr
65 {
66     guint32 num_pkts;           /* Number of packets in the file */
67     guint32 start_time;         /* Capture start time in PC format */
68     guint16 media_type;         /* IANA ifType of packet source */
69     guint16 max_length;         /* Max allowable stored packet length */
70     guint16 file_flags;         /* File type flags */
71                                 /*   Bit 0 indicates indexes present */
72     guint16 file_version;       /* Version number of this file format */
73     guint32 media_speed;        /* ifSpeed of packet source in bits/sec. */
74     guint16 media_param;        /* Media-specific extra parameter. */
75     char    RESERVED_[102];     /* MUST BE ALL ZEROS FOR FUTURE COMPATABILITY */
76     char    description[64];    /* File description (null terminated) */
77 };
78
79
80 /* Packet status bits */
81 #define PS_LONG             0x01
82 #define PS_SHORT            0x02
83 #define PS_ERRORED          0x04
84 #define PS_1ST_AFTER_DROP   0x08
85 #define PS_APPROX_ORDER     0x10
86 #define PS_SENT             0x40
87 #define PS_ABORTED          0x80
88
89 /* Visual Packet Header */
90 /* This structure is used to extract information */
91 struct visual_pkt_hdr
92 {
93     guint32 ts_delta;           /* Time stamp - msecs since start of capture */
94     guint16 orig_len;           /* Actual length of packet */
95     guint16 incl_len;           /* Number of octets captured in file */
96     guint32 status;             /* Packet status flags (media specific) */
97     guint8  encap_hint;         /* Encapsulation type hint */
98     guint8  encap_skip;         /* Number of bytes to skip before decoding */
99     char    RESERVED_[6];       /* RESERVED - must be zero */
100 };
101
102 /* Optional Visual ATM Packet Header */
103 /* This structure is used to extract information */
104 struct visual_atm_hdr
105 {
106    guint16 vpi;           /* 4 bits of zeros; 12 bits of ATM VPI */
107    guint16 vci;           /* ATM VCI */
108    guint8  info;          /* 4 bits version; 3 bits unused-zero; 1 bit direction */
109    guint8  category;      /* indicates type of traffic. 4 bits of status + 4 bits of type */
110    guint16 cell_count;    /* number of cells that make up this pdu */
111    guint32 data_length;   /* PDU data length for AAL-5 PDUs, all others - cellcount * 48 */
112    guint32 ts_secs;       /* seonds value of sysUpTime when the last cell of this PDU was captured */
113    guint32 ts_nsec;       /* nanoseonds value of sysUpTime when the last cell of this PDU was captured */
114
115 };
116
117 /* visual_atm_hdr info bit definitions */
118 #define FROM_NETWORK       0x01
119 #define ATM_VER_MASK       0xf0  /* Not currently displayed */
120
121 /* visual_atm_hdr category definitions */
122 /* High nibble - not currently displayed */
123 #define VN_INCOMPLETE      0x40
124 #define VN_BAD_CRC         0x80
125 #define VN_CAT_STAT_MASK   0xf0
126 /* Low nibble */
127 #define VN_UNKNOWN         0x00
128 #define VN_AAL1            0x01
129 #define VN_AAL2            0x02
130 #define VN_AAL34           0x03
131 #define VN_O191            0x04
132 #define VN_AAL5            0x05
133 #define VN_OAM             0x0a
134 #define VN_RM              0x0b
135 #define VN_IDLE            0x0c
136 #define VN_CAT_TYPE_MASK   0x0f
137
138
139 /* Additional information for reading Visual files */
140 struct visual_read_info
141 {
142     guint32 num_pkts;           /* Number of pkts in the file */
143     guint32 current_pkt;        /* Next packet to be read */
144     time_t  start_time;         /* Capture start time in seconds */
145 };
146
147
148 /* Additional information for writing Visual files */
149 struct visual_write_info
150 {
151     time_t  start_time;         /* Capture start time in seconds */
152     int     index_table_index;  /* Index of the next index entry */
153     int     index_table_size;   /* Allocated size of the index table */
154     guint32 * index_table;      /* File offsets for the packets */
155     guint32 next_offset;        /* Offset of next packet */
156 };
157
158
159 /* Local functions to handle file reads and writes */
160 static gboolean visual_read(wtap *wth, int *err, gchar **err_info,
161     gint64 *data_offset);
162 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
163     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
164 static gboolean visual_read_packet(wtap *wth, FILE_T fh,
165     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
166 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
167     const guint8 *pd, int *err, gchar **err_info);
168 static gboolean visual_dump_close(wtap_dumper *wdh, int *err);
169 static void visual_dump_free(wtap_dumper *wdh);
170
171
172 /* Open a file for reading */
173 wtap_open_return_val visual_open(wtap *wth, int *err, gchar **err_info)
174 {
175     char magic[sizeof visual_magic];
176     struct visual_file_hdr vfile_hdr;
177     struct visual_read_info * visual;
178     int encap;
179
180     /* Check the magic string at the start of the file */
181     if (!wtap_read_bytes(wth->fh, magic, sizeof magic, err, err_info))
182     {
183         if (*err != WTAP_ERR_SHORT_READ)
184             return WTAP_OPEN_ERROR;
185         return WTAP_OPEN_NOT_MINE;
186     }
187     if (memcmp(magic, visual_magic, sizeof visual_magic) != 0)
188     {
189         return WTAP_OPEN_NOT_MINE;
190     }
191
192     /* Read the rest of the file header. */
193     if (!wtap_read_bytes(wth->fh, &vfile_hdr, sizeof vfile_hdr, err, err_info))
194     {
195         return WTAP_OPEN_ERROR;
196     }
197
198     /* Verify the file version is known */
199     vfile_hdr.file_version = pletoh16(&vfile_hdr.file_version);
200     if (vfile_hdr.file_version != 1)
201     {
202         *err = WTAP_ERR_UNSUPPORTED;
203         *err_info = g_strdup_printf("visual: file version %u unsupported", vfile_hdr.file_version);
204         return WTAP_OPEN_ERROR;
205     }
206
207     /* Translate the encapsulation type; these values are SNMP ifType
208        values, as found in http://www.iana.org/assignments/smi-numbers.
209
210        Note that a file with media type 22 ("propPointToPointSerial") may
211        contain Cisco HDLC or PPP over HDLC.  This will get sorted out after
212        the first packet is read.
213
214        XXX - should we use WTAP_ENCAP_PER_PACKET for that? */
215     switch (pletoh16(&vfile_hdr.media_type))
216     {
217     case  6:    /* ethernet-csmacd */
218         encap = WTAP_ENCAP_ETHERNET;
219         break;
220
221     case  9:    /* IEEE802.5 */
222         encap = WTAP_ENCAP_TOKEN_RING;
223         break;
224
225     case 16:    /* lapb */
226         encap = WTAP_ENCAP_LAPB;
227         break;
228
229     case 22:    /* propPointToPointSerial */
230     case 118:   /* HDLC */
231         encap = WTAP_ENCAP_CHDLC_WITH_PHDR;
232         break;
233
234     case 32:    /* frame-relay */
235         encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
236         break;
237
238     case 37:    /* ATM */
239        encap = WTAP_ENCAP_ATM_PDUS;
240        break;
241
242     default:
243         *err = WTAP_ERR_UNSUPPORTED;
244         *err_info = g_strdup_printf("visual: network type %u unknown or unsupported",
245                                      vfile_hdr.media_type);
246         return WTAP_OPEN_ERROR;
247     }
248
249     /* Fill in the wiretap struct with data from the file header */
250     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_VISUAL_NETWORKS;
251     wth->file_encap = encap;
252     wth->snapshot_length = pletoh16(&vfile_hdr.max_length);
253
254     /* Set up the pointers to the handlers for this file type */
255     wth->subtype_read = visual_read;
256     wth->subtype_seek_read = visual_seek_read;
257     wth->file_tsprec = WTAP_TSPREC_MSEC;
258
259     /* Add Visual-specific information to the wiretap struct for later use. */
260     visual = (struct visual_read_info *)g_malloc(sizeof(struct visual_read_info));
261     wth->priv = (void *)visual;
262     visual->num_pkts = pletoh32(&vfile_hdr.num_pkts);
263     visual->start_time = pletoh32(&vfile_hdr.start_time);
264     visual->current_pkt = 1;
265
266     return WTAP_OPEN_MINE;
267 }
268
269
270 /* Read the next available packet from the file.  This is called
271    in a loop to sequentially read the entire file one time.  After
272    the file has been read once, any Future access to the packets is
273    done through seek_read. */
274 static gboolean visual_read(wtap *wth, int *err, gchar **err_info,
275     gint64 *data_offset)
276 {
277     struct visual_read_info *visual = (struct visual_read_info *)wth->priv;
278
279     /* Check for the end of the packet data.  Note that a check for file EOF
280        will not work because there are index values stored after the last
281        packet's data. */
282     if (visual->current_pkt > visual->num_pkts)
283     {
284         *err = 0;   /* it's just an EOF, not an error */
285         return FALSE;
286     }
287     visual->current_pkt++;
288
289     *data_offset = file_tell(wth->fh);
290
291     return visual_read_packet(wth, wth->fh, &wth->phdr, wth->frame_buffer,
292             err, err_info);
293 }
294
295 /* Read packet header and data for random access. */
296 static gboolean visual_seek_read(wtap *wth, gint64 seek_off,
297     struct wtap_pkthdr *phdr, 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, phdr, 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
313 visual_read_packet(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
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     phdr->rec_type = REC_TYPE_PACKET;
334     phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
335
336     /* Set the packet time and length. */
337     relmsecs = pletoh32(&vpkt_hdr.ts_delta);
338     phdr->ts.secs = visual->start_time + relmsecs/1000;
339     phdr->ts.nsecs = (relmsecs % 1000)*1000000;
340
341     phdr->len = pletoh16(&vpkt_hdr.orig_len);
342
343     packet_status = pletoh32(&vpkt_hdr.status);
344
345     /* Do encapsulation-specific processing.
346
347        Most Visual capture types include the FCS in the original length
348        value, but don't include the FCS as part of the payload or captured
349        length.  This is different from the model used in most other capture
350        file formats, including pcap and pcap-ng in cases where the FCS isn't
351        captured (which are the typical cases), and causes the RTP audio
352        payload save to fail since then captured len != orig len.
353
354        We adjust the original length to remove the FCS bytes we counted based
355        on the file encapsualtion type.  The only downside to this fix is
356        throughput calculations will be slightly lower as it won't include
357        the FCS bytes.  However, as noted, that problem also exists with
358        other capture formats.
359
360        We also set status flags.  The only status currently supported for
361        all encapsulations is direction.  This either goes in the p2p or the
362        X.25 pseudo header.  It would probably be better to move this up
363        into the phdr. */
364     switch (wth->file_encap)
365     {
366     case WTAP_ENCAP_ETHERNET:
367         /* Ethernet has a 4-byte FCS. */
368         if (phdr->len < 4)
369         {
370             *err = WTAP_ERR_BAD_FILE;
371             *err_info = g_strdup_printf("visual: Ethernet packet has %u-byte original packet, less than the FCS length",
372                         phdr->len);
373             return FALSE;
374         }
375         phdr->len -= 4;
376
377         /* XXX - the above implies that there's never an FCS; should this
378            set the FCS length to 0? */
379         phdr->pseudo_header.eth.fcs_len = -1;
380         break;
381
382     case WTAP_ENCAP_CHDLC_WITH_PHDR:
383         /* This has a 2-byte FCS. */
384         if (phdr->len < 2)
385         {
386             *err = WTAP_ERR_BAD_FILE;
387             *err_info = g_strdup_printf("visual: Cisco HDLC packet has %u-byte original packet, less than the FCS length",
388                         phdr->len);
389             return FALSE;
390         }
391         phdr->len -= 2;
392
393         phdr->pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
394         break;
395
396     case WTAP_ENCAP_PPP_WITH_PHDR:
397         /* No FCS.
398            XXX - true?  Note that PPP can negotiate no FCS, a 2-byte FCS,
399            or a 4-byte FCS. */
400         phdr->pseudo_header.p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
401         break;
402
403     case WTAP_ENCAP_FRELAY_WITH_PHDR:
404         /* This has a 2-byte FCS. */
405         if (phdr->len < 2)
406         {
407             *err = WTAP_ERR_BAD_FILE;
408             *err_info = g_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
409                         phdr->len);
410             return FALSE;
411         }
412         phdr->len -= 2;
413
414         phdr->pseudo_header.x25.flags =
415             (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
416         break;
417
418     case WTAP_ENCAP_LAPB:
419         /* This has a 2-byte FCS. */
420         if (phdr->len < 2)
421         {
422             *err = WTAP_ERR_BAD_FILE;
423             *err_info = g_strdup_printf("visual: Frame Relay packet has %u-byte original packet, less than the FCS length",
424                         phdr->len);
425             return FALSE;
426         }
427         phdr->len -= 2;
428
429         phdr->pseudo_header.x25.flags =
430             (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
431         break;
432
433     case WTAP_ENCAP_ATM_PDUS:
434         /* ATM original length doesn't include any FCS. Do nothing to
435            the packet length.
436
437            ATM packets have an additional packet header; read and
438            process it. */
439         if (!wtap_read_bytes(fh, &vatm_hdr, (unsigned int)sizeof vatm_hdr, err, err_info))
440         {
441             return FALSE;
442         }
443
444         /* Remove ATM header from length of included bytes in capture, as
445            this header was appended by the processor doing the packet
446            reassembly, and was not transmitted across the wire */
447         packet_size -= (guint32)sizeof vatm_hdr;
448
449         /* Set defaults */
450         phdr->pseudo_header.atm.type = TRAF_UNKNOWN;
451         phdr->pseudo_header.atm.subtype = TRAF_ST_UNKNOWN;
452         phdr->pseudo_header.atm.aal5t_len = 0;
453
454         /* Next two items not supported. Defaulting to zero */
455         phdr->pseudo_header.atm.aal5t_u2u = 0;
456         phdr->pseudo_header.atm.aal5t_chksum = 0;
457
458         /* Flags appear only to convey that packet is a raw cell. Set to 0 */
459         phdr->pseudo_header.atm.flags = 0;
460
461         /* Not supported. Defaulting to zero */
462         phdr->pseudo_header.atm.aal2_cid = 0;
463
464         switch(vatm_hdr.category & VN_CAT_TYPE_MASK )
465         {
466         case VN_AAL1:
467             phdr->pseudo_header.atm.aal = AAL_1;
468             break;
469
470         case VN_AAL2:
471             phdr->pseudo_header.atm.aal = AAL_2;
472             break;
473
474         case VN_AAL34:
475             phdr->pseudo_header.atm.aal = AAL_3_4;
476             break;
477
478         case VN_AAL5:
479             phdr->pseudo_header.atm.aal = AAL_5;
480             phdr->pseudo_header.atm.type = TRAF_LLCMX;
481             phdr->pseudo_header.atm.aal5t_len = pntoh32(&vatm_hdr.data_length);
482             break;
483
484         case VN_OAM:
485         /* Marking next 3 as OAM versus unknown */
486         case VN_O191:
487         case VN_IDLE:
488         case VN_RM:
489             phdr->pseudo_header.atm.aal = AAL_OAMCELL;
490             break;
491
492         case VN_UNKNOWN:
493         default:
494             phdr->pseudo_header.atm.aal = AAL_UNKNOWN;
495             break;
496         }
497         phdr->pseudo_header.atm.vpi = pntoh16(&vatm_hdr.vpi) & 0x0FFF;
498         phdr->pseudo_header.atm.vci = pntoh16(&vatm_hdr.vci);
499         phdr->pseudo_header.atm.cells = pntoh16(&vatm_hdr.cell_count);
500
501         /* Using bit value of 1 (DCE -> DTE) to indicate From Network */
502         phdr->pseudo_header.atm.channel = vatm_hdr.info & FROM_NETWORK;
503         break;
504
505     /* Not sure about token ring. Just leaving alone for now. */
506     case WTAP_ENCAP_TOKEN_RING:
507     default:
508         break;
509     }
510
511     phdr->caplen = packet_size;
512
513     /* Check for too-large packet. */
514     if (packet_size > WTAP_MAX_PACKET_SIZE)
515     {
516         /* Probably a corrupt capture file; don't blow up trying
517           to allocate space for an immensely-large packet. */
518         *err = WTAP_ERR_BAD_FILE;
519         *err_info = g_strdup_printf("visual: File has %u-byte packet, bigger than maximum of %u",
520             packet_size, WTAP_MAX_PACKET_SIZE);
521         return FALSE;
522     }
523
524     /* Read the packet data */
525     if (!wtap_read_packet_bytes(fh, buf, packet_size, err, err_info))
526         return FALSE;
527
528     if (wth->file_encap == WTAP_ENCAP_CHDLC_WITH_PHDR)
529     {
530         /* Fill in the encapsulation.  Visual files have a media type in the
531            file header and an encapsulation type in each packet header.  Files
532            with a media type of HDLC can be either Cisco EtherType or PPP.
533
534            The encapsulation hint values we've seen are:
535
536              2 - seen in an Ethernet capture
537              13 - seen in a PPP capture; possibly also seen in Cisco HDLC
538                   captures
539              14 - seen in a PPP capture; probably seen only for PPP.
540
541            According to bug 2005, the collection probe can be configured
542            for PPP, in which case the encapsulation hint is 14, or can
543            be configured for auto-detect, in which case the encapsulation
544            hint is 13, and the encapsulation must be guessed from the
545            packet contents.  Auto-detect is the default. */
546         pd = ws_buffer_start_ptr(buf);
547
548         /* If PPP is specified in the encap hint, then use that */
549         if (vpkt_hdr.encap_hint == 14)
550         {
551             /* But first we need to examine the first three octets to
552                try to determine the proper encapsulation, see RFC 2364. */
553             if (packet_size >= 3 &&
554                 (0xfe == pd[0]) && (0xfe == pd[1]) && (0x03 == pd[2]))
555             {
556                 /* It is actually LLC encapsulated PPP */
557                 phdr->pkt_encap = WTAP_ENCAP_ATM_RFC1483;
558             }
559             else
560             {
561                 /* It is actually PPP */
562                 phdr->pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
563             }
564         }
565         else
566         {
567             /* Otherwise, we need to examine the first two octets to
568                try to determine the encapsulation. */
569             if (packet_size >= 2 && (0xff == pd[0]) && (0x03 == pd[1]))
570             {
571                 /* It is actually PPP */
572                 phdr->pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
573             }
574         }
575     }
576
577     return TRUE;
578 }
579
580 /* Check for media types that may be written in Visual file format.
581    Returns 0 if the specified encapsulation type is supported,
582    an error indication otherwise. */
583 int visual_dump_can_write_encap(int encap)
584 {
585     /* Per-packet encapsulations aren't supported. */
586     if (encap == WTAP_ENCAP_PER_PACKET)
587         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
588
589     /* Check for supported encapsulation types */
590     switch (encap)
591     {
592     case WTAP_ENCAP_ETHERNET:
593     case WTAP_ENCAP_TOKEN_RING:
594     case WTAP_ENCAP_LAPB:
595     case WTAP_ENCAP_CHDLC_WITH_PHDR:
596     case WTAP_ENCAP_FRELAY_WITH_PHDR:
597     case WTAP_ENCAP_PPP:
598     case WTAP_ENCAP_PPP_WITH_PHDR:
599         return 0;
600     }
601
602     return WTAP_ERR_UNWRITABLE_ENCAP;
603 }
604
605
606 /* Open a file for writing.
607    Returns TRUE on success, FALSE on failure; sets "*err" to an
608    error code on failure */
609 gboolean visual_dump_open(wtap_dumper *wdh, int *err)
610 {
611     struct visual_write_info *visual;
612
613     /* Set the write routines for a visual file. */
614     wdh->subtype_write = visual_dump;
615     wdh->subtype_close = visual_dump_close;
616
617     /* Create a struct to hold file information for the duration
618        of the write */
619     visual = (struct visual_write_info *)g_malloc(sizeof(struct visual_write_info));
620     wdh->priv = (void *)visual;
621     visual->index_table_index = 0;
622     visual->index_table_size = 1024;
623     visual->index_table = 0;
624     visual->next_offset = CAPTUREFILE_HEADER_SIZE;
625
626     /* All of the fields in the file header aren't known yet so
627        just skip over it for now.  It will be created after all
628        of the packets have been written. */
629     if (wtap_dump_file_seek(wdh, CAPTUREFILE_HEADER_SIZE, SEEK_SET, err) == -1)
630         return FALSE;
631
632     return TRUE;
633 }
634
635
636 /* Write a packet to a Visual dump file.
637    Returns TRUE on success, FALSE on failure. */
638 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
639     const guint8 *pd, int *err, gchar **err_info _U_)
640 {
641     const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
642     struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
643     struct visual_pkt_hdr vpkt_hdr;
644     size_t hdr_size = sizeof vpkt_hdr;
645     guint delta_msec;
646     guint32 packet_status;
647
648     /* We can only write packet records. */
649     if (phdr->rec_type != REC_TYPE_PACKET) {
650         *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
651         return FALSE;
652     }
653
654     /* Don't write anything we're not willing to read. */
655     if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
656         *err = WTAP_ERR_PACKET_TOO_LARGE;
657         return FALSE;
658     }
659
660     /* If the visual structure was never allocated then nothing useful
661        can be done. */
662     if (visual == 0)
663         return FALSE;
664
665     /* Zero out unused and reserved fields in the packet header. */
666     memset(&vpkt_hdr, 0, hdr_size);
667
668     /* Visual UpTime capture files have a capture start time in the
669        file header.  Each packet has a capture time (in msec) relative
670        to the file start time.  Use the time of the first packet as the
671        file start time. */
672     if (visual->index_table_index == 0)
673     {
674         /* This is the first packet.  Save its start time as the file time. */
675         visual->start_time = phdr->ts.secs;
676
677         /* Initialize the index table */
678         visual->index_table = (guint32 *)g_malloc(1024 * sizeof *visual->index_table);
679         visual->index_table_size = 1024;
680     }
681
682     /* Calculate milliseconds since capture start. */
683     delta_msec = phdr->ts.nsecs / 1000000;
684     delta_msec += (guint32)((phdr->ts.secs - visual->start_time) * 1000);
685     vpkt_hdr.ts_delta = GUINT32_TO_LE(delta_msec);
686
687     /* Fill in the length fields. */
688     vpkt_hdr.orig_len = GUINT16_TO_LE(phdr->len);
689     vpkt_hdr.incl_len = GUINT16_TO_LE(phdr->caplen);
690
691     /* Fill in the encapsulation hint for the file's media type. */
692     switch (wdh->encap)
693     {
694     case WTAP_ENCAP_ETHERNET:   /* Ethernet */
695         vpkt_hdr.encap_hint = 2;
696         break;
697     case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
698         vpkt_hdr.encap_hint = 3;
699         break;
700     case WTAP_ENCAP_PPP:        /* PPP */
701     case WTAP_ENCAP_PPP_WITH_PHDR:
702         vpkt_hdr.encap_hint = 14;
703         break;
704     case WTAP_ENCAP_CHDLC_WITH_PHDR:      /* HDLC Router */
705         vpkt_hdr.encap_hint = 13;
706         break;
707     case WTAP_ENCAP_FRELAY_WITH_PHDR:     /* Frame Relay Auto-detect */
708         vpkt_hdr.encap_hint = 12;
709         break;
710     case WTAP_ENCAP_LAPB:       /* Unknown */
711     default:
712         vpkt_hdr.encap_hint = 1;
713         break;
714     }
715
716     /* Set status flags.  The only status currently supported for all
717        encapsulations is direction.  This either goes in the p2p or the
718        X.25 pseudo header.  It would probably be better to move this up
719        into the phdr. */
720     packet_status = 0;
721     switch (wdh->encap)
722     {
723     case WTAP_ENCAP_CHDLC_WITH_PHDR:
724         packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
725         break;
726
727     case WTAP_ENCAP_FRELAY_WITH_PHDR:
728     case WTAP_ENCAP_LAPB:
729         packet_status |=
730             ((pseudo_header->x25.flags & FROM_DCE) ? 0x00 : PS_SENT);
731         break;
732     }
733     vpkt_hdr.status = GUINT32_TO_LE(packet_status);
734
735     /* Write the packet header. */
736     if (!wtap_dump_file_write(wdh, &vpkt_hdr, hdr_size, err))
737         return FALSE;
738
739     /* Write the packet data */
740     if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
741         return FALSE;
742
743     /* Store the frame offset in the index table. */
744     if (visual->index_table_index >= visual->index_table_size)
745     {
746         /* End of table reached.  Reallocate with a larger size */
747         visual->index_table_size *= 2;
748         visual->index_table = (guint32 *)g_realloc(visual->index_table,
749             visual->index_table_size * sizeof *visual->index_table);
750     }
751     visual->index_table[visual->index_table_index] = GUINT32_TO_LE(visual->next_offset);
752
753     /* Update the table index and offset for the next frame. */
754     visual->index_table_index++;
755     visual->next_offset += (guint32) hdr_size + phdr->caplen;
756
757     return TRUE;
758 }
759
760
761 /* Finish writing to a dump file.
762    Returns TRUE on success, FALSE on failure. */
763 static gboolean visual_dump_close(wtap_dumper *wdh, int *err)
764 {
765     struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
766     size_t n_to_write;
767     struct visual_file_hdr vfile_hdr;
768     const char *magicp;
769     size_t magic_size;
770
771     /* If the visual structure was never allocated then nothing useful
772        can be done. */
773     if (visual == 0)
774         return FALSE;
775
776     /* Write out the frame table at the end of the file. */
777     if (visual->index_table)
778     {
779         /* Write the index table to the file. */
780         n_to_write = visual->index_table_index * sizeof *visual->index_table;
781         if (!wtap_dump_file_write(wdh, visual->index_table, n_to_write, err))
782         {
783             visual_dump_free(wdh);
784             return FALSE;
785         }
786     }
787
788     /* Write the magic number at the start of the file. */
789     if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
790         return FALSE;
791     magicp = visual_magic;
792     magic_size = sizeof visual_magic;
793     if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
794     {
795         visual_dump_free(wdh);
796         return FALSE;
797     }
798
799     /* Initialize the file header with zeroes for the reserved fields. */
800     memset(&vfile_hdr, '\0', sizeof vfile_hdr);
801     vfile_hdr.num_pkts = GUINT32_TO_LE(visual->index_table_index);
802     vfile_hdr.start_time = GUINT32_TO_LE(visual->start_time);
803     vfile_hdr.max_length = GUINT16_TO_LE(65535);
804     vfile_hdr.file_flags = GUINT16_TO_LE(1);  /* indexes are present */
805     vfile_hdr.file_version = GUINT16_TO_LE(1);
806     g_strlcpy(vfile_hdr.description, "Wireshark file", 64);
807
808     /* Translate the encapsulation type */
809     switch (wdh->encap)
810     {
811     case WTAP_ENCAP_ETHERNET:
812         vfile_hdr.media_type = GUINT16_TO_LE(6);
813         break;
814
815     case WTAP_ENCAP_TOKEN_RING:
816         vfile_hdr.media_type = GUINT16_TO_LE(9);
817         break;
818
819     case WTAP_ENCAP_LAPB:
820         vfile_hdr.media_type = GUINT16_TO_LE(16);
821         break;
822
823     case WTAP_ENCAP_PPP:        /* PPP is differentiated from CHDLC in PktHdr */
824     case WTAP_ENCAP_PPP_WITH_PHDR:
825     case WTAP_ENCAP_CHDLC_WITH_PHDR:
826         vfile_hdr.media_type = GUINT16_TO_LE(22);
827         break;
828
829     case WTAP_ENCAP_FRELAY_WITH_PHDR:
830         vfile_hdr.media_type = GUINT16_TO_LE(32);
831         break;
832     }
833
834     /* Write the file header following the magic bytes. */
835     if (!wtap_dump_file_write(wdh, &vfile_hdr, sizeof vfile_hdr, err))
836     {
837         visual_dump_free(wdh);
838         return FALSE;
839     }
840
841     /* Deallocate the file write data */
842     visual_dump_free(wdh);
843     return TRUE;
844 }
845
846
847 /* Free the memory allocated by a visual file writer. */
848 static void visual_dump_free(wtap_dumper *wdh)
849 {
850     struct visual_write_info * visual = (struct visual_write_info *)wdh->priv;
851
852     if (visual)
853     {
854         /* Free the index table memory. */
855         if (visual->index_table)
856             g_free(visual->index_table);
857     }
858 }
859
860 /*
861  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
862  *
863  * Local variables:
864  * c-basic-offset: 4
865  * tab-width: 8
866  * indent-tabs-mode: nil
867  * End:
868  *
869  * vi: set shiftwidth=4 tabstop=8 expandtab:
870  * :indentSize=4:tabSize=8:noTabs=true:
871  */