summaryrefslogtreecommitdiffstats
path: root/frame_tvbuff.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /frame_tvbuff.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'frame_tvbuff.c')
-rw-r--r--frame_tvbuff.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/frame_tvbuff.c b/frame_tvbuff.c
new file mode 100644
index 0000000..1aec22c
--- /dev/null
+++ b/frame_tvbuff.c
@@ -0,0 +1,331 @@
+/* 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-or-later
+ */
+
+#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, wtap_rec *rec, Buffer *buf)
+{
+ int err;
+ gchar *err_info;
+ gboolean ok = TRUE;
+
+ /* 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, rec, buf, &err, &err_info)) {
+ /* XXX - report error! */
+ switch (err) {
+ case WTAP_ERR_BAD_FILE:
+ g_free(err_info);
+ ok = FALSE;
+ break;
+ }
+ }
+ return ok;
+}
+
+static GPtrArray *buffer_cache = NULL;
+
+static void
+frame_cache(struct tvb_frame *frame_tvb)
+{
+ wtap_rec rec; /* Record metadata */
+
+ wtap_rec_init(&rec);
+
+ 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 = g_new(struct Buffer, 1);
+ }
+
+ ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset);
+
+ if (!frame_read(frame_tvb, &rec, frame_tvb->buf))
+ { /* TODO: THROW(???); */ }
+ }
+
+ frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
+
+ wtap_rec_cleanup(&rec);
+}
+
+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->contained_length = tvb->reported_length;
+ 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->contained_length = cloned_tvb->reported_length;
+ 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->contained_length = tvb->reported_length;
+ 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));
+}