aboutsummaryrefslogtreecommitdiffstats
path: root/epan/reassemble.c
diff options
context:
space:
mode:
authorJakub Zawadzki <darkjames-ws@darkjames.pl>2013-07-14 14:42:05 +0000
committerJakub Zawadzki <darkjames-ws@darkjames.pl>2013-07-14 14:42:05 +0000
commitc766e78cfa1527ed242580b808635b0b5966cf3e (patch)
tree7a4318d94e33c292936eb8cffca5e5ff31e73c55 /epan/reassemble.c
parentd924325d37c8724a447f76f8789063580bd86876 (diff)
Rewrite reassemble API to use TVBs instead of raw data.
(it seems to be working for TCP ^^) svn path=/trunk/; revision=50580
Diffstat (limited to 'epan/reassemble.c')
-rw-r--r--epan/reassemble.c137
1 files changed, 69 insertions, 68 deletions
diff --git a/epan/reassemble.c b/epan/reassemble.c
index 413fa8e385..98fd8b97c9 100644
--- a/epan/reassemble.c
+++ b/epan/reassemble.c
@@ -339,8 +339,8 @@ free_all_fragments(gpointer key_arg _U_, gpointer value, gpointer user_data _U_)
for (fd_head = (fragment_data *)value; fd_head != NULL; fd_head = tmp_fd) {
tmp_fd=fd_head->next;
- if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED))
- g_free(fd_head->data);
+ if(fd_head->tvb_data && !(fd_head->flags&FD_SUBSET_TVB))
+ tvb_free(fd_head->tvb_data);
g_slice_free(fragment_data, fd_head);
}
@@ -383,8 +383,8 @@ free_all_reassembled_fragments(gpointer key_arg, gpointer value,
* free_fragments()
*/
if (fd_head->flags != FD_VISITED_FREE) {
- if (fd_head->flags & FD_NOT_MALLOCED)
- fd_head->data = NULL;
+ if (fd_head->flags & FD_SUBSET_TVB)
+ fd_head->tvb_data = NULL;
g_ptr_array_add(allocated_fragments, fd_head);
fd_head->flags = FD_VISITED_FREE;
}
@@ -400,7 +400,8 @@ free_fragments(gpointer data, gpointer user_data _U_)
{
fragment_data *fd_head = (fragment_data *) data;
- g_free(fd_head->data);
+ if (fd_head->tvb_data)
+ tvb_free(fd_head->tvb_data);
g_slice_free(fragment_data, fd_head);
}
@@ -568,14 +569,14 @@ insert_fd_head(reassembly_table *table, fragment_data *fd_head,
* Othervise the function will return NULL.
*
* So, if you call fragment_delete and it returns non-NULL, YOU are responsible to
- * g_free() that buffer.
+ * tvb_free() that buffer.
*/
-unsigned char *
+tvbuff_t *
fragment_delete(reassembly_table *table, const packet_info *pinfo,
const guint32 id, const void *data)
{
fragment_data *fd_head, *fd;
- unsigned char *fd_data=NULL;
+ tvbuff_t *fd_tvb_data=NULL;
gpointer key;
fd_head = lookup_fd_head(table, pinfo, id, data, &key);
@@ -584,21 +585,21 @@ fragment_delete(reassembly_table *table, const packet_info *pinfo,
return NULL;
}
- fd_data=fd_head->data;
+ fd_tvb_data=fd_head->tvb_data;
/* loop over all partial fragments and free any buffers */
for(fd=fd_head->next;fd;){
fragment_data *tmp_fd;
tmp_fd=fd->next;
- if( !(fd->flags&FD_NOT_MALLOCED) )
- g_free(fd->data);
+ if (fd->tvb_data && !(fd->flags & FD_SUBSET_TVB))
+ tvb_free(fd->tvb_data);
g_slice_free(fragment_data, fd);
fd=tmp_fd;
}
g_slice_free(fragment_data, fd_head);
g_hash_table_remove(table->fragment_table, key);
- return fd_data;
+ return fd_tvb_data;
}
/* This function is used to check if there is partial or completed reassembly state
@@ -862,7 +863,8 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fragment_data *fd;
fragment_data *fd_i;
guint32 max, dfpos, fraglen;
- unsigned char *old_data;
+ tvbuff_t *old_tvb_data;
+ char *data;
/* create new fd describing this fragment */
fd = g_slice_new(fragment_data);
@@ -872,7 +874,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fd->offset = frag_offset;
fd->fragment_nr_offset = 0; /* will only be used with sequence */
fd->len = frag_data_len;
- fd->data = NULL;
+ fd->tvb_data = NULL;
fd->error = NULL;
/*
@@ -896,9 +898,9 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
* point old fds to malloc'ed data.
*/
for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){
- if( !fd_i->data ) {
- fd_i->data = fd_head->data + fd_i->offset;
- fd_i->flags |= FD_NOT_MALLOCED;
+ if( !fd_i->tvb_data ) {
+ fd_i->tvb_data = tvb_new_subset_remaining(fd_head->tvb_data, fd_i->offset);
+ fd_i->flags |= FD_SUBSET_TVB;
}
fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
}
@@ -995,7 +997,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fd_head->flags |= FD_TOOLONGFRAGMENT;
}
/* make sure it doesn't conflict with previous data */
- else if ( memcmp(fd_head->data+fd->offset,
+ else if ( tvb_memeql(fd_head->tvb_data, fd->offset,
tvb_get_ptr(tvb,offset,fd->len),fd->len) ){
fd->flags |= FD_OVERLAPCONFLICT;
fd_head->flags |= FD_OVERLAPCONFLICT;
@@ -1012,8 +1014,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
* XXX - what if we didn't capture the entire fragment due
* to a too-short snapshot length?
*/
- fd->data = (unsigned char *)g_malloc(fd->len);
- tvb_memcpy(tvb, fd->data, offset, fd->len);
+ fd->tvb_data = tvb_clone_offset_len(tvb, offset, fd->len);
LINK_FRAG(fd_head,fd);
@@ -1056,8 +1057,10 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
* free all fragments
*/
/* store old data just in case */
- old_data=fd_head->data;
- fd_head->data = (unsigned char *)g_malloc(fd_head->datalen);
+ old_tvb_data=fd_head->tvb_data;
+ data = g_malloc(fd_head->datalen);
+ fd_head->tvb_data = tvb_new_real_data(data, fd_head->datalen, fd_head->datalen);
+ tvb_set_free_cb(fd_head->tvb_data, g_free);
/* add all data fragments */
for (dfpos=0,fd_i=fd_head;fd_i;fd_i=fd_i->next) {
@@ -1113,7 +1116,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fd_head->error = "dfpos < offset";
} else if (dfpos - fd_i->offset > fd_i->len)
fd_head->error = "dfpos - offset > len";
- else if (!fd_head->data)
+ else if (!fd_head->tvb_data)
fd_head->error = "no data";
else {
fraglen = fd_i->len;
@@ -1137,12 +1140,14 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fraglen = fd_head->datalen - fd_i->offset;
}
if (fd_i->offset < dfpos) {
+ guint32 cmp_len = MIN(fd_i->len,(dfpos-fd_i->offset));
+
fd_i->flags |= FD_OVERLAP;
fd_head->flags |= FD_OVERLAP;
- if ( memcmp(fd_head->data+fd_i->offset,
- fd_i->data,
- MIN(fd_i->len,(dfpos-fd_i->offset))
- ) ) {
+ if ( memcmp(data + fd_i->offset,
+ tvb_get_ptr(fd_i->tvb_data, 0, cmp_len),
+ cmp_len)
+ ) {
fd_i->flags |= FD_OVERLAPCONFLICT;
fd_head->flags |= FD_OVERLAPCONFLICT;
}
@@ -1153,8 +1158,8 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
*/
fd_head->error = "fraglen < dfpos - offset";
} else {
- memcpy(fd_head->data+dfpos,
- fd_i->data+(dfpos-fd_i->offset),
+ memcpy(data+dfpos,
+ tvb_get_ptr(fd_i->tvb_data, (dfpos-fd_i->offset), fraglen-(dfpos-fd_i->offset)),
fraglen-(dfpos-fd_i->offset));
dfpos=MAX(dfpos, (fd_i->offset + fraglen));
}
@@ -1165,15 +1170,18 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fd_head->error = "offset + len < offset";
}
}
- if (fd_i->flags & FD_NOT_MALLOCED)
- fd_i->flags &= ~FD_NOT_MALLOCED;
- else
- g_free(fd_i->data);
- fd_i->data=NULL;
+
+ if (fd_i->flags & FD_SUBSET_TVB)
+ fd_i->flags &= ~FD_SUBSET_TVB;
+ else if (fd_i->tvb_data)
+ tvb_free(fd_i->tvb_data);
+
+ fd_i->tvb_data=NULL;
}
}
- g_free(old_data);
+ if (old_tvb_data)
+ tvb_free(old_tvb_data);
/* mark this packet as defragmented.
allows us to skip any trailing fragments */
fd_head->flags |= FD_DEFRAGMENTED;
@@ -1474,7 +1482,8 @@ fragment_defragment_and_free (fragment_data *fd_head, const packet_info *pinfo)
fragment_data *fd_i = NULL;
fragment_data *last_fd = NULL;
guint32 dfpos = 0, size = 0;
- void *old_data = NULL;
+ tvbuff_t *old_tvb_data = NULL;
+ char *data;
for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
if(!last_fd || last_fd->offset!=fd_i->offset){
@@ -1484,8 +1493,10 @@ fragment_defragment_and_free (fragment_data *fd_head, const packet_info *pinfo)
}
/* store old data in case the fd_i->data pointers refer to it */
- old_data=fd_head->data;
- fd_head->data = (unsigned char *)g_malloc(size);
+ old_tvb_data=fd_head->tvb_data;
+ data = g_malloc(size);
+ fd_head->tvb_data = tvb_new_real_data(data, size, size);
+ tvb_set_free_cb(fd_head->tvb_data, g_free);
fd_head->len = size; /* record size for caller */
/* add all data fragments */
@@ -1494,14 +1505,14 @@ fragment_defragment_and_free (fragment_data *fd_head, const packet_info *pinfo)
if (fd_i->len) {
if(!last_fd || last_fd->offset != fd_i->offset) {
/* First fragment or in-sequence fragment */
- memcpy(fd_head->data+dfpos, fd_i->data, fd_i->len);
+ memcpy(data+dfpos, tvb_get_ptr(fd_i->tvb_data, 0, fd_i->len), fd_i->len);
dfpos += fd_i->len;
} else {
/* duplicate/retransmission/overlap */
fd_i->flags |= FD_OVERLAP;
fd_head->flags |= FD_OVERLAP;
if(last_fd->len != fd_i->len
- || memcmp(last_fd->data, fd_i->data, last_fd->len) ) {
+ || tvb_memeql(last_fd->tvb_data, 0, tvb_get_ptr(fd_i->tvb_data, 0, last_fd->len), last_fd->len) ) {
fd_i->flags |= FD_OVERLAPCONFLICT;
fd_head->flags |= FD_OVERLAPCONFLICT;
}
@@ -1512,13 +1523,14 @@ fragment_defragment_and_free (fragment_data *fd_head, const packet_info *pinfo)
/* we have defragmented the pdu, now free all fragments*/
for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) {
- if( fd_i->flags & FD_NOT_MALLOCED )
- fd_i->flags &= ~FD_NOT_MALLOCED;
- else
- g_free(fd_i->data);
- fd_i->data=NULL;
+ if (fd_i->flags & FD_SUBSET_TVB)
+ fd_i->flags &= ~FD_SUBSET_TVB;
+ else if (fd_i->tvb_data)
+ tvb_free(fd_i->tvb_data);
+ fd_i->tvb_data=NULL;
}
- g_free(old_data);
+ if (old_tvb_data)
+ tvb_free(old_tvb_data);
/* mark this packet as defragmented.
* allows us to skip any trailing fragments.
@@ -1564,17 +1576,17 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
guint32 lastdfpos = 0;
dfpos = 0;
for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){
- if( !fd_i->data ) {
+ if( !fd_i->tvb_data ) {
if( fd_i->flags & FD_OVERLAP ) {
/* this is a duplicate of the previous
* fragment. */
- fd_i->data = fd_head->data + lastdfpos;
+ fd_i->tvb_data = tvb_new_subset_remaining(fd_head->tvb_data, lastdfpos);
} else {
- fd_i->data = fd_head->data + dfpos;
+ fd_i->tvb_data = tvb_new_subset_remaining(fd_head->tvb_data, dfpos);
lastdfpos = dfpos;
dfpos += fd_i->len;
}
- fd_i->flags |= FD_NOT_MALLOCED;
+ fd_i->flags |= FD_SUBSET_TVB;
}
fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
}
@@ -1592,7 +1604,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
fd->frame = pinfo->fd->num;
fd->offset = frag_number_work;
fd->len = frag_data_len;
- fd->data = NULL;
+ fd->tvb_data = NULL;
fd->error = NULL;
if (!more_frags) {
@@ -1659,7 +1671,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
return TRUE;
}
DISSECTOR_ASSERT(fd_head->len >= dfpos + fd->len);
- if ( memcmp(fd_head->data+dfpos,
+ if (tvb_memeql(fd_head->tvb_data, dfpos,
tvb_get_ptr(tvb,offset,fd->len),fd->len) ){
/*
* They have the same length, but the
@@ -1717,8 +1729,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, const int offset,
*/
/* check len, there may be a fragment with 0 len, that is actually the tail */
if (fd->len) {
- fd->data = (unsigned char *)g_malloc(fd->len);
- tvb_memcpy(tvb, fd->data, offset, fd->len);
+ fd->tvb_data = tvb_clone_offset_len(tvb, offset, fd->len);
}
LINK_FRAG(fd_head,fd);
@@ -2063,7 +2074,7 @@ fragment_start_seq_check(reassembly_table *table, const packet_info *pinfo,
fd_head->fragment_nr_offset = 0;
fd_head->len = 0;
fd_head->flags = FD_BLOCKSEQUENCE|FD_DATALEN_SET;
- fd_head->data = NULL;
+ fd_head->tvb_data = NULL;
fd_head->reassembled_in = 0;
fd_head->error = NULL;
@@ -2154,22 +2165,12 @@ process_reassembled_data(tvbuff_t *tvb, const int offset, packet_info *pinfo,
/*
* Yes.
* Allocate a new tvbuff, referring to the
- * reassembled payload.
- */
- if (fd_head->flags & FD_BLOCKSEQUENCE) {
- next_tvb = tvb_new_real_data(fd_head->data,
- fd_head->len, fd_head->len);
- } else {
- next_tvb = tvb_new_real_data(fd_head->data,
- fd_head->datalen, fd_head->datalen);
- }
-
- /*
- * Add the tvbuff to the list of tvbuffs to which
+ * reassembled payload, and set
+ * the tvbuff to the list of tvbuffs to which
* the tvbuff we were handed refers, so it'll get
* cleaned up when that tvbuff is cleaned up.
*/
- tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
/* Add the defragmented data to the data source list. */
add_new_data_source(pinfo, next_tvb, name);