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