Move file format definitions to the header file.

Put the code to read the packet header and the packet data into routines
(which also fixes some places where observer_seek_read() was using the
sequential file handle rather than the random file handle), make the
packet header reader skip over the TLVs,

Do some additional sanity checking.

Wiretap supports nanosecond resolution; provide nanosecond resolution
time stamps.

Rename some structure members to match their purpose (they're TLV
counts, not flags).

Remove the TLV header from the TLV structures (and eliminate TLV
structures if we don't have the contents or they're just a string); if
we process them, we'll probably end up reading the header and data
separately.

Add some information about some of the TLVs in expert information packets.

svn path=/trunk/; revision=17870
This commit is contained in:
Guy Harris 2006-04-16 00:52:36 +00:00
parent b33cccd47f
commit 749faec6a3
2 changed files with 226 additions and 165 deletions

View File

@ -42,10 +42,6 @@ static const int observer_encap[] = {
};
#define NUM_OBSERVER_ENCAPS (sizeof observer_encap / sizeof observer_encap[0])
#define OBSERVER_UNDEFINED 0xFF
#define OBSERVER_ETHERNET 0x00
#define OBSERVER_TOKENRING 0x01
#define OBSERVER_FDDI 0x02
static const int from_wtap_encap[] = {
OBSERVER_UNDEFINED,
OBSERVER_ETHERNET,
@ -55,9 +51,6 @@ static const int from_wtap_encap[] = {
#define CAPTUREFILE_HEADER_SIZE sizeof(capture_file_header)
#define INFORMATION_TYPE_ALIAS_LIST 0x01
#define INFORMATION_TYPE_COMMENT 0x02
/*
* The time in Observer files is in nanoseconds since midnight, January 1,
* 2000, 00:00:00 local time.
@ -95,12 +88,17 @@ static void init_time_offset(void)
}
}
static gboolean fill_time_struct(guint64 ns_since2000, observer_time* time_conversion);
static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
long *data_offset);
static gboolean observer_seek_read(wtap *wth, long seek_off,
union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
int *err, gchar **err_info);
static int read_packet_header(FILE_T fh, packet_entry_header *packet_header,
int *err, gchar **err_info);
static gboolean read_packet_data(FILE_T fh, int offset_to_frame, int offset,
guint8 *pd, int length, int *err, char **err_info);
static gboolean skip_to_next_packet(wtap *wth, int offset,
int offset_to_next_packet, int *err, char **err_info);
static gboolean observer_dump_close(wtap_dumper *wdh, int *err);
static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err);
@ -165,7 +163,7 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
/* Check the data link type. */
if (packet_header.network_type >= NUM_OBSERVER_ENCAPS) {
*err = WTAP_ERR_UNSUPPORTED_ENCAP;
*err_info = g_strdup_printf("observer: network type %u unknown or unsupported", packet_header.network_type);
*err_info = g_strdup_printf("Observer: network type %u unknown or unsupported", packet_header.network_type);
return -1;
}
wth->file_encap = observer_encap[packet_header.network_type];
@ -198,13 +196,8 @@ int network_instruments_open(wtap *wth, int *err, gchar **err_info)
static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
long *data_offset)
{
int bytes_read;
long seek_increment;
long seconds, useconds;
int offset;
packet_entry_header packet_header;
observer_time packet_time;
/*
* Skip records other than data records.
@ -212,87 +205,57 @@ static gboolean observer_read(wtap *wth, int *err, gchar **err_info,
for (;;) {
*data_offset = wth->data_offset;
/* pull off the packet header */
bytes_read = file_read(&packet_header, sizeof packet_header, 1, wth->fh);
if (bytes_read != sizeof packet_header) {
*err = file_error(wth->fh);
if (*err != 0)
return -1;
return 0;
}
wth->data_offset += bytes_read;
/* process the packet header, including TLVs */
offset = read_packet_header(wth->fh, &packet_header, err,
err_info);
if (offset <= 0)
return FALSE; /* EOF or error */
/* check the packet's magic number; the magic number is all 8's,
so the byte order doesn't matter */
if (packet_header.packet_magic != observer_packet_magic) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record: Invalid magic number 0x%08x",
GUINT32_FROM_LE(packet_header.packet_magic));
return FALSE;
}
wth->data_offset += offset;
/* check the packet's record type, and skip non-data
packets */
if (packet_header.packet_type == TYPE_DATA_PACKET)
if (packet_header.packet_type == PACKET_TYPE_DATA_PACKET)
break;
/* skip to next packet */
packet_header.offset_to_next_packet =
GUINT16_FROM_LE(packet_header.offset_to_next_packet);
if (packet_header.offset_to_next_packet < sizeof(packet_header)) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to next packet %u < %lu)",
packet_header.offset_to_next_packet,
(unsigned long)sizeof(packet_header));
return FALSE;
}
seek_increment = packet_header.offset_to_next_packet - sizeof(packet_header);
if(seek_increment>0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
}
wth->data_offset += seek_increment;
if (!skip_to_next_packet(wth, offset,
packet_header.offset_to_next_packet, err, err_info))
return FALSE; /* EOF or error */
}
/* convert from observer time to wiretap time */
packet_header.nano_seconds_since_2000 =
GUINT64_FROM_LE(packet_header.nano_seconds_since_2000);
fill_time_struct(packet_header.nano_seconds_since_2000, &packet_time);
useconds = (long)(packet_time.useconds_from_1970 - ((guint64)packet_time.seconds_from_1970)*1000000);
seconds = (long)packet_time.seconds_from_1970;
/* set-up the packet header */
packet_header.network_size =
GUINT16_FROM_LE(packet_header.network_size);
/* neglect frame markers for wiretap */
if (packet_header.network_size < 4) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record: Packet length %u < 4",
packet_header.network_size);
return FALSE;
}
packet_header.network_size -= 4;
packet_header.captured_size =
GUINT16_FROM_LE(packet_header.captured_size);
wth->phdr.pkt_encap = observer_encap[packet_header.network_type];
wth->phdr.len = packet_header.network_size-4; /* neglect frame markers for wiretap */
wth->phdr.len = packet_header.network_size;
wth->phdr.caplen = MIN(packet_header.captured_size, wth->phdr.len);
wth->phdr.ts.secs = seconds;
wth->phdr.ts.nsecs = useconds * 1000;
/* get to the frame data */
packet_header.offset_to_frame =
GUINT16_FROM_LE(packet_header.offset_to_frame);
if (packet_header.offset_to_frame < sizeof(packet_header)) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to frame %u < %lu)",
packet_header.offset_to_frame,
(unsigned long)sizeof(packet_header));
return FALSE;
}
seek_increment = packet_header.offset_to_frame - sizeof(packet_header);
if(seek_increment>0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
}
wth->data_offset += seek_increment;
packet_header.nano_seconds_since_2000 =
GUINT64_FROM_LE(packet_header.nano_seconds_since_2000);
wth->phdr.ts.secs =
(time_t) (packet_header.nano_seconds_since_2000/1000000000 + seconds1970to2000);
wth->phdr.ts.nsecs = packet_header.nano_seconds_since_2000%1000000000;
/* set-up the packet buffer */
buffer_assure_space(wth->frame_buffer, packet_header.captured_size);
wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer), packet_header.captured_size, wth->fh, err);
/* read data */
if (!read_packet_data(wth->fh, packet_header.offset_to_frame, offset,
buffer_start_ptr(wth->frame_buffer), packet_header.captured_size,
err, err_info))
return FALSE;
wth->data_offset += packet_header.captured_size;
offset += packet_header.captured_size;
/* update the pseudo header */
switch (wth->file_encap) {
@ -312,44 +275,21 @@ static gboolean observer_seek_read(wtap *wth, long seek_off,
int *err, gchar **err_info)
{
packet_entry_header packet_header;
long seek_increment;
int bytes_read;
int offset;
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
/* pull off the packet header */
bytes_read = file_read(&packet_header, sizeof packet_header, 1, wth->random_fh);
if (bytes_read != sizeof packet_header) {
*err = file_error(wth->fh);
if (*err != 0)
return -1;
return 0;
}
/* process the packet header, including TLVs */
offset = read_packet_header(wth->random_fh, &packet_header, err,
err_info);
if (offset <= 0)
return FALSE; /* EOF or error */
/* check the packets magic number */
if (packet_header.packet_magic != observer_packet_magic) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup("Observer: bad magic number for record in observer_seek_read");
/* read data */
if (!read_packet_data(wth->random_fh, packet_header.offset_to_frame,
offset, pd, length, err, err_info))
return FALSE;
}
/* get the frame offset */
packet_header.offset_to_frame =
GUINT16_FROM_LE(packet_header.offset_to_frame);
seek_increment = packet_header.offset_to_frame - sizeof(packet_header);
if(seek_increment>0) {
if (file_seek(wth->random_fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
}
/* read in the packet */
bytes_read = file_read(pd, 1, length, wth->random_fh);
if (bytes_read != length) {
*err = file_error(wth->fh);
return FALSE;
}
/* update the pseudo header */
switch (wth->file_encap) {
@ -363,15 +303,114 @@ static gboolean observer_seek_read(wtap *wth, long seek_off,
return TRUE;
}
gboolean fill_time_struct(guint64 ns_since2000, observer_time* time_conversion)
static int
read_packet_header(FILE_T fh, packet_entry_header *packet_header, int *err,
gchar **err_info)
{
time_conversion->ns_since2000 = ns_since2000;
time_conversion->us_since2000 = ns_since2000/1000;
time_conversion->sec_since2000 = ns_since2000/1000000000;
int offset;
int bytes_read;
guint i;
tlv_header tlvh;
int seek_increment;
time_conversion->seconds_from_1970 = (time_t) (seconds1970to2000 + time_conversion->sec_since2000);
time_conversion->useconds_from_1970 = ((guint64)seconds1970to2000*1000000)+time_conversion->us_since2000;
offset = 0;
/* pull off the packet header */
bytes_read = file_read(packet_header, sizeof *packet_header, 1, fh);
if (bytes_read != sizeof *packet_header) {
*err = file_error(fh);
if (*err != 0)
return -1;
return 0; /* EOF */
}
offset += bytes_read;
/* check the packet's magic number; the magic number is all 8's,
so the byte order doesn't matter */
if (packet_header->packet_magic != observer_packet_magic) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record: Invalid magic number 0x%08x",
GUINT32_FROM_LE(packet_header->packet_magic));
return -1;
}
/* 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, 1, fh);
if (bytes_read != sizeof tlvh) {
*err = file_error(fh);
if (*err == 0)
*err = WTAP_ERR_SHORT_READ;
return -1;
}
offset += bytes_read;
tlvh.length = GUINT16_FROM_LE(tlvh.length);
if (tlvh.length < sizeof tlvh) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (TLV length %u < %lu)",
tlvh.length, (unsigned long)sizeof tlvh);
return -1;
}
/* skip the TLV data */
seek_increment = tlvh.length - sizeof tlvh;
if(seek_increment>0) {
if (file_seek(fh, seek_increment, SEEK_CUR, err) == -1)
return -1;
}
offset += seek_increment;
}
packet_header->offset_to_frame =
GUINT16_FROM_LE(packet_header->offset_to_frame);
return offset;
}
static gboolean
read_packet_data(FILE_T fh, int offset_to_frame, int offset, guint8 *pd,
int length, int *err, char **err_info)
{
int seek_increment;
/* get to the packet data */
if (offset_to_frame < offset) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to frame %d < %d)",
offset_to_frame, offset);
return FALSE;
}
seek_increment = offset_to_frame - offset;
if(seek_increment>0) {
if (file_seek(fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
}
/* read in the packet */
wtap_file_read_expected_bytes(pd, length, fh, err);
return TRUE;
}
static gboolean
skip_to_next_packet(wtap *wth, int offset, int offset_to_next_packet, int *err,
char **err_info)
{
int seek_increment;
if (offset_to_next_packet < offset) {
*err = WTAP_ERR_BAD_RECORD;
*err_info = g_strdup_printf("Observer: bad record (offset to next packet %d < %d)",
offset_to_next_packet, offset);
return FALSE;
}
seek_increment = offset_to_next_packet - offset;
if(seek_increment>0) {
if (file_seek(wth->fh, seek_increment, SEEK_CUR, err) == -1)
return FALSE;
}
wth->data_offset += seek_increment;
return TRUE;
}
@ -425,7 +464,7 @@ gboolean network_instruments_dump_open(wtap_dumper *wdh, gboolean cant_seek, int
memset(&file_header, 0x00, sizeof(capture_file_header));
strcpy(file_header.observer_version, network_instruments_magic);
file_header.offset_to_first_packet = sizeof(capture_file_header) + sizeof(tlv_header) + strlen(comment);
file_header.extra_information_present = 0x01; /* actually the number of information elements */
file_header.number_of_information_elements = 1;
if(!fwrite(&file_header, sizeof(capture_file_header), 1, wdh->fh)) {
*err = errno;
return FALSE;
@ -477,8 +516,8 @@ static gboolean observer_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
packet_header.offset_to_next_packet = GUINT16_TO_LE(sizeof(packet_entry_header) + phdr->caplen);
packet_header.network_type = niobserver->network_type;
packet_header.flags = 0x00;
packet_header.extra_information = 0x00;
packet_header.packet_type = 0x00;
packet_header.number_of_information_elements = 0;
packet_header.packet_type = PACKET_TYPE_DATA_PACKET;
packet_header.packet_number = GUINT64_TO_LE(niobserver->packet_count);
packet_header.original_packet_number = GUINT64_TO_LE(niobserver->packet_count);
niobserver->packet_count++;

View File

@ -31,11 +31,53 @@ typedef struct capture_file_header
char observer_version[32];
guint16 offset_to_first_packet;
char probe_instance;
char extra_information_present;
guint8 number_of_information_elements; /* number of TLVs in the header */
} capture_file_header;
#define TYPE_DATA_PACKET 0
#define TYPE_EXPERT_INFORMATION_PACKET 1
typedef struct tlv_header
{
guint16 type;
guint16 length; /* includes the length of the TLV header */
} tlv_header;
/*
* TLV type values.
*/
#define INFORMATION_TYPE_ALIAS_LIST 0x01
#define INFORMATION_TYPE_COMMENT 0x02 /* ASCII text */
typedef struct packet_entry_header
{
guint32 packet_magic;
guint32 network_speed;
guint16 captured_size;
guint16 network_size;
guint16 offset_to_frame;
guint16 offset_to_next_packet;
guint8 network_type;
guint8 flags;
guint8 number_of_information_elements; /* number of TLVs in the header */
guint8 packet_type;
guint16 errors;
guint16 reserved;
guint64 packet_number;
guint64 original_packet_number;
guint64 nano_seconds_since_2000;
} packet_entry_header;
/*
* Network type values.
*/
#define OBSERVER_UNDEFINED 0xFF
#define OBSERVER_ETHERNET 0x00
#define OBSERVER_TOKENRING 0x01
#define OBSERVER_FDDI 0x02
/*
* Packet type values.
*/
#define PACKET_TYPE_DATA_PACKET 0
#define PACKET_TYPE_EXPERT_INFORMATION_PACKET 1
/*
* The Observer document indicates that the types of expert information
@ -49,57 +91,37 @@ typedef struct capture_file_header
*
* Wireless Channel Change (markers showing what channel was being
* currently listened to)
*
* That information appears to be contained in TLVs.
*/
typedef struct packet_entry_header
/*
* TLV type values.
*/
#define INFORMATION_TYPE_NETWORK_LOAD 0x0100
#define INFORMATION_TYPE_CAPTURE_START_STOP 0x0104
/*
* Might some of these be broadcast and multicast packet counts?
*/
typedef struct tlv_network_load
{
guint32 packet_magic;
guint32 network_speed;
guint16 captured_size;
guint16 network_size;
guint16 offset_to_frame;
guint16 offset_to_next_packet;
guint8 network_type;
guint8 flags;
guint8 extra_information;
guint8 packet_type;
guint16 errors;
guint16 reserved;
guint64 packet_number;
guint64 original_packet_number;
guint64 nano_seconds_since_2000;
} packet_entry_header;
guint32 unknown1;
guint32 unknown2;
guint32 unknown3;
guint32 packets_per_second;
guint32 unknown4;
guint32 bytes_per_second;
guint32 unknown5;
} tlv_network_load;
typedef struct tlv_header
typedef struct tlv_capture_start_stop
{
guint16 type;
guint16 length;
} tlv_header;
typedef struct tlv_alias_list
{
tlv_header header;
char alias_list[1];
} tlv_alias_list;
typedef struct tlv_user_commnent
{
tlv_header header;
char user_comment[1];
} tlv_user_comment;
typedef struct observer_time
{
guint64 ns_since2000; /* given in packet_entry_header */
guint64 us_since2000; /* Micro-Seconds since 1-1-2000 */
guint64 sec_since2000; /* Seconds since 1-1-2000 */
time_t seconds_from_1970;
guint64 useconds_from_1970;
} observer_time;
guint32 start_stop;
} tlv_capture_start_stop;
#define START_STOP_TYPE_STOP 0
#define START_STOP_TYPE_START 1
#endif