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
This commit is contained in:
Anders Broman 2007-02-21 06:19:03 +00:00
parent d5f4bfe773
commit e2cab6caa9
3 changed files with 1366 additions and 248 deletions

View File

@ -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);
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;
/* 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);
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:
*/

View File

@ -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,

1057
epan/reassemble_test.c Normal file

File diff suppressed because it is too large Load Diff