diff options
-rw-r--r-- | epan/reassemble.c | 171 | ||||
-rw-r--r-- | epan/reassemble_test.c | 1769 |
2 files changed, 1859 insertions, 81 deletions
diff --git a/epan/reassemble.c b/epan/reassemble.c index cc0924e4eb..b291b47dcc 100644 --- a/epan/reassemble.c +++ b/epan/reassemble.c @@ -996,7 +996,7 @@ fragment_add_work(fragment_head *fd_head, tvbuff_t *tvb, const int offset, { fragment_item *fd; fragment_item *fd_i; - guint32 max, dfpos, fraglen; + guint32 max, dfpos, fraglen, overlap; tvbuff_t *old_tvb_data; guint8 *data; @@ -1110,6 +1110,12 @@ fragment_add_work(fragment_head *fd_head, tvbuff_t *tvb, const int offset, * The entire defragmented packet is in fd_head->data. * Even if we have previously defragmented this packet, we still * check it. Someone might play overlap and TTL games. + * + * XXX: This code generally doesn't get called (unlike the versions + * in _add_seq*) because of the exceptions thrown above unless + * partial_reassembly has been set, but that doesn't seem right + * in the case of overlap as the flags don't get set. Shouldn't the + * behavior match the version with sequence numbers? */ if (fd_head->flags & FD_DEFRAGMENTED) { guint32 end_offset = fd->offset + fd->len; @@ -1208,92 +1214,96 @@ fragment_add_work(fragment_head *fd_head, tvbuff_t *tvb, const int offset, * done for fragments with (offset+len) <= fd_head->datalen * and thus within the newly g_malloc'd buffer. */ - if (fd_i->offset + fd_i->len > dfpos) { - if (fd_i->offset >= fd_head->datalen) { + + if (fd_i->offset >= fd_head->datalen) { + /* + * Fragment starts after the end + * of the reassembled packet. + * + * This can happen if the length was + * set after the offending fragment + * was added to the reassembly. + * + * Flag this fragment, but don't + * try to extract any data from + * it, as there's no place to put + * it. + * + * XXX - add different flag value + * for this. + */ + fd_i->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + } else if (fd_i->offset + fd_i->len < fd_i->offset) { + /* Integer overflow, unhandled by rest of + * code so error out. This check handles + * all possible remaining overflows. + */ + fd_head->error = "offset + len < offset"; + } else if (!fd_i->tvb_data) { + fd_head->error = "no data"; + } else { + fraglen = fd_i->len; + if (fd_i->offset + fraglen > fd_head->datalen) { /* - * Fragment starts after the end - * of the reassembled packet. - * - * This can happen if the length was - * set after the offending fragment - * was added to the reassembly. + * Fragment goes past the end + * of the packet, as indicated + * by the last fragment. * - * Flag this fragment, but don't - * try to extract any data from - * it, as there's no place to put - * it. + * This can happen if the + * length was set after the + * offending fragment was + * added to the reassembly. * - * XXX - add different flag value - * for this. + * Mark it as such, and only + * copy from it what fits in + * the packet. */ fd_i->flags |= FD_TOOLONGFRAGMENT; fd_head->flags |= FD_TOOLONGFRAGMENT; - } else if (dfpos < fd_i->offset) { - /* - * XXX - can this happen? We've - * already rejected fragments that - * start past the end of the - * reassembled datagram, and - * the loop that calculated max - * should have ruled out gaps, - * but could fd_i->offset + - * fd_i->len overflow? - */ - fd_head->error = "dfpos < offset"; - } else if (dfpos - fd_i->offset > fd_i->len) - fd_head->error = "dfpos - offset > len"; - else if (!fd_i->tvb_data) - fd_head->error = "no data"; - else { - fraglen = fd_i->len; - if (fd_i->offset + fraglen > fd_head->datalen) { - /* - * Fragment goes past the end - * of the packet, as indicated - * by the last fragment. - * - * This can happen if the - * length was set after the - * offending fragment was - * added to the reassembly. - * - * Mark it as such, and only - * copy from it what fits in - * the packet. - */ - fd_i->flags |= FD_TOOLONGFRAGMENT; - fd_head->flags |= FD_TOOLONGFRAGMENT; - 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(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; - } - } - if (fraglen < dfpos - fd_i->offset) { - /* - * XXX - can this happen? - */ - fd_head->error = "fraglen < dfpos - offset"; - } else { - 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)); + fraglen = fd_head->datalen - fd_i->offset; + } + overlap = dfpos - fd_i->offset; + /* Guaranteed to be >= 0, previous code + * has checked for gaps. */ + if (overlap) { + /* duplicate/retransmission/overlap */ + guint32 cmp_len = MIN(fd_i->len,overlap); + + fd_i->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + 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; } } - } else { - if (fd_i->offset + fd_i->len < fd_i->offset) { - /* Integer overflow? */ - fd_head->error = "offset + len < offset"; + /* XXX: As in the fragment_add_seq funcs + * like fragment_defragment_and_free() the + * existing behavior does not overwrite + * overlapping bytes even if there is a + * conflict. It only adds new bytes. + * + * Since we only add fragments to a reassembly + * if the reassembly isn't complete, the most + * common case for overlap conflicts is when + * an earlier reassembly isn't fully contained + * in the capture, and we've reused an + * indentification number / wrapped around + * offset sequence numbers much later in the + * capture. In that case, we probably *do* + * want to overwrite conflicting bytes, since + * the earlier fragments didn't form a complete + * reassembly and should be effectively thrown + * out rather than mixed with the new ones? + */ + if (fd_i->offset + fraglen > dfpos) { + memcpy(data+dfpos, + tvb_get_ptr(fd_i->tvb_data, overlap, fraglen-overlap), + fraglen-overlap); + dfpos = fd_i->offset + fraglen; } } @@ -1578,8 +1588,9 @@ fragment_add_check(reassembly_table *table, tvbuff_t *tvb, const int offset, * If this is a short frame, then we can't, and don't, do * reassembly on it. We just give up. */ - if (tvb_reported_length(tvb) > tvb_captured_length(tvb)) + if (!tvb_bytes_exist(tvb, offset, frag_data_len)) { return NULL; + } if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset, frag_data_len, more_frags)) { diff --git a/epan/reassemble_test.c b/epan/reassemble_test.c index dbb9e1f914..c253c385cb 100644 --- a/epan/reassemble_test.c +++ b/epan/reassemble_test.c @@ -48,6 +48,8 @@ #include <epan/tvbuff.h> #include <epan/reassemble.h> +#include "exceptions.h" + static int failure = 0; #define ASSERT(b) \ @@ -190,7 +192,7 @@ print_tables(void) { 1 12 1 0 60 T 5 0 13 2 0 60 T 15 0 12 3 2 60 F 5 - 0 12 4 1 60 F 15 + 0 12 4 1 60 T 15 */ static void test_simple_fragment_add_seq(void) @@ -1510,7 +1512,1756 @@ test_missing_data_fragment_add_seq_next_3(void) } #endif +/********************************************************************************** + * + * fragment_add + * + *********************************************************************************/ + +/* Simple test case for fragment_add. + * Adds three fragments (out of order, with one for a different datagram in between), + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_offset len more tvb_offset + 0 12 1 0 50 T 10 + 1 12 1 0 60 T 5 + 0 13 2 0 60 T 15 + 0 12 3 110 60 F 5 + 0 12 4 50 60 T 15 +*/ +static void +test_simple_fragment_add(void) +{ + fragment_head *fd_head, *fdh0; + fragment_item *fd; + + printf("Starting test test_simple_fragment_add\n"); + + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* adding the same fragment again should do nothing, even with different + * offset etc */ + pinfo.fd->visited = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 0, 60, TRUE); + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* start another pdu (just to confuse things) */ + pinfo.fd->visited = 0; + pinfo.num = 2; + fd_head=fragment_add(&test_reassembly_table, tvb, 15, &pinfo, 13, NULL, + 0, 60, TRUE); + ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* now we add the terminal fragment of the first datagram */ + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 60, FALSE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* finally, add the missing fragment */ + pinfo.num = 4; + fd_head=fragment_add(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, + 50, 60, TRUE); + + ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame number of fragment in assembly */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused in fragment_add */ + ASSERT_EQ(170,fd_head->datalen); /* total datalen of assembly */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* offset */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(50,fd->offset); /* offset */ + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(110,fd->offset); /* offset */ + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+15,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,60)); + +#if 0 + print_fragment_table(); +#endif + + /* what happens if we revisit the packets now? */ + fdh0 = fd_head; + pinfo.fd->visited = 1; + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 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_POINTER(fdh0,fd_head); + + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 60, FALSE); + ASSERT_EQ_POINTER(fdh0,fd_head); + + pinfo.num = 4; + fd_head=fragment_add(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, + 50, 60, TRUE); + ASSERT_EQ_POINTER(fdh0,fd_head); + +#if 0 + print_fragment_table(); +#endif +} + +/* This tests the functionality of fragment_set_partial_reassembly for + * fragment_add based reassembly. + * + * We add a sequence of fragments thus: + * seq_off frame tvb_off len (initial) more_frags + * ------- ----- ------- --- -------------------- + * 0 1 10 50 false + * 50 2 0 40 true + * 50 3 0 40 true (a duplicate fragment) + * 90 4 20 100 false + * 190 5 0 40 false + */ +static void +test_fragment_add_partial_reassembly(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_partial_reassembly\n"); + + /* generally it's probably fair to assume that we will be called with + * more_frags=FALSE. + */ + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(1,fd_head->frame); /* max frame in reassembly */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(50,fd_head->datalen); /* the length of data we we have */ + ASSERT_EQ(1,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + ASSERT_EQ(1,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* offset */ + ASSERT_EQ(50,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ_POINTER(NULL,fd_head->next->tvb_data); + ASSERT_EQ_POINTER(NULL,fd_head->next->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + + /* now we announce that the reassembly wasn't complete after all. */ + fragment_set_partial_reassembly(&test_reassembly_table, &pinfo, 12, NULL); + + /* 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.num = 2; + fd_head=fragment_add(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, + 50, 40, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(2,fd_head->frame); /* max frame in reassembly */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + /* ASSERT_EQ(0,fd_head->datalen); + * reassembly not finished; datalen not well defined. + * Current implemenation has it as 0, could change to 90 without issues */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(0,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* offset */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(FD_SUBSET_TVB,fd->flags); + ASSERT_EQ_POINTER(tvb_get_ptr(fd_head->tvb_data,0,0),tvb_get_ptr(fd->tvb_data,0,0)); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); /* offset */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* Another copy of the second segment. + */ + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, + 50, 40, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); + ASSERT_NE_POINTER(NULL,fd_head); + ASSERT_EQ(3,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + /* ASSERT_EQ(0,fd_head->datalen); + * reassembly not finished; datalen not well defined. + * Current implemenation has it as 0, could change to 90 without issues */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(0,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(FD_SUBSET_TVB,fd->flags); + ASSERT_EQ_POINTER(tvb_get_ptr(fd_head->tvb_data,0,0),tvb_get_ptr(fd->tvb_data,0,0)); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + + + /* have another go at wrapping things up */ + pinfo.num = 4; + fd_head=fragment_add(&test_reassembly_table, tvb, 20, &pinfo, 12, NULL, + 90, 100, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(190,fd_head->datalen); /* the length of data we have */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(90,fd->offset); + ASSERT_EQ(100,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data,40)); + ASSERT(!tvb_memeql(fd_head->tvb_data,90,data+20,100)); + + + /* do it again (this time it is more complicated, with an overlap in the + * reassembly) */ + + fragment_set_partial_reassembly(&test_reassembly_table, &pinfo, 12, NULL); + + pinfo.num = 5; + fragment_add(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, + 190, 40, FALSE); + + fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); + ASSERT_NE_POINTER(NULL,fd_head); + ASSERT_EQ(5,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(230,fd_head->datalen); /* the length of data we have */ + ASSERT_EQ(5,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(90,fd->offset); + ASSERT_EQ(100,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(5,fd->frame); + ASSERT_EQ(190,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data,40)); + ASSERT(!tvb_memeql(fd_head->tvb_data,90,data+20,100)); + ASSERT(!tvb_memeql(fd_head->tvb_data,190,data,40)); +} + +/* XXX: Is the proper behavior here really throwing an exception instead + * of setting FD_OVERLAP? + */ +/* Test case for fragment_add with duplicated (e.g., retransmitted) data. + * Adds three fragments--adding the 1st one twice at the end-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_off len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 50 60 T 5 + 0 12 3 110 40 F 5 + 0 12 4 0 50 T 10 +*/ +static void +test_fragment_add_duplicate_first(void) +{ + fragment_head *fd_head; + fragment_item *fd; + volatile gboolean ex_thrown; + + printf("Starting test test_fragment_add_duplicate_first\n"); + + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the last fragment */ + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 40, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* Add the first fragment again */ + pinfo.num = 4; + /* XXX: The current reassemble.c code for fragment_add() throws an + * exception and doesn't try to add a duplicate if and only if the + * assembly is already completed. This means that it doesn't get + * put in the linked list. This is counter to how the _seq functions + * work, as well as to how this code works if a duplicate comes in the + * middle instead of at the end. Test matches current code, but the + * current code should perhaps be changed. */ + ex_thrown = FALSE; + TRY { + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, TRUE); + } + CATCH(ReassemblyError) { + ex_thrown = TRUE; + } + ENDTRY; + + ASSERT_EQ(TRUE, ex_thrown); + + /* Reassembly should have still succeeded */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + /*ASSERT_EQ(4,fd_head->frame); max frame we have */ + ASSERT_EQ(3,fd_head->frame); /* never add the duplicate frame */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(3,fd_head->reassembled_in); + /* ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); */ + /* FD_OVERLAP doesn't get set because we hit the exception early */ + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + /* + fd = fd_head->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); */ + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} + + +/* Test case for fragment_add with duplicated (e.g., retransmitted) data. + * Adds three fragments--adding the 2nd one twice-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_off len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 50 60 T 5 + 0 12 3 50 60 T 5 + 0 12 4 110 40 F 5 +*/ +static void +test_fragment_add_duplicate_middle(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_duplicate_middle\n"); + + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Now, add the 2nd segment again (but in a different frame) */ + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 50, 60, TRUE); + + /* This duplicate fragment should have been ignored */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* finally, add the last fragment */ + pinfo.num = 4; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 40, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} + +/* XXX: Is the proper behavior here really throwing an exception instead + * of setting FD_OVERLAP? + */ +/* Test case for fragment_add with duplicated (e.g., retransmitted) data. + * Adds three fragments--adding the 3rd one twice-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 1 60 T 5 + 0 12 3 2 40 F 5 + 0 12 4 2 40 F 5 +*/ +static void +test_fragment_add_duplicate_last(void) +{ + fragment_head *fd_head; + fragment_item *fd; + volatile gboolean ex_thrown; + + printf("Starting test test_fragment_add_duplicate_last\n"); + + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the last fragment */ + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 40, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* Add the last fragment again */ + pinfo.num = 4; + /* XXX: The current reassemble.c code for fragment_add() throws an + * exception and doesn't try to add a duplicate if and only if the + * assembly is already completed. This means that it doesn't get + * put in the linked list. This is counter to how the _seq functions + * work, as well as to how this code works if a duplicate comes in the + * middle instead of at the end. Test matches current code, but the + * current code should perhaps be changed. */ + ex_thrown = FALSE; + TRY { + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 40, FALSE); + } + CATCH(ReassemblyError) { + ex_thrown = TRUE; + } + ENDTRY; + + ASSERT_EQ(TRUE, ex_thrown); + + /* Reassembly should have still succeeded */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + /* ASSERT_EQ(4,fd_head->frame); never add the last frame again */ + ASSERT_EQ(3,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(3,fd_head->reassembled_in); + /* ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + * FD_OVERLAP doesn't get set since we don't add a fragment after the + * end but throw an exception instead. */ + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + + /* Duplicate packet never gets added + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); */ + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} + +/* Test case for fragment_add with duplicated (e.g., retransmitted) data + * where the retransmission "conflicts" with the original transmission + * (contents are different). + * Adds three fragments--adding the 2nd one twice-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_off len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 50 60 T 5 + 0 12 3 50 60 T 15 + 0 12 4 110 40 F 5 +*/ +static void +test_fragment_add_duplicate_conflict(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_duplicate_conflict\n"); + + pinfo.num = 1; + fd_head=fragment_add(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Now, add the 2nd segment again (but in a different frame and with + * different data) + */ + pinfo.num = 3; + fd_head=fragment_add(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, + 50, 60, TRUE); + + /* This duplicate fragment should have been ignored */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* finally, add the last fragment */ + pinfo.num = 4; + fd_head=fragment_add(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, + 110, 40, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP|FD_OVERLAPCONFLICT,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP|FD_OVERLAPCONFLICT,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} + +/********************************************************************************** + * + * fragment_add_check + * + *********************************************************************************/ + +/* Simple test case for fragment_add_check. + * Adds three fragments (out of order, with one for a different datagram in between), + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_offset len more tvb_offset + 0 12 1 0 50 T 10 + 1 12 1 0 60 T 5 + 0 13 2 0 60 T 15 + 0 12 3 110 60 F 5 + 0 12 4 50 60 T 15 +*/ +static void +test_simple_fragment_add_check(void) +{ + fragment_head *fd_head, *fdh0; + fragment_item *fd; + + printf("Starting test test_simple_fragment_add_check\n"); + + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* adding the same fragment again should do nothing, even with different + * offset etc */ + pinfo.fd->visited = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 0, 60, TRUE); + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* start another pdu (just to confuse things) */ + pinfo.fd->visited = 0; + pinfo.num = 2; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 15, &pinfo, 13, + NULL, 0, 60, TRUE); + ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* now we add the terminal fragment of the first datagram */ + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 60, FALSE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* finally, add the missing fragment */ + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 15, &pinfo, 12, + NULL, 50, 60, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(3,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame number of fragment in assembly */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused in fragment_add */ + ASSERT_EQ(170,fd_head->datalen); /* total datalen of assembly */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+15,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,60)); + +#if 0 + print_fragment_table(); +#endif + + /* what happens if we revisit the packets now? */ + fdh0 = fd_head; + pinfo.fd->visited = 1; + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 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_POINTER(fdh0,fd_head); + + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 60, FALSE); + ASSERT_EQ_POINTER(fdh0,fd_head); + + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 15, &pinfo, 12, + NULL, 50, 60, TRUE); + ASSERT_EQ_POINTER(fdh0,fd_head); + +#if 0 + print_fragment_table(); +#endif +} + +#if 0 +/* XXX: fragment_set_partial_reassembly() does not work for fragment_add_check + * because it doesn't remove the previously completed reassembly from + * reassembled_table (and lookup_fd_head() only looks in the fragment + * table, not the reassembled_table) */ +/* This tests the functionality of fragment_set_partial_reassembly for + * fragment_add_check based reassembly. + * + * We add a sequence of fragments thus: + * seq_off frame tvb_off len (initial) more_frags + * ------- ----- ------- --- -------------------- + * 0 1 10 50 false + * 50 2 0 40 true + * 50 3 0 40 true (a duplicate fragment) + * 90 4 20 100 false + * 190 5 0 40 false + */ +static void +test_fragment_add_check_partial_reassembly(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_check_partial_reassembly\n"); + + /* generally it's probably fair to assume that we will be called with + * more_frags=FALSE. + */ + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, FALSE); + + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(1,fd_head->frame); /* max frame in reassembly */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(50,fd_head->datalen); /* the length of data we we have */ + ASSERT_EQ(1,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + ASSERT_EQ(1,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* offset */ + ASSERT_EQ(50,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ_POINTER(NULL,fd_head->next->tvb_data); + ASSERT_EQ_POINTER(NULL,fd_head->next->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + + /* now we announce that the reassembly wasn't complete after all. */ + fragment_set_partial_reassembly(&test_reassembly_table, &pinfo, 12, NULL); + + /* 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.num = 2; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 0, &pinfo, 12, + NULL, 50, 40, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(2,fd_head->frame); /* max frame in reassembly */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + /* ASSERT_EQ(0,fd_head->datalen); + * reassembly not finished; datalen not well defined. + * Current implemenation has it as 0, could change to 90 without issues */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(0,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* offset */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(FD_SUBSET_TVB,fd->flags); + ASSERT_EQ_POINTER(tvb_get_ptr(fd_head->tvb_data,0,0),tvb_get_ptr(fd->tvb_data,0,0)); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); /* offset */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* Another copy of the second segment. + */ + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 0, &pinfo, 12, + NULL, 50, 40, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); + ASSERT_NE_POINTER(NULL,fd_head); + ASSERT_EQ(3,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + /* ASSERT_EQ(0,fd_head->datalen); + * reassembly not finished; datalen not well defined. + * Current implemenation has it as 0, could change to 90 without issues */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(0,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(FD_SUBSET_TVB,fd->flags); + ASSERT_EQ_POINTER(tvb_get_ptr(fd_head->tvb_data,0,0),tvb_get_ptr(fd->tvb_data,0,0)); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + + + /* have another go at wrapping things up */ + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 20, &pinfo, 12, + NULL, 90, 100, FALSE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(190,fd_head->datalen); /* the length of data we have */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(90,fd->offset); + ASSERT_EQ(100,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data,40)); + ASSERT(!tvb_memeql(fd_head->tvb_data,90,data+20,100)); + + + /* do it again (this time it is more complicated, with an overlap in the + * reassembly) */ + + fragment_set_partial_reassembly(&test_reassembly_table, &pinfo, 12, NULL); + + pinfo.num = 5; + fragment_add_check(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, + 190, 40, FALSE); + + fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); + ASSERT_NE_POINTER(NULL,fd_head); + ASSERT_EQ(5,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(230,fd_head->datalen); /* the length of data we have */ + ASSERT_EQ(5,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(90,fd->offset); + ASSERT_EQ(100,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(5,fd->frame); + ASSERT_EQ(190,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data,40)); + ASSERT(!tvb_memeql(fd_head->tvb_data,90,data+20,100)); + ASSERT(!tvb_memeql(fd_head->tvb_data,190,data,40)); +} +#endif + +#if 0 +/* XXX: fragment_add_check moves completed reassemblies to the + * reassembled_table, so adding a duplicated fragment after the end doesn't + * get marked as duplicate, but starts a new reassembly. This is the correct + * thing for very long captures where the identification field gets reused, + * somewhat wrong when it is retransmitted data (it won't get marked as such + * but doesn't interfere with defragmentation too much), and very wrong when + * there is both retransmitted data and later on the identification field + * gets reused (the dangling data will get added to the wrong reassembly.) + * + * Not sure what behavior to check. Possibly both behaviors should be supported, + * perhaps being affected by how close pinfo.num is to the reassembly, though + * that gets complicated. + */ +/* Test case for fragment_add_check with duplicated (e.g., retransmitted) data. + * Adds three fragments--adding the 1st one twice at the end-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_off len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 50 60 T 5 + 0 12 3 110 40 F 5 + 0 12 4 0 50 T 10 +*/ +static void +test_fragment_add_check_duplicate_first(void) +{ + fragment_head *fd_head; + fragment_item *fd; + volatile gboolean ex_thrown; + + printf("Starting test test_fragment_add_check_duplicate_first\n"); + + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the last fragment */ + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 40, FALSE); + + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(3,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* Add the first fragment again */ + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, TRUE); + + /* Reassembly should have still succeeded */ + /* XXX: Current behavior is to start a new reassembly - which is + * the proper behavior in a long capture that reuses the id, but the + * wrong thing when it's actually a retransmission. Should the distinction + * be made by analyzing pinfo.num to see if it is nearby? Or is that the + * dissector's job? */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(3,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + /*ASSERT_EQ(4,fd_head->frame); max frame we have */ + ASSERT_EQ(3,fd_head->frame); /* never add the duplicate frame */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(3,fd_head->reassembled_in); + /* ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); */ + /* FD_OVERLAP doesn't get set because we hit the exception early */ + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + /* + fd = fd_head->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); */ + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} +#endif + +/* Test case for fragment_add_check with duplicated (e.g., retransmitted) data. + * Adds three fragments--adding the 2nd one twice-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_off len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 50 60 T 5 + 0 12 3 50 60 T 5 + 0 12 4 110 40 F 5 +*/ +static void +test_fragment_add_check_duplicate_middle(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_check_duplicate_middle\n"); + + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Now, add the 2nd segment again (but in a different frame) */ + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 50, 60, TRUE); + + /* This duplicate fragment should have been ignored */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* finally, add the last fragment */ + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 40, FALSE); + + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(4,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} + +#if 0 +/* XXX: same issue as test_fragment_add_check_duplicate_first, above. + */ +/* Test case for fragment_add_check with duplicated (e.g., retransmitted) data. + * Adds three fragments--adding the 3rd one twice-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 1 60 T 5 + 0 12 3 2 40 F 5 + 0 12 4 2 40 F 5 +*/ +static void +test_fragment_add_check_duplicate_last(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_check_duplicate_last\n"); + + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the last fragment */ + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 40, FALSE); + + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(3,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* Add the last fragment again */ + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 40, FALSE); + + /* Reassembly should have still succeeded */ + /* XXX: Current behavior is to start a new reassembly */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(3,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + /* ASSERT_EQ(4,fd_head->frame); never add the last frame again */ + ASSERT_EQ(3,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(3,fd_head->reassembled_in); + /* ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + * FD_OVERLAP doesn't get set since we don't add a fragment after the + * end but start a new assembly instead. */ + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + + /* Duplicate packet never gets added + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); */ + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} +#endif + +/* Test case for fragment_add_check with duplicated (e.g., retransmitted) data + * where the retransmission "conflicts" with the original transmission + * (contents are different). + * Adds three fragments--adding the 2nd one twice-- + * and checks that they are reassembled correctly. + */ +/* visit id frame frag_off len more tvb_offset + 0 12 1 0 50 T 10 + 0 12 2 50 60 T 5 + 0 12 3 50 60 T 15 + 0 12 4 110 40 F 5 +*/ +static void +test_fragment_add_check_duplicate_conflict(void) +{ + fragment_head *fd_head; + fragment_item *fd; + + printf("Starting test test_fragment_add_check_duplicate_conflict\n"); + + pinfo.num = 1; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 10, &pinfo, 12, + NULL, 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Add the 2nd segment */ + pinfo.num = 2; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 50, 60, TRUE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* Now, add the 2nd segment again (but in a different frame and with + * different data) + */ + pinfo.num = 3; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 15, &pinfo, 12, + NULL, 50, 60, TRUE); + + ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_EQ_POINTER(NULL,fd_head); + + /* finally, add the last fragment */ + pinfo.num = 4; + fd_head=fragment_add_check(&test_reassembly_table, tvb, 5, &pinfo, 12, + NULL, 110, 40, FALSE); + + ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); + ASSERT_EQ(4,g_hash_table_size(test_reassembly_table.reassembled_table)); + ASSERT_NE_POINTER(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(4,fd_head->frame); /* max frame we have */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(150,fd_head->datalen); + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_DATALEN_SET|FD_OVERLAP|FD_OVERLAPCONFLICT,fd_head->flags); + ASSERT_NE_POINTER(NULL,fd_head->tvb_data); + ASSERT_NE_POINTER(NULL,fd_head->next); + + fd = fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(50,fd->offset); + ASSERT_EQ(60,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP|FD_OVERLAPCONFLICT,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_NE_POINTER(NULL,fd->next); + + fd = fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(110,fd->offset); + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ_POINTER(NULL,fd->tvb_data); + ASSERT_EQ_POINTER(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+10,50)); + ASSERT(!tvb_memeql(fd_head->tvb_data,50,data+5,60)); + ASSERT(!tvb_memeql(fd_head->tvb_data,110,data+5,40)); + +#if 0 + print_fragment_table(); +#endif +} /********************************************************************************** * * main @@ -1543,6 +3294,22 @@ main(int argc _U_, char **argv _U_) #if 0 test_fragment_add_seq_check_multiple #endif + test_simple_fragment_add, /* frag table only */ + test_fragment_add_partial_reassembly, + test_fragment_add_duplicate_first, + test_fragment_add_duplicate_middle, + test_fragment_add_duplicate_last, + test_fragment_add_duplicate_conflict, + test_simple_fragment_add_check, /* frag table only */ +#if 0 + test_fragment_add_check_partial_reassembly, + test_fragment_add_check_duplicate_first, +#endif + test_fragment_add_check_duplicate_middle, +#if 0 + test_fragment_add_check_duplicate_last, +#endif + test_fragment_add_check_duplicate_conflict, }; /* a tvbuff for testing with */ |