summaryrefslogtreecommitdiff
path: root/epan
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2007-02-21 06:19:03 +0000
committerAnders Broman <anders.broman@ericsson.com>2007-02-21 06:19:03 +0000
commite2cab6caa975f33bf5fde17cad8f2eb2cc58e60f (patch)
treecf279b2b97fbd8c3476b39718e7cc2834f0a0d21 /epan
parentd5f4bfe77361552a244dcefc8ec74ee0a2aac61f (diff)
downloadwireshark-e2cab6caa975f33bf5fde17cad8f2eb2cc58e60f.tar.gz
From Richard van der Hoff:
01_reassemble_test.patch ------------------------ I didn't want to do anything without some unit tests, so here they are. This allows a standalone binary, epan/reassemble_test, to be built; this can be run from the commandline and should end up printing out "success" if all goes well. NOTE the changes to makefile.am NOT checked in currently. Incidentally: is it possible to get the buildbot to run things like this, exntest and tvbtest? 02_reassemble_refactor.patch ---------------------------- fragment_add_seq, fragment_add_dcerpc_dg and fragment_add_seq_check_work were all pretty much carbon-copies of each other. This patch factors out the common parts of the routines into a new routine, fragment_add_seq_key(). 03_reassemble_partial_reassembly.patch --------------------------------------- This makes fragment_set_partial_reassembly() work for datagrams assembled with fragment_add_seq(). The patch itself is actually quite small, but it adds another unit test which is reasonably lengthy. svn path=/trunk/; revision=20888
Diffstat (limited to 'epan')
-rw-r--r--epan/reassemble.c446
-rw-r--r--epan/reassemble.h113
-rw-r--r--epan/reassemble_test.c1057
3 files changed, 1367 insertions, 249 deletions
diff --git a/epan/reassemble.c b/epan/reassemble.c
index 4224c39664..9a19f8566d 100644
--- a/epan/reassemble.c
+++ b/epan/reassemble.c
@@ -64,6 +64,33 @@ static int fragment_init_count = 200;
fd_i->next=(fd); \
}
+/* copy a fragment key to heap store to insert in the hash */
+static void *fragment_key_copy(const void *k)
+{
+ const fragment_key* key = (const fragment_key*) k;
+ fragment_key *new_key = g_mem_chunk_alloc(fragment_key_chunk);
+
+ COPY_ADDRESS(&new_key->src, &key->src);
+ COPY_ADDRESS(&new_key->dst, &key->dst);
+ new_key->id = key->id;
+ return new_key;
+}
+
+/* copy a dcerpc fragment key to heap store to insert in the hash */
+static void *dcerpc_fragment_key_copy(const void *k)
+{
+ const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
+ dcerpc_fragment_key *new_key = se_alloc(sizeof(dcerpc_fragment_key));
+
+ COPY_ADDRESS(&new_key->src, &key->src);
+ COPY_ADDRESS(&new_key->dst, &key->dst);
+ new_key->id = key->id;
+ new_key->act_id = key->act_id;
+
+ return new_key;
+}
+
+
static gint
fragment_equal(gconstpointer k1, gconstpointer k2)
{
@@ -445,6 +472,7 @@ fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table,
if(fd_head){
fd_head->datalen = tot_len;
+ fd_head->flags |= FD_DATALEN_SET;
}
return;
@@ -624,7 +652,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
}
fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
}
- fd_head->flags ^= FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY;
+ fd_head->flags &= ~(FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY|FD_DATALEN_SET);
fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
fd_head->datalen=0;
fd_head->reassembled_in=0;
@@ -634,7 +662,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
/*
* This is the tail fragment in the sequence.
*/
- if (fd_head->datalen) {
+ if (fd_head->flags & FD_DATALEN_SET) {
/* ok we have already seen other tails for this packet
* it might be a duplicate.
*/
@@ -650,6 +678,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
* length of the packet
*/
fd_head->datalen = fd->offset + fd->len;
+ fd_head->flags |= FD_DATALEN_SET;
}
}
@@ -696,7 +725,7 @@ fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
LINK_FRAG(fd_head,fd);
- if( !(fd_head->datalen) ){
+ if( !(fd_head->flags & FD_DATALEN_SET) ){
/* if we dont know the datalen, there are still missing
* packets. Cheaper than the check below.
*/
@@ -1066,12 +1095,43 @@ fragment_add_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
static gboolean
fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
packet_info *pinfo, guint32 frag_number,
- guint32 frag_data_len, gboolean more_frags)
+ guint32 frag_data_len, gboolean more_frags,
+ guint32 flags)
{
fragment_data *fd;
fragment_data *fd_i;
fragment_data *last_fd;
guint32 max, dfpos, size;
+ void *old_data;
+
+ /* if the partial reassembly flag has been set, and we are extending
+ * the pdu, un-reassemble the pdu. This means pointing old fds to malloc'ed data.
+ */
+ if(fd_head->flags & FD_DEFRAGMENTED && frag_number >= fd_head->datalen &&
+ fd_head->flags & FD_PARTIAL_REASSEMBLY){
+ 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->flags & FD_OVERLAP ) {
+ /* this is a duplicate of the previous
+ * fragment. */
+ fd_i->data = fd_head->data + lastdfpos;
+ } else {
+ fd_i->data = fd_head->data + dfpos;
+ lastdfpos = dfpos;
+ dfpos += fd_i->len;
+ }
+ fd_i->flags |= FD_NOT_MALLOCED;
+ }
+ fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
+ }
+ fd_head->flags &= ~(FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY|FD_DATALEN_SET);
+ fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS);
+ fd_head->datalen=0;
+ fd_head->reassembled_in=0;
+ }
+
/* create new fd describing this fragment */
fd = g_mem_chunk_alloc(fragment_data_chunk);
@@ -1086,7 +1146,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
/*
* This is the tail fragment in the sequence.
*/
- if (fd_head->datalen) {
+ if (fd_head->flags&FD_DATALEN_SET) {
/* ok we have already seen other tails for this packet
* it might be a duplicate.
*/
@@ -1103,6 +1163,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
* the length of the packet!)
*/
fd_head->datalen = fd->offset;
+ fd_head->flags |= FD_DATALEN_SET;
}
}
@@ -1209,7 +1270,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
LINK_FRAG(fd_head,fd);
- if( !(fd_head->datalen) ){
+ if( !(fd_head->flags & FD_DATALEN_SET) ){
/* if we dont know the sequence number of the last fragment,
* there are definitely still missing packets. Cheaper than
* the check below.
@@ -1253,6 +1314,8 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
}
last_fd=fd_i;
}
+ /* store old data in case the fd_i->data pointers refer to it */
+ old_data=fd_head->data;
fd_head->data = g_malloc(size);
fd_head->len = size; /* record size for caller */
@@ -1268,7 +1331,7 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
/* duplicate/retransmission/overlap */
fd_i->flags |= FD_OVERLAP;
fd_head->flags |= FD_OVERLAP;
- if( (last_fd->len!=fd_i->datalen)
+ if( (last_fd->len!=fd_i->len)
|| memcmp(last_fd->data, fd_i->data, last_fd->len) ){
fd->flags |= FD_OVERLAPCONFLICT;
fd_head->flags |= FD_OVERLAPCONFLICT;
@@ -1280,12 +1343,16 @@ fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset,
/* 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->data){
- g_free(fd_i->data);
- fd_i->data=NULL;
- }
+ if( fd_i->flags & FD_NOT_MALLOCED )
+ fd_i->flags &= ~FD_NOT_MALLOCED;
+ else
+ g_free(fd_i->data);
+ fd_i->data=NULL;
}
+ if( old_data )
+ g_free(old_data);
+
/* mark this packet as defragmented.
allows us to skip any trailing fragments */
fd_head->flags |= FD_DEFRAGMENTED;
@@ -1311,15 +1378,50 @@ fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
GHashTable *fragment_table, guint32 frag_number,
guint32 frag_data_len, gboolean more_frags)
{
- fragment_key key, *new_key;
- fragment_data *fd_head;
+ fragment_key key;
/* create key to search hash with */
key.src = pinfo->src;
key.dst = pinfo->dst;
key.id = id;
- fd_head = g_hash_table_lookup(fragment_table, &key);
+ return fragment_add_seq_key(tvb, offset, pinfo,
+ &key, fragment_key_copy,
+ fragment_table, frag_number,
+ frag_data_len, more_frags, 0);
+}
+
+
+fragment_data *
+fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
+ void *v_act_id,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags)
+{
+ e_uuid_t *act_id = (e_uuid_t *)v_act_id;
+ dcerpc_fragment_key key;
+
+ /* create key to search hash with */
+ key.src = pinfo->src;
+ key.dst = pinfo->dst;
+ key.id = id;
+ key.act_id = *act_id;
+
+ return fragment_add_seq_key(tvb, offset, pinfo,
+ &key, dcerpc_fragment_key_copy,
+ fragment_table, frag_number,
+ frag_data_len, more_frags, 0);
+}
+
+fragment_data *
+fragment_add_seq_key(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ void *key, fragment_key_copier key_copier,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags,
+ guint32 flags)
+{
+ fragment_data *fd_head;
+ fd_head = g_hash_table_lookup(fragment_table, key);
/* have we already seen this frame ?*/
if (pinfo->fd->flags.visited) {
@@ -1348,21 +1450,89 @@ fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
fd_head->data=NULL;
fd_head->reassembled_in=0;
+ if((flags & (REASSEMBLE_FLAGS_NO_FRAG_NUMBER|REASSEMBLE_FLAGS_802_11_HACK))
+ && !more_frags) {
+ /*
+ * This is the last fragment for this packet, and
+ * is the only one we've seen.
+ *
+ * Either we don't have sequence numbers, in which
+ * case we assume this is the first fragment for
+ * this packet, or we're doing special 802.11
+ * processing, in which case we assume it's one
+ * of those reassembled packets with a non-zero
+ * fragment number (see packet-80211.c); just
+ * return a pointer to the head of the list;
+ * fragment_add_seq_check will then add it to the table
+ * of reassembled packets.
+ */
+ fd_head->reassembled_in=pinfo->fd->num;
+ return fd_head;
+ }
+
/*
* We're going to use the key to insert the fragment,
- * so allocate a structure for it, and copy the
- * addresses, allocating new buffers for the address
- * data.
+ * so copy it to a long-term store.
*/
- new_key = g_mem_chunk_alloc(fragment_key_chunk);
- COPY_ADDRESS(&new_key->src, &key.src);
- COPY_ADDRESS(&new_key->dst, &key.dst);
- new_key->id = key.id;
- g_hash_table_insert(fragment_table, new_key, fd_head);
+ if(key_copier != NULL)
+ key = key_copier(key);
+ g_hash_table_insert(fragment_table, key, fd_head);
+
+ /*
+ * If we weren't given an initial fragment number,
+ * make it 0.
+ */
+ if (flags & REASSEMBLE_FLAGS_NO_FRAG_NUMBER)
+ frag_number = 0;
+ } else {
+ if (flags & REASSEMBLE_FLAGS_NO_FRAG_NUMBER) {
+ fragment_data *fd;
+ /*
+ * If we weren't given an initial fragment number,
+ * use the next expected fragment number as the fragment
+ * number for this fragment.
+ */
+ for (fd = fd_head; fd != NULL; fd = fd->next) {
+ if (fd->next == NULL)
+ frag_number = fd->offset + 1;
+ }
+ }
}
+ /*
+ * XXX I've copied this over from the old separate
+ * fragment_add_seq_check_work, but I'm not convinced it's doing the
+ * right thing -- rav
+ *
+ * If we don't have all the data that is in this fragment,
+ * then we can't, and don't, do reassembly on it.
+ *
+ * If it's the first frame, handle it as an unfragmented packet.
+ * Otherwise, just handle it as a fragment.
+ *
+ * If "more_frags" isn't set, we get rid of the entry in the
+ * hash table for this reassembly, as we don't need it any more.
+ */
+ if ((flags & REASSEMBLE_FLAGS_CHECK_DATA_PRESENT) &&
+ !tvb_bytes_exist(tvb, offset, frag_data_len)) {
+ if (!more_frags) {
+ gpointer orig_key;
+ /*
+ * Remove this from the table of in-progress
+ * reassemblies, and free up any memory used for
+ * it in that table.
+ */
+ if (g_hash_table_lookup_extended(fragment_table, key,
+ &orig_key, NULL)) {
+ fragment_unhash(fragment_table, (fragment_key *)orig_key);
+ }
+ }
+ fd_head -> flags |= FD_DATA_NOT_PRESENT;
+ return frag_number == 0 ? fd_head : NULL;
+ }
+
if (fragment_add_seq_work(fd_head, tvb, offset, pinfo,
- frag_number, frag_data_len, more_frags)) {
+ frag_number, frag_data_len, more_frags, flags)) {
/*
* Reassembly is complete.
*/
@@ -1375,79 +1545,6 @@ fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
}
}
-fragment_data *
-fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
- void *v_act_id,
- GHashTable *fragment_table, guint32 frag_number,
- guint32 frag_data_len, gboolean more_frags)
-{
- dcerpc_fragment_key key, *new_key;
- fragment_data *fd_head;
- e_uuid_t *act_id = (e_uuid_t *)v_act_id;
-
- /* create key to search hash with */
- key.src = pinfo->src;
- key.dst = pinfo->dst;
- key.id = id;
- key.act_id = *act_id;
-
- fd_head = g_hash_table_lookup(fragment_table, &key);
-
- /* have we already seen this frame ?*/
- if (pinfo->fd->flags.visited) {
- if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) {
- return fd_head;
- } else {
- return NULL;
- }
- }
-
- if (fd_head==NULL){
- /* not found, this must be the first snooped fragment for this
- * packet. Create list-head.
- */
- fd_head=g_mem_chunk_alloc(fragment_data_chunk);
-
- /* head/first structure in list only holds no other data than
- * 'datalen' then we don't have to change the head of the list
- * even if we want to keep it sorted
- */
- fd_head->next=NULL;
- fd_head->datalen=0;
- fd_head->offset=0;
- fd_head->len=0;
- fd_head->flags=FD_BLOCKSEQUENCE;
- fd_head->data=NULL;
- fd_head->reassembled_in=0;
-
- /*
- * We're going to use the key to insert the fragment,
- * so allocate a structure for it, and copy the
- * addresses, allocating new buffers for the address
- * data.
- */
- new_key = se_alloc(sizeof(dcerpc_fragment_key));
- COPY_ADDRESS(&new_key->src, &key.src);
- COPY_ADDRESS(&new_key->dst, &key.dst);
- new_key->id = key.id;
- new_key->act_id = key.act_id;
- g_hash_table_insert(fragment_table, new_key, fd_head);
- }
-
- if (fragment_add_seq_work(fd_head, tvb, offset, pinfo,
- frag_number, frag_data_len, more_frags)) {
- /*
- * Reassembly is complete.
- */
- return fd_head;
- } else {
- /*
- * Reassembly isn't complete.
- */
- return NULL;
- }
-}
-
/*
* This does the work for "fragment_add_seq_check()" and
* "fragment_add_seq_next()".
@@ -1468,10 +1565,10 @@ fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id
*
* This fragment is added to the linked list of fragments for this packet.
*
- * If "more_frags" is false and "frag_802_11_hack" (as the name implies,
- * a special hack for 802.11) or "no_frag_number" (implying messages must be
- * in order since there's no sequence number) are true, then this (one
- * element) list is returned.
+ * If "more_frags" is false and REASSEMBLE_FLAGS_802_11_HACK (as the name
+ * implies, a special hack for 802.11) or REASSEMBLE_FLAGS_NO_FRAG_NUMBER
+ * (implying messages must be in order since there's no sequence number) are
+ * set in "flags", then this (one element) list is returned.
*
* If, after processing this fragment, we have all the fragments,
* "fragment_add_seq_check_work()" removes that from the fragment hash
@@ -1487,12 +1584,11 @@ fragment_add_seq_check_work(tvbuff_t *tvb, int offset, packet_info *pinfo,
guint32 id, GHashTable *fragment_table,
GHashTable *reassembled_table, guint32 frag_number,
guint32 frag_data_len, gboolean more_frags,
- gboolean no_frag_number, gboolean frag_802_11_hack)
+ guint32 flags)
{
reassembled_key reass_key;
- fragment_key key, *new_key, *old_key;
- gpointer orig_key, value;
- fragment_data *fd_head, *fd;
+ fragment_key key;
+ fragment_data *fd_head;
/*
* Have we already seen this frame?
@@ -1509,122 +1605,34 @@ fragment_add_seq_check_work(tvbuff_t *tvb, int offset, packet_info *pinfo,
key.dst = pinfo->dst;
key.id = id;
- if (!g_hash_table_lookup_extended(fragment_table, &key,
- &orig_key, &value)) {
- /* not found, this must be the first snooped fragment for this
- * packet. Create list-head.
- */
- fd_head=g_mem_chunk_alloc(fragment_data_chunk);
-
- /* head/first structure in list only holds no other data than
- * 'datalen' then we don't have to change the head of the list
- * even if we want to keep it sorted
- */
- fd_head->next=NULL;
- fd_head->datalen=0;
- fd_head->offset=0;
- fd_head->len=0;
- fd_head->flags=FD_BLOCKSEQUENCE;
- fd_head->data=NULL;
- fd_head->reassembled_in=0;
-
- if ((no_frag_number || frag_802_11_hack) && !more_frags) {
- /*
- * This is the last fragment for this packet, and
- * is the only one we've seen.
- *
- * Either we don't have sequence numbers, in which
- * case we assume this is the first fragment for
- * this packet, or we're doing special 802.11
- * processing, in which case we assume it's one
- * of those reassembled packets with a non-zero
- * fragment number (see packet-80211.c); just
- * add the fragment to the table of reassembled
- * packets, and return a pointer to the head of
- * the list.
- */
- fragment_reassembled(fd_head, pinfo,
- reassembled_table, id);
+ fd_head = fragment_add_seq_key(tvb, offset, pinfo,
+ &key, fragment_key_copy,
+ fragment_table, frag_number,
+ frag_data_len, more_frags, flags|REASSEMBLE_FLAGS_CHECK_DATA_PRESENT);
+ if (fd_head) {
+ gpointer orig_key;
+
+ if(fd_head->flags & FD_DATA_NOT_PRESENT) {
+ /* this is the first fragment of a datagram with
+ * truncated fragments. Don't move it to the
+ * reassembled table. */
return fd_head;
}
-
- /*
- * We're going to use the key to insert the fragment,
- * so allocate a structure for it, and copy the
- * addresses, allocating new buffers for the address
- * data.
- */
- new_key = g_mem_chunk_alloc(fragment_key_chunk);
- COPY_ADDRESS(&new_key->src, &key.src);
- COPY_ADDRESS(&new_key->dst, &key.dst);
- new_key->id = key.id;
- g_hash_table_insert(fragment_table, new_key, fd_head);
-
- orig_key = new_key; /* for unhashing it later */
-
- /*
- * If we weren't given an initial fragment number,
- * make it 0.
- */
- if (no_frag_number)
- frag_number = 0;
- } else {
- /*
- * We found it.
- */
- fd_head = value;
-
- /*
- * If we weren't given an initial fragment number,
- * use the next expected fragment number as the fragment
- * number for this fragment.
- */
- if (no_frag_number) {
- for (fd = fd_head; fd != NULL; fd = fd->next) {
- if (fd->next == NULL)
- frag_number = fd->offset + 1;
- }
- }
- }
-
- /*
- * If we don't have all the data that is in this fragment,
- * then we can't, and don't, do reassembly on it.
- *
- * If it's the first frame, handle it as an unfragmented packet.
- * Otherwise, just handle it as a fragment.
- *
- * If "more_frags" isn't set, we get rid of the entry in the
- * hash table for this reassembly, as we don't need it any more.
- */
- if (!tvb_bytes_exist(tvb, offset, frag_data_len)) {
- if (!more_frags) {
- /*
- * Remove this from the table of in-progress
- * reassemblies, and free up any memory used for
- * it in that table.
- */
- old_key = orig_key;
- fragment_unhash(fragment_table, old_key);
- }
- return frag_number == 0 ? fd_head : NULL;
- }
-
- if (fragment_add_seq_work(fd_head, tvb, offset, pinfo,
- frag_number, frag_data_len, more_frags)) {
+
/*
* Reassembly is complete.
* Remove this from the table of in-progress
* reassemblies, add it to the table of
* reassembled packets, and return it.
*/
-
- /*
- * Remove this from the table of in-progress reassemblies,
- * and free up any memory used for it in that table.
- */
- old_key = orig_key;
- fragment_unhash(fragment_table, old_key);
+ if (g_hash_table_lookup_extended(fragment_table, &key,
+ &orig_key, NULL)) {
+ /*
+ * Remove this from the table of in-progress reassemblies,
+ * and free up any memory used for it in that table.
+ */
+ fragment_unhash(fragment_table, (fragment_key *)orig_key);
+ }
/*
* Add this item to the table of reassembled packets.
@@ -1647,7 +1655,7 @@ fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
{
return fragment_add_seq_check_work(tvb, offset, pinfo, id,
fragment_table, reassembled_table, frag_number, frag_data_len,
- more_frags, FALSE, FALSE);
+ more_frags, 0);
}
fragment_data *
@@ -1658,7 +1666,7 @@ fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo,
{
return fragment_add_seq_check_work(tvb, offset, pinfo, id,
fragment_table, reassembled_table, frag_number, frag_data_len,
- more_frags, FALSE, TRUE);
+ more_frags, REASSEMBLE_FLAGS_802_11_HACK);
}
fragment_data *
@@ -1669,7 +1677,7 @@ fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo,
{
return fragment_add_seq_check_work(tvb, offset, pinfo, id,
fragment_table, reassembled_table, 0, frag_data_len,
- more_frags, TRUE, FALSE);
+ more_frags, REASSEMBLE_FLAGS_NO_FRAG_NUMBER);
}
/*
@@ -1925,3 +1933,11 @@ show_fragment_seq_tree(fragment_data *fd_head, const fragment_items *fit,
return show_fragment_errs_in_col(fd_head, fit, pinfo);
}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * tab-width: 8
+ * End:
+ */
diff --git a/epan/reassemble.h b/epan/reassemble.h
index 923a60f645..1197cbb7ab 100644
--- a/epan/reassemble.h
+++ b/epan/reassemble.h
@@ -51,12 +51,28 @@
into the defragmented packet */
#define FD_BLOCKSEQUENCE 0x0100
+/* if REASSEMBLE_FLAGS_CHECK_DATA_PRESENT is set, and the first fragment is
+ * incomplete, this flag is set in the flags word on the fd_head returned.
+ *
+ * It's all a fudge to preserve historical behaviour.
+ */
+#define FD_DATA_NOT_PRESENT 0x0200
+
+/* This flag is set in the to denote that datalen has ben set to a valid value.
+ * It's implied by FD_DEFRAGMENTED (we must know the total length of the
+ * datagram if we have defragmented it...)
+ */
+#define FD_DATALEN_SET 0x0400
+
typedef struct _fragment_data {
struct _fragment_data *next;
guint32 frame;
guint32 offset;
guint32 len;
- guint32 datalen; /*Only valid in first item of list */
+ guint32 datalen; /* Only valid in first item of list and when
+ * flags&FD_DATALEN_SET is set;
+ * number of bytes or (if flags&FD_BLOCKSEQUENCE set)
+ * segments in the datagram */
guint32 reassembled_in; /* frame where this PDU was reassembled,
only valid in the first item of the list
and when FD_DEFRAGMENTED is set*/
@@ -64,6 +80,26 @@ typedef struct _fragment_data {
unsigned char *data;
} fragment_data;
+
+/*
+ * Flags for fragment_add_seq_*
+ */
+
+/* we don't have any sequence numbers - fragments are assumed to appear in
+ * order */
+#define REASSEMBLE_FLAGS_NO_FRAG_NUMBER 0x0001
+
+/* a special fudge for the 802.11 dissector */
+#define REASSEMBLE_FLAGS_802_11_HACK 0x0002
+
+/* causes fragment_add_seq_key to check that all the fragment data is present
+ * in the tvb, and if not, do something a bit odd. */
+#define REASSEMBLE_FLAGS_CHECK_DATA_PRESENT 0x0004
+
+/* a function for copying hash keys */
+typedef void *(*fragment_key_copier)(const void *key);
+
+
/*
* Initialize a fragment table.
*/
@@ -105,10 +141,51 @@ extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset,
/* same as fragment_add() but this one assumes frag_number is a block
sequence number. note that frag_number is 0 for the first fragment. */
+
+/*
+ * These functions add a new fragment to the fragment hash table,
+ * assuming that frag_number is a block sequence number (starting from zero for
+ * the first fragment of each datagram).
+ *
+ * If this is the first fragment seen for this datagram, a new
+ * "fragment_data" structure is allocated to refer to the reassembled
+ * packet, and:
+ *
+ * if "more_frags" is false, and either we have no sequence numbers, or
+ * are using the 802.11 hack, it is assumed that this is the only fragment
+ * in the datagram. The structure is not added to the hash
+ * table, and not given any fragments to refer to, but is just returned.
+ *
+ * In this latter case reassembly wasn't done (since there was only one
+ * fragment in the packet); dissectors can check the 'next' pointer on the
+ * returned list to see if this case was hit or not.
+ *
+ * Otherwise, this fragment is just added to the linked list of fragments
+ * for this packet; the fragment_data is also added to the fragment hash if
+ * necessary.
+ *
+ * If this packet completes assembly, these functions return the head of the
+ * fragment data; otherwise, they return null.
+ */
+
+/* "key" should be an arbitrary key used for indexing the fragment hash;
+ * "key_copier" is called to copy the key to a more appropriate store before
+ * inserting a new entry to the hash.
+ */
+extern fragment_data *
+fragment_add_seq_key(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ void *key, fragment_key_copier key_copier,
+ GHashTable *fragment_table, guint32 frag_number,
+ guint32 frag_data_len, gboolean more_frags,
+ guint32 flags);
+
+/* a wrapper for fragment_add_seq_key - uses a key of source, dest and frame number */
extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo,
guint32 id, GHashTable *fragment_table, guint32 frag_number,
guint32 frag_data_len, gboolean more_frags);
+/* another wrapper for fragment_add_seq_key - uses a key of source, dest, frame
+ * number and act_id */
extern fragment_data *
fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id,
void *act_id,
@@ -116,44 +193,12 @@ fragment_add_dcerpc_dg(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id
guint32 frag_data_len, gboolean more_frags);
/*
- * These functions add a new fragment to the fragment hash table.
- * If this is the first fragment seen for this datagram, a new
- * "fragment_data" structure is allocated to refer to the reassembled,
- * packet, and:
- *
- * in "fragment_add_seq_802_11()", if "more_frags" is false,
- * the structure is not added to the hash table, and not given
- * any fragments to refer to, but is just returned;
- *
- * otherwise, this fragment is added to the linked list of fragments
- * for this packet, and the "fragment_data" structure is put into
- * the hash table.
- *
- * Otherwise, this fragment is just added to the linked list of fragments
- * for this packet.
+ * These routines extend fragment_add_seq_key to use a "reassembled_table".
*
* If, after processing this fragment, we have all the fragments, they
* remove that from the fragment hash table if necessary and add it
* to the table of reassembled fragments, and return a pointer to the
* head of the fragment list.
- *
- * If this is the first fragment we've seen, and "more_frags" is false,
- * the fragment is added to the list. "fragment_add_seq_check()" will
- * return NULL (waiting for the earlier sequence numbers) while
- * "fragment_add_seq_802_11()" (a special hack for the 802.11 dissector) and
- * "fragment_add_seq_next()" will return a pointer to the (one element) list.
- * In this latter case reassembly wasn't done (since there was only one
- * fragment in the packet); dissectors can check the 'next' pointer on the
- * returned list to see if this case was hit or not.
- *
- * Otherwise, they return NULL.
- *
- * "fragment_add_seq_check()" and "fragment_add_seq_802_11()" assume
- * frag_number is a block sequence number.
- * The bsn for the first block is 0.
- *
- * "fragment_add_seq_next()" is for protocols with no sequence number,
- * and assumes fragments always appear in sequence.
*/
extern fragment_data *
fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo,
diff --git a/epan/reassemble_test.c b/epan/reassemble_test.c
new file mode 100644
index 0000000000..8f48946684
--- /dev/null
+++ b/epan/reassemble_test.c
@@ -0,0 +1,1057 @@
+/* Standalone program to test functionality of reassemble.h API
+ *
+ * These aren't particularly complete - they just test a few corners of
+ * functionality which I was interested in. In particular, they only test the
+ * fragment_add_seq_* (ie, FD_BLOCKSEQUENCE) family of routines. However,
+ * hopefully they will inspire people to write additional tests, and provide a
+ * useful basis on which to do so.
+ *
+ * $Id$
+ *
+ * Copyright (c) 2007 MX Telecom Ltd. <richardv@mxtelecom.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <epan/emem.h>
+#include <epan/packet.h>
+#include <epan/packet_info.h>
+#include <epan/proto.h>
+#include <epan/tvbuff.h>
+#include <epan/reassemble.h>
+
+#include <epan/dissectors/packet-dcerpc.h>
+
+#define ASSERT(b) do_test((b),"Assertion failed at line %i: %s\n", __LINE__, #b)
+#define ASSERT_EQ(exp,act) do_test((exp)==(act),"Assertion failed at line %i: %s==%s (%i==%i)\n", __LINE__, #exp, #act, exp, act)
+#define ASSERT_NE(exp,act) do_test((exp)!=(act),"Assertion failed at line %i: %s!=%s (%i!=%i)\n", __LINE__, #exp, #act, exp, act)
+
+int failure = 0;
+
+void do_test(int condition, char *format, ...)
+{
+ va_list ap;
+
+ if(condition)
+ return;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ failure = 1;
+
+ /* many of the tests assume this routine doesn't return on failure; if we
+ * do, it may provide more information, but may cause a segfault. Uncomment
+ * this line if you wish.
+ */
+ exit(1);
+}
+
+#define DATA_LEN 256
+
+char *data;
+tvbuff_t *tvb;
+packet_info pinfo;
+
+/* fragment_table maps from datagram ids to head of fragment_data list
+ reassembled_table maps from <packet number,datagram id> to head of
+ fragment_data list */
+GHashTable *fragment_table = NULL, *reassembled_table = NULL;
+
+/**********************************************************************************
+ *
+ * fragment_add_seq
+ *
+ *********************************************************************************/
+
+/* Simple test case for fragment_add_seq.
+ * Adds three fragments (out of order, with one for a different datagram in between),
+ * and checks that they are reassembled correctly.
+ */
+static void test_simple_fragment_add_seq(void)
+{
+ fragment_data *fd_head, *fdh0;
+
+ printf("Starting test test_simple_fragment_add_seq\n");
+
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table,
+ 0, 50, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* adding the same fragment again should do nothing, even with different
+ * offset etc */
+ pinfo.fd->flags.visited = 1;
+ fd_head=fragment_add_seq(tvb, 5, &pinfo, 12, fragment_table,
+ 0, 60, TRUE);
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* start another pdu (just to confuse things) */
+ pinfo.fd->flags.visited = 0;
+ pinfo.fd->num = 2;
+ fd_head=fragment_add_seq(tvb, 15, &pinfo, 13, fragment_table,
+ 0, 60, TRUE);
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* now we add the terminal fragment of the first datagram */
+ pinfo.fd->num = 3;
+ fd_head=fragment_add_seq(tvb, 5, &pinfo, 12, fragment_table,
+ 2, 60, FALSE);
+
+ /* we haven't got all the fragments yet ... */
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* finally, add the missing fragment */
+ pinfo.fd->num = 4;
+ fd_head=fragment_add_seq(tvb, 15, &pinfo, 12, fragment_table,
+ 1, 60, TRUE);
+
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(170,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(4,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ ASSERT_EQ(1,fd_head->next->frame);
+ ASSERT_EQ(0,fd_head->next->offset); /* seqno */
+ ASSERT_EQ(50,fd_head->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->data);
+ ASSERT_NE(NULL,fd_head->next->next);
+
+ ASSERT_EQ(4,fd_head->next->next->frame);
+ ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */
+ ASSERT_EQ(60,fd_head->next->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->next->data);
+ ASSERT_NE(NULL,fd_head->next->next->next);
+
+ ASSERT_EQ(3,fd_head->next->next->next->frame);
+ ASSERT_EQ(2,fd_head->next->next->next->offset); /* seqno */
+ ASSERT_EQ(60,fd_head->next->next->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->next->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->next->next->data);
+ ASSERT_EQ(NULL,fd_head->next->next->next->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+ ASSERT(!memcmp(fd_head->data+50,data+15,60));
+ ASSERT(!memcmp(fd_head->data+110,data+5,60));
+
+ /* what happens if we revisit the packets now? */
+ fdh0 = fd_head;
+ pinfo.fd->flags.visited = 1;
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table,
+ 0, 50, TRUE);
+ /*
+ * this api relies on the caller to check fd_head -> reassembled_in
+ *
+ * Redoing all the tests seems like overkill - just check the pointer
+ */
+ ASSERT_EQ(fdh0,fd_head);
+
+ pinfo.fd->num = 3;
+ fd_head=fragment_add_seq(tvb, 5, &pinfo, 12, fragment_table,
+ 2, 60, FALSE);
+ ASSERT_EQ(fdh0,fd_head);
+
+ pinfo.fd->num = 4;
+ fd_head=fragment_add_seq(tvb, 15, &pinfo, 12, fragment_table,
+ 1, 60, TRUE);
+ ASSERT_EQ(fdh0,fd_head);
+}
+
+/* XXX ought to have some tests for overlapping fragments */
+
+/* This tests the functionality of fragment_set_partial_reassembly for
+ * FD_BLOCKSEQUENCE reassembly.
+ *
+ * We add a sequence of fragments thus:
+ * seqno frame offset len (initial) more_frags
+ * ----- ----- ------ --- --------------------
+ * 0 1 10 50 false
+ * 1 2 0 40 true
+ * 1 3 0 40 true (a duplicate fragment)
+ * 2 4 20 100 false
+ * 3 5 0 40 false
+ */
+static void test_fragment_add_seq_partial_reassembly(void)
+{
+ fragment_data *fd_head, *fd;
+
+ printf("Starting test test_fragment_add_seq_partial_reassembly\n");
+
+ /* generally it's probably fair to assume that we will be called with
+ * more_frags=FALSE.
+ */
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table,
+ 0, 50, FALSE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(50,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(1,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ ASSERT_EQ(1,fd_head->next->frame);
+ ASSERT_EQ(0,fd_head->next->offset); /* seqno */
+ ASSERT_EQ(50,fd_head->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->data);
+ ASSERT_EQ(NULL,fd_head->next->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+
+ /* now we announce that the reassembly wasn't complete after all. */
+ fragment_set_partial_reassembly(&pinfo,12,fragment_table);
+
+ /* and add another segment. To mix things up slightly (and so that we can
+ * check on the state of things), we're going to set the more_frags flag
+ * here
+ */
+ pinfo.fd->num = 2;
+ fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table,
+ 1, 40, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ fd_head=fragment_get(&pinfo,12,fragment_table);
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ /* ASSERT_EQ(50,fd_head->len); the length of data we have */
+ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(0,fd_head->reassembled_in);
+ ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ fd=fd_head->next;
+ ASSERT_EQ(1,fd->frame);
+ ASSERT_EQ(0,fd->offset); /* seqno */
+ ASSERT_EQ(50,fd->len); /* segment length */
+ ASSERT_EQ(FD_NOT_MALLOCED,fd->flags);
+ ASSERT_EQ(fd_head->data,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(2,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_NE(NULL,fd->data);
+ ASSERT_EQ(NULL,fd->next);
+
+ /* Another copy of the second segment.
+ */
+ pinfo.fd->num = 3;
+ fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table,
+ 1, 40, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+ fd_head=fragment_get(&pinfo,12,fragment_table);
+ ASSERT_NE(NULL,fd_head);
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ /* ASSERT_EQ(50,fd_head->len); the length of data we have */
+ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(0,fd_head->reassembled_in);
+ ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ fd=fd_head->next;
+ ASSERT_EQ(1,fd->frame);
+ ASSERT_EQ(0,fd->offset); /* seqno */
+ ASSERT_EQ(50,fd->len); /* segment length */
+ ASSERT_EQ(FD_NOT_MALLOCED,fd->flags);
+ ASSERT_EQ(fd_head->data,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(2,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_NE(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(3,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_NE(NULL,fd->data);
+ ASSERT_EQ(NULL,fd->next);
+
+
+
+ /* have another go at wrapping things up */
+ pinfo.fd->num = 4;
+ fd_head=fragment_add_seq(tvb, 20, &pinfo, 12, fragment_table,
+ 2, 100, FALSE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(190,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(4,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ fd=fd_head->next;
+ ASSERT_EQ(1,fd->frame);
+ ASSERT_EQ(0,fd->offset); /* seqno */
+ ASSERT_EQ(50,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(2,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(3,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(FD_OVERLAP,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(4,fd->frame);
+ ASSERT_EQ(2,fd->offset); /* seqno */
+ ASSERT_EQ(100,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_EQ(NULL,fd->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+ ASSERT(!memcmp(fd_head->data+50,data,40));
+ ASSERT(!memcmp(fd_head->data+90,data+20,100));
+
+
+ /* do it again (this time it is more complicated, with an overlap in the
+ * reassembly) */
+
+ fragment_set_partial_reassembly(&pinfo,12,fragment_table);
+
+ pinfo.fd->num = 5;
+ fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table,
+ 3, 40, FALSE);
+
+ fd_head=fragment_get(&pinfo,12,fragment_table);
+ ASSERT_NE(NULL,fd_head);
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(230,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(3,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(5,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ fd=fd_head->next;
+ ASSERT_EQ(1,fd->frame);
+ ASSERT_EQ(0,fd->offset); /* seqno */
+ ASSERT_EQ(50,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(2,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(3,fd->frame);
+ ASSERT_EQ(1,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(FD_OVERLAP,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(4,fd->frame);
+ ASSERT_EQ(2,fd->offset); /* seqno */
+ ASSERT_EQ(100,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_NE(NULL,fd->next);
+
+ fd=fd->next;
+ ASSERT_EQ(5,fd->frame);
+ ASSERT_EQ(3,fd->offset); /* seqno */
+ ASSERT_EQ(40,fd->len); /* segment length */
+ ASSERT_EQ(0,fd->flags);
+ ASSERT_EQ(NULL,fd->data);
+ ASSERT_EQ(NULL,fd->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+ ASSERT(!memcmp(fd_head->data+50,data,40));
+ ASSERT(!memcmp(fd_head->data+90,data+20,100));
+ ASSERT(!memcmp(fd_head->data+190,data,40));
+}
+
+/**********************************************************************************
+ *
+ * fragment_add_dcerpc_dg
+ *
+ *********************************************************************************/
+
+/* This can afford to be reasonably minimal, as it's just the same logic with a
+ * different hash key to fragment_add_seq
+ */
+static void test_fragment_add_dcerpc_dg(void)
+{
+ e_uuid_t act_id = {1,2,3,{4,5,6,7,8,9,10,11}};
+
+ fragment_data *fd_head, *fdh0;
+ GHashTable *fragment_table = NULL;
+
+ printf("Starting test test_fragment_add_dcerpc_dg\n");
+
+ /* we need our own fragment table */
+ dcerpc_fragment_table_init(&fragment_table);
+ fd_head=fragment_add_dcerpc_dg(tvb, 10, &pinfo, 12, &act_id, fragment_table,
+ 0, 50, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* start another pdu (just to confuse things) */
+ pinfo.fd->num = 2;
+ fd_head=fragment_add_dcerpc_dg(tvb, 15, &pinfo, 13, &act_id, fragment_table,
+ 0, 60, TRUE);
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* another pdu, with the same fragment_id, but a different act_id, to the
+ * first one */
+ pinfo.fd->num = 3;
+ act_id.Data1=2;
+ fd_head=fragment_add_dcerpc_dg(tvb, 15, &pinfo, 12, &act_id, fragment_table,
+ 0, 60, TRUE);
+ ASSERT_EQ(3,g_hash_table_size(fragment_table));
+ ASSERT_EQ(NULL,fd_head);
+ act_id.Data1=1;
+
+ /* now we add the terminal fragment of the first datagram */
+ pinfo.fd->num = 4;
+ fd_head=fragment_add_dcerpc_dg(tvb, 5, &pinfo, 12, &act_id, fragment_table,
+ 1, 60, FALSE);
+
+ ASSERT_EQ(3,g_hash_table_size(fragment_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(110,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(4,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+ ASSERT(!memcmp(fd_head->data+50,data+5,60));
+
+ /* what happens if we revisit the packets now? */
+ fdh0 = fd_head;
+ pinfo.fd->flags.visited = 1;
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_dcerpc_dg(tvb, 10, &pinfo, 12, &act_id, fragment_table,
+ 0, 50, TRUE);
+ /*
+ * this api relies on the caller to check fd_head -> reassembled_in
+ *
+ * Redoing all the tests seems like overkill - just check the pointer
+ */
+ ASSERT_EQ(fdh0,fd_head);
+}
+
+/**********************************************************************************
+ *
+ * fragment_add_seq_check
+ *
+ *********************************************************************************/
+
+
+/* This routine is used for both fragment_add_seq_802_11 and
+ * fragment_add_seq_check.
+ *
+ * Adds a couple of out-of-order fragments and checks their reassembly.
+ */
+static void test_fragment_add_seq_check_work(
+ fragment_data *(*fn)(tvbuff_t *, int, packet_info *, guint32, GHashTable *,
+ GHashTable *, guint32, guint32, gboolean))
+{
+ fragment_data *fd_head;
+
+ pinfo.fd -> num = 1;
+ fd_head=fn(tvb, 10, &pinfo, 12, fragment_table,
+ reassembled_table, 0, 50, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* start another pdu (just to confuse things) */
+ pinfo.fd->num = 2;
+ fd_head=fn(tvb, 15, &pinfo, 13, fragment_table,
+ reassembled_table, 0, 60, TRUE);
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* add the terminal fragment of the first datagram */
+ pinfo.fd->num = 3;
+ fd_head=fn(tvb, 5, &pinfo, 12, fragment_table,
+ reassembled_table, 2, 60, FALSE);
+
+ /* we haven't got all the fragments yet ... */
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* finally, add the missing fragment */
+ pinfo.fd->num = 4;
+ fd_head=fn(tvb, 15, &pinfo, 12, fragment_table,
+ reassembled_table, 1, 60, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(3,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(170,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(4,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ ASSERT_EQ(1,fd_head->next->frame);
+ ASSERT_EQ(0,fd_head->next->offset); /* seqno */
+ ASSERT_EQ(50,fd_head->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->data);
+ ASSERT_NE(NULL,fd_head->next->next);
+
+ ASSERT_EQ(4,fd_head->next->next->frame);
+ ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */
+ ASSERT_EQ(60,fd_head->next->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->next->data);
+ ASSERT_NE(NULL,fd_head->next->next->next);
+
+ ASSERT_EQ(3,fd_head->next->next->next->frame);
+ ASSERT_EQ(2,fd_head->next->next->next->offset); /* seqno */
+ ASSERT_EQ(60,fd_head->next->next->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->next->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->next->next->data);
+ ASSERT_EQ(NULL,fd_head->next->next->next->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+ ASSERT(!memcmp(fd_head->data+50,data+15,60));
+ ASSERT(!memcmp(fd_head->data+110,data+5,60));
+}
+
+/* Simple test case for fragment_add_seq_check
+ */
+static void test_fragment_add_seq_check(void)
+{
+ printf("Starting test test_fragment_add_seq_check\n");
+
+ test_fragment_add_seq_check_work(fragment_add_seq_check);
+}
+
+
+/* This tests the case that the 802.11 hack does something different for: when
+ * the terminal segment in a fragmented datagram arrives first.
+ */
+static void test_fragment_add_seq_check_1(void)
+{
+ fragment_data *fd_head;
+
+ printf("Starting test test_fragment_add_seq_check_1\n");
+
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq_check(tvb, 10, &pinfo, 12, fragment_table,
+ reassembled_table, 1, 50, FALSE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* Now add the missing segment */
+ pinfo.fd->num = 2;
+ fd_head=fragment_add_seq_check(tvb, 5, &pinfo, 12, fragment_table,
+ reassembled_table, 0, 60, TRUE);
+
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(2,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(110,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(2,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ ASSERT_EQ(2,fd_head->next->frame);
+ ASSERT_EQ(0,fd_head->next->offset); /* seqno */
+ ASSERT_EQ(60,fd_head->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->data);
+ ASSERT_NE(NULL,fd_head->next->next);
+
+ ASSERT_EQ(1,fd_head->next->next->frame);
+ ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */
+ ASSERT_EQ(50,fd_head->next->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->next->data);
+ ASSERT_EQ(NULL,fd_head->next->next->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+5,60));
+ ASSERT(!memcmp(fd_head->data+60,data+10,50));
+}
+
+/**********************************************************************************
+ *
+ * fragment_add_seq_802_11
+ *
+ *********************************************************************************/
+
+/* Tests the 802.11 hack.
+ */
+static void test_fragment_add_seq_802_11_0(void)
+{
+ fragment_data *fd_head;
+
+ printf("Starting test test_fragment_add_seq_802_11_0\n");
+
+ /* the 802.11 hack is that some non-fragmented datagrams have non-zero
+ * fragment_number; test for this. */
+
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq_802_11(tvb, 10, &pinfo, 12, fragment_table,
+ reassembled_table, 10, 50, FALSE);
+
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(1,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(0,fd_head->len); /* unused */
+ ASSERT_EQ(0,fd_head->datalen); /* unused */
+ ASSERT_EQ(1,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE,fd_head->flags);
+ ASSERT_EQ(NULL,fd_head->data);
+ ASSERT_EQ(NULL,fd_head->next);
+}
+
+/* Reuse the fragment_add_seq_check testcases */
+static void test_fragment_add_seq_802_11_1(void)
+{
+ printf("Starting test test_fragment_add_seq_802_11_1\n");
+ test_fragment_add_seq_check_work(fragment_add_seq_802_11);
+}
+
+/**********************************************************************************
+ *
+ * fragment_add_seq_next
+ *
+ *********************************************************************************/
+
+/* Simple test case for fragment_add_seq_next.
+ * Adds a couple of fragments (with one for a different datagram in between),
+ * and checks that they are reassembled correctly.
+ */
+static void test_simple_fragment_add_seq_next(void)
+{
+ fragment_data *fd_head;
+
+ printf("Starting test test_simple_fragment_add_seq_next\n");
+
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 12, fragment_table,
+ reassembled_table, 50, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* adding the same fragment again should do nothing, even with different
+ * offset etc */
+ pinfo.fd->flags.visited = 1;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table,
+ reassembled_table, 60, TRUE);
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* start another pdu (just to confuse things) */
+ pinfo.fd->flags.visited = 0;
+ pinfo.fd->num = 2;
+ fd_head=fragment_add_seq_next(tvb, 15, &pinfo, 13, fragment_table,
+ reassembled_table, 60, TRUE);
+ ASSERT_EQ(2,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+
+ /* now we add the terminal fragment of the first datagram */
+ pinfo.fd->num = 3;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table,
+ reassembled_table, 60, FALSE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(2,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(110,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(3,fd_head->reassembled_in);
+ ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags);
+ ASSERT_NE(NULL,fd_head->data);
+ ASSERT_NE(NULL,fd_head->next);
+
+ ASSERT_EQ(1,fd_head->next->frame);
+ ASSERT_EQ(0,fd_head->next->offset); /* seqno */
+ ASSERT_EQ(50,fd_head->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->data);
+ ASSERT_NE(NULL,fd_head->next->next);
+
+ ASSERT_EQ(3,fd_head->next->next->frame);
+ ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */
+ ASSERT_EQ(60,fd_head->next->next->len); /* segment length */
+ ASSERT_EQ(0,fd_head->next->next->flags);
+ ASSERT_EQ(NULL,fd_head->next->next->data);
+ ASSERT_EQ(NULL,fd_head->next->next->next);
+
+ /* test the actual reassembly */
+ ASSERT(!memcmp(fd_head->data,data+10,50));
+ ASSERT(!memcmp(fd_head->data+50,data+5,60));
+}
+
+
+/* This tests the case where some data is missing from one of the fragments.
+ * It should prevent reassembly.
+ */
+static void test_missing_data_fragment_add_seq_next(void)
+{
+ fragment_data *fd_head;
+
+ printf("Starting test test_missing_data_fragment_add_seq_next\n");
+
+ /* attempt to add a fragment which is longer than the data available */
+ pinfo.fd->num = 1;
+ fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 12, fragment_table,
+ reassembled_table, DATA_LEN-9, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure. Reassembly failed so everything
+ * should be null (meaning, just use the original tvb) */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(0,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(0,fd_head->reassembled_in);
+ ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags & 0x1ff);
+ ASSERT_EQ(NULL,fd_head->data);
+ ASSERT_EQ(NULL,fd_head->next);
+
+ /* add another fragment (with all data present) */
+ pinfo.fd->num = 4;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table,
+ reassembled_table, 60, FALSE);
+
+ /* XXX: it's not clear that this is the right result; however it's what the
+ * code does...
+ */
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+
+ /* check what happens when we revisit the packets */
+ pinfo.fd->flags.visited = TRUE;
+ pinfo.fd->num = 1;
+
+ fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 12, fragment_table,
+ reassembled_table, DATA_LEN-9, TRUE);
+
+ /* We just look in the reassembled_table for this packet. It never got put
+ * there, so this always returns null.
+ *
+ * That's crazy, because it means that the subdissector will see the data
+ * exactly once - on the first pass through the capture (well, assuming it
+ * doesn't bother to check fd_head->reassembled_in); however, that's
+ * what the code does...
+ */
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ pinfo.fd->num = 4;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table,
+ reassembled_table, 60, FALSE);
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+}
+
+
+/*
+ * we're going to do something similar now, but this time it is the second
+ * fragment which has something missing.
+ */
+static void test_missing_data_fragment_add_seq_next_2(void)
+{
+ fragment_data *fd_head;
+
+ printf("Starting test test_missing_data_fragment_add_seq_next_2\n");
+
+ pinfo.fd->num = 11;
+ fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 24, fragment_table,
+ reassembled_table, 50, TRUE);
+
+ ASSERT_EQ(1,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ pinfo.fd->num = 12;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 24, fragment_table,
+ reassembled_table, DATA_LEN-4, FALSE);
+
+ /* XXX: again, i'm really dubious about this. Surely this should return all
+ * the data we had, for a best-effort attempt at dissecting it?
+ * And it ought to go into the reassembled table?
+ */
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ /* check what happens when we revisit the packets */
+ pinfo.fd->flags.visited = TRUE;
+ pinfo.fd->num = 11;
+
+ fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 24, fragment_table,
+ reassembled_table, 50, TRUE);
+
+ /* As before, this returns NULL because the fragment isn't in the
+ * reassembled_table. At least this is a bit more consistent than before.
+ */
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+ pinfo.fd->num = 12;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 24, fragment_table,
+ reassembled_table, DATA_LEN-4, FALSE);
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(0,g_hash_table_size(reassembled_table));
+ ASSERT_EQ(NULL,fd_head);
+
+}
+
+/*
+ * This time, our datagram only has one segment, but it has data missing.
+ */
+static void test_missing_data_fragment_add_seq_next_3(void)
+{
+ fragment_data *fd_head;
+
+ printf("Starting test test_missing_data_fragment_add_seq_next_3\n");
+
+ pinfo.fd->num = 20;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 30, fragment_table,
+ reassembled_table, DATA_LEN-4, FALSE);
+
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(1,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+
+ /* check the contents of the structure. */
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(0,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(20,fd_head->reassembled_in);
+ ASSERT_EQ(FD_BLOCKSEQUENCE|FD_DEFRAGMENTED,fd_head->flags);
+ ASSERT_EQ(NULL,fd_head->data);
+ ASSERT_EQ(NULL,fd_head->next);
+
+ /* revisiting the packet ought to produce the same result. */
+ pinfo.fd->flags.visited = TRUE;
+
+ pinfo.fd->num = 20;
+ fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 30, fragment_table,
+ reassembled_table, DATA_LEN-4, FALSE);
+
+ ASSERT_EQ(0,g_hash_table_size(fragment_table));
+ ASSERT_EQ(1,g_hash_table_size(reassembled_table));
+ ASSERT_NE(NULL,fd_head);
+ ASSERT_EQ(0,fd_head->frame); /* unused */
+ ASSERT_EQ(0,fd_head->offset); /* unused */
+ ASSERT_EQ(0,fd_head->len); /* the length of data we have */
+ ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */
+ ASSERT_EQ(20,fd_head->reassembled_in);
+ ASSERT_EQ(FD_BLOCKSEQUENCE|FD_DEFRAGMENTED,fd_head->flags);
+ ASSERT_EQ(NULL,fd_head->data);
+ ASSERT_EQ(NULL,fd_head->next);
+}
+
+
+/**********************************************************************************
+ *
+ * main
+ *
+ *********************************************************************************/
+
+int main(int argc, char **argv)
+{
+ frame_data fd;
+ char src[] = {1,2,3,4}, dst[] = {5,6,7,8};
+ unsigned int i;
+ void (*tests[])(void) = {
+ test_simple_fragment_add_seq,
+ test_fragment_add_seq_partial_reassembly,
+ test_fragment_add_dcerpc_dg,
+ test_fragment_add_seq_check,
+ test_fragment_add_seq_check_1,
+ test_fragment_add_seq_802_11_0,
+ test_fragment_add_seq_802_11_1,
+ test_simple_fragment_add_seq_next,
+ test_missing_data_fragment_add_seq_next,
+ test_missing_data_fragment_add_seq_next_2,
+ test_missing_data_fragment_add_seq_next_3
+ };
+
+ /* we don't use our params */
+ argc=argc; argv=argv;
+
+ /* initialise stuff */
+ ep_init_chunk();
+ tvbuff_init();
+ reassemble_init();
+
+ /* a tvbuff for testing with */
+ data = g_malloc(DATA_LEN);
+ /* make sure it's full of stuff */
+ for(i=0; i<DATA_LEN; i++) {
+ data[i]=i & 0xFF;
+ }
+ tvb = tvb_new_real_data(data, DATA_LEN, DATA_LEN*2);
+
+ /* other test stuff */
+ pinfo.fd = &fd;
+ fd.flags.visited = 0;
+ SET_ADDRESS(&pinfo.src,AT_IPv4,4,src);
+ SET_ADDRESS(&pinfo.dst,AT_IPv4,4,dst);
+
+ /*************************************************************************/
+ for(i=0; i < sizeof(tests)/sizeof(tests[0]); i++ ) {
+ /* re-init the fragment tables */
+ fragment_table_init(&fragment_table);
+ ASSERT(fragment_table != NULL);
+
+ reassembled_table_init(&reassembled_table);
+ ASSERT(reassembled_table != NULL);
+
+ pinfo.fd->flags.visited = FALSE;
+
+ tests[i]();
+ }
+
+ printf(failure?"FAILURE\n":"SUCCESS\n");
+ return failure;
+}