Export libwireshark symbols using WS_DLL_PUBLIC define
[metze/wireshark/wip.git] / wiretap / 5views.c
1 /* 5views.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include <errno.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include "wtap-int.h"
29 #include "file_wrappers.h"
30 #include "buffer.h"
31 #include "5views.h"
32
33
34 typedef struct
35 {
36         guint32 Signature;
37         guint32 Size;           /* Total size of Header in bytes (included Signature) */
38         guint32 Version;        /* Identify version and so the format of this record */
39         guint32 DataSize;       /* Total size of data included in the Info Record (except the header size) */
40         guint32 FileType;       /* Type of the file */
41         guint32 Reserved[3];    /* Reserved for future use */
42 }t_5VW_Info_Header;
43
44 typedef struct
45 {
46         guint32 Type;   /* Id of the attribute */
47         guint16 Size;   /* Size of the data part of the attribute (not including header size) */
48         guint16 Nb;     /* Number of elements */
49 }t_5VW_Attributes_Header;
50
51
52 #define CST_5VW_INFO_HEADER_KEY         0xAAAAAAAAU             /* signature */
53
54 #define CST_5VW_INFO_RECORD_VERSION     0x00010000U             /* version */
55
56 #define CST_5VW_DECALE_FILE_TYPE        24
57 #define CST_5VW_SECTION_CAPTURES        0x08U
58 #define CST_5VW_CAPTURES_FILE           (CST_5VW_SECTION_CAPTURES << CST_5VW_DECALE_FILE_TYPE)          /* 0x08000000 */
59 #define CST_5VW_FLAT_FILE               0x10000000U
60 #define CST_5VW_CAPTURE_FILEID          (CST_5VW_FLAT_FILE | CST_5VW_CAPTURES_FILE)
61 #define CST_5VW_FAMILY_CAP_ETH          0x01U
62 #define CST_5VW_FAMILY_CAP_WAN          0x02U
63 #define CST_5VW_DECALE_FILE_FAMILY      12
64 #define CST_5VW_CAP_ETH                 (CST_5VW_FAMILY_CAP_ETH << CST_5VW_DECALE_FILE_FAMILY)  /* 0x00001000 */
65 #define CST_5VW_CAP_WAN                 (CST_5VW_FAMILY_CAP_WAN << CST_5VW_DECALE_FILE_FAMILY)  /* 0x00002000 */
66 #define CST_5VW_CAPTURE_ETH_FILEID      (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_ETH)
67 #define CST_5VW_CAPTURE_WAN_FILEID      (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_WAN)
68
69 #define CST_5VW_CAPTURE_FILE_TYPE_MASK  0xFF000000U
70
71 #define CST_5VW_FRAME_RECORD            0x00000000U
72 #define CST_5VW_RECORDS_HEADER_KEY      0x3333EEEEU
73
74 typedef struct
75 {
76         t_5VW_Info_Header       Info_Header;
77         t_5VW_Attributes_Header HeaderDateCreation;
78         guint32                 Time;
79         t_5VW_Attributes_Header HeaderNbFrames;
80         guint32                 TramesStockeesInFile;
81 }t_5VW_Capture_Header;
82
83 typedef struct
84 {
85         guint32 Key;                    /* 0x3333EEEE */
86         guint16 HeaderSize;             /* Actual size of this header in bytes (32) */
87         guint16 HeaderType;             /* Exact type of this header (0x4000) */
88         guint32 RecType;                /* Type of record */
89         guint32 RecSubType;             /* Subtype of record */
90         guint32 RecSize;                /* Size of one record */
91         guint32 RecNb;                  /* Number of records */
92         guint32 Utc;
93         guint32 NanoSecondes;
94         guint32 RecInfo;                /* Info about Alarm / Event / Frame captured */
95 }t_5VW_TimeStamped_Header;
96
97
98 #define CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES   0x20000000U
99 #define CST_5VW_IA_DATE_CREATION                0x80000007U     /* Struct t_Attrib_Date_Create */
100 #define CST_5VW_TIMESTAMPED_HEADER_TYPE         0x4000U
101 #define CST_5VW_CAPTURES_RECORD         (CST_5VW_SECTION_CAPTURES << 28)        /* 0x80000000 */
102 #define CST_5VW_SYSTEM_RECORD           0x00000000U
103
104 static gboolean _5views_read(wtap *wth, int *err, gchar **err_info,
105     gint64 *data_offset);
106 static gboolean _5views_read_rec_data(FILE_T fh, guint8 *pd, int length,
107     int *err, gchar **err_info);
108 static int _5views_read_header(wtap *wth, FILE_T fh,
109     t_5VW_TimeStamped_Header  *hdr, int *err, gchar **err_info);
110 static gboolean _5views_seek_read(wtap *wth, gint64 seek_off,
111     struct wtap_pkthdr *phdr, guint8 *pd, int length,
112     int *err, gchar **err_info);
113
114
115 static gboolean _5views_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, const guint8 *pd, int *err);
116 static gboolean _5views_dump_close(wtap_dumper *wdh, int *err);
117
118
119 int _5views_open(wtap *wth, int *err, gchar **err_info)
120 {
121         int bytes_read;
122         t_5VW_Capture_Header Capture_Header;
123         int encap = WTAP_ENCAP_UNKNOWN;
124
125         errno = WTAP_ERR_CANT_READ;
126         bytes_read = file_read(&Capture_Header.Info_Header, sizeof(t_5VW_Info_Header), wth->fh);
127         if (bytes_read != sizeof(t_5VW_Info_Header)) {
128                 *err = file_error(wth->fh, err_info);
129                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
130                         return -1;
131                 return 0;
132         }
133
134         /*      Check whether that's 5Views format or not */
135         if(Capture_Header.Info_Header.Signature != CST_5VW_INFO_HEADER_KEY)
136         {
137                 return 0;
138         }
139
140         /* Check Version */
141         Capture_Header.Info_Header.Version =
142             pletohl(&Capture_Header.Info_Header.Version);
143         switch (Capture_Header.Info_Header.Version) {
144
145         case CST_5VW_INFO_RECORD_VERSION:
146                 break;
147
148         default:
149                 *err = WTAP_ERR_UNSUPPORTED;
150                 *err_info = g_strdup_printf("5views: header version %u unsupported", Capture_Header.Info_Header.Version);
151                 return -1;
152         }
153
154         /* Check File Type */
155         Capture_Header.Info_Header.FileType =
156             pletohl(&Capture_Header.Info_Header.FileType);
157         if((Capture_Header.Info_Header.FileType & CST_5VW_CAPTURE_FILE_TYPE_MASK) != CST_5VW_CAPTURE_FILEID)
158         {
159                 *err = WTAP_ERR_UNSUPPORTED;
160                 *err_info = g_strdup_printf("5views: file is not a capture file (filetype is %u)", Capture_Header.Info_Header.Version);
161                 return -1;
162         }
163
164         /* Check possible Encap */
165         switch (Capture_Header.Info_Header.FileType) {
166         case CST_5VW_CAPTURE_ETH_FILEID:
167                 encap = WTAP_ENCAP_ETHERNET;
168                 break;
169 /*      case CST_5VW_CAPTURE_WAN_FILEID:
170                 break;
171 */
172         default:
173                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
174                 *err_info = g_strdup_printf("5views: network type %u unknown or unsupported",
175                     Capture_Header.Info_Header.FileType);
176                 return -1;
177         }
178
179         /* read the remaining header information */
180         bytes_read = file_read(&Capture_Header.HeaderDateCreation, sizeof (t_5VW_Capture_Header) - sizeof(t_5VW_Info_Header), wth->fh);
181         if (bytes_read != sizeof (t_5VW_Capture_Header)- sizeof(t_5VW_Info_Header) ) {
182                 *err = file_error(wth->fh, err_info);
183                 if (*err == 0)
184                         *err = WTAP_ERR_SHORT_READ;
185                 return -1;
186         }
187
188         /* This is a 5views capture file */
189         wth->file_type = WTAP_FILE_5VIEWS;
190         wth->subtype_read = _5views_read;
191         wth->subtype_seek_read = _5views_seek_read;
192         wth->file_encap = encap;
193         wth->snapshot_length = 0;       /* not available in header */
194         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
195
196         return 1;
197 }
198
199 /* Read the next packet */
200 static gboolean
201 _5views_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
202 {
203         t_5VW_TimeStamped_Header TimeStamped_Header;
204         int     bytes_read;
205         guint packet_size;
206         guint orig_size;
207
208         do
209         {
210                 bytes_read = _5views_read_header(wth, wth->fh, &TimeStamped_Header, err, err_info);
211                 if (bytes_read == -1) {
212                         /*
213                          * We failed to read the header.
214                          */
215                         return FALSE;
216                 }
217
218                 TimeStamped_Header.Key = pletohl(&TimeStamped_Header.Key);
219                 if(TimeStamped_Header.Key != CST_5VW_RECORDS_HEADER_KEY) {
220                         *err = WTAP_ERR_BAD_FILE;
221                         *err_info = g_strdup_printf("5views: Time-stamped header has bad key value 0x%08X",
222                             TimeStamped_Header.Key);
223                         return FALSE;
224                 }
225
226                 TimeStamped_Header.RecSubType =
227                     pletohl(&TimeStamped_Header.RecSubType);
228                 TimeStamped_Header.RecSize =
229                     pletohl(&TimeStamped_Header.RecSize);
230                 if(TimeStamped_Header.RecSubType != CST_5VW_FRAME_RECORD) {
231                         if (file_seek(wth->fh, TimeStamped_Header.RecSize, SEEK_CUR, err) == -1)
232                                 return FALSE;
233                 } else
234                         break;
235         } while (1);
236
237         packet_size = TimeStamped_Header.RecSize;
238         orig_size = TimeStamped_Header.RecSize;
239         if (packet_size > WTAP_MAX_PACKET_SIZE) {
240                 /*
241                  * Probably a corrupt capture file; don't blow up trying
242                  * to allocate space for an immensely-large packet.
243                  */
244                 *err = WTAP_ERR_BAD_FILE;
245                 *err_info = g_strdup_printf("5views: File has %u-byte packet, bigger than maximum of %u",
246                     packet_size, WTAP_MAX_PACKET_SIZE);
247                 return FALSE;
248         }
249
250         *data_offset = file_tell(wth->fh);
251
252         buffer_assure_space(wth->frame_buffer, packet_size);
253         if (!_5views_read_rec_data(wth->fh, buffer_start_ptr(wth->frame_buffer),
254             packet_size, err, err_info))
255                 return FALSE;   /* Read error */
256
257         TimeStamped_Header.Utc = pletohl(&TimeStamped_Header.Utc);
258         TimeStamped_Header.NanoSecondes =
259             pletohl(&TimeStamped_Header.NanoSecondes);
260         wth->phdr.presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
261         wth->phdr.ts.secs = TimeStamped_Header.Utc;
262         wth->phdr.ts.nsecs = TimeStamped_Header.NanoSecondes;
263         wth->phdr.caplen = packet_size;
264         wth->phdr.len = orig_size;
265
266         switch (wth->file_encap) {
267
268         case WTAP_ENCAP_ETHERNET:
269                 /* We assume there's no FCS in this frame. */
270                 wth->phdr.pseudo_header.eth.fcs_len = 0;
271                 break;
272         }
273
274         return TRUE;
275 }
276
277
278
279 static gboolean
280 _5views_read_rec_data(FILE_T fh, guint8 *pd, int length, int *err,
281    gchar **err_info)
282 {
283         int     bytes_read;
284
285         errno = WTAP_ERR_CANT_READ;
286         bytes_read = file_read(pd, length, fh);
287
288         if (bytes_read != length) {
289                 *err = file_error(fh, err_info);
290                 if (*err == 0)
291                         *err = WTAP_ERR_SHORT_READ;
292                 return FALSE;
293         }
294         return TRUE;
295 }
296
297
298 /* Read the header of the next packet; if "silent" is TRUE, don't complain
299    to the console, as we're testing to see if the file appears to be of a
300    particular type.
301
302    Return -1 on an error, or the number of bytes of header read on success. */
303 static int
304 _5views_read_header(wtap *wth _U_, FILE_T fh, t_5VW_TimeStamped_Header  *hdr,   int *err, gchar **err_info)
305 {
306         int     bytes_read, bytes_to_read;
307
308         bytes_to_read = sizeof(t_5VW_TimeStamped_Header);
309
310         /* Read record header. */
311         bytes_read = file_read(hdr, bytes_to_read, fh);
312         if (bytes_read != bytes_to_read) {
313                 *err = file_error(fh, err_info);
314                 if (*err == 0 && bytes_read != 0) {
315                         *err = WTAP_ERR_SHORT_READ;
316                 }
317                 return -1;
318         }
319
320         return bytes_read;
321 }
322
323 static gboolean
324 _5views_seek_read(wtap *wth, gint64 seek_off,
325     struct wtap_pkthdr *phdr, guint8 *pd, int length,
326     int *err, gchar **err_info)
327 {
328         union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
329         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
330                 return FALSE;
331         /*
332          * Read the packet data.
333          */
334         if (!_5views_read_rec_data(wth->random_fh, pd, length, err, err_info))
335                 return FALSE;
336
337         switch (wth->file_encap) {
338
339         case WTAP_ENCAP_ETHERNET:
340                 /* We assume there's no FCS in this frame. */
341                 pseudo_header->eth.fcs_len = 0;
342                 break;
343         }
344
345         return TRUE;
346 }
347
348
349
350 typedef struct {
351         guint32 nframes;
352 } _5views_dump_t;
353
354 static const int wtap_encap[] = {
355         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
356         CST_5VW_CAPTURE_ETH_FILEID,             /* WTAP_ENCAP_ETHERNET -> Ethernet */
357 };
358 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
359
360 /* Returns 0 if we could write the specified encapsulation type,
361    an error indication otherwise. */
362 int _5views_dump_can_write_encap(int encap)
363 {
364         /* Per-packet encapsulations aren't supported. */
365         if (encap == WTAP_ENCAP_PER_PACKET)
366                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
367
368         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
369                 return WTAP_ERR_UNSUPPORTED_ENCAP;
370
371         return 0;
372 }
373
374 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
375    failure */
376 gboolean _5views_dump_open(wtap_dumper *wdh, int *err)
377 {
378         _5views_dump_t *_5views;
379
380         /* We can't fill in all the fields in the file header, as we
381            haven't yet written any packets.  As we'll have to rewrite
382            the header when we've written out all the packets, we just
383            skip over the header for now. */
384         if (fseek(wdh->fh, sizeof(t_5VW_Capture_Header), SEEK_SET) == -1) {
385                 *err = errno;
386                 return FALSE;
387         }
388
389         /* This is a 5Views file */
390         wdh->subtype_write = _5views_dump;
391         wdh->subtype_close = _5views_dump_close;
392         _5views = (_5views_dump_t *)g_malloc(sizeof(_5views_dump_t));
393         wdh->priv = (void *)_5views;
394         _5views->nframes = 0;
395
396         return TRUE;
397 }
398
399 /* Write a record for a packet to a dump file.
400    Returns TRUE on success, FALSE on failure. */
401 static gboolean _5views_dump(wtap_dumper *wdh,
402         const struct wtap_pkthdr *phdr,
403         const guint8 *pd, int *err)
404 {
405         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
406         static t_5VW_TimeStamped_Header HeaderFrame;
407
408         /* Frame Header */
409         /* constant fields */
410         HeaderFrame.Key = htolel(CST_5VW_RECORDS_HEADER_KEY);
411         HeaderFrame.HeaderSize = htoles(sizeof(t_5VW_TimeStamped_Header));
412         HeaderFrame.HeaderType = htoles(CST_5VW_TIMESTAMPED_HEADER_TYPE);
413         HeaderFrame.RecType = htolel(CST_5VW_CAPTURES_RECORD | CST_5VW_SYSTEM_RECORD);
414         HeaderFrame.RecSubType = htolel(CST_5VW_FRAME_RECORD);
415         HeaderFrame.RecNb = htolel(1);
416
417         /* record-dependant fields */
418         HeaderFrame.Utc = htolel(phdr->ts.secs);
419         HeaderFrame.NanoSecondes = htolel(phdr->ts.nsecs);
420         HeaderFrame.RecSize = htolel(phdr->len);
421         HeaderFrame.RecInfo = htolel(0);
422
423         /* write the record header */
424         if (!wtap_dump_file_write(wdh, &HeaderFrame,
425             sizeof(t_5VW_TimeStamped_Header), err))
426                 return FALSE;
427
428         /* write the data */
429         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
430                 return FALSE;
431
432         _5views->nframes ++;
433
434         return TRUE;
435 }
436
437 static gboolean _5views_dump_close(wtap_dumper *wdh, int *err)
438 {
439         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
440         t_5VW_Capture_Header file_hdr;
441
442         if (fseek(wdh->fh, 0, SEEK_SET) == -1) {
443                 *err = errno;
444                 return FALSE;
445         }
446
447         /* fill in the Info_Header */
448         file_hdr.Info_Header.Signature = htolel(CST_5VW_INFO_HEADER_KEY);
449         file_hdr.Info_Header.Size = htolel(sizeof(t_5VW_Info_Header));  /* Total size of Header in bytes (included Signature) */
450         file_hdr.Info_Header.Version = htolel(CST_5VW_INFO_RECORD_VERSION); /* Identify version and so the format of this record */
451         file_hdr.Info_Header.DataSize = htolel(sizeof(t_5VW_Attributes_Header)
452                                         + sizeof(guint32)
453                                         + sizeof(t_5VW_Attributes_Header)
454                                         + sizeof(guint32));
455                                         /* Total size of data included in the Info Record (except the header size) */
456         file_hdr.Info_Header.FileType = htolel(wtap_encap[wdh->encap]); /* Type of the file */
457         file_hdr.Info_Header.Reserved[0] = 0;   /* Reserved for future use */
458         file_hdr.Info_Header.Reserved[1] = 0;   /* Reserved for future use */
459         file_hdr.Info_Header.Reserved[2] = 0;   /* Reserved for future use */
460
461         /* fill in the HeaderDateCreation */
462         file_hdr.HeaderDateCreation.Type = htolel(CST_5VW_IA_DATE_CREATION);    /* Id of the attribute */
463         file_hdr.HeaderDateCreation.Size = htoles(sizeof(guint32));     /* Size of the data part of the attribute (not including header size) */
464         file_hdr.HeaderDateCreation.Nb = htoles(1);                     /* Number of elements */
465
466         /* fill in the Time field */
467 #ifdef _WIN32
468         _tzset();
469 #endif
470         file_hdr.Time = htolel(time(NULL));
471
472         /* fill in the Time field */
473         file_hdr.HeaderNbFrames.Type = htolel(CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES);   /* Id of the attribute */
474         file_hdr.HeaderNbFrames.Size = htoles(sizeof(guint32)); /* Size of the data part of the attribute (not including header size) */
475         file_hdr.HeaderNbFrames.Nb = htoles(1);                 /* Number of elements */
476
477         /* fill in the number of frames saved */
478         file_hdr.TramesStockeesInFile = htolel(_5views->nframes);
479
480         /* Write the file header. */
481         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof(t_5VW_Capture_Header),
482             err))
483                 return FALSE;
484
485         return TRUE;
486 }