-/*
- * $Id$
- */
-
/***************************************************************************
network_instruments.c - description
-------------------
* *
***************************************************************************/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "wtap-int.h"
#include "file_wrappers.h"
-#include "buffer.h"
#include "network_instruments.h"
static const char network_instruments_magic[] = {"ObserverPktBufferVersion=15.00"};
static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset);
static gboolean observer_seek_read(wtap *wth, gint64 seek_off,
- union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
- int *err, gchar **err_info);
-static int read_packet_header(FILE_T fh, union wtap_pseudo_header *pseudo_header,
+ struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
+static int read_packet_header(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header,
packet_entry_header *packet_header, int *err, gchar **err_info);
+static gboolean process_packet_header(wtap *wth,
+ packet_entry_header *packet_header, struct wtap_pkthdr *phdr, int *err,
+ gchar **err_info);
static int read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header,
- guint8 *pd, int length, int *err, char **err_info);
+ Buffer *buf, int length, int *err, char **err_info);
static gboolean skip_to_next_packet(wtap *wth, int offset_to_next_packet,
int current_offset_from_packet_header, int *err, char **err_info);
static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
- const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err);
+ const guint8 *pd, int *err, gchar **err_info);
static gint observer_to_wtap_encap(int observer_encap);
static gint wtap_to_observer_encap(int wtap_encap);
-int network_instruments_open(wtap *wth, int *err, gchar **err_info)
+wtap_open_return_val network_instruments_open(wtap *wth, int *err, gchar **err_info)
{
- int bytes_read;
int offset;
capture_file_header file_header;
guint i;
packet_entry_header packet_header;
observer_dump_private_state * private_state = NULL;
- errno = WTAP_ERR_CANT_READ;
offset = 0;
/* read in the buffer file header */
- bytes_read = file_read(&file_header, sizeof file_header, wth->fh);
- if (bytes_read != sizeof file_header) {
- *err = file_error(wth->fh, err_info);
- if (*err != 0)
- return -1;
- return 0;
+ if (!wtap_read_bytes(wth->fh, &file_header, sizeof file_header,
+ err, err_info)) {
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
}
- offset += bytes_read;
+ offset += (int)sizeof file_header;
CAPTURE_FILE_HEADER_FROM_LE_IN_PLACE(file_header);
/* check if version info is present */
if (memcmp(file_header.observer_version, network_instruments_magic, true_magic_length)!=0) {
- return 0;
+ return WTAP_OPEN_NOT_MINE;
}
/* initialize the private state */
break;
/* read the TLV header */
- bytes_read = file_read(&tlvh, sizeof tlvh, wth->fh);
- if (bytes_read != sizeof tlvh) {
- *err = file_error(wth->fh, err_info);
- if (*err == 0)
- *err = WTAP_ERR_SHORT_READ;
- return -1;
- }
- offset += bytes_read;
+ if (!wtap_read_bytes(wth->fh, &tlvh, sizeof tlvh, err, err_info))
+ return WTAP_OPEN_ERROR;
+ offset += (int)sizeof tlvh;
TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
if (tlvh.length < sizeof tlvh) {
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
tlvh.length, (unsigned long)sizeof tlvh);
- return -1;
+ return WTAP_OPEN_ERROR;
}
/* process (or skip over) the current TLV */
switch (tlvh.type) {
case INFORMATION_TYPE_TIME_INFO:
- bytes_read = file_read(&private_state->time_format, sizeof private_state->time_format, wth->fh);
- if (bytes_read != sizeof private_state->time_format) {
- *err = file_error(wth->fh, err_info);
- if(*err == 0)
- *err = WTAP_ERR_SHORT_READ;
- return -1;
- }
+ if (!wtap_read_bytes(wth->fh, &private_state->time_format,
+ sizeof private_state->time_format,
+ err, err_info))
+ return WTAP_OPEN_ERROR;
private_state->time_format = GUINT32_FROM_LE(private_state->time_format);
- offset += bytes_read;
+ offset += (int)sizeof private_state->time_format;
break;
default:
seek_increment = tlvh.length - (int)sizeof tlvh;
if (seek_increment > 0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
- return -1;
+ return WTAP_OPEN_ERROR;
}
offset += seek_increment;
}
*err = WTAP_ERR_BAD_FILE;
*err_info = g_strdup_printf("Observer: bad record (offset to first packet %d < %d)",
header_offset, offset);
- return FALSE;
+ return WTAP_OPEN_ERROR;
}
seek_increment = header_offset - offset;
if (seek_increment > 0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
- return -1;
+ return WTAP_OPEN_ERROR;
}
/* pull off the packet header */
- bytes_read = file_read(&packet_header, sizeof packet_header, wth->fh);
- if (bytes_read != sizeof packet_header) {
- *err = file_error(wth->fh, err_info);
- if (*err != 0)
- return -1;
- return 0;
- }
+ if (!wtap_read_bytes(wth->fh, &packet_header, sizeof packet_header,
+ err, err_info))
+ return WTAP_OPEN_ERROR;
PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(packet_header);
/* check the packet's magic number */
if (packet_header.packet_magic != observer_packet_magic) {
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup_printf("Observer: unsupported packet version %ul", packet_header.packet_magic);
- return -1;
+ return WTAP_OPEN_ERROR;
}
/* check the data link type */
if (observer_to_wtap_encap(packet_header.network_type) == WTAP_ENCAP_UNKNOWN) {
- *err = WTAP_ERR_UNSUPPORTED_ENCAP;
+ *err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
- return -1;
+ return WTAP_OPEN_ERROR;
}
wth->file_encap = observer_to_wtap_encap(packet_header.network_type);
wth->subtype_close = NULL;
wth->subtype_sequential_close = NULL;
wth->snapshot_length = 0; /* not available in header */
- wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
- wth->file_type = WTAP_FILE_NETWORK_INSTRUMENTS;
+ wth->file_tsprec = WTAP_TSPREC_NSEC;
+ wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_NETWORK_INSTRUMENTS;
/* reset the pointer to the first packet */
- if (file_seek(wth->fh, header_offset, SEEK_SET,
- err) == -1)
- return -1;
- wth->data_offset = header_offset;
+ if (file_seek(wth->fh, header_offset, SEEK_SET, err) == -1)
+ return WTAP_OPEN_ERROR;
init_gmt_to_localtime_offset();
- return 1;
+ return WTAP_OPEN_MINE;
}
/* Reads the next packet. */
static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
gint64 *data_offset)
{
- int bytes_consumed;
- int offset_from_packet_header = 0;
+ int header_bytes_consumed;
+ int data_bytes_consumed;
packet_entry_header packet_header;
/* skip records other than data records */
for (;;) {
- *data_offset = wth->data_offset;
+ *data_offset = file_tell(wth->fh);
/* process the packet header, including TLVs */
- bytes_consumed = read_packet_header(wth->fh, &wth->pseudo_header, &packet_header, err,
+ header_bytes_consumed = read_packet_header(wth, wth->fh, &wth->phdr.pseudo_header, &packet_header, err,
err_info);
- if (bytes_consumed <= 0)
+ if (header_bytes_consumed <= 0)
return FALSE; /* EOF or error */
- wth->data_offset += bytes_consumed;
-
if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
break;
/* skip to next packet */
- offset_from_packet_header = (int) (wth->data_offset - *data_offset);
if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
- offset_from_packet_header, err, err_info)) {
+ header_bytes_consumed, err, err_info)) {
return FALSE; /* EOF or error */
}
}
- /* neglect frame markers for wiretap */
- if (packet_header.network_size < 4) {
- *err = WTAP_ERR_BAD_FILE;
- *err_info = g_strdup_printf("Observer: bad record: Packet length %u < 4",
- packet_header.network_size);
+ if (!process_packet_header(wth, &packet_header, &wth->phdr, err, err_info))
return FALSE;
- }
-
- /* set the wiretap packet header fields */
- wth->phdr.pkt_encap = observer_to_wtap_encap(packet_header.network_type);
- if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
- wth->phdr.len = packet_header.network_size;
- wth->phdr.caplen = packet_header.captured_size;
- } else {
- wth->phdr.len = packet_header.network_size - 4;
- wth->phdr.caplen = MIN(packet_header.captured_size, wth->phdr.len);
- }
-
- /* set the wiretap timestamp, assuming for the moment that Observer encoded it in GMT */
- wth->phdr.ts.secs = (time_t) ((packet_header.nano_seconds_since_2000 / 1000000000) + ansi_to_observer_epoch_offset);
- wth->phdr.ts.nsecs = (int) (packet_header.nano_seconds_since_2000 % 1000000000);
-
- /* adjust to local time, if necessary, also accounting for DST if the frame
- was captured while it was in effect */
- if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
- {
- struct tm daylight_tm;
- struct tm standard_tm;
- time_t dst_offset;
-
- /* the Observer timestamp was encoded as local time, so add a
- correction from local time to GMT */
- wth->phdr.ts.secs += gmt_to_localtime_offset;
-
- /* perform a DST adjustment if necessary */
- standard_tm = *localtime(&wth->phdr.ts.secs);
- if (standard_tm.tm_isdst > 0) {
- daylight_tm = standard_tm;
- standard_tm.tm_isdst = 0;
- dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
- wth->phdr.ts.secs -= dst_offset;
- }
- }
-
- /* update the pseudo header */
- switch (wth->file_encap) {
- case WTAP_ENCAP_ETHERNET:
- /* There is no FCS in the frame */
- wth->pseudo_header.eth.fcs_len = 0;
- break;
- case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
- /* Updated in read_packet_header */
- break;
- }
-
- /* set-up the packet buffer */
- buffer_assure_space(wth->frame_buffer, packet_header.captured_size);
/* read the frame data */
- offset_from_packet_header = (int) (wth->data_offset - *data_offset);
- bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
- offset_from_packet_header, buffer_start_ptr(wth->frame_buffer),
- packet_header.captured_size, err, err_info);
- if (bytes_consumed < 0) {
+ data_bytes_consumed = read_packet_data(wth->fh, packet_header.offset_to_frame,
+ header_bytes_consumed, wth->frame_buffer,
+ wth->phdr.caplen, err, err_info);
+ if (data_bytes_consumed < 0) {
return FALSE;
}
- wth->data_offset += bytes_consumed;
/* skip over any extra bytes following the frame data */
- offset_from_packet_header = (int) (wth->data_offset - *data_offset);
if (!skip_to_next_packet(wth, packet_header.offset_to_next_packet,
- offset_from_packet_header, err, err_info)) {
+ header_bytes_consumed + data_bytes_consumed, err, err_info)) {
return FALSE;
}
/* Reads a packet at an offset. */
static gboolean observer_seek_read(wtap *wth, gint64 seek_off,
- union wtap_pseudo_header *pseudo_header, guint8 *pd, int length,
- int *err, gchar **err_info)
+ struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
{
+ union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
packet_entry_header packet_header;
int offset;
+ int data_bytes_consumed;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
/* process the packet header, including TLVs */
- offset = read_packet_header(wth->random_fh, pseudo_header, &packet_header, err,
+ offset = read_packet_header(wth, wth->random_fh, pseudo_header, &packet_header, err,
err_info);
if (offset <= 0)
return FALSE; /* EOF or error */
- /* update the pseudo header */
- switch (wth->file_encap) {
-
- case WTAP_ENCAP_ETHERNET:
- /* There is no FCS in the frame */
- pseudo_header->eth.fcs_len = 0;
- break;
- case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
- /* Updated in read_packet_header */
- break;
- }
+ if (!process_packet_header(wth, &packet_header, phdr, err, err_info))
+ return FALSE;
/* read the frame data */
- if (!read_packet_data(wth->random_fh, packet_header.offset_to_frame,
- offset, pd, length, err, err_info))
+ data_bytes_consumed = read_packet_data(wth->random_fh, packet_header.offset_to_frame,
+ offset, buf, phdr->caplen, err, err_info);
+ if (data_bytes_consumed < 0) {
return FALSE;
+ }
return TRUE;
}
static int
-read_packet_header(FILE_T fh, union wtap_pseudo_header *pseudo_header,
+read_packet_header(wtap *wth, FILE_T fh, union wtap_pseudo_header *pseudo_header,
packet_entry_header *packet_header, int *err, gchar **err_info)
{
int offset;
- int bytes_read;
guint i;
tlv_header tlvh;
int seek_increment;
offset = 0;
/* pull off the packet header */
- bytes_read = file_read(packet_header, sizeof *packet_header, fh);
- if (bytes_read != sizeof *packet_header) {
- *err = file_error(fh, err_info);
+ if (!wtap_read_bytes_or_eof(fh, packet_header, sizeof *packet_header,
+ err, err_info)) {
if (*err != 0)
return -1;
return 0; /* EOF */
}
- offset += bytes_read;
+ offset += (int)sizeof *packet_header;
PACKET_ENTRY_HEADER_FROM_LE_IN_PLACE(*packet_header);
/* check the packet's magic number */
return -1;
}
+ /* initialize the pseudo header */
+ switch (wth->file_encap) {
+ case WTAP_ENCAP_ETHERNET:
+ /* There is no FCS in the frame */
+ pseudo_header->eth.fcs_len = 0;
+ break;
+ case WTAP_ENCAP_IEEE_802_11_WITH_RADIO:
+ memset(&pseudo_header->ieee_802_11, 0, sizeof(pseudo_header->ieee_802_11));
+ pseudo_header->ieee_802_11.fcs_len = 0;
+ pseudo_header->ieee_802_11.decrypted = FALSE;
+ pseudo_header->ieee_802_11.datapad = FALSE;
+ pseudo_header->ieee_802_11.phy = PHDR_802_11_PHY_UNKNOWN;
+ /* Updated below */
+ break;
+ }
+
/* process extra information */
for (i = 0; i < packet_header->number_of_information_elements; i++) {
/* read the TLV header */
- bytes_read = file_read(&tlvh, sizeof tlvh, fh);
- if (bytes_read != sizeof tlvh) {
- *err = file_error(fh, err_info);
- if (*err == 0)
- *err = WTAP_ERR_SHORT_READ;
+ if (!wtap_read_bytes(fh, &tlvh, sizeof tlvh, err, err_info))
return -1;
- }
- offset += bytes_read;
+ offset += (int)sizeof tlvh;
TLV_HEADER_FROM_LE_IN_PLACE(tlvh);
if (tlvh.length < sizeof tlvh) {
/* process (or skip over) the current TLV */
switch (tlvh.type) {
case INFORMATION_TYPE_WIRELESS:
- bytes_read = file_read(&wireless_header, sizeof wireless_header, fh);
- if (bytes_read != sizeof wireless_header) {
- *err = file_error(fh, err_info);
- if(*err == 0)
- *err = WTAP_ERR_SHORT_READ;
+ if (!wtap_read_bytes(fh, &wireless_header, sizeof wireless_header,
+ err, err_info))
return -1;
- }
- /* update the pseudo header */
- pseudo_header->ieee_802_11.fcs_len = 0;
+ /* set decryption status */
+ /* XXX - what other bits are there in conditions? */
+ pseudo_header->ieee_802_11.decrypted = (wireless_header.conditions & WIRELESS_WEP_SUCCESS) != 0;
+ pseudo_header->ieee_802_11.has_channel = TRUE;
pseudo_header->ieee_802_11.channel = wireless_header.frequency;
+ pseudo_header->ieee_802_11.has_data_rate = TRUE;
pseudo_header->ieee_802_11.data_rate = wireless_header.rate;
- pseudo_header->ieee_802_11.signal_level = wireless_header.strengthPercent;
- offset += bytes_read;
+ pseudo_header->ieee_802_11.has_signal_percent = TRUE;
+ pseudo_header->ieee_802_11.signal_percent = wireless_header.strengthPercent;
+ offset += (int)sizeof wireless_header;
break;
default:
/* skip the TLV data */
return offset;
}
+static gboolean
+process_packet_header(wtap *wth, packet_entry_header *packet_header,
+ struct wtap_pkthdr *phdr, int *err, gchar **err_info)
+{
+ /* set the wiretap packet header fields */
+ phdr->rec_type = REC_TYPE_PACKET;
+ phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
+ phdr->pkt_encap = observer_to_wtap_encap(packet_header->network_type);
+ if(wth->file_encap == WTAP_ENCAP_FIBRE_CHANNEL_FC2_WITH_FRAME_DELIMS) {
+ phdr->len = packet_header->network_size;
+ phdr->caplen = packet_header->captured_size;
+ } else {
+ /*
+ * XXX - what are those 4 bytes?
+ *
+ * The comment in the code said "neglect frame markers for wiretap",
+ * but in the captures I've seen, there's no actual data corresponding
+ * to them that might be a "frame marker".
+ *
+ * Instead, the packets had a network_size 4 bytes larger than the
+ * captured_size; does the network_size include the CRC, even
+ * though it's not included in a capture? If so, most other
+ * network analyzers that have a "network size" and a "captured
+ * size" don't include the CRC in the "network size" if they
+ * don't include the CRC in a full-length captured packet; the
+ * "captured size" is less than the "network size" only if a
+ * user-specified "snapshot length" caused the packet to be
+ * sliced at a particular point.
+ *
+ * That's the model that wiretap and Wireshark/TShark use, so
+ * we implement that model here.
+ */
+ if (packet_header->network_size < 4) {
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("Observer: bad record: Packet length %u < 4",
+ packet_header->network_size);
+ return FALSE;
+ }
+
+ phdr->len = packet_header->network_size - 4;
+ phdr->caplen = MIN(packet_header->captured_size, phdr->len);
+ }
+ /*
+ * The maximum value of packet_header->captured_size is 65535, which
+ * is less than WTAP_MAX_PACKET_SIZE will ever be, so we don't need
+ * to check it.
+ */
+
+ /* set the wiretap timestamp, assuming for the moment that Observer encoded it in GMT */
+ phdr->ts.secs = (time_t) ((packet_header->nano_seconds_since_2000 / 1000000000) + ansi_to_observer_epoch_offset);
+ phdr->ts.nsecs = (int) (packet_header->nano_seconds_since_2000 % 1000000000);
+
+ /* adjust to local time, if necessary, also accounting for DST if the frame
+ was captured while it was in effect */
+ if (((observer_dump_private_state*)wth->priv)->time_format == TIME_INFO_LOCAL)
+ {
+ struct tm daylight_tm;
+ struct tm standard_tm;
+ time_t dst_offset;
+
+ /* the Observer timestamp was encoded as local time, so add a
+ correction from local time to GMT */
+ phdr->ts.secs += gmt_to_localtime_offset;
+
+ /* perform a DST adjustment if necessary */
+ standard_tm = *localtime(&phdr->ts.secs);
+ if (standard_tm.tm_isdst > 0) {
+ daylight_tm = standard_tm;
+ standard_tm.tm_isdst = 0;
+ dst_offset = mktime(&standard_tm) - mktime(&daylight_tm);
+ phdr->ts.secs -= dst_offset;
+ }
+ }
+
+ return TRUE;
+}
+
static int
-read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header, guint8 *pd,
+read_packet_data(FILE_T fh, int offset_to_frame, int current_offset_from_packet_header, Buffer *buf,
int length, int *err, char **err_info)
{
int seek_increment;
bytes_consumed += seek_increment;
}
+ /* set-up the packet buffer */
+ ws_buffer_assure_space(buf, length);
+
/* read in the packet data */
- wtap_file_read_expected_bytes(pd, length, fh, err, err_info);
+ if (!wtap_read_packet_bytes(fh, buf, length, err, err_info))
+ return FALSE;
bytes_consumed += length;
return bytes_consumed;
if (seek_increment > 0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
- wth->data_offset += seek_increment;
}
return TRUE;
return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
if (encap < 0 || (wtap_to_observer_encap(encap) == OBSERVER_UNDEFINED))
- return WTAP_ERR_UNSUPPORTED_ENCAP;
+ return WTAP_ERR_UNWRITABLE_ENCAP;
return 0;
}
/* Write a record for a packet to a dump file.
Returns TRUE on success, FALSE on failure. */
static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
- const union wtap_pseudo_header *pseudo_header _U_, const guint8 *pd,
- int *err)
+ const guint8 *pd,
+ int *err, gchar **err_info _U_)
{
observer_dump_private_state * private_state = NULL;
packet_entry_header packet_header;
guint64 seconds_since_2000;
+ /* We can only write packet records. */
+ if (phdr->rec_type != REC_TYPE_PACKET) {
+ *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+ return FALSE;
+ }
+
+ /* The captured size field is 16 bits, so there's a hard limit of
+ 65535. */
+ if (phdr->caplen > 65535) {
+ *err = WTAP_ERR_PACKET_TOO_LARGE;
+ return FALSE;
+ }
+
/* convert the number of seconds since epoch from ANSI-relative to
Observer-relative */
if (phdr->ts.secs < ansi_to_observer_epoch_offset) {
}
return OBSERVER_UNDEFINED;
}
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */