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