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