diff options
Diffstat (limited to 'wiretap/5views.c')
-rw-r--r-- | wiretap/5views.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/wiretap/5views.c b/wiretap/5views.c new file mode 100644 index 00000000..c474804a --- /dev/null +++ b/wiretap/5views.c @@ -0,0 +1,501 @@ +/* 5views.c + * + * Wiretap Library + * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" +#include <string.h> + +#include "wtap-int.h" +#include "file_wrappers.h" +#include "5views.h" + + +typedef struct +{ + guint32 Signature; + guint32 Size; /* Total size of Header in bytes (included Signature) */ + guint32 Version; /* Identify version and so the format of this record */ + guint32 DataSize; /* Total size of data included in the Info Record (except the header size) */ + guint32 FileType; /* Type of the file */ + guint32 Reserved[3]; /* Reserved for future use */ +}t_5VW_Info_Header; + +typedef struct +{ + guint32 Type; /* Id of the attribute */ + guint16 Size; /* Size of the data part of the attribute (not including header size) */ + guint16 Nb; /* Number of elements */ +}t_5VW_Attributes_Header; + + +#define CST_5VW_INFO_HEADER_KEY 0xAAAAAAAAU /* signature */ + +#define CST_5VW_INFO_RECORD_VERSION 0x00010000U /* version */ + +#define CST_5VW_DECALE_FILE_TYPE 24 +#define CST_5VW_SECTION_CAPTURES 0x08U +#define CST_5VW_CAPTURES_FILE (CST_5VW_SECTION_CAPTURES << CST_5VW_DECALE_FILE_TYPE) /* 0x08000000 */ +#define CST_5VW_FLAT_FILE 0x10000000U +#define CST_5VW_CAPTURE_FILEID (CST_5VW_FLAT_FILE | CST_5VW_CAPTURES_FILE) +#define CST_5VW_FAMILY_CAP_ETH 0x01U +#define CST_5VW_FAMILY_CAP_WAN 0x02U +#define CST_5VW_DECALE_FILE_FAMILY 12 +#define CST_5VW_CAP_ETH (CST_5VW_FAMILY_CAP_ETH << CST_5VW_DECALE_FILE_FAMILY) /* 0x00001000 */ +#define CST_5VW_CAP_WAN (CST_5VW_FAMILY_CAP_WAN << CST_5VW_DECALE_FILE_FAMILY) /* 0x00002000 */ +#define CST_5VW_CAPTURE_ETH_FILEID (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_ETH) +#define CST_5VW_CAPTURE_WAN_FILEID (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_WAN) + +#define CST_5VW_CAPTURE_FILE_TYPE_MASK 0xFF000000U + +#define CST_5VW_FRAME_RECORD 0x00000000U +#define CST_5VW_RECORDS_HEADER_KEY 0x3333EEEEU + +typedef struct +{ + t_5VW_Info_Header Info_Header; + t_5VW_Attributes_Header HeaderDateCreation; + guint32 Time; + t_5VW_Attributes_Header HeaderNbFrames; + guint32 TramesStockeesInFile; +}t_5VW_Capture_Header; + +typedef struct +{ + guint32 Key; /* 0x3333EEEE */ + guint16 HeaderSize; /* Actual size of this header in bytes (32) */ + guint16 HeaderType; /* Exact type of this header (0x4000) */ + guint32 RecType; /* Type of record */ + guint32 RecSubType; /* Subtype of record */ + guint32 RecSize; /* Size of one record */ + guint32 RecNb; /* Number of records */ + guint32 Utc; + guint32 NanoSecondes; + guint32 RecInfo; /* Info about Alarm / Event / Frame captured */ +}t_5VW_TimeStamped_Header; + + +#define CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES 0x20000000U +#define CST_5VW_IA_DATE_CREATION 0x80000007U /* Struct t_Attrib_Date_Create */ +#define CST_5VW_TIMESTAMPED_HEADER_TYPE 0x4000U +#define CST_5VW_CAPTURES_RECORD (CST_5VW_SECTION_CAPTURES << 28) /* 0x80000000 */ +#define CST_5VW_SYSTEM_RECORD 0x00000000U + +static gboolean _5views_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, + gchar **err_info, gint64 *data_offset); +static gboolean _5views_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, + Buffer *buf, int *err, gchar **err_info); +static int _5views_read_header(wtap *wth, FILE_T fh, t_5VW_TimeStamped_Header *hdr, + wtap_rec *rec, int *err, gchar **err_info); + +static gboolean _5views_dump(wtap_dumper *wdh, const wtap_rec *rec, const guint8 *pd, int *err, gchar **err_info); +static gboolean _5views_dump_finish(wtap_dumper *wdh, int *err, gchar **err_info); + +static int _5views_file_type_subtype = -1; + +void register_5views(void); + +wtap_open_return_val +_5views_open(wtap *wth, int *err, gchar **err_info) +{ + t_5VW_Capture_Header Capture_Header; + int encap = WTAP_ENCAP_UNKNOWN; + + if (!wtap_read_bytes(wth->fh, &Capture_Header.Info_Header, + sizeof(t_5VW_Info_Header), err, err_info)) { + if (*err != WTAP_ERR_SHORT_READ) + return WTAP_OPEN_ERROR; + return WTAP_OPEN_NOT_MINE; + } + + /* Check whether that's 5Views format or not */ + if(Capture_Header.Info_Header.Signature != CST_5VW_INFO_HEADER_KEY) + { + return WTAP_OPEN_NOT_MINE; + } + + /* Check Version */ + Capture_Header.Info_Header.Version = + pletoh32(&Capture_Header.Info_Header.Version); + switch (Capture_Header.Info_Header.Version) { + + case CST_5VW_INFO_RECORD_VERSION: + break; + + default: + *err = WTAP_ERR_UNSUPPORTED; + *err_info = ws_strdup_printf("5views: header version %u unsupported", Capture_Header.Info_Header.Version); + return WTAP_OPEN_ERROR; + } + + /* Check File Type */ + Capture_Header.Info_Header.FileType = + pletoh32(&Capture_Header.Info_Header.FileType); + if((Capture_Header.Info_Header.FileType & CST_5VW_CAPTURE_FILE_TYPE_MASK) != CST_5VW_CAPTURE_FILEID) + { + *err = WTAP_ERR_UNSUPPORTED; + *err_info = ws_strdup_printf("5views: file is not a capture file (filetype is %u)", Capture_Header.Info_Header.Version); + return WTAP_OPEN_ERROR; + } + + /* Check possible Encap */ + switch (Capture_Header.Info_Header.FileType) { + case CST_5VW_CAPTURE_ETH_FILEID: + encap = WTAP_ENCAP_ETHERNET; + break; +/* case CST_5VW_CAPTURE_WAN_FILEID: + break; +*/ + default: + *err = WTAP_ERR_UNSUPPORTED; + *err_info = ws_strdup_printf("5views: network type %u unknown or unsupported", + Capture_Header.Info_Header.FileType); + return WTAP_OPEN_ERROR; + } + + /* read the remaining header information */ + if (!wtap_read_bytes(wth->fh, &Capture_Header.HeaderDateCreation, + sizeof (t_5VW_Capture_Header) - sizeof(t_5VW_Info_Header), err, err_info)) + return WTAP_OPEN_ERROR; + + /* This is a 5views capture file */ + wth->file_type_subtype = _5views_file_type_subtype; + wth->subtype_read = _5views_read; + wth->subtype_seek_read = _5views_seek_read; + wth->file_encap = encap; + wth->snapshot_length = 0; /* not available in header */ + wth->file_tsprec = WTAP_TSPREC_NSEC; + + /* + * Add an IDB; we don't know how many interfaces were + * involved, so we just say one interface, about which + * we only know the link-layer type, snapshot length, + * and time stamp resolution. + */ + wtap_add_generated_idb(wth); + + return WTAP_OPEN_MINE; +} + +/* Read the next packet */ +static gboolean +_5views_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, + gchar **err_info, gint64 *data_offset) +{ + t_5VW_TimeStamped_Header TimeStamped_Header; + + /* + * Keep reading until we see a record with a subtype of + * CST_5VW_FRAME_RECORD. + */ + do + { + *data_offset = file_tell(wth->fh); + + /* Read record header. */ + if (!_5views_read_header(wth, wth->fh, &TimeStamped_Header, + rec, err, err_info)) + return FALSE; + + if (TimeStamped_Header.RecSubType == CST_5VW_FRAME_RECORD) { + /* + * OK, this is a packet. + */ + break; + } + + /* + * Not a packet - skip to the next record. + */ + if (!wtap_read_bytes(wth->fh, NULL, TimeStamped_Header.RecSize, err, err_info)) + return FALSE; + } while (1); + + if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) { + /* + * Probably a corrupt capture file; don't blow up trying + * to allocate space for an immensely-large packet. + */ + *err = WTAP_ERR_BAD_FILE; + *err_info = ws_strdup_printf("5views: File has %u-byte packet, bigger than maximum of %u", + rec->rec_header.packet_header.caplen, WTAP_MAX_PACKET_SIZE_STANDARD); + return FALSE; + } + + return wtap_read_packet_bytes(wth->fh, buf, + rec->rec_header.packet_header.caplen, err, err_info); +} + +static gboolean +_5views_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, + Buffer *buf, int *err, gchar **err_info) +{ + t_5VW_TimeStamped_Header TimeStamped_Header; + + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + return FALSE; + + /* + * Read the header. + */ + if (!_5views_read_header(wth, wth->random_fh, &TimeStamped_Header, + rec, err, err_info)) { + if (*err == 0) + *err = WTAP_ERR_SHORT_READ; + return FALSE; + } + + /* + * Read the packet data. + */ + return wtap_read_packet_bytes(wth->random_fh, buf, rec->rec_header.packet_header.caplen, + err, err_info); +} + +/* Read the header of the next packet. Return TRUE on success, FALSE + on error. */ +static gboolean +_5views_read_header(wtap *wth, FILE_T fh, t_5VW_TimeStamped_Header *hdr, + wtap_rec *rec, int *err, gchar **err_info) +{ + /* Read record header. */ + if (!wtap_read_bytes_or_eof(fh, hdr, (unsigned int)sizeof(t_5VW_TimeStamped_Header), + err, err_info)) + return FALSE; + + hdr->Key = pletoh32(&hdr->Key); + if (hdr->Key != CST_5VW_RECORDS_HEADER_KEY) { + *err = WTAP_ERR_BAD_FILE; + *err_info = ws_strdup_printf("5views: Time-stamped header has bad key value 0x%08X", + hdr->Key); + return FALSE; + } + + hdr->RecSubType = pletoh32(&hdr->RecSubType); + hdr->RecSize = pletoh32(&hdr->RecSize); + hdr->Utc = pletoh32(&hdr->Utc); + hdr->NanoSecondes = pletoh32(&hdr->NanoSecondes); + + rec->rec_type = REC_TYPE_PACKET; + rec->block = wtap_block_create(WTAP_BLOCK_PACKET); + rec->presence_flags = WTAP_HAS_TS; + rec->ts.secs = hdr->Utc; + rec->ts.nsecs = hdr->NanoSecondes; + rec->rec_header.packet_header.caplen = hdr->RecSize; + rec->rec_header.packet_header.len = hdr->RecSize; + + switch (wth->file_encap) { + + case WTAP_ENCAP_ETHERNET: + /* We assume there's no FCS in this frame. */ + rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0; + break; + } + + return TRUE; +} + +typedef struct { + guint32 nframes; +} _5views_dump_t; + +static const int wtap_encap[] = { + -1, /* WTAP_ENCAP_UNKNOWN -> unsupported */ + CST_5VW_CAPTURE_ETH_FILEID, /* WTAP_ENCAP_ETHERNET -> Ethernet */ +}; +#define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0]) + +/* Returns 0 if we could write the specified encapsulation type, + an error indication otherwise. */ +static int _5views_dump_can_write_encap(int encap) +{ + /* Per-packet encapsulations aren't supported. */ + if (encap == WTAP_ENCAP_PER_PACKET) + return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; + + if (encap < 0 || (unsigned int) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1) + return WTAP_ERR_UNWRITABLE_ENCAP; + + return 0; +} + +/* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on + failure */ +static gboolean _5views_dump_open(wtap_dumper *wdh, int *err, gchar **err_info _U_) +{ + _5views_dump_t *_5views; + + /* We can't fill in all the fields in the file header, as we + haven't yet written any packets. As we'll have to rewrite + the header when we've written out all the packets, we just + skip over the header for now. */ + if (wtap_dump_file_seek(wdh, sizeof(t_5VW_Capture_Header), SEEK_SET, err) == -1) + return FALSE; + + /* This is a 5Views file */ + wdh->subtype_write = _5views_dump; + wdh->subtype_finish = _5views_dump_finish; + _5views = g_new(_5views_dump_t, 1); + wdh->priv = (void *)_5views; + _5views->nframes = 0; + + return TRUE; +} + +/* Write a record for a packet to a dump file. + Returns TRUE on success, FALSE on failure. */ +static gboolean _5views_dump(wtap_dumper *wdh, + const wtap_rec *rec, + const guint8 *pd, int *err, gchar **err_info _U_) +{ + _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv; + t_5VW_TimeStamped_Header HeaderFrame; + + /* We can only write packet records. */ + if (rec->rec_type != REC_TYPE_PACKET) { + *err = WTAP_ERR_UNWRITABLE_REC_TYPE; + return FALSE; + } + + /* + * Make sure this packet doesn't have a link-layer type that + * differs from the one for the file. + */ + if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) { + *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED; + return FALSE; + } + + /* Don't write out something bigger than we can read. */ + if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) { + *err = WTAP_ERR_PACKET_TOO_LARGE; + return FALSE; + } + + /* Frame Header */ + /* constant fields */ + HeaderFrame.Key = GUINT32_TO_LE(CST_5VW_RECORDS_HEADER_KEY); + HeaderFrame.HeaderSize = GUINT16_TO_LE(sizeof(t_5VW_TimeStamped_Header)); + HeaderFrame.HeaderType = GUINT16_TO_LE(CST_5VW_TIMESTAMPED_HEADER_TYPE); + HeaderFrame.RecType = GUINT32_TO_LE(CST_5VW_CAPTURES_RECORD | CST_5VW_SYSTEM_RECORD); + HeaderFrame.RecSubType = GUINT32_TO_LE(CST_5VW_FRAME_RECORD); + HeaderFrame.RecNb = GUINT32_TO_LE(1); + + /* record-dependent fields */ + /* + * XXX - is the frame time signed, or unsigned? If it's signed, + * we should check against G_MININT32 and G_MAXINT32 and make + * Utc a gint32. + */ + if (rec->ts.secs < 0 || rec->ts.secs > WTAP_NSTIME_32BIT_SECS_MAX) { + *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED; + return FALSE; + } + HeaderFrame.Utc = GUINT32_TO_LE((guint32)rec->ts.secs); + HeaderFrame.NanoSecondes = GUINT32_TO_LE(rec->ts.nsecs); + HeaderFrame.RecSize = GUINT32_TO_LE(rec->rec_header.packet_header.len); + HeaderFrame.RecInfo = GUINT32_TO_LE(0); + + /* write the record header */ + if (!wtap_dump_file_write(wdh, &HeaderFrame, + sizeof(t_5VW_TimeStamped_Header), err)) + return FALSE; + + /* write the data */ + if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err)) + return FALSE; + + _5views->nframes ++; + + return TRUE; +} + +static gboolean _5views_dump_finish(wtap_dumper *wdh, int *err, gchar **err_info _U_) +{ + _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv; + t_5VW_Capture_Header file_hdr; + + if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1) + return FALSE; + + /* fill in the Info_Header */ + file_hdr.Info_Header.Signature = GUINT32_TO_LE(CST_5VW_INFO_HEADER_KEY); + file_hdr.Info_Header.Size = GUINT32_TO_LE(sizeof(t_5VW_Info_Header)); /* Total size of Header in bytes (included Signature) */ + file_hdr.Info_Header.Version = GUINT32_TO_LE(CST_5VW_INFO_RECORD_VERSION); /* Identify version and so the format of this record */ + file_hdr.Info_Header.DataSize = GUINT32_TO_LE(sizeof(t_5VW_Attributes_Header) + + sizeof(guint32) + + sizeof(t_5VW_Attributes_Header) + + sizeof(guint32)); + /* Total size of data included in the Info Record (except the header size) */ + file_hdr.Info_Header.FileType = GUINT32_TO_LE(wtap_encap[wdh->file_encap]); /* Type of the file */ + file_hdr.Info_Header.Reserved[0] = 0; /* Reserved for future use */ + file_hdr.Info_Header.Reserved[1] = 0; /* Reserved for future use */ + file_hdr.Info_Header.Reserved[2] = 0; /* Reserved for future use */ + + /* fill in the HeaderDateCreation */ + file_hdr.HeaderDateCreation.Type = GUINT32_TO_LE(CST_5VW_IA_DATE_CREATION); /* Id of the attribute */ + file_hdr.HeaderDateCreation.Size = GUINT16_TO_LE(sizeof(guint32)); /* Size of the data part of the attribute (not including header size) */ + file_hdr.HeaderDateCreation.Nb = GUINT16_TO_LE(1); /* Number of elements */ + + /* fill in the Time field */ +#ifdef _WIN32 + _tzset(); +#endif + file_hdr.Time = GUINT32_TO_LE(time(NULL)); + + /* fill in the Time field */ + file_hdr.HeaderNbFrames.Type = GUINT32_TO_LE(CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES); /* Id of the attribute */ + file_hdr.HeaderNbFrames.Size = GUINT16_TO_LE(sizeof(guint32)); /* Size of the data part of the attribute (not including header size) */ + file_hdr.HeaderNbFrames.Nb = GUINT16_TO_LE(1); /* Number of elements */ + + /* fill in the number of frames saved */ + file_hdr.TramesStockeesInFile = GUINT32_TO_LE(_5views->nframes); + + /* Write the file header. */ + if (!wtap_dump_file_write(wdh, &file_hdr, sizeof(t_5VW_Capture_Header), + err)) + return FALSE; + + return TRUE; +} + +static const struct supported_block_type _5views_blocks_supported[] = { + /* + * We support packet blocks, with no comments or other options. + */ + { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } +}; + +static const struct file_type_subtype_info _5views_info = { + "InfoVista 5View capture", "5views", "5vw", NULL, + TRUE, BLOCKS_SUPPORTED(_5views_blocks_supported), + _5views_dump_can_write_encap, _5views_dump_open, NULL +}; + +void register_5views(void) +{ + _5views_file_type_subtype = wtap_register_file_type_subtype(&_5views_info); + + /* + * Register name for backwards compatibility with the + * wtap_filetypes table in Lua. + */ + wtap_register_backwards_compatibility_lua_name("5VIEWS", + _5views_file_type_subtype); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=8 tabstop=8 noexpandtab: + * :indentSize=8:tabSize=8:noTabs=false: + */ |