summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--epan/tvbuff-int.h3
-rw-r--r--epan/tvbuff.c42
-rw-r--r--epan/tvbuff.h8
-rw-r--r--frame_tvbuff.c178
4 files changed, 218 insertions, 13 deletions
diff --git a/epan/tvbuff-int.h b/epan/tvbuff-int.h
index 2aee4c16a2..d8d4cba314 100644
--- a/epan/tvbuff-int.h
+++ b/epan/tvbuff-int.h
@@ -37,6 +37,8 @@ struct tvb_ops {
gint (*tvb_find_guint8)(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle);
gint (*tvb_pbrk_guint8)(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle);
+
+ tvbuff_t *(*tvb_clone)(tvbuff_t *tvb, guint abs_offset, guint abs_length);
};
typedef struct {
@@ -114,5 +116,6 @@ struct tvb_composite {
tvb_comp_t composite;
};
+WS_DLL_PUBLIC tvbuff_t *tvb_new(const struct tvb_ops *ops);
#endif
diff --git a/epan/tvbuff.c b/epan/tvbuff.c
index 91701a801f..6de6b7df35 100644
--- a/epan/tvbuff.c
+++ b/epan/tvbuff.c
@@ -629,7 +629,40 @@ tvb_composite_finalize(tvbuff_t *tvb)
tvb->initialized = TRUE;
}
+static tvbuff_t *
+tvb_generic_clone_offset_len(tvbuff_t *tvb, guint offset, guint len)
+{
+ tvbuff_t *cloned_tvb;
+
+ guint8 *data = (guint8 *) g_malloc(len);
+
+ tvb_memcpy(tvb, data, offset, len);
+
+ cloned_tvb = tvb_new_real_data(data, len, len);
+ tvb_set_free_cb(cloned_tvb, g_free);
+
+ return cloned_tvb;
+}
+
+tvbuff_t *
+tvb_clone_offset_len(tvbuff_t *tvb, guint offset, guint len)
+{
+ if (tvb->ops->tvb_clone) {
+ tvbuff_t *cloned_tvb;
+
+ cloned_tvb = tvb->ops->tvb_clone(tvb, offset, len);
+ if (cloned_tvb)
+ return cloned_tvb;
+ }
+
+ return tvb_generic_clone_offset_len(tvb, offset, len);
+}
+tvbuff_t *
+tvb_clone(tvbuff_t *tvb)
+{
+ return tvb_clone_offset_len(tvb, 0, tvb->length);
+}
guint
tvb_length(const tvbuff_t *tvb)
@@ -2000,6 +2033,12 @@ subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *n
return tvb_pbrk_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needles, found_needle);
}
+static tvbuff_t *
+subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+{
+ return tvb_clone_offset_len(tvb, abs_offset, abs_length);
+}
+
/* Find size of stringz (NUL-terminated string) by looking for terminating
* NUL. The size of the string includes the terminating NUL.
*
@@ -3645,6 +3684,7 @@ static const struct tvb_ops tvb_real_ops = {
NULL, /* memcpy */
NULL, /* find_guint8 */
NULL, /* pbrk_guint8 */
+ NULL, /* clone */
};
static inline const struct tvb_ops *get_tvb_real_ops(void) { return &tvb_real_ops; }
@@ -3657,6 +3697,7 @@ static const struct tvb_ops tvb_subset_ops = {
subset_memcpy, /* memcpy */
subset_find_guint8, /* find_guint8 */
subset_pbrk_guint8, /* pbrk_guint8 */
+ subset_clone, /* clone */
};
static inline const struct tvb_ops *get_tvb_subset_ops(void) { return &tvb_subset_ops; }
@@ -3669,6 +3710,7 @@ static const struct tvb_ops tvb_composite_ops = {
NULL, /* composite_memcpy */ /* memcpy */
NULL, /* find_guint8 XXX */
NULL, /* pbrk_guint8 XXX */
+ NULL, /* clone */
};
static inline const struct tvb_ops *get_tvb_composite_ops(void) { return &tvb_composite_ops; }
diff --git a/epan/tvbuff.h b/epan/tvbuff.h
index 7a851112df..144e8c9b1a 100644
--- a/epan/tvbuff.h
+++ b/epan/tvbuff.h
@@ -57,8 +57,6 @@ extern "C" {
struct tvbuff;
typedef struct tvbuff tvbuff_t;
-struct tvb_ops;
-
/** @defgroup tvbuff Testy, Virtual(-izable) Buffers
*
* Dissector use and management
@@ -115,14 +113,16 @@ struct tvb_ops;
typedef void (*tvbuff_free_cb_t)(void*);
-WS_DLL_PUBLIC tvbuff_t *tvb_new(const struct tvb_ops *ops);
-
/** Extracts 'number of bits' starting at 'bit offset'.
* Returns a pointer to a newly initialized ep_alloc'd REAL_DATA
* tvbuff with the bits octet aligned.
*/
WS_DLL_PUBLIC tvbuff_t* tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits);
+WS_DLL_PUBLIC tvbuff_t *tvb_clone(tvbuff_t *tvb);
+
+WS_DLL_PUBLIC tvbuff_t *tvb_clone_offset_len(tvbuff_t *tvb, guint offset, guint len);
+
/** Free a tvbuff_t and all tvbuffs chained from it
* The tvbuff must be 'the 'head' (initial) tvb of a chain or
* must not be in a chain.
diff --git a/frame_tvbuff.c b/frame_tvbuff.c
index 5af5b3bc23..20635fd958 100644
--- a/frame_tvbuff.c
+++ b/frame_tvbuff.c
@@ -31,16 +31,119 @@
#include <epan/tvbuff.h>
#include "frame_tvbuff.h"
+#include "globals.h"
-/* XXX, to read data with wtap_seek_read() we need:
- * cf->wth, fdata->file_off, fdata->cap_len
- * add when ready to structure below
- */
+#include "wtap-int.h" /* for ->random_fh */
struct tvb_frame {
struct tvbuff tvb;
+
+ Buffer *buf; /* Packet data */
+
+ wtap *wth; /**< Wiretap session */
+ 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;
+
+ /* sanity check, capture file was closed? */
+ if (cfile.wth != frame_tvb->wth)
+ return FALSE;
+
+ if (!wtap_seek_read(frame_tvb->wth, frame_tvb->file_off, phdr, buf, frame_tvb->tvb.length, &err, &err_info)) {
+ switch (err) {
+ case WTAP_ERR_UNSUPPORTED_ENCAP:
+ case WTAP_ERR_BAD_FILE:
+ g_free(err_info);
+ break;
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static void
+frame_invalidate(struct tvb_frame *frame_tvb)
+{
+ struct wtap_pkthdr phdr; /* Packet header */
+
+ if (frame_tvb->buf == NULL) {
+ frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer));
+
+ /* XXX, register frame_tvb to some list which frees from time to time not used buffers :] */
+ buffer_init(frame_tvb->buf, frame_tvb->tvb.length);
+
+ if (!frame_read(frame_tvb, &phdr, frame_tvb->buf))
+ { /* TODO: THROW(???); */ }
+ }
+
+ frame_tvb->tvb.real_data = buffer_start_ptr(frame_tvb->buf);
+}
+
+static void
+frame_free(tvbuff_t *tvb)
+{
+ struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
+
+ if (frame_tvb->buf) {
+ buffer_free(frame_tvb->buf);
+
+ g_free(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_invalidate(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_invalidate(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_invalidate(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 guint8 *needles, guchar *found_needle)
+{
+ struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
+
+ frame_invalidate(frame_tvb);
+
+ return tvb_pbrk_guint8(tvb, abs_offset, limit, needles, found_needle);
+}
+
static gsize
frame_sizeof(void)
{
@@ -50,23 +153,28 @@ frame_sizeof(void)
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 = {
frame_sizeof, /* size */
- NULL, /* free */
+ frame_free, /* free */
frame_offset, /* offset */
- NULL, /* get_ptr */
- NULL, /* memcpy */
- NULL, /* find_guint8 */
- NULL, /* pbrk_guint8 */
+ 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 frame_data *fd, const guint8 *buf)
{
+ struct tvb_frame *frame_tvb;
tvbuff_t *tvb;
tvb = tvb_new(&tvb_frame_ops);
@@ -104,6 +212,21 @@ frame_tvbuff_new(const frame_data *fd, const guint8 *buf)
*/
tvb->ds_tvb = tvb;
+ frame_tvb = (struct tvb_frame *) tvb;
+
+ /* XXX, how to handle fd->file_off == -1 (edited packet) ?? */
+ /* don't care, reassemble code was doing whole copy of data, so it'll work the same */
+
+ /* XXX, wtap_can_seek() */
+ if (fd && cfile.wth && cfile.wth->random_fh) {
+ frame_tvb->wth = cfile.wth;
+ frame_tvb->file_off = fd->file_off;
+ frame_tvb->offset = 0;
+ } else
+ frame_tvb->wth = NULL;
+
+ frame_tvb->buf = NULL;
+
return tvb;
}
@@ -112,3 +235,40 @@ frame_tvbuff_new_buffer(const frame_data *fd, Buffer *buf)
{
return frame_tvbuff_new(fd, 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->wth)
+ 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->wth = frame_tvb->wth;
+ cloned_frame_tvb->file_off = frame_tvb->file_off;
+ cloned_frame_tvb->offset = abs_offset;
+ cloned_frame_tvb->buf = NULL;
+
+ return cloned_tvb;
+}