Move the new files to the same places as in automake.
[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, guint8 *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 guint8 *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_FILE;
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     wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
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     if (wth->phdr.len > WTAP_MAX_PACKET_SIZE) {
426     /* Check if wth->phdr.len is sane, small values of wth.phdr.len before
427        the case loop above can cause integer underflows */ 
428         *err = WTAP_ERR_BAD_FILE;
429         *err_info = g_strdup_printf("visual: File has %u-byte original packet, bigger than maximum of %u",
430                     wth->phdr.len, WTAP_MAX_PACKET_SIZE);
431         return FALSE;
432     }
433
434     /* Sanity check */
435     if (wth->phdr.len < wth->phdr.caplen)
436     {
437        wth->phdr.len = wth->phdr.caplen;
438     }
439
440     /* Set the pseudo_header. */
441     visual_set_pseudo_header(wth->file_encap, &vpkt_hdr, &vatm_hdr, &wth->pseudo_header);
442
443     /* Fill in the encapsulation.  Visual files have a media type in the
444        file header and an encapsulation type in each packet header.  Files
445        with a media type of HDLC can be either Cisco EtherType or PPP.
446
447        The encapsulation hint values we've seen are:
448
449          2 - seen in an Ethernet capture
450          13 - seen in a PPP capture; possibly also seen in Cisco HDLC
451               captures
452          14 - seen in a PPP capture; probably seen only for PPP */
453     if (wth->file_encap == WTAP_ENCAP_CHDLC_WITH_PHDR)
454     {
455         /* If PPP is specified in the encap hint, then use that */
456         if (vpkt_hdr.encap_hint == 14)
457         {
458               /* But first we need to examine the first three octets to
459                try to determine the proper encapsulation, see RFC 2364. */
460             guint8 *buf = buffer_start_ptr(wth->frame_buffer);
461             if ((0xfe == buf[0]) && (0xfe == buf[1]) && (0x03 == buf[2]))
462             {
463                 /* It is actually LLC encapsulated PPP */
464                 wth->phdr.pkt_encap = WTAP_ENCAP_ATM_RFC1483;
465             }
466             else
467             {
468                 /* It is actually PPP */
469                 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
470             }
471         }
472         else
473         {
474             /* Otherwise, we need to examine the first two octets to
475                try to determine the encapsulation. */
476             guint8 *buf = buffer_start_ptr(wth->frame_buffer);
477             if ((0xff == buf[0]) && (0x03 == buf[1]))
478             {
479                 /* It is actually PPP */
480                 wth->phdr.pkt_encap = WTAP_ENCAP_PPP_WITH_PHDR;
481             }
482         }
483     }
484     return TRUE;
485 }
486
487 /* Read packet data for random access.
488    This gets the packet data and rebuilds the pseudo header so that
489    the direction flag works. */
490 static gboolean visual_seek_read (wtap *wth, gint64 seek_off,
491     union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
492     int *err, gchar **err_info)
493 {
494     struct visual_pkt_hdr vpkt_hdr;
495     struct visual_atm_hdr vatm_hdr;
496     int phdr_size = sizeof(vpkt_hdr);
497     int ahdr_size = sizeof(vatm_hdr);
498     int bytes_read;
499     int header_size;
500
501     /* Get the size of the visual packet header to skip */
502     header_size = sizeof(struct visual_pkt_hdr);
503
504     /* If ATM capture, need to skip over visual ATM packet header too */
505     if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
506     {
507        header_size += (int)sizeof(struct visual_atm_hdr);
508     }
509     
510     /* Seek to the packet header */
511     if (file_seek(wth->random_fh, seek_off - header_size,
512                   SEEK_SET, err) == -1)
513         return FALSE;
514
515     /* Read the packet header to get the status flags. */
516     errno = WTAP_ERR_CANT_READ;
517     bytes_read = file_read(&vpkt_hdr, phdr_size, wth->random_fh);
518     if (bytes_read != phdr_size) {
519         *err = file_error(wth->random_fh, err_info);
520         if (*err == 0)
521             *err = WTAP_ERR_SHORT_READ;
522         return FALSE;
523     }
524     
525     /* Check for additional ATM packet header */
526     if (wth->file_encap == WTAP_ENCAP_ATM_PDUS)
527     {
528        /* Read the atm packet header */
529        errno = WTAP_ERR_CANT_READ;
530        bytes_read = file_read(&vatm_hdr, ahdr_size, wth->random_fh);
531        if (bytes_read != ahdr_size)
532        {
533            *err = file_error(wth->fh, err_info);
534            if (*err == 0 && bytes_read != 0)
535            {
536                *err = WTAP_ERR_SHORT_READ;
537            }
538            return FALSE;
539        }
540     }
541
542     /* Read the packet data. */
543     errno = WTAP_ERR_CANT_READ;
544     bytes_read = file_read(pd, len, wth->random_fh);
545     if (bytes_read != len) {
546         if (*err == 0)
547             *err = WTAP_ERR_SHORT_READ;
548         return FALSE;
549     }
550
551     /* Set the pseudo_header. */
552     visual_set_pseudo_header(wth->file_encap, &vpkt_hdr, &vatm_hdr, pseudo_header);
553
554     return TRUE;
555 }
556
557 static void visual_set_pseudo_header(int encap, struct visual_pkt_hdr *vpkt_hdr,
558     struct visual_atm_hdr *vatm_hdr, union wtap_pseudo_header *pseudo_header)
559 {
560     guint32 packet_status;
561
562     /* Set status flags.  The only status currently supported for all
563        encapsulations is direction.  This either goes in the p2p or the
564        X.25 pseudo header.  It would probably be better to move this up
565        into the phdr. */
566     packet_status = pletohl(&vpkt_hdr->status);
567     switch (encap)
568     {
569     case WTAP_ENCAP_ETHERNET:
570         /* XXX - is there an FCS in the frame? */
571         pseudo_header->eth.fcs_len = -1;
572         break;
573
574     case WTAP_ENCAP_CHDLC_WITH_PHDR:
575     case WTAP_ENCAP_PPP_WITH_PHDR:
576         pseudo_header->p2p.sent = (packet_status & PS_SENT) ? TRUE : FALSE;
577         break;
578
579     case WTAP_ENCAP_FRELAY_WITH_PHDR:
580     case WTAP_ENCAP_LAPB:
581         pseudo_header->x25.flags =
582             (packet_status & PS_SENT) ? 0x00 : FROM_DCE;
583         break;
584
585     case WTAP_ENCAP_ATM_PDUS:
586        /* Set defaults */
587        pseudo_header->atm.type = TRAF_UNKNOWN;
588        pseudo_header->atm.subtype = TRAF_ST_UNKNOWN;
589        pseudo_header->atm.aal5t_len = 0;
590
591        /* Next two items not supported. Defaulting to zero */
592        pseudo_header->atm.aal5t_u2u = 0;
593        pseudo_header->atm.aal5t_chksum = 0;
594        
595        /* Flags appear only to convey that packet is a raw cell. Set to 0 */
596        pseudo_header->atm.flags = 0; 
597        
598        /* Not supported. Defaulting to zero */
599        pseudo_header->atm.aal2_cid = 0;
600
601        switch(vatm_hdr->category & VN_CAT_TYPE_MASK )
602        {
603        case VN_AAL1:
604           pseudo_header->atm.aal = AAL_1;
605           break;
606
607        case VN_AAL2:
608           pseudo_header->atm.aal = AAL_2;
609           break;
610        
611        case VN_AAL34:
612           pseudo_header->atm.aal = AAL_3_4;
613           break;
614        
615        case VN_AAL5:
616           pseudo_header->atm.aal = AAL_5;
617           pseudo_header->atm.type = TRAF_LLCMX;
618           pseudo_header->atm.aal5t_len = pntohl(&vatm_hdr->data_length);
619           break;
620        
621        case VN_OAM:
622        /* Marking next 3 as OAM versus unknown */
623        case VN_O191:
624        case VN_IDLE:
625        case VN_RM:
626           pseudo_header->atm.aal = AAL_OAMCELL;
627           break;
628
629        case VN_UNKNOWN:
630        default:
631           pseudo_header->atm.aal = AAL_UNKNOWN;
632           break;
633
634        }
635        pseudo_header->atm.vpi = pntohs(&vatm_hdr->vpi) & 0x0FFF;
636        pseudo_header->atm.vci = pntohs(&vatm_hdr->vci);
637        pseudo_header->atm.cells = pntohs(&vatm_hdr->cell_count);
638        
639        /* Using bit value of 1 (DCE -> DTE) to indicate From Network */
640        pseudo_header->atm.channel = vatm_hdr->info & FROM_NETWORK;
641        
642        break;
643     }
644 }
645
646 /* Check for media types that may be written in Visual file format.
647    Returns 0 if the specified encapsulation type is supported,
648    an error indication otherwise. */
649 int visual_dump_can_write_encap(int encap)
650 {
651     /* Per-packet encapsulations aren't supported. */
652     if (encap == WTAP_ENCAP_PER_PACKET)
653         return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
654
655     /* Check for supported encapsulation types */
656     switch (encap)
657     {
658     case WTAP_ENCAP_ETHERNET:
659     case WTAP_ENCAP_TOKEN_RING:
660     case WTAP_ENCAP_LAPB:
661     case WTAP_ENCAP_CHDLC_WITH_PHDR:
662     case WTAP_ENCAP_FRELAY_WITH_PHDR:
663     case WTAP_ENCAP_PPP:
664     case WTAP_ENCAP_PPP_WITH_PHDR:
665         return 0;
666     }
667
668     return WTAP_ERR_UNSUPPORTED_ENCAP;
669 }
670
671
672 /* Open a file for writing.
673    Returns TRUE on success, FALSE on failure; sets "*err" to an
674    error code on failure */
675 gboolean visual_dump_open(wtap_dumper *wdh, int *err)
676 {
677     struct visual_write_info *visual;
678
679     /* Set the write routines for a visual file. */
680     wdh->subtype_write = visual_dump;
681     wdh->subtype_close = visual_dump_close;
682
683     /* Create a struct to hold file information for the duration
684        of the write */
685     visual = (struct visual_write_info *)g_malloc(sizeof(struct visual_write_info));
686     wdh->priv = (void *)visual;
687     visual->index_table_index = 0;
688     visual->index_table_size = 1024;
689     visual->index_table = 0;
690     visual->next_offset = CAPTUREFILE_HEADER_SIZE;
691
692     /* All of the fields in the file header aren't known yet so
693        just skip over it for now.  It will be created after all
694        of the packets have been written. */
695     if (fseek(wdh->fh, CAPTUREFILE_HEADER_SIZE, SEEK_SET) == -1) {
696         *err = errno;
697         return FALSE;
698     }
699
700     return TRUE;
701 }
702
703
704 /* Write a packet to a Visual dump file.
705    Returns TRUE on success, FALSE on failure. */
706 static gboolean visual_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
707     const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
708 {
709     struct visual_write_info * visual = wdh->priv;
710     struct visual_pkt_hdr vpkt_hdr;
711     size_t hdr_size = sizeof vpkt_hdr;
712     unsigned delta_msec;
713     guint32 packet_status;
714
715     /* If the visual structure was never allocated then nothing useful
716        can be done. */
717     if (visual == 0)
718         return FALSE;
719
720     /* Zero out unused and reserved fields in the packet header. */
721     memset(&vpkt_hdr, 0, hdr_size);
722
723     /* Visual UpTime capture files have a capture start time in the
724        file header.  Each packet has a capture time (in msec) relative
725        to the file start time.  Use the time of the first packet as the
726        file start time. */
727     if (visual->index_table_index == 0)
728     {
729         /* This is the first packet.  Save its start time as the file time. */
730         visual->start_time = (guint32) phdr->ts.secs;
731
732         /* Initialize the index table */
733         visual->index_table = g_malloc(1024 * sizeof *visual->index_table);
734         visual->index_table_size = 1024;
735     }
736
737     /* Calculate milliseconds since capture start. */
738     delta_msec = phdr->ts.nsecs / 1000000;
739     delta_msec += ( (guint32) phdr->ts.secs - visual->start_time) * 1000;
740     vpkt_hdr.ts_delta = htolel(delta_msec);
741
742     /* Fill in the length fields. */
743     vpkt_hdr.orig_len = htoles(phdr->len);
744     vpkt_hdr.incl_len = htoles(phdr->caplen);
745
746     /* Fill in the encapsulation hint for the file's media type. */
747     switch (wdh->encap)
748     {
749     case WTAP_ENCAP_ETHERNET:   /* Ethernet */
750         vpkt_hdr.encap_hint = 2;
751         break;
752     case WTAP_ENCAP_TOKEN_RING: /* Token Ring */
753         vpkt_hdr.encap_hint = 3;
754         break;
755     case WTAP_ENCAP_PPP:        /* PPP */
756     case WTAP_ENCAP_PPP_WITH_PHDR:
757         vpkt_hdr.encap_hint = 14;
758         break;
759     case WTAP_ENCAP_CHDLC_WITH_PHDR:      /* HDLC Router */
760         vpkt_hdr.encap_hint = 13;
761         break;
762     case WTAP_ENCAP_FRELAY_WITH_PHDR:     /* Frame Relay Auto-detect */
763         vpkt_hdr.encap_hint = 12;
764         break;
765     case WTAP_ENCAP_LAPB:       /* Unknown */
766     default:
767         vpkt_hdr.encap_hint = 1;
768         break;
769     }
770
771     /* Set status flags.  The only status currently supported for all
772        encapsulations is direction.  This either goes in the p2p or the
773        X.25 pseudo header.  It would probably be better to move this up
774        into the phdr. */
775     packet_status = 0;
776     switch (wdh->encap)
777     {
778     case WTAP_ENCAP_CHDLC_WITH_PHDR:
779         packet_status |= (pseudo_header->p2p.sent ? PS_SENT : 0x00);
780         break;
781
782     case WTAP_ENCAP_FRELAY_WITH_PHDR:
783     case WTAP_ENCAP_LAPB:
784         packet_status |=
785             ((pseudo_header->x25.flags & FROM_DCE) ? 0x00 : PS_SENT);
786         break;
787     }
788     vpkt_hdr.status = htolel(packet_status);
789
790     /* Write the packet header. */
791     if (!wtap_dump_file_write(wdh, &vpkt_hdr, hdr_size, err))
792         return FALSE;
793
794     /* Write the packet data */
795     if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
796         return FALSE;
797
798     /* Store the frame offset in the index table. */
799     if (visual->index_table_index >= visual->index_table_size)
800     {
801         /* End of table reached.  Reallocate with a larger size */
802         visual->index_table_size *= 2;
803         visual->index_table = g_realloc(visual->index_table,
804             visual->index_table_size * sizeof *visual->index_table);
805     }
806     visual->index_table[visual->index_table_index] = htolel(visual->next_offset);
807
808     /* Update the table index and offset for the next frame. */
809     visual->index_table_index++;
810     visual->next_offset += (guint32) hdr_size + phdr->caplen;
811
812     return TRUE;
813 }
814
815
816 /* Finish writing to a dump file.
817    Returns TRUE on success, FALSE on failure. */
818 static gboolean visual_dump_close(wtap_dumper *wdh, int *err)
819 {
820     struct visual_write_info * visual = wdh->priv;
821     size_t n_to_write;
822     struct visual_file_hdr vfile_hdr;
823     const char *magicp;
824     size_t magic_size;
825
826     /* If the visual structure was never allocated then nothing useful
827        can be done. */
828     if (visual == 0)
829         return FALSE;
830
831     /* Write out the frame table at the end of the file. */
832     if (visual->index_table)
833     {
834         /* Write the index table to the file. */
835         n_to_write = visual->index_table_index * sizeof *visual->index_table;
836         if (!wtap_dump_file_write(wdh, visual->index_table, n_to_write, err))
837         {
838             visual_dump_free(wdh);
839             return FALSE;
840         }
841     }
842
843     /* Write the magic number at the start of the file. */
844     fseek(wdh->fh, 0, SEEK_SET);
845     magicp = visual_magic;
846     magic_size = sizeof visual_magic;
847     if (!wtap_dump_file_write(wdh, magicp, magic_size, err))
848     {
849         visual_dump_free(wdh);
850         return FALSE;
851     }
852
853     /* Initialize the file header with zeroes for the reserved fields. */
854     memset(&vfile_hdr, '\0', sizeof vfile_hdr);
855     vfile_hdr.num_pkts = htolel(visual->index_table_index);
856     vfile_hdr.start_time = htolel(visual->start_time);
857     vfile_hdr.max_length = htoles(65535);
858     vfile_hdr.file_flags = htoles(1);  /* indexes are present */
859     vfile_hdr.file_version = htoles(1);
860     g_strlcpy(vfile_hdr.description, "Wireshark file", 64);
861
862     /* Translate the encapsulation type */
863     switch (wdh->encap)
864     {
865     case WTAP_ENCAP_ETHERNET:
866         vfile_hdr.media_type = htoles(6);
867         break;
868
869     case WTAP_ENCAP_TOKEN_RING:
870         vfile_hdr.media_type = htoles(9);
871         break;
872
873     case WTAP_ENCAP_LAPB:
874         vfile_hdr.media_type = htoles(16);
875         break;
876
877     case WTAP_ENCAP_PPP:        /* PPP is differentiated from CHDLC in PktHdr */
878     case WTAP_ENCAP_PPP_WITH_PHDR:
879     case WTAP_ENCAP_CHDLC_WITH_PHDR:
880         vfile_hdr.media_type = htoles(22);
881         break;
882
883     case WTAP_ENCAP_FRELAY_WITH_PHDR:
884         vfile_hdr.media_type = htoles(32);
885         break;
886     }
887
888     /* Write the file header following the magic bytes. */
889     if (!wtap_dump_file_write(wdh, &vfile_hdr, sizeof vfile_hdr, err))
890     {
891         visual_dump_free(wdh);
892         return FALSE;
893     }
894
895     /* Deallocate the file write data */
896     visual_dump_free(wdh);
897     return TRUE;
898 }
899
900
901 /* Free the memory allocated by a visual file writer. */
902 static void visual_dump_free(wtap_dumper *wdh)
903 {
904     struct visual_write_info * visual = wdh->priv;
905
906     if (visual)
907     {
908         /* Free the index table memory. */
909         if (visual->index_table)
910             g_free(visual->index_table);
911     }
912 }