![Guy Harris](/assets/img/avatar_default.png)
Have the routines that create them take a pointer to a struct packet_provider_data, store that in the tvbuff data, and use it to get the wtap from which packets are being read. While we're at it, don't include globals.h in any header files, and include it in source files iff the source file actually uses cfile. Add whatever includes that requires. Change-Id: I9f1ee391f951dc427ff62c80f67aa4877a37c229 Reviewed-on: https://code.wireshark.org/review/24733 Reviewed-by: Guy Harris <guy@alum.mit.edu>
341 lines
8.3 KiB
C
341 lines
8.3 KiB
C
/* frame_tvbuff.c
|
|
* Implements a tvbuff for frame
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include <epan/packet.h>
|
|
#include <epan/tvbuff-int.h>
|
|
#include <epan/tvbuff.h>
|
|
|
|
#include "frame_tvbuff.h"
|
|
|
|
#include "wiretap/wtap-int.h" /* for ->random_fh */
|
|
|
|
struct tvb_frame {
|
|
struct tvbuff tvb;
|
|
|
|
Buffer *buf; /* Packet data */
|
|
|
|
const struct packet_provider_data *prov; /* provider of packet information */
|
|
gint64 file_off; /**< File offset */
|
|
|
|
guint offset;
|
|
};
|
|
|
|
static gboolean
|
|
frame_read(struct tvb_frame *frame_tvb, struct wtap_pkthdr *phdr, Buffer *buf)
|
|
{
|
|
int err;
|
|
gchar *err_info;
|
|
|
|
/* XXX, what if phdr->caplen isn't equal to
|
|
* frame_tvb->tvb.length + frame_tvb->offset?
|
|
*/
|
|
if (!wtap_seek_read(frame_tvb->prov->wth, frame_tvb->file_off, phdr, buf, &err, &err_info)) {
|
|
/* XXX - report error! */
|
|
switch (err) {
|
|
case WTAP_ERR_BAD_FILE:
|
|
g_free(err_info);
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static GPtrArray *buffer_cache = NULL;
|
|
|
|
static void
|
|
frame_cache(struct tvb_frame *frame_tvb)
|
|
{
|
|
struct wtap_pkthdr phdr; /* Packet header */
|
|
|
|
wtap_phdr_init(&phdr);
|
|
|
|
if (frame_tvb->buf == NULL) {
|
|
if G_UNLIKELY(!buffer_cache) buffer_cache = g_ptr_array_sized_new(1024);
|
|
|
|
if (buffer_cache->len > 0) {
|
|
frame_tvb->buf = (struct Buffer *) g_ptr_array_remove_index(buffer_cache, buffer_cache->len - 1);
|
|
} else {
|
|
frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer));
|
|
}
|
|
|
|
ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset);
|
|
|
|
if (!frame_read(frame_tvb, &phdr, frame_tvb->buf))
|
|
{ /* TODO: THROW(???); */ }
|
|
}
|
|
|
|
frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
|
|
|
|
wtap_phdr_cleanup(&phdr);
|
|
}
|
|
|
|
static void
|
|
frame_free(tvbuff_t *tvb)
|
|
{
|
|
struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
if (frame_tvb->buf) {
|
|
ws_buffer_free(frame_tvb->buf);
|
|
g_ptr_array_add(buffer_cache, frame_tvb->buf);
|
|
}
|
|
}
|
|
|
|
static const guint8 *
|
|
frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_)
|
|
{
|
|
struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
frame_cache(frame_tvb);
|
|
|
|
return tvb->real_data + abs_offset;
|
|
}
|
|
|
|
static void *
|
|
frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
|
|
{
|
|
struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
frame_cache(frame_tvb);
|
|
|
|
return memcpy(target, tvb->real_data + abs_offset, abs_length);
|
|
}
|
|
|
|
static gint
|
|
frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
|
|
{
|
|
struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
|
|
const guint8 *result;
|
|
|
|
frame_cache(frame_tvb);
|
|
|
|
result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit);
|
|
if (result)
|
|
return (gint) (result - tvb->real_data);
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
static gint
|
|
frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
|
|
{
|
|
struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
frame_cache(frame_tvb);
|
|
|
|
return tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle);
|
|
}
|
|
|
|
static guint
|
|
frame_offset(const tvbuff_t *tvb _U_, const guint counter)
|
|
{
|
|
/* XXX: frame_tvb->offset */
|
|
return counter;
|
|
}
|
|
|
|
static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length);
|
|
|
|
static const struct tvb_ops tvb_frame_ops = {
|
|
sizeof(struct tvb_frame), /* size */
|
|
|
|
frame_free, /* free */
|
|
frame_offset, /* offset */
|
|
frame_get_ptr, /* get_ptr */
|
|
frame_memcpy, /* memcpy */
|
|
frame_find_guint8, /* find_guint8 */
|
|
frame_pbrk_guint8, /* pbrk_guint8 */
|
|
frame_clone, /* clone */
|
|
};
|
|
|
|
/* based on tvb_new_real_data() */
|
|
tvbuff_t *
|
|
frame_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
|
|
const guint8 *buf)
|
|
{
|
|
struct tvb_frame *frame_tvb;
|
|
tvbuff_t *tvb;
|
|
|
|
tvb = tvb_new(&tvb_frame_ops);
|
|
|
|
/*
|
|
* XXX - currently, the length arguments in
|
|
* tvbuff structure are signed, but the captured
|
|
* and reported length values are unsigned; this means
|
|
* that length values > 2^31 - 1 will appear as
|
|
* negative lengths
|
|
*
|
|
* Captured length values that large will already
|
|
* have been filtered out by the Wiretap modules
|
|
* (the file will be reported as corrupted), to
|
|
* avoid trying to allocate large chunks of data.
|
|
*
|
|
* Reported length values will not have been
|
|
* filtered out, and should not be filtered out,
|
|
* as those lengths are not necessarily invalid.
|
|
*
|
|
* For now, we clip the reported length at G_MAXINT
|
|
*
|
|
* (XXX, is this still a problem?) There was an exception when we call
|
|
* tvb_new_real_data() now there's no one
|
|
*/
|
|
|
|
tvb->real_data = buf;
|
|
tvb->length = fd->cap_len;
|
|
tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
|
|
tvb->initialized = TRUE;
|
|
|
|
/*
|
|
* This is the top-level real tvbuff for this data source,
|
|
* so its data source tvbuff is itself.
|
|
*/
|
|
tvb->ds_tvb = tvb;
|
|
|
|
frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
/* XXX, wtap_can_seek() */
|
|
if (prov->wth && prov->wth->random_fh) {
|
|
frame_tvb->prov = prov;
|
|
frame_tvb->file_off = fd->file_off;
|
|
frame_tvb->offset = 0;
|
|
} else
|
|
frame_tvb->prov = NULL;
|
|
|
|
frame_tvb->buf = NULL;
|
|
|
|
return tvb;
|
|
}
|
|
|
|
tvbuff_t *
|
|
frame_tvbuff_new_buffer(const struct packet_provider_data *prov,
|
|
const frame_data *fd, Buffer *buf)
|
|
{
|
|
return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
|
|
}
|
|
|
|
static tvbuff_t *
|
|
frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
|
|
{
|
|
struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
tvbuff_t *cloned_tvb;
|
|
struct tvb_frame *cloned_frame_tvb;
|
|
|
|
/* file not seekable */
|
|
if (!frame_tvb->prov)
|
|
return NULL;
|
|
|
|
abs_offset += frame_tvb->offset;
|
|
|
|
cloned_tvb = tvb_new(&tvb_frame_ops);
|
|
|
|
/* data will be read when needed */
|
|
cloned_tvb->real_data = NULL;
|
|
cloned_tvb->length = abs_length;
|
|
cloned_tvb->reported_length = abs_length; /* XXX? */
|
|
cloned_tvb->initialized = TRUE;
|
|
|
|
/*
|
|
* This is the top-level real tvbuff for this data source,
|
|
* so its data source tvbuff is itself.
|
|
*/
|
|
cloned_tvb->ds_tvb = cloned_tvb;
|
|
|
|
cloned_frame_tvb = (struct tvb_frame *) cloned_tvb;
|
|
cloned_frame_tvb->prov = frame_tvb->prov;
|
|
cloned_frame_tvb->file_off = frame_tvb->file_off;
|
|
cloned_frame_tvb->offset = abs_offset;
|
|
cloned_frame_tvb->buf = NULL;
|
|
|
|
return cloned_tvb;
|
|
}
|
|
|
|
|
|
/* based on tvb_new_real_data() */
|
|
tvbuff_t *
|
|
file_tvbuff_new(const struct packet_provider_data *prov, const frame_data *fd,
|
|
const guint8 *buf)
|
|
{
|
|
struct tvb_frame *frame_tvb;
|
|
tvbuff_t *tvb;
|
|
|
|
tvb = tvb_new(&tvb_frame_ops);
|
|
|
|
/*
|
|
* XXX - currently, the length arguments in
|
|
* tvbuff structure are signed, but the captured
|
|
* and reported length values are unsigned; this means
|
|
* that length values > 2^31 - 1 will appear as
|
|
* negative lengths
|
|
*
|
|
* Captured length values that large will already
|
|
* have been filtered out by the Wiretap modules
|
|
* (the file will be reported as corrupted), to
|
|
* avoid trying to allocate large chunks of data.
|
|
*
|
|
* Reported length values will not have been
|
|
* filtered out, and should not be filtered out,
|
|
* as those lengths are not necessarily invalid.
|
|
*
|
|
* For now, we clip the reported length at G_MAXINT
|
|
*
|
|
* (XXX, is this still a problem?) There was an exception when we call
|
|
* tvb_new_real_data() now there's no one
|
|
*/
|
|
|
|
tvb->real_data = buf;
|
|
tvb->length = fd->cap_len;
|
|
tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
|
|
tvb->initialized = TRUE;
|
|
|
|
/*
|
|
* This is the top-level real tvbuff for this data source,
|
|
* so its data source tvbuff is itself.
|
|
*/
|
|
tvb->ds_tvb = tvb;
|
|
|
|
frame_tvb = (struct tvb_frame *) tvb;
|
|
|
|
/* XXX, wtap_can_seek() */
|
|
if (prov->wth && prov->wth->random_fh) {
|
|
frame_tvb->prov = prov;
|
|
frame_tvb->file_off = fd->file_off;
|
|
frame_tvb->offset = 0;
|
|
} else
|
|
frame_tvb->prov = NULL;
|
|
|
|
frame_tvb->buf = NULL;
|
|
|
|
return tvb;
|
|
}
|
|
|
|
tvbuff_t *
|
|
file_tvbuff_new_buffer(const struct packet_provider_data *prov,
|
|
const frame_data *fd, Buffer *buf)
|
|
{
|
|
return frame_tvbuff_new(prov, fd, ws_buffer_start_ptr(buf));
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - http://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:
|
|
*/
|