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