The "file types" we have are actually combinations of types and
[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_seek_read(wtap *wth, gint64 seek_off,
107     struct wtap_pkthdr *phdr, Buffer *buf, int length,
108     int *err, gchar **err_info);
109 static int _5views_read_header(wtap *wth, FILE_T fh, t_5VW_TimeStamped_Header *hdr,
110     struct wtap_pkthdr *phdr, int *err, gchar **err_info);
111
112 static gboolean _5views_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, const guint8 *pd, int *err);
113 static gboolean _5views_dump_close(wtap_dumper *wdh, int *err);
114
115
116 int _5views_open(wtap *wth, int *err, gchar **err_info)
117 {
118         int bytes_read;
119         t_5VW_Capture_Header Capture_Header;
120         int encap = WTAP_ENCAP_UNKNOWN;
121
122         errno = WTAP_ERR_CANT_READ;
123         bytes_read = file_read(&Capture_Header.Info_Header, sizeof(t_5VW_Info_Header), wth->fh);
124         if (bytes_read != sizeof(t_5VW_Info_Header)) {
125                 *err = file_error(wth->fh, err_info);
126                 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
127                         return -1;
128                 return 0;
129         }
130
131         /*      Check whether that's 5Views format or not */
132         if(Capture_Header.Info_Header.Signature != CST_5VW_INFO_HEADER_KEY)
133         {
134                 return 0;
135         }
136
137         /* Check Version */
138         Capture_Header.Info_Header.Version =
139             pletohl(&Capture_Header.Info_Header.Version);
140         switch (Capture_Header.Info_Header.Version) {
141
142         case CST_5VW_INFO_RECORD_VERSION:
143                 break;
144
145         default:
146                 *err = WTAP_ERR_UNSUPPORTED;
147                 *err_info = g_strdup_printf("5views: header version %u unsupported", Capture_Header.Info_Header.Version);
148                 return -1;
149         }
150
151         /* Check File Type */
152         Capture_Header.Info_Header.FileType =
153             pletohl(&Capture_Header.Info_Header.FileType);
154         if((Capture_Header.Info_Header.FileType & CST_5VW_CAPTURE_FILE_TYPE_MASK) != CST_5VW_CAPTURE_FILEID)
155         {
156                 *err = WTAP_ERR_UNSUPPORTED;
157                 *err_info = g_strdup_printf("5views: file is not a capture file (filetype is %u)", Capture_Header.Info_Header.Version);
158                 return -1;
159         }
160
161         /* Check possible Encap */
162         switch (Capture_Header.Info_Header.FileType) {
163         case CST_5VW_CAPTURE_ETH_FILEID:
164                 encap = WTAP_ENCAP_ETHERNET;
165                 break;
166 /*      case CST_5VW_CAPTURE_WAN_FILEID:
167                 break;
168 */
169         default:
170                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
171                 *err_info = g_strdup_printf("5views: network type %u unknown or unsupported",
172                     Capture_Header.Info_Header.FileType);
173                 return -1;
174         }
175
176         /* read the remaining header information */
177         bytes_read = file_read(&Capture_Header.HeaderDateCreation, sizeof (t_5VW_Capture_Header) - sizeof(t_5VW_Info_Header), wth->fh);
178         if (bytes_read != sizeof (t_5VW_Capture_Header)- sizeof(t_5VW_Info_Header) ) {
179                 *err = file_error(wth->fh, err_info);
180                 if (*err == 0)
181                         *err = WTAP_ERR_SHORT_READ;
182                 return -1;
183         }
184
185         /* This is a 5views capture file */
186         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_5VIEWS;
187         wth->subtype_read = _5views_read;
188         wth->subtype_seek_read = _5views_seek_read;
189         wth->file_encap = encap;
190         wth->snapshot_length = 0;       /* not available in header */
191         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
192
193         return 1;
194 }
195
196 /* Read the next packet */
197 static gboolean
198 _5views_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
199 {
200         t_5VW_TimeStamped_Header TimeStamped_Header;
201
202         /*
203          * Keep reading until we see a record with a subtype of
204          * CST_5VW_FRAME_RECORD.
205          */
206         do
207         {
208                 *data_offset = file_tell(wth->fh);
209
210                 /* Read record header. */
211                 if (!_5views_read_header(wth, wth->fh, &TimeStamped_Header,
212                     &wth->phdr, err, err_info))
213                         return FALSE;
214
215                 if (TimeStamped_Header.RecSubType == CST_5VW_FRAME_RECORD) {
216                         /*
217                          * OK, this is a packet.
218                          */
219                         break;
220                 }
221
222                 /*
223                  * Not a packet - skip to the next record.
224                  */
225                 if (file_seek(wth->fh, TimeStamped_Header.RecSize, SEEK_CUR, err) == -1)
226                         return FALSE;
227         } while (1);
228
229         if (wth->phdr.caplen > WTAP_MAX_PACKET_SIZE) {
230                 /*
231                  * Probably a corrupt capture file; don't blow up trying
232                  * to allocate space for an immensely-large packet.
233                  */
234                 *err = WTAP_ERR_BAD_FILE;
235                 *err_info = g_strdup_printf("5views: File has %u-byte packet, bigger than maximum of %u",
236                     wth->phdr.caplen, WTAP_MAX_PACKET_SIZE);
237                 return FALSE;
238         }
239
240         return wtap_read_packet_bytes(wth->fh, wth->frame_buffer,
241             wth->phdr.caplen, err, err_info);
242 }
243
244 static gboolean
245 _5views_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
246     Buffer *buf, int length, int *err, gchar **err_info)
247 {
248         t_5VW_TimeStamped_Header TimeStamped_Header;
249
250         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
251                 return FALSE;
252
253         /*
254          * Read the header.
255          */
256         if (!_5views_read_header(wth, wth->random_fh, &TimeStamped_Header,
257             phdr, err, err_info))
258                 return FALSE;
259
260         /*
261          * Read the packet data.
262          */
263         return wtap_read_packet_bytes(wth->random_fh, buf, length,
264             err, err_info);
265 }
266
267 /* Read the header of the next packet.  Return TRUE on success, FALSE
268    on error. */
269 static gboolean
270 _5views_read_header(wtap *wth, FILE_T fh, t_5VW_TimeStamped_Header *hdr,
271     struct wtap_pkthdr *phdr, int *err, gchar **err_info)
272 {
273         int     bytes_read, bytes_to_read;
274
275         bytes_to_read = sizeof(t_5VW_TimeStamped_Header);
276
277         /* Read record header. */
278         bytes_read = file_read(hdr, bytes_to_read, fh);
279         if (bytes_read != bytes_to_read) {
280                 *err = file_error(fh, err_info);
281                 if (*err == 0 && bytes_read != 0) {
282                         *err = WTAP_ERR_SHORT_READ;
283                 }
284                 return FALSE;
285         }
286
287         hdr->Key = pletohl(&hdr->Key);
288         if (hdr->Key != CST_5VW_RECORDS_HEADER_KEY) {
289                 *err = WTAP_ERR_BAD_FILE;
290                 *err_info = g_strdup_printf("5views: Time-stamped header has bad key value 0x%08X",
291                     hdr->Key);
292                 return FALSE;
293         }
294
295         hdr->RecSubType = pletohl(&hdr->RecSubType);
296         hdr->RecSize = pletohl(&hdr->RecSize);
297         hdr->Utc = pletohl(&hdr->Utc);
298         hdr->NanoSecondes = pletohl(&hdr->NanoSecondes);
299
300         phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
301         phdr->ts.secs = hdr->Utc;
302         phdr->ts.nsecs = hdr->NanoSecondes;
303         phdr->caplen = hdr->RecSize;
304         phdr->len = hdr->RecSize;
305
306         switch (wth->file_encap) {
307
308         case WTAP_ENCAP_ETHERNET:
309                 /* We assume there's no FCS in this frame. */
310                 phdr->pseudo_header.eth.fcs_len = 0;
311                 break;
312         }
313
314         return TRUE;
315 }
316
317 typedef struct {
318         guint32 nframes;
319 } _5views_dump_t;
320
321 static const int wtap_encap[] = {
322         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
323         CST_5VW_CAPTURE_ETH_FILEID,             /* WTAP_ENCAP_ETHERNET -> Ethernet */
324 };
325 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
326
327 /* Returns 0 if we could write the specified encapsulation type,
328    an error indication otherwise. */
329 int _5views_dump_can_write_encap(int encap)
330 {
331         /* Per-packet encapsulations aren't supported. */
332         if (encap == WTAP_ENCAP_PER_PACKET)
333                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
334
335         if (encap < 0 || (unsigned) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
336                 return WTAP_ERR_UNSUPPORTED_ENCAP;
337
338         return 0;
339 }
340
341 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
342    failure */
343 gboolean _5views_dump_open(wtap_dumper *wdh, int *err)
344 {
345         _5views_dump_t *_5views;
346
347         /* We can't fill in all the fields in the file header, as we
348            haven't yet written any packets.  As we'll have to rewrite
349            the header when we've written out all the packets, we just
350            skip over the header for now. */
351         if (wtap_dump_file_seek(wdh, sizeof(t_5VW_Capture_Header), SEEK_SET, err) == -1) 
352                 return FALSE;
353
354         /* This is a 5Views file */
355         wdh->subtype_write = _5views_dump;
356         wdh->subtype_close = _5views_dump_close;
357         _5views = (_5views_dump_t *)g_malloc(sizeof(_5views_dump_t));
358         wdh->priv = (void *)_5views;
359         _5views->nframes = 0;
360
361         return TRUE;
362 }
363
364 /* Write a record for a packet to a dump file.
365    Returns TRUE on success, FALSE on failure. */
366 static gboolean _5views_dump(wtap_dumper *wdh,
367         const struct wtap_pkthdr *phdr,
368         const guint8 *pd, int *err)
369 {
370         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
371         t_5VW_TimeStamped_Header HeaderFrame;
372
373         /* Frame Header */
374         /* constant fields */
375         HeaderFrame.Key = htolel(CST_5VW_RECORDS_HEADER_KEY);
376         HeaderFrame.HeaderSize = htoles(sizeof(t_5VW_TimeStamped_Header));
377         HeaderFrame.HeaderType = htoles(CST_5VW_TIMESTAMPED_HEADER_TYPE);
378         HeaderFrame.RecType = htolel(CST_5VW_CAPTURES_RECORD | CST_5VW_SYSTEM_RECORD);
379         HeaderFrame.RecSubType = htolel(CST_5VW_FRAME_RECORD);
380         HeaderFrame.RecNb = htolel(1);
381
382         /* record-dependent fields */
383         HeaderFrame.Utc = htolel(phdr->ts.secs);
384         HeaderFrame.NanoSecondes = htolel(phdr->ts.nsecs);
385         HeaderFrame.RecSize = htolel(phdr->len);
386         HeaderFrame.RecInfo = htolel(0);
387
388         /* write the record header */
389         if (!wtap_dump_file_write(wdh, &HeaderFrame,
390             sizeof(t_5VW_TimeStamped_Header), err))
391                 return FALSE;
392
393         /* write the data */
394         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
395                 return FALSE;
396
397         _5views->nframes ++;
398
399         return TRUE;
400 }
401
402 static gboolean _5views_dump_close(wtap_dumper *wdh, int *err)
403 {
404         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
405         t_5VW_Capture_Header file_hdr;
406
407         if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1) 
408                 return FALSE;
409
410         /* fill in the Info_Header */
411         file_hdr.Info_Header.Signature = htolel(CST_5VW_INFO_HEADER_KEY);
412         file_hdr.Info_Header.Size = htolel(sizeof(t_5VW_Info_Header));  /* Total size of Header in bytes (included Signature) */
413         file_hdr.Info_Header.Version = htolel(CST_5VW_INFO_RECORD_VERSION); /* Identify version and so the format of this record */
414         file_hdr.Info_Header.DataSize = htolel(sizeof(t_5VW_Attributes_Header)
415                                         + sizeof(guint32)
416                                         + sizeof(t_5VW_Attributes_Header)
417                                         + sizeof(guint32));
418                                         /* Total size of data included in the Info Record (except the header size) */
419         file_hdr.Info_Header.FileType = htolel(wtap_encap[wdh->encap]); /* Type of the file */
420         file_hdr.Info_Header.Reserved[0] = 0;   /* Reserved for future use */
421         file_hdr.Info_Header.Reserved[1] = 0;   /* Reserved for future use */
422         file_hdr.Info_Header.Reserved[2] = 0;   /* Reserved for future use */
423
424         /* fill in the HeaderDateCreation */
425         file_hdr.HeaderDateCreation.Type = htolel(CST_5VW_IA_DATE_CREATION);    /* Id of the attribute */
426         file_hdr.HeaderDateCreation.Size = htoles(sizeof(guint32));     /* Size of the data part of the attribute (not including header size) */
427         file_hdr.HeaderDateCreation.Nb = htoles(1);                     /* Number of elements */
428
429         /* fill in the Time field */
430 #ifdef _WIN32
431         _tzset();
432 #endif
433         file_hdr.Time = htolel(time(NULL));
434
435         /* fill in the Time field */
436         file_hdr.HeaderNbFrames.Type = htolel(CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES);   /* Id of the attribute */
437         file_hdr.HeaderNbFrames.Size = htoles(sizeof(guint32)); /* Size of the data part of the attribute (not including header size) */
438         file_hdr.HeaderNbFrames.Nb = htoles(1);                 /* Number of elements */
439
440         /* fill in the number of frames saved */
441         file_hdr.TramesStockeesInFile = htolel(_5views->nframes);
442
443         /* Write the file header. */
444         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof(t_5VW_Capture_Header),
445             err))
446                 return FALSE;
447
448         return TRUE;
449 }