/* 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. * * December 2010: * 1. reassemble_test can be run under valgrind to detect any memory leaks in the * Wireshark reassembly code. * Specifically: code has been added to free dynamically allocated memory * after each test (or at program completion) so that valgrind will report * only actual memory leaks. * The following command can be used to run reassemble_test under valgrind: * env \ * G_DEBUG=gc-friendly \ * G_SLICE=always-malloc \ * valgrind --leak-check=full --show-reachable=yes ./reassemble_test * * 2. Debug functions have been added which will print information * about the fd-chains associated with the fragment_table and the * reassembled table. * #define debug to enable the code. * * Copyright (c) 2007 MX Telecom Ltd. * * Wireshark - Network traffic analyzer * By Gerald Combs * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include "config.h" #include #include #include #include #include #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) static int failure = 0; static void do_test(gboolean condition, const 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 static char *data; static tvbuff_t *tvb; static packet_info pinfo; /* fragment_table maps from datagram ids to fragment_head reassembled_table maps from to fragment_head */ static reassembly_table test_reassembly_table; #ifdef debug /************************************************* * Util fcns to display * fragment_table & reassembled_table fd-chains ************************************************/ static struct _fd_flags { guint32 flag; gchar *flag_name; } fd_flags[] = { {FD_DEFRAGMENTED ,"DF"}, {FD_DATALEN_SET ,"DS"}, {FD_SUBSET_TVB, ,"ST"}, {FD_BLOCKSEQUENCE ,"BS"}, {FD_DATA_NOT_PRESENT ,"NP"}, {FD_PARTIAL_REASSEMBLY ,"PR"}, {FD_OVERLAP ,"OL"}, {FD_OVERLAPCONFLICT ,"OC"}, {FD_MULTIPLETAILS ,"MT"}, {FD_TOOLONGFRAGMENT ,"TL"}, }; #define N_FD_FLAGS (signed)(sizeof(fd_flags)/sizeof(struct _fd_flags)) static void print_fd(fragment_head *fd, gboolean is_head) { int i; g_assert(fd != NULL); printf(" %08x %08x %3d %3d %3d", fd, fd->next, fd->frame, fd->offset, fd->len); if (is_head) { printf(" %3d %3d", fd->datalen, fd->reassembled_in); } else { printf( " "); } printf(" 0x%08x", fd->data); for (i=0; iflags & fd_flags[i].flag) ? fd_flags[i].flag_name : " "); } printf("\n"); } static void print_fd_chain(fragment_head *fd_head) { fragment_item *fdp; g_assert(fd_head != NULL); print_fd(fd_head, TRUE); for (fdp=fd_head->next; fdp != NULL; fdp=fdp->next) { print_fd(fdp, FALSE); } } static void print_fragment_table_chain(gpointer k, gpointer v, gpointer ud) { fragment_key *key = (fragment_key*)k; fragment_head *fd_head = (fragment_head *)v; printf(" --> FT: %3d 0x%08x 0x%08x\n", key->id, *(guint32 *)(key->src.data), *(guint32 *)(key->dst.data)); print_fd_chain(fd_head); } static void print_fragment_table(void) { printf("\n Fragment Table -------\n"); g_hash_table_foreach(fragment_table, print_fragment_table_chain, NULL); } static void print_reassembled_table_chain(gpointer k, gpointer v, gpointer ud) { reassembled_key *key = (reassembled_key*)k; fragment_head *fd_head = (fragment_head *)v; printf(" --> RT: %5d %5d\n", key->id, key->frame); print_fd_chain(fd_head); } static void print_reassembled_table(void) { printf("\n Reassembled Table ----\n"); g_hash_table_foreach(test_reassembly_table.reassembled_table, print_reassembled_table_chain, NULL); } static void print_tables(void) { print_fragment_table(); print_reassembled_table(); } #endif /********************************************************************************** * * 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. */ /* visit id frame frag 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 2 60 F 5 0 12 4 1 60 F 15 */ static void test_simple_fragment_add_seq(void) { fragment_head *fd_head, *fdh0; printf("Starting test test_simple_fragment_add_seq\n"); pinfo.fd->num = 1; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 0, 60, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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(&test_reassembly_table, tvb, 15, &pinfo, 13, NULL, 0, 60, TRUE, 0); ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.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(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 60, FALSE, 0); /* we haven't got all the fragments yet ... */ ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* finally, add the missing fragment */ pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, 1, 60, TRUE, 0); ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.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->tvb_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->tvb_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->tvb_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->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next->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->flags.visited = 1; pinfo.fd->num = 1; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); /* * 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(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 60, FALSE, 0); ASSERT_EQ(fdh0,fd_head); pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, 1, 60, TRUE, 0); ASSERT_EQ(fdh0,fd_head); #if 0 print_fragment_table(); #endif } /* 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_head *fd_head; fragment_item *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(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, FALSE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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->tvb_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->tvb_data); ASSERT_EQ(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.fd->num = 2; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, 1, 40, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); 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->tvb_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_SUBSET_TVB,fd->flags); ASSERT_EQ(tvb_get_ptr(fd_head->tvb_data,0,0),tvb_get_ptr(fd->tvb_data,0,0)); 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->tvb_data); ASSERT_EQ(NULL,fd->next); /* Another copy of the second segment. */ pinfo.fd->num = 3; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, 1, 40, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); 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->tvb_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_SUBSET_TVB,fd->flags); ASSERT_EQ(tvb_get_ptr(fd_head->tvb_data,0,0),tvb_get_ptr(fd->tvb_data,0,0)); 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->tvb_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->tvb_data); ASSERT_EQ(NULL,fd->next); /* have another go at wrapping things up */ pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 20, &pinfo, 12, NULL, 2, 100, FALSE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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->tvb_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->tvb_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->tvb_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->tvb_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->tvb_data); ASSERT_EQ(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.fd->num = 5; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, 3, 40, FALSE, 0); fd_head=fragment_get(&test_reassembly_table, &pinfo, 12, NULL); 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->tvb_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->tvb_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->tvb_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->tvb_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->tvb_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->tvb_data); ASSERT_EQ(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)); } /* Test case for fragment_add_seq with duplicated (e.g., retransmitted) data. * Adds three fragments--adding the 1st 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 0 50 T 10 */ static void test_fragment_add_seq_duplicate_first(void) { fragment_head *fd_head; printf("Starting test test_fragment_add_seq_duplicate_first\n"); pinfo.fd->num = 1; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Add the 2nd segment */ pinfo.fd->num = 2; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 1, 60, TRUE, 0); /* we haven't got all the fragments yet ... */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Add the last fragment */ pinfo.fd->num = 3; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 40, FALSE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_NE(NULL,fd_head); /* Add the first fragment again */ pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); /* Reassembly should have still succeeded */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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(150,fd_head->len); /* the length of data we have */ ASSERT_EQ(2,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_OVERLAP,fd_head->flags); ASSERT_NE(NULL,fd_head->tvb_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->tvb_data); ASSERT_NE(NULL,fd_head->next->next); ASSERT_EQ(4,fd_head->next->next->frame); ASSERT_EQ(0,fd_head->next->next->offset); /* seqno */ ASSERT_EQ(50,fd_head->next->next->len); /* segment length */ ASSERT_EQ(FD_OVERLAP,fd_head->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next); ASSERT_EQ(2,fd_head->next->next->next->frame); ASSERT_EQ(1,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->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next->next); ASSERT_EQ(3,fd_head->next->next->next->next->frame); ASSERT_EQ(2,fd_head->next->next->next->next->offset); /* seqno */ ASSERT_EQ(40,fd_head->next->next->next->next->len); /* segment length */ ASSERT_EQ(0,fd_head->next->next->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->next->next->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next->next->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_seq 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 len more tvb_offset 0 12 1 0 50 T 10 0 12 2 1 60 T 5 0 12 3 1 60 T 5 0 12 4 3 40 F 5 */ static void test_fragment_add_seq_duplicate_middle(void) { fragment_head *fd_head; printf("Starting test test_fragment_add_seq_duplicate_middle\n"); pinfo.fd->num = 1; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Add the 2nd segment */ pinfo.fd->num = 2; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 1, 60, TRUE, 0); /* we haven't got all the fragments yet ... */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Now, add the 2nd segment again (but in a different frame) */ pinfo.fd->num = 3; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 1, 60, TRUE, 0); /* This duplicate fragment should have been ignored */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* finally, add the last fragment */ pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 40, FALSE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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(150,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->tvb_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->tvb_data); ASSERT_NE(NULL,fd_head->next->next); ASSERT_EQ(2,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->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next); ASSERT_EQ(3,fd_head->next->next->next->frame); ASSERT_EQ(1,fd_head->next->next->next->offset); /* seqno */ ASSERT_EQ(60,fd_head->next->next->next->len); /* segment length */ ASSERT_EQ(FD_OVERLAP,fd_head->next->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->next->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next->next); ASSERT_EQ(4,fd_head->next->next->next->next->frame); ASSERT_EQ(2,fd_head->next->next->next->next->offset); /* seqno */ ASSERT_EQ(40,fd_head->next->next->next->next->len); /* segment length */ ASSERT_EQ(0,fd_head->next->next->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->next->next->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next->next->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_seq 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_seq_duplicate_last(void) { fragment_head *fd_head; printf("Starting test test_fragment_add_seq_duplicate_last\n"); pinfo.fd->num = 1; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Add the 2nd segment */ pinfo.fd->num = 2; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 1, 60, TRUE, 0); /* we haven't got all the fragments yet ... */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Add the last fragment */ pinfo.fd->num = 3; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 40, FALSE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_NE(NULL,fd_head); /* Add the last fragment again */ pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 40, FALSE, 0); /* Reassembly should have still succeeded */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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(150,fd_head->len); /* the length of data we have */ ASSERT_EQ(2,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_OVERLAP,fd_head->flags); ASSERT_NE(NULL,fd_head->tvb_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->tvb_data); ASSERT_NE(NULL,fd_head->next->next); ASSERT_EQ(2,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->tvb_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(40,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->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next->next); ASSERT_EQ(4,fd_head->next->next->next->next->frame); ASSERT_EQ(2,fd_head->next->next->next->next->offset); /* seqno */ ASSERT_EQ(40,fd_head->next->next->next->next->len); /* segment length */ ASSERT_EQ(FD_OVERLAP,fd_head->next->next->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->next->next->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next->next->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_seq 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 len more tvb_offset 0 12 1 0 50 T 10 0 12 2 1 60 T 5 0 12 3 1 60 T 15 0 12 4 2 40 F 5 */ static void test_fragment_add_seq_duplicate_conflict(void) { fragment_head *fd_head; printf("Starting test test_fragment_add_seq_duplicate_conflict\n"); pinfo.fd->num = 1; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Add the 2nd segment */ pinfo.fd->num = 2; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 1, 60, TRUE, 0); /* we haven't got all the fragments yet ... */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* Now, add the 2nd segment again (but in a different frame and with * different data) */ pinfo.fd->num = 3; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, 1, 60, TRUE, 0); /* This duplicate fragment should have been ignored */ ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(NULL,fd_head); /* finally, add the last fragment */ pinfo.fd->num = 4; fd_head=fragment_add_seq(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 40, FALSE, 0); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.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(150,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_OVERLAPCONFLICT,fd_head->flags); ASSERT_NE(NULL,fd_head->tvb_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->tvb_data); ASSERT_NE(NULL,fd_head->next->next); ASSERT_EQ(2,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->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next); ASSERT_EQ(3,fd_head->next->next->next->frame); ASSERT_EQ(1,fd_head->next->next->next->offset); /* seqno */ ASSERT_EQ(60,fd_head->next->next->next->len); /* segment length */ ASSERT_EQ(FD_OVERLAP|FD_OVERLAPCONFLICT,fd_head->next->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->next->tvb_data); ASSERT_NE(NULL,fd_head->next->next->next->next); ASSERT_EQ(4,fd_head->next->next->next->next->frame); ASSERT_EQ(2,fd_head->next->next->next->next->offset); /* seqno */ ASSERT_EQ(40,fd_head->next->next->next->next->len); /* segment length */ ASSERT_EQ(0,fd_head->next->next->next->next->flags); ASSERT_EQ(NULL,fd_head->next->next->next->next->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next->next->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_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. */ /* visit id frame frag len more tvb_offset 0 12 1 0 50 T 10 0 13 2 0 60 T 15 0 12 3 2 60 F 5 0 12 4 1 60 F 15 */ static void test_fragment_add_seq_check_work(fragment_head *(*fn)(reassembly_table *, tvbuff_t *, const int, const packet_info *, const guint32, const void *, const guint32, const guint32, const gboolean)) { fragment_head *fd_head; pinfo.fd -> num = 1; fd_head=fn(&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(NULL,fd_head); /* start another pdu (just to confuse things) */ pinfo.fd->num = 2; fd_head=fn(&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(NULL,fd_head); /* add the terminal fragment of the first datagram */ pinfo.fd->num = 3; fd_head=fn(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 2, 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(NULL,fd_head); /* finally, add the missing fragment */ pinfo.fd->num = 4; fd_head=fn(&test_reassembly_table, tvb, 15, &pinfo, 12, NULL, 1, 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(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->tvb_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->tvb_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->tvb_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->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next->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_tables(); #endif } /* 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_head *fd_head; printf("Starting test test_fragment_add_seq_check_1\n"); pinfo.fd->num = 1; fd_head=fragment_add_seq_check(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 1, 50, FALSE); 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(NULL,fd_head); /* Now add the missing segment */ pinfo.fd->num = 2; fd_head=fragment_add_seq_check(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 0, 60, TRUE); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.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->tvb_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->tvb_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->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->next); /* test the actual reassembly */ ASSERT(!tvb_memeql(fd_head->tvb_data,0,data+5,60)); ASSERT(!tvb_memeql(fd_head->tvb_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_head *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(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 10, 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(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->tvb_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_check_multiple * *********************************************************************************/ /* Test 2 partial frags from 2 diff datagrams in the same frame */ /* datagram #1: frame 1 + first part of frame 2 datagram #1: last part of frame 2 + frame 3 Is this a valid scenario ? The result of calling fragment_add_seq_check(&test_reassembly_table, ) for these fragments is a reassembled_table with: id, frame 1 => first_datagram; ["reassembled in" frame 2] id, frame 2 => second_datagram; ["reassembled in" frame 3] id, frame 3 => second_datagram; Note that the id, frame 2 => first datagram was overwritten by the entry for the second datagram. Is this OK ? IE: When dissected/displayed will the reassembled datagram 1 appear with frame 2 ?? */ /* visit id frame frag len more tvb_offset 0 12 1 0 50 T 10 0 12 2 1 20 F 5 0 12 2 0 25 T 25 0 12 3 1 60 F 0 */ /* Is this a valid scenario ? Is this OK ? IE: When dissected/displayed: Will the reassembled datagram 1 appear with frame 2 ?? */ #if 0 static void test_fragment_add_seq_check_multiple(void) { fragment_head *fd_head; pinfo.fd -> num = 1; fd_head=fragment_add_seq_check(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 0, 50, TRUE); /* add the terminal fragment of the first datagram */ pinfo.fd->num = 2; fd_head=fragment_add_seq_check(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 1, 20, FALSE); print_tables(); /* Now: start a second datagram with the first fragment in frame #2 */ pinfo.fd->num = 2; fd_head=fragment_add_seq_check(&test_reassembly_table, tvb, 25, &pinfo, 12, NULL, 0, 25, TRUE); /* add the terminal fragment of the second datagram */ pinfo.fd->num = 3; fd_head=fragment_add_seq_check(&test_reassembly_table, tvb, 0, &pinfo, 12, NULL, 1, 60, FALSE); print_tables(); } #endif /********************************************************************************** * * 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_head *fd_head; printf("Starting test test_simple_fragment_add_seq_next\n"); pinfo.fd->num = 1; fd_head= fragment_add_seq_next(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 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(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(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 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(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(&test_reassembly_table, tvb, 15, &pinfo, 13, NULL, 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(NULL,fd_head); /* now we add the terminal fragment of the first datagram */ pinfo.fd->num = 3; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 60, FALSE); ASSERT_EQ(1,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(2,g_hash_table_size(test_reassembly_table.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->tvb_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->tvb_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->tvb_data); ASSERT_EQ(NULL,fd_head->next->next->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)); } /* 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_head *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(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, DATA_LEN-9, 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_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->tvb_data); ASSERT_EQ(NULL,fd_head->next); /* add another fragment (with all data present) */ pinfo.fd->num = 4; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 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(test_reassembly_table.fragment_table)); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.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(&test_reassembly_table, tvb, 10, &pinfo, 12, NULL, 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(test_reassembly_table.fragment_table)); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); ASSERT_EQ(NULL,fd_head); pinfo.fd->num = 4; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 5, &pinfo, 12, NULL, 60, FALSE); 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(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_head *fd_head; printf("Starting test test_missing_data_fragment_add_seq_next_2\n"); pinfo.fd->num = 11; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 10, &pinfo, 24, NULL, 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(NULL,fd_head); pinfo.fd->num = 12; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 5, &pinfo, 24, NULL, 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(test_reassembly_table.fragment_table)); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.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(&test_reassembly_table, tvb, 10, &pinfo, 24, NULL, 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(test_reassembly_table.fragment_table)); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.reassembled_table)); ASSERT_EQ(NULL,fd_head); pinfo.fd->num = 12; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 5, &pinfo, 24, NULL, DATA_LEN-4, FALSE); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.fragment_table)); ASSERT_EQ(0,g_hash_table_size(test_reassembly_table.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_head *fd_head; printf("Starting test test_missing_data_fragment_add_seq_next_3\n"); pinfo.fd->num = 20; fd_head=fragment_add_seq_next(&test_reassembly_table, tvb, 5, &pinfo, 30, NULL, DATA_LEN-4, 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(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->tvb_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(&test_reassembly_table, tvb, 5, &pinfo, 30, NULL, DATA_LEN-4, 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(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->tvb_data); ASSERT_EQ(NULL,fd_head->next); } /********************************************************************************** * * main * *********************************************************************************/ int main(int argc _U_, char **argv _U_) { frame_data fd; static const guint8 src[] = {1,2,3,4}, dst[] = {5,6,7,8}; unsigned int i; static void (*tests[])(void) = { test_simple_fragment_add_seq, /* frag table only */ test_fragment_add_seq_partial_reassembly, test_fragment_add_seq_duplicate_first, test_fragment_add_seq_duplicate_middle, test_fragment_add_seq_duplicate_last, test_fragment_add_seq_duplicate_conflict, test_fragment_add_seq_check, /* frag + reassemble */ 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, #if 0 test_fragment_add_seq_check_multiple #endif }; /* a tvbuff for testing with */ data = (char *)g_malloc(DATA_LEN); /* make sure it's full of stuff */ for(i=0; iflags.visited = FALSE; tests[i](); /* Free memory used by the tables */ reassembly_table_destroy(&test_reassembly_table); } tvb_free(tvb); tvb = NULL; g_free(data); data = NULL; printf(failure?"FAILURE\n":"SUCCESS\n"); return failure; } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */