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