file_read() can return -1; don't just blindly add it to a previous
[obnox/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 gboolean visual_seek_read(wtap *wth, gint64 seek_off,
168     union wtap_pseudo_header *pseudo_header, guchar *pd, int packet_size,
169     int *err, gchar **err_info);
170 static void visual_set_pseudo_header(int encap, struct visual_pkt_hdr *vpkt_hdr,
171     struct visual_atm_hdr *vatm_hdr, union wtap_pseudo_header *pseudo_header);
172 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
173     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
174 static gboolean visual_dump_close(wtap_dumper *wdh, int *err);
175 static void visual_dump_free(wtap_dumper *wdh);
176
177
178 /* Open a file for reading */
179 int visual_open(wtap *wth, int *err, gchar **err_info)
180 {
181     int bytes_read;
182     char magic[sizeof visual_magic];
183     struct visual_file_hdr vfile_hdr;
184     struct visual_read_info * visual;
185     int encap;
186
187     /* Check the magic string at the start of the file */
188     errno = WTAP_ERR_CANT_READ;
189     bytes_read = file_read(magic, sizeof magic, wth->fh);
190     if (bytes_read != sizeof magic)
191     {
192         *err = file_error(wth->fh, err_info);
193         if (*err != 0)
194             return -1;
195         return 0;
196     }
197     if (memcmp(magic, visual_magic, sizeof visual_magic) != 0)
198     {
199         return 0;
200     }
201
202     /* Read the rest of the file header. */
203     errno = WTAP_ERR_CANT_READ;
204     bytes_read = file_read(&vfile_hdr, sizeof vfile_hdr, wth->fh);
205     if (bytes_read != sizeof vfile_hdr)
206     {
207         *err = file_error(wth->fh, err_info);
208         if (*err != 0)
209             return -1;
210         return 0;
211     }
212
213     /* Verify the file version is known */
214     vfile_hdr.file_version = pletohs(&vfile_hdr.file_version);
215     if (vfile_hdr.file_version != 1)
216     {
217         *err = WTAP_ERR_UNSUPPORTED;
218         *err_info = g_strdup_printf("visual: file version %u unsupported", vfile_hdr.file_version);
219         return -1;
220     }
221
222     /* Translate the encapsulation type; these values are SNMP ifType
223        values, as found in http://www.iana.org/assignments/smi-numbers.
224
225        Note that a file with media type 22 ("propPointToPointSerial") may
226        contain Cisco HDLC or PPP over HDLC.  This will get sorted out after
227        the first packet is read.
228
229        XXX - should we use WTAP_ENCAP_PER_PACKET for that? */
230     switch (pletohs(&vfile_hdr.media_type))
231     {
232     case  6:    /* ethernet-csmacd */
233         encap = WTAP_ENCAP_ETHERNET;
234         break;
235
236     case  9:    /* IEEE802.5 */
237         encap = WTAP_ENCAP_TOKEN_RING;
238         break;
239
240     case 16:    /* lapb */
241         encap = WTAP_ENCAP_LAPB;
242         break;
243
244     case 22:    /* propPointToPointSerial */
245     case 118:   /* HDLC */
246         encap = WTAP_ENCAP_CHDLC_WITH_PHDR;
247         break;
248
249     case 32:    /* frame-relay */
250         encap = WTAP_ENCAP_FRELAY_WITH_PHDR;
251         break;
252
253     case 37:    /* ATM */
254        encap = WTAP_ENCAP_ATM_PDUS;
255        break;
256
257     default:
258         *err = WTAP_ERR_UNSUPPORTED_ENCAP;
259         *err_info = g_strdup_printf("visual: network type %u unknown or unsupported",
260                                      vfile_hdr.media_type);
261         return -1;
262     }
263
264     /* Fill in the wiretap struct with data from the file header */
265     wth->file_type = WTAP_FILE_VISUAL_NETWORKS;
266     wth->file_encap = encap;
267     wth->snapshot_length = pletohs(&vfile_hdr.max_length);
268
269     /* Save the pointer to the beginning of the packet data so
270        that the later seek_reads work correctly. */
271     wth->data_offset = CAPTUREFILE_HEADER_SIZE;
272
273     /* Set up the pointers to the handlers for this file type */
274     wth->subtype_read = visual_read;
275     wth->subtype_seek_read = visual_seek_read;
276     wth->tsprecision = WTAP_FILE_TSPREC_USEC;
277
278     /* Add Visual-specific information to the wiretap struct for later use. */
279     visual = (struct visual_read_info *)g_malloc(sizeof(struct visual_read_info));
280     wth->priv = (void *)visual;
281     visual->num_pkts = pletohl(&vfile_hdr.num_pkts);
282     visual->start_time = ((double) pletohl(&vfile_hdr.start_time)) * 1000000;
283     visual->current_pkt = 1;
284
285     return 1;
286 }
287
288
289 /* Read the next available packet from the file.  This is called
290    in a loop to sequentially read the entire file one time.  After
291    the file has been read once, any Future access to the packets is
292    done through seek_read. */
293 static gboolean visual_read(wtap *wth, int *err, gchar **err_info,
294     gint64 *data_offset)
295 {
296     struct visual_read_info *visual = (struct visual_read_info *)wth->priv;
297     guint32 packet_size = 0;
298     int bytes_read;
299     struct visual_pkt_hdr vpkt_hdr;
300     struct visual_atm_hdr vatm_hdr;
301     int phdr_size = sizeof(vpkt_hdr);
302     int ahdr_size = sizeof(vatm_hdr);
303     time_t  secs;
304     guint32 usecs;
305     double  t;
306
307     /* Check for the end of the packet data.  Note that a check for file EOF
308        will not work because there are index values stored after the last
309        packet's data. */
310     if (visual->current_pkt > visual->num_pkts)
311     {
312         *err = 0;   /* it's just an EOF, not an error */
313         return FALSE;
314     }
315     visual->current_pkt++;
316
317     /* Read the packet header. */
318     errno = WTAP_ERR_CANT_READ;
319     bytes_read = file_read(&vpkt_hdr, phdr_size, wth->fh);
320     if (bytes_read != phdr_size)
321     {
322         *err = file_error(wth->fh, err_info);
323         if (*err == 0 && bytes_read != 0)
324         {
325             *err = WTAP_ERR_SHORT_READ;
326         }
327         return FALSE;
328     }
329     wth->data_offset += phdr_size;
330
331     /* Get the included length of data. This includes extra headers + payload */
332     packet_size = pletohs(&vpkt_hdr.incl_len);
333
334     /* Check for additional ATM packet header */
335     if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
336     {
337        /* Read the atm packet header. */
338        errno = WTAP_ERR_CANT_READ;
339        bytes_read = file_read(&vatm_hdr, ahdr_size, wth->fh);
340        if (bytes_read != ahdr_size)
341        {
342            *err = file_error(wth->fh, err_info);
343            if (*err == 0 && bytes_read != 0)
344            {
345                *err = WTAP_ERR_SHORT_READ;
346            }
347            return FALSE;
348        }
349        wth->data_offset += ahdr_size;
350        
351        /* Remove ATM header from length of included bytes in capture, as 
352           this header was appended by the processor doing the packet reassembly,
353           and was not transmitted across the wire */
354        packet_size -= ahdr_size;
355     }
356
357     /* Read the packet data. */
358     if (packet_size > WTAP_MAX_PACKET_SIZE)
359     {
360         /* Probably a corrupt capture file; don't blow up trying
361           to allocate space for an immensely-large packet. */
362         *err = WTAP_ERR_BAD_RECORD;
363         *err_info = g_strdup_printf("visual: File has %u-byte packet, bigger than maximum of %u",
364             packet_size, WTAP_MAX_PACKET_SIZE);
365         return FALSE;
366     }
367     buffer_assure_space(wth->frame_buffer, packet_size);
368     *data_offset = wth->data_offset;
369     errno = WTAP_ERR_CANT_READ;
370     bytes_read = file_read(buffer_start_ptr(wth->frame_buffer),
371             packet_size, wth->fh);
372
373     if (bytes_read != (int) packet_size)
374     {
375         *err = file_error(wth->fh, err_info);
376         if (*err == 0)
377             *err = WTAP_ERR_SHORT_READ;
378         return FALSE;
379     }
380     wth->data_offset += packet_size;
381
382     /* Set the packet time and length. */
383     t = visual->start_time;
384     t += ((double)pletohl(&vpkt_hdr.ts_delta))*1000;
385     secs = (time_t)(t/1000000);
386     usecs = (guint32)(t - secs*1000000);
387     wth->phdr.ts.secs = secs;
388     wth->phdr.ts.nsecs = usecs * 1000;
389     
390     /* Most visual capture types include FCS checks in the original length value, but
391     * but don't include the FCS as part of the payload or captured length. 
392     * This causes the RTP audio payload save to fail since then captured len != orig len.
393     * Adjusting the original length to remove the FCS bytes we counted based
394     * on the file encapsualtion type.
395     *
396     * Only downside to this fix is throughput calculations will be slightly lower
397     * as they won't include the FCS bytes.
398     */
399
400     wth->phdr.caplen = packet_size;
401     wth->phdr.len = pletohs(&vpkt_hdr.orig_len);
402
403     switch (wth->file_encap)
404     {
405     case WTAP_ENCAP_ETHERNET:
406        wth->phdr.len -= 4;
407        break;
408     
409     case WTAP_ENCAP_FRELAY_WITH_PHDR:
410     case WTAP_ENCAP_CHDLC_WITH_PHDR:
411     case WTAP_ENCAP_LAPB:
412        wth->phdr.len -= 2;
413        break;
414
415     /* ATM original length doesn't include any FCS. Do nothing. */
416     case WTAP_ENCAP_ATM_PDUS:
417     /* Not sure about token ring. Just leaving alone for now. */
418     case WTAP_ENCAP_TOKEN_RING:
419     default:
420        break;
421     }
422
423     /* Sanity check */
424     if (wth->phdr.len < wth->phdr.caplen)
425     {
426        wth->phdr.len = wth->phdr.caplen;
427     }
428
429     /* Set the pseudo_header. */
430     visual_set_pseudo_header(wth->file_encap, &vpkt_hdr, &vatm_hdr, &wth->pseudo_header);
431
432     /* Fill in the encapsulation.  Visual files have a media type in the
433        file header and an encapsulation type in each packet header.  Files
434        with a media type of HDLC can be either Cisco EtherType or PPP.
435
436        The encapsulation hint values we've seen are:
437
438          2 - seen in an Ethernet capture
439          13 - seen in a PPP capture; possibly also seen in Cisco HDLC
440               captures
441          14 - seen in a PPP capture; probably seen only for PPP */
442     if (wth->file_encap == WTAP_ENCAP_CHDLC_WITH_PHDR)
443     {
444         /* If PPP is specified in the encap hint, then use that */
445         if (vpkt_hdr.encap_hint == 14)
446         {
447               /* But first we need to examine the first three octets to
448                try to determine the proper encapsulation, see RFC 2364. */
449             guint8 *buf = buffer_start_ptr(wth->frame_buffer);
450             if ((0xfe == buf[0]) && (0xfe == buf[1]) && (0x03 == buf[2]))
451             {
452                 /* It is actually LLC encapsulated PPP */
453                 wth->phdr.pkt_encap = WTAP_ENCAP_ATM_RFC1483;
454             }
455             else
456             {
457                 /* It is actually PPP */
458                 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
459             }
460         }
461         else
462         {
463             /* Otherwise, we need to examine the first two octets to
464                try to determine the encapsulation. */
465             guint8 *buf = buffer_start_ptr(wth->frame_buffer);
466             if ((0xff == buf[0]) && (0x03 == buf[1]))
467             {
468                 /* It is actually PPP */
469                 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
470             }
471         }
472     }
473     return TRUE;
474 }
475
476 /* Read packet data for random access.
477    This gets the packet data and rebuilds the pseudo header so that
478    the direction flag works. */
479 static gboolean visual_seek_read (wtap *wth, gint64 seek_off,
480     union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
481     int *err, gchar **err_info)
482 {
483     struct visual_pkt_hdr vpkt_hdr;
484     struct visual_atm_hdr vatm_hdr;
485     int phdr_size = sizeof(vpkt_hdr);
486     int ahdr_size = sizeof(vatm_hdr);
487     int bytes_read;
488     int header_size;
489
490     /* Get the size of the visual packet header to skip */
491     header_size = sizeof(struct visual_pkt_hdr);
492
493     /* If ATM capture, need to skip over visual ATM packet header too */
494     if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
495     {
496        header_size += (int)sizeof(struct visual_atm_hdr);
497     }
498     
499     /* Seek to the packet header */
500     if (file_seek(wth->random_fh, seek_off - header_size,
501                   SEEK_SET, err) == -1)
502         return FALSE;
503
504     /* Read the packet header to get the status flags. */
505     errno = WTAP_ERR_CANT_READ;
506     bytes_read = file_read(&vpkt_hdr, phdr_size, wth->random_fh);
507     if (bytes_read != phdr_size) {
508         *err = file_error(wth->random_fh, err_info);
509         if (*err == 0)
510             *err = WTAP_ERR_SHORT_READ;
511         return FALSE;
512     }
513     
514     /* Check for additional ATM packet header */
515     if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
516     {
517        /* Read the atm packet header */
518        errno = WTAP_ERR_CANT_READ;
519        bytes_read = file_read(&vatm_hdr, ahdr_size, wth->random_fh);
520        if (bytes_read != ahdr_size)
521        {
522            *err = file_error(wth->fh, err_info);
523            if (*err == 0 && bytes_read != 0)
524            {
525                *err = WTAP_ERR_SHORT_READ;
526            }
527            return FALSE;
528        }
529     }
530
531     /* Read the packet data. */
532     errno = WTAP_ERR_CANT_READ;
533     bytes_read = file_read(pd, len, wth->random_fh);
534     if (bytes_read != len) {
535         if (*err == 0)
536             *err = WTAP_ERR_SHORT_READ;
537         return FALSE;
538     }
539
540     /* Set the pseudo_header. */
541     visual_set_pseudo_header(wth->file_encap, &vpkt_hdr, &vatm_hdr, pseudo_header);
542
543     return TRUE;
544 }
545
546 static void visual_set_pseudo_header(int encap, struct visual_pkt_hdr *vpkt_hdr,
547     struct visual_atm_hdr *vatm_hdr, union wtap_pseudo_header *pseudo_header)
548 {
549     guint32 packet_status;
550
551     /* Set status flags.  The only status currently supported for all
552        encapsulations is direction.  This either goes in the p2p or the
553        X.25 pseudo header.  It would probably be better to move this up
554        into the phdr. */
555     packet_status = pletohl(&vpkt_hdr->status);
556     switch (encap)
557     {
558     case WTAP_ENCAP_ETHERNET:
559         /* XXX - is there an FCS in the frame? */
560         pseudo_header->eth.fcs_len = -1;
561         break;
562
563     case WTAP_ENCAP_CHDLC_WITH_PHDR:
564     case WTAP_ENCAP_PPP_WITH_PHDR:
565         pseudo_header->p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
566         break;
567
568     case WTAP_ENCAP_FRELAY_WITH_PHDR:
569     case WTAP_ENCAP_LAPB:
570         pseudo_header->x25.flags =
571             (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
572         break;
573
574     case WTAP_ENCAP_ATM_PDUS:
575        /* Set defaults */
576        pseudo_header->atm.type = TRAF_UNKNOWN;
577        pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
578        pseudo_header->atm.aal5t_len = 0;
579
580        /* Next two items not supported. Defaulting to zero */
581        pseudo_header->atm.aal5t_u2u = 0;
582        pseudo_header->atm.aal5t_chksum = 0;
583        
584        /* Flags appear only to convey that packet is a raw cell. Set to 0 */
585        pseudo_header->atm.flags = 0; 
586        
587        /* Not supported. Defaulting to zero */
588        pseudo_header->atm.aal2_cid = 0;
589
590        switch(vatm_hdr->category & VN_CAT_TYPE_MASK )
591        {
592        case VN_AAL1:
593           pseudo_header->atm.aal = AAL_1;
594           break;
595
596        case VN_AAL2:
597           pseudo_header->atm.aal = AAL_2;
598           break;
599        
600        case VN_AAL34:
601           pseudo_header->atm.aal = AAL_3_4;
602           break;
603        
604        case VN_AAL5:
605           pseudo_header->atm.aal = AAL_5;
606           pseudo_header->atm.type = TRAF_LLCMX;
607           pseudo_header->atm.aal5t_len = pntohl(&vatm_hdr->data_length);
608           break;
609        
610        case VN_OAM:
611        /* Marking next 3 as OAM versus unknown */
612        case VN_O191:
613        case VN_IDLE:
614        case VN_RM:
615           pseudo_header->atm.aal = AAL_OAMCELL;
616           break;
617
618        case VN_UNKNOWN:
619        default:
620           pseudo_header->atm.aal = AAL_UNKNOWN;
621           break;
622
623        }
624        pseudo_header->atm.vpi = pntohs(&vatm_hdr->vpi) & 0x0FFF;
625        pseudo_header->atm.vci = pntohs(&vatm_hdr->vci);
626        pseudo_header->atm.cells = pntohs(&vatm_hdr->cell_count);
627        
628        /* Using bit value of 1 (DCE -> DTE) to indicate From Network */
629        pseudo_header->atm.channel = vatm_hdr->info & FROM_NETWORK;
630        
631        break;
632     }
633 }
634
635 /* Check for media types that may be written in Visual file format.
636    Returns 0 if the specified encapsulation type is supported,
637    an error indication otherwise. */
638 int visual_dump_can_write_encap(int encap)
639 {
640     /* Per-packet encapsulations aren't supported. */
641     if (encap == WTAP_ENCAP_PER_PACKET)
642         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
643
644     /* Check for supported encapsulation types */
645     switch (encap)
646     {
647     case WTAP_ENCAP_ETHERNET:
648     case WTAP_ENCAP_TOKEN_RING:
649     case WTAP_ENCAP_LAPB:
650     case WTAP_ENCAP_CHDLC_WITH_PHDR:
651     case WTAP_ENCAP_FRELAY_WITH_PHDR:
652     case WTAP_ENCAP_PPP:
653     case WTAP_ENCAP_PPP_WITH_PHDR:
654         return 0;
655     }
656
657     return WTAP_ERR_UNSUPPORTED_ENCAP;
658 }
659
660
661 /* Open a file for writing.
662    Returns TRUE on success, FALSE on failure; sets "*err" to an
663    error code on failure */
664 gboolean visual_dump_open(wtap_dumper *wdh, int *err)
665 {
666     struct visual_write_info *visual;
667
668     /* Set the write routines for a visual file. */
669     wdh->subtype_write = visual_dump;
670     wdh->subtype_close = visual_dump_close;
671
672     /* Create a struct to hold file information for the duration
673        of the write */
674     visual = (struct visual_write_info *)g_malloc(sizeof(struct visual_write_info));
675     wdh->priv = (void *)visual;
676     visual->index_table_index = 0;
677     visual->index_table_size = 1024;
678     visual->index_table = 0;
679     visual->next_offset = CAPTUREFILE_HEADER_SIZE;
680
681     /* All of the fields in the file header aren't known yet so
682        just skip over it for now.  It will be created after all
683        of the packets have been written. */
684     if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
685         *err = errno;
686         return FALSE;
687     }
688
689     return TRUE;
690 }
691
692
693 /* Write a packet to a Visual dump file.
694    Returns TRUE on success, FALSE on failure. */
695 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
696     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
697 {
698     struct visual_write_info * visual = wdh->priv;
699     struct visual_pkt_hdr vpkt_hdr;
700     size_t hdr_size = sizeof vpkt_hdr;
701     unsigned delta_msec;
702     guint32 packet_status;
703
704     /* If the visual structure was never allocated then nothing useful
705        can be done. */
706     if (visual == 0)
707         return FALSE;
708
709     /* Zero out unused and reserved fields in the packet header. */
710     memset(&vpkt_hdr, 0, hdr_size);
711
712     /* Visual UpTime capture files have a capture start time in the
713        file header.  Each packet has a capture time (in msec) relative
714        to the file start time.  Use the time of the first packet as the
715        file start time. */
716     if (visual->index_table_index == 0)
717     {
718         /* This is the first packet.  Save its start time as the file time. */
719         visual->start_time = (guint32) phdr->ts.secs;
720
721         /* Initialize the index table */
722         visual->index_table = g_malloc(1024 * sizeof *visual->index_table);
723         visual->index_table_size = 1024;
724     }
725
726     /* Calculate milliseconds since capture start. */
727     delta_msec = phdr->ts.nsecs / 1000000;
728     delta_msec += ( (guint32) phdr->ts.secs - visual->start_time) * 1000;
729     vpkt_hdr.ts_delta = htolel(delta_msec);
730
731     /* Fill in the length fields. */
732     vpkt_hdr.orig_len = htoles(phdr->len);
733     vpkt_hdr.incl_len = htoles(phdr->caplen);
734
735     /* Fill in the encapsulation hint for the file's media type. */
736     switch (wdh->encap)
737     {
738     case WTAP_ENCAP_ETHERNET:   /* Ethernet */
739         vpkt_hdr.encap_hint = 2;
740         break;
741     case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
742         vpkt_hdr.encap_hint = 3;
743         break;
744     case WTAP_ENCAP_PPP:        /* PPP */
745     case WTAP_ENCAP_PPP_WITH_PHDR:
746         vpkt_hdr.encap_hint = 14;
747         break;
748     case WTAP_ENCAP_CHDLC_WITH_PHDR:      /* HDLC Router */
749         vpkt_hdr.encap_hint = 13;
750         break;
751     case WTAP_ENCAP_FRELAY_WITH_PHDR:     /* Frame Relay Auto-detect */
752         vpkt_hdr.encap_hint = 12;
753         break;
754     case WTAP_ENCAP_LAPB:       /* Unknown */
755     default:
756         vpkt_hdr.encap_hint = 1;
757         break;
758     }
759
760     /* Set status flags.  The only status currently supported for all
761        encapsulations is direction.  This either goes in the p2p or the
762        X.25 pseudo header.  It would probably be better to move this up
763        into the phdr. */
764     packet_status = 0;
765     switch (wdh->encap)
766     {
767     case WTAP_ENCAP_CHDLC_WITH_PHDR:
768         packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
769         break;
770
771     case WTAP_ENCAP_FRELAY_WITH_PHDR:
772     case WTAP_ENCAP_LAPB:
773         packet_status |=
774             ((pseudo_header->x25.flags & FROM_DCE) ? 0x00 : PS_SENT);
775         break;
776     }
777     vpkt_hdr.status = htolel(packet_status);
778
779     /* Write the packet header. */
780     if (!wtap_dump_file_write(wdh, &vpkt_hdr, hdr_size, err))
781         return FALSE;
782
783     /* Write the packet data */
784     if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
785         return FALSE;
786
787     /* Store the frame offset in the index table. */
788     if (visual->index_table_index >= visual->index_table_size)
789     {
790         /* End of table reached.  Reallocate with a larger size */
791         visual->index_table_size *= 2;
792         visual->index_table = g_realloc(visual->index_table,
793             visual->index_table_size * sizeof *visual->index_table);
794     }
795     visual->index_table[visual->index_table_index] = htolel(visual->next_offset);
796
797     /* Update the table index and offset for the next frame. */
798     visual->index_table_index++;
799     visual->next_offset += (guint32) hdr_size + phdr->caplen;
800
801     return TRUE;
802 }
803
804
805 /* Finish writing to a dump file.
806    Returns TRUE on success, FALSE on failure. */
807 static gboolean visual_dump_close(wtap_dumper *wdh, int *err)
808 {
809     struct visual_write_info * visual = wdh->priv;
810     size_t n_to_write;
811     struct visual_file_hdr vfile_hdr;
812     const char *magicp;
813     size_t magic_size;
814
815     /* If the visual structure was never allocated then nothing useful
816        can be done. */
817     if (visual == 0)
818         return FALSE;
819
820     /* Write out the frame table at the end of the file. */
821     if (visual->index_table)
822     {
823         /* Write the index table to the file. */
824         n_to_write = visual->index_table_index * sizeof *visual->index_table;
825         if (!wtap_dump_file_write(wdh, visual->index_table, n_to_write, err))
826         {
827             visual_dump_free(wdh);
828             return FALSE;
829         }
830     }
831
832     /* Write the magic number at the start of the file. */
833     fseek(wdh->fh, 0, SEEK_SET);
834     magicp = visual_magic;
835     magic_size = sizeof visual_magic;
836     if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
837     {
838         visual_dump_free(wdh);
839         return FALSE;
840     }
841
842     /* Initialize the file header with zeroes for the reserved fields. */
843     memset(&vfile_hdr, '\0', sizeof vfile_hdr);
844     vfile_hdr.num_pkts = htolel(visual->index_table_index);
845     vfile_hdr.start_time = htolel(visual->start_time);
846     vfile_hdr.max_length = htoles(65535);
847     vfile_hdr.file_flags = htoles(1);  /* indexes are present */
848     vfile_hdr.file_version = htoles(1);
849     g_strlcpy(vfile_hdr.description, "Wireshark file", 64);
850
851     /* Translate the encapsulation type */
852     switch (wdh->encap)
853     {
854     case WTAP_ENCAP_ETHERNET:
855         vfile_hdr.media_type = htoles(6);
856         break;
857
858     case WTAP_ENCAP_TOKEN_RING:
859         vfile_hdr.media_type = htoles(9);
860         break;
861
862     case WTAP_ENCAP_LAPB:
863         vfile_hdr.media_type = htoles(16);
864         break;
865
866     case WTAP_ENCAP_PPP:        /* PPP is differentiated from CHDLC in PktHdr */
867     case WTAP_ENCAP_PPP_WITH_PHDR:
868     case WTAP_ENCAP_CHDLC_WITH_PHDR:
869         vfile_hdr.media_type = htoles(22);
870         break;
871
872     case WTAP_ENCAP_FRELAY_WITH_PHDR:
873         vfile_hdr.media_type = htoles(32);
874         break;
875     }
876
877     /* Write the file header following the magic bytes. */
878     if (!wtap_dump_file_write(wdh, &vfile_hdr, sizeof vfile_hdr, err))
879     {
880         visual_dump_free(wdh);
881         return FALSE;
882     }
883
884     /* Deallocate the file write data */
885     visual_dump_free(wdh);
886     return TRUE;
887 }
888
889
890 /* Free the memory allocated by a visual file writer. */
891 static void visual_dump_free(wtap_dumper *wdh)
892 {
893     struct visual_write_info * visual = wdh->priv;
894
895     if (visual)
896     {
897         /* Free the index table memory. */
898         if (visual->index_table)
899             g_free(visual->index_table);
900     }
901 }