#include "pico_config.h" #include "pico_ipv6.h" #include "pico_icmp6.h" #include "pico_ipv4.h" #include "pico_icmp4.h" #include "pico_stack.h" #include "pico_eth.h" #include "pico_udp.h" #include "pico_tcp.h" #include "pico_socket.h" #include "pico_device.h" #include "pico_tree.h" #include "pico_constants.h" #include "pico_fragments.h" #include "./modules/pico_fragments.c" #include "check.h" Suite *pico_suite(void); /* Mock! */ static int transport_recv_called = 0; static uint32_t buffer_len_transport_receive = 0; #define TESTPROTO 0x99 #define TESTID 0x11 int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto) { fail_if(proto != TESTPROTO); transport_recv_called++; buffer_len_transport_receive = f->buffer_len; pico_frame_discard(f); return 0; } static int timer_add_called = 0; uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg) { IGNORE_PARAMETER(expire); IGNORE_PARAMETER(arg); fail_if(timer != pico_frag_expire); timer_add_called++; return 0; } static int timer_cancel_called = 0; void pico_timer_cancel(uint32_t id) { IGNORE_PARAMETER(id); timer_cancel_called++; } static int icmp4_frag_expired_called = 0; int pico_icmp4_frag_expired(struct pico_frame *f) { fail_unless(IS_IPV4(f)); icmp4_frag_expired_called++; return 0; } static int icmp6_frag_expired_called = 0; int pico_icmp6_frag_expired(struct pico_frame *f) { fail_unless(IS_IPV6(f)); icmp6_frag_expired_called++; return 0; } START_TEST(tc_pico_ipv6_frag_compare) { struct pico_frame *a, *b; a = pico_frame_alloc(10); fail_if(!a); b = pico_frame_alloc(10); fail_if(!b); a->frag = 0xaa00; b->frag = 0xbb00; fail_unless(pico_ipv6_frag_compare(a, b) < 0); fail_unless(pico_ipv6_frag_compare(b, a) > 0); b->frag = 0xaa00; fail_unless(pico_ipv6_frag_compare(a, b) == 0); pico_frame_discard(a); pico_frame_discard(b); } END_TEST START_TEST(tc_pico_ipv4_frag_compare) { struct pico_frame *a, *b; a = pico_frame_alloc(10); fail_if(!a); b = pico_frame_alloc(10); fail_if(!b); a->frag = 0xaa00; b->frag = 0xbb00; fail_unless(pico_ipv4_frag_compare(a, b) < 0); fail_unless(pico_ipv4_frag_compare(b, a) > 0); b->frag = 0xaa00; fail_unless(pico_ipv4_frag_compare(a, b) == 0); pico_frame_discard(a); pico_frame_discard(b); } END_TEST START_TEST(tc_pico_ipv6_fragments_complete) { struct pico_frame *a, *b; transport_recv_called = 0; timer_cancel_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = 1; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20; /* off = 32 */ pico_tree_insert(&ipv6_fragments, a); pico_tree_insert(&ipv6_fragments, b); pico_set_mm_failure(1); pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV6); fail_if(transport_recv_called != 0); fail_if(timer_cancel_called != 0); pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV6); fail_if(transport_recv_called != 1); fail_if(timer_cancel_called != 1); } END_TEST START_TEST(tc_pico_ipv4_fragments_complete) { struct pico_frame *a, *b; transport_recv_called = 0; timer_cancel_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u; /* off = 32 */ pico_tree_insert(&ipv4_fragments, a); pico_tree_insert(&ipv4_fragments, b); pico_set_mm_failure(1); pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV4); fail_if(transport_recv_called != 0); fail_if(timer_cancel_called != 0); pico_fragments_complete(64, TESTPROTO, PICO_PROTO_IPV4); fail_if(transport_recv_called != 1); fail_if(timer_cancel_called != 1); } END_TEST START_TEST(tc_pico_fragments_complete) { /* Done in the two tests above */ } END_TEST START_TEST(tc_pico_fragments_empty_tree) { PICO_TREE_DECLARE(tree, pico_ipv4_frag_compare); struct pico_frame *a = NULL, *b = NULL; pico_fragments_empty_tree(NULL); a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); /* Make sure we have different frames a and b (because of compare functions in PICO_TREE_DECLARE) */ a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u; /* off = 32 */ /* Insert them in the tree */ pico_tree_insert(&tree, a); pico_tree_insert(&tree, b); pico_fragments_empty_tree(&tree); /* Is tree empty? */ fail_if(!pico_tree_empty(&tree)); } END_TEST START_TEST(tc_pico_fragments_check_complete) { struct pico_frame *a, *b; fail_if(pico_fragments_check_complete(&ipv4_fragments, TESTPROTO, PICO_PROTO_IPV4) != 1); fail_if(pico_fragments_check_complete(&ipv6_fragments, TESTPROTO, PICO_PROTO_IPV6) != 1); /* Case 1: IPV4 all packets received */ transport_recv_called = 0; timer_cancel_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u; /* off = 32 */ pico_tree_insert(&ipv4_fragments, a); pico_tree_insert(&ipv4_fragments, b); fail_if(pico_fragments_check_complete(&ipv4_fragments, TESTPROTO, PICO_PROTO_IPV4) != 0); fail_if(transport_recv_called != 1); fail_if(timer_cancel_called != 1); /* Case 2: IPV6 all packets received */ transport_recv_called = 0; timer_cancel_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = 1; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20; /* off = 32 */ pico_tree_insert(&ipv6_fragments, a); pico_tree_insert(&ipv6_fragments, b); fail_if(pico_fragments_check_complete(&ipv6_fragments, TESTPROTO, PICO_PROTO_IPV6) != 0); fail_if(transport_recv_called != 1); fail_if(timer_cancel_called != 1); /* Case 3: IPV4 NOT all packets received */ transport_recv_called = 0; timer_cancel_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u | PICO_IPV4_MOREFRAG; /* off = 32 + more frags */ /* b->frag = PICO_IPV4_MOREFRAG; /\* more frags *\/ */ pico_tree_insert(&ipv4_fragments, a); pico_tree_insert(&ipv4_fragments, b); fail_if(pico_fragments_check_complete(&ipv4_fragments, TESTPROTO, PICO_PROTO_IPV4) == 0); fail_if(transport_recv_called != 0); fail_if(timer_cancel_called != 0); /* Case 4: IPV6 NOT all packets received */ transport_recv_called = 0; timer_cancel_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = 1; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 1; /* more frags */ pico_tree_insert(&ipv6_fragments, a); pico_tree_insert(&ipv6_fragments, b); fail_if(pico_fragments_check_complete(&ipv6_fragments, TESTPROTO, PICO_PROTO_IPV6) == 0); fail_if(transport_recv_called != 0); fail_if(timer_cancel_called != 0); } END_TEST START_TEST(tc_pico_fragments_send_notify) { struct pico_frame *a = NULL; char ipv4_multicast_address[] = { "224.0.0.1" }; icmp4_frag_expired_called = 0; /* Case 1: NULL fragment */ pico_fragments_send_notify(NULL); /* Notify should not be send when supplied a NULL argument */ fail_if(icmp4_frag_expired_called); /* Case 2: fragment with offset > 0 */ a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv4_hdr); a->buffer[0] = 0x40; /* IPV4 */ a->frag = 0x20 >> 3u; /* off = 32 */ pico_fragments_send_notify(a); /* fragment has offset > 0, no notify should be sent */ fail_if(icmp4_frag_expired_called); /* Case 3: fragment with offset > 0 & multicast address */ pico_string_to_ipv4(ipv4_multicast_address, &((struct pico_ipv4_hdr*)(a->net_hdr))->dst.addr); pico_fragments_send_notify(a); /* fragment has offset > 0 AND multicast address, no notify should be sent */ fail_if(icmp4_frag_expired_called); /* Case 4: fragment with offset == 0 */ a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv4_hdr); a->buffer[0] = 0x40; /* IPV4 */ a->frag = PICO_IPV4_MOREFRAG; /* more frags */ pico_string_to_ipv4("127.0.0.1", &((struct pico_ipv4_hdr*)(a->net_hdr))->dst.addr); /* Set a non-nulticast address */ pico_fragments_send_notify(a); /* fragment has offset == 0, notify should be sent */ fail_if(!icmp4_frag_expired_called); /* Case 5: fragment with offset == 0 & multicast address */ icmp4_frag_expired_called = 0; /* reset flag */ pico_string_to_ipv4(ipv4_multicast_address, &((struct pico_ipv4_hdr*)(a->net_hdr))->dst.addr); pico_fragments_send_notify(a); /* fragment has offset == 0 but multicast address, notify should NOT sent */ fail_if(icmp4_frag_expired_called); /* Cleanup */ pico_frame_discard(a); } END_TEST START_TEST(tc_pico_frag_expire) { struct pico_frame *a, *b; /* Addr setup, choose a unicast addr */ struct pico_ip6 addr_1 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; char ipv4_multicast_address[] = { "224.0.0.1" }; struct pico_ip6 ipv6_multicast_addr = {{ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; /* Clear env vars */ icmp4_frag_expired_called = 0; icmp6_frag_expired_called = 0; /* Common tests */ /* Case 1: tree is NULL */ pico_frag_expire(0, NULL); fail_if(icmp4_frag_expired_called); fail_if(icmp6_frag_expired_called); /* IPV4 TESTS */ /* Initial setup */ a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* Case 1: first fragment was not received, do not send notify + empty tree */ a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv4_hdr); a->buffer[0] = 0x40; /* IPV4 */ a->frag = 0x20 >> 3u; /* off = 32 */ pico_tree_insert(&ipv4_fragments, a); pico_frag_expire(0, (void*)(&ipv4_fragments)); fail_if(icmp4_frag_expired_called); fail_if(!pico_tree_empty(&ipv4_fragments)); /* Case 2: first fragment was received, send notify + empty tree */ b->net_hdr = b->buffer; b->net_len = sizeof(struct pico_ipv4_hdr); b->buffer[0] = 0x40; /* IPV4 */ b->frag = PICO_IPV4_MOREFRAG; /* more frags */ pico_tree_insert(&ipv4_fragments, b); pico_frag_expire(0, (void*)(&ipv4_fragments)); fail_if(!icmp4_frag_expired_called); fail_if(!pico_tree_empty(&ipv4_fragments)); /* Case 3: first fragment was received but it is multicast, do not send notify + empty tree */ /* Reallocate frame, it was discarded in the last pico_frag_expire() */ b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* Reset env vars */ icmp4_frag_expired_called = 0; b->net_hdr = b->buffer; b->net_len = sizeof(struct pico_ipv4_hdr); b->buffer[0] = 0x40; /* IPV4 */ b->frag = PICO_IPV4_MOREFRAG; /* more frags */ pico_string_to_ipv4(ipv4_multicast_address, &((struct pico_ipv4_hdr*)(b->net_hdr))->dst.addr); pico_tree_insert(&ipv4_fragments, b); pico_frag_expire(0, (void*)(&ipv4_fragments)); fail_if(icmp4_frag_expired_called); fail_if(!pico_tree_empty(&ipv4_fragments)); /* IPV6 TESTS */ /* re-allocate frames, they were discarded in pico_frag_expire */ a = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* Case 4: first fragment was not received, do not send notify + empty tree */ a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv6_hdr); a->buffer[0] = 0x60; /* IPV6 */ a->frag = 0x20; /* off = 32 */ memcpy(((struct pico_ipv6_hdr*)(a->net_hdr))->dst.addr, addr_1.addr, PICO_SIZE_IP6); pico_tree_insert(&ipv6_fragments, a); pico_frag_expire(0, (void*)(&ipv6_fragments)); fail_if(icmp6_frag_expired_called); fail_if(!pico_tree_empty(&ipv6_fragments)); /* Case 5: first fragment was received, send notify + empty tree */ b->net_hdr = b->buffer; b->net_len = sizeof(struct pico_ipv6_hdr); b->buffer[0] = 0x60; /* IPV6 */ b->frag = 1; memcpy(((struct pico_ipv6_hdr*)(b->net_hdr))->dst.addr, addr_1.addr, PICO_SIZE_IP6); pico_tree_insert(&ipv6_fragments, b); pico_frag_expire(0, (void*)(&ipv6_fragments)); fail_if(!icmp6_frag_expired_called); fail_if(!pico_tree_empty(&ipv6_fragments)); /* Case 6: first fragment was received but it is multicast, do not send notify + empty tree */ /* Reallocate frame, it was discarded in the last pico_frag_expire() */ b = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* Reset env vars */ icmp6_frag_expired_called = 0; b->net_hdr = b->buffer; b->net_len = sizeof(struct pico_ipv4_hdr); b->buffer[0] = 0x60; /* IPV4 */ b->frag = 1; memcpy(((struct pico_ipv6_hdr*)(b->net_hdr))->dst.addr, ipv6_multicast_addr.addr, PICO_SIZE_IP6); pico_tree_insert(&ipv6_fragments, b); pico_frag_expire(0, (void*)(&ipv6_fragments)); fail_if(icmp6_frag_expired_called); fail_if(!pico_tree_empty(&ipv6_fragments)); } END_TEST START_TEST(tc_pico_ipv6_frag_timer_on) { /* Reset env variable */ timer_add_called = 0; pico_ipv6_frag_timer_on(); /* Was timer added? */ fail_if(!timer_add_called); } END_TEST START_TEST(tc_pico_ipv4_frag_timer_on) { /* Reset env variable */ timer_add_called = 0; pico_ipv4_frag_timer_on(); /* Was timer added? */ fail_if(!timer_add_called); } END_TEST START_TEST(tc_pico_ipv6_frag_match) { struct pico_frame *a, *b; struct pico_ipv6_hdr *ha, *hb; /* Addr setup */ struct pico_ip6 addr_1 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }}; struct pico_ip6 addr_2 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 }}; /* Inital setup */ a = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* Case 1: net hdr(s) are NULL */ a->net_hdr = NULL; b->net_hdr = NULL; fail_if(pico_ipv6_frag_match(a, b) != -2); /* Init a frame */ a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv6_hdr); fail_if(pico_ipv6_frag_match(a, b) != -2); /* Init b frame */ b->net_hdr = b->buffer; b->net_len = sizeof(struct pico_ipv6_hdr); /* Init hdrs for rest of tests*/ ha = (struct pico_ipv6_hdr *)a->net_hdr; hb = (struct pico_ipv6_hdr *)b->net_hdr; /* Case 2: src addr are different*/ /* Init a and b net hdr adresses */ memcpy(ha->src.addr, addr_1.addr, PICO_SIZE_IP6); memcpy(ha->dst.addr, addr_2.addr, PICO_SIZE_IP6); memcpy(hb->src.addr, addr_2.addr, PICO_SIZE_IP6); memcpy(hb->dst.addr, addr_2.addr, PICO_SIZE_IP6); fail_if(pico_ipv6_frag_match(a, b) != 1); /* Case 3: dst addr are different*/ /* Init a and b net hdr adresses */ memcpy(ha->src.addr, addr_1.addr, PICO_SIZE_IP6); memcpy(ha->dst.addr, addr_2.addr, PICO_SIZE_IP6); memcpy(hb->src.addr, addr_1.addr, PICO_SIZE_IP6); memcpy(hb->dst.addr, addr_1.addr, PICO_SIZE_IP6); fail_if(pico_ipv6_frag_match(a, b) != 2); /* Case 4: fragments are the same (src and dst are the same)*/ /* Init a and b net hdr adresses */ memcpy(ha->src.addr, addr_1.addr, PICO_SIZE_IP6); memcpy(ha->dst.addr, addr_2.addr, PICO_SIZE_IP6); memcpy(hb->src.addr, addr_1.addr, PICO_SIZE_IP6); memcpy(hb->dst.addr, addr_2.addr, PICO_SIZE_IP6); fail_if(pico_ipv6_frag_match(a, b) != 0); /* Cleanup */ pico_frame_discard(a); pico_frame_discard(b); } END_TEST START_TEST(tc_pico_ipv4_frag_match) { struct pico_frame *a, *b; struct pico_ipv4_hdr *ha, *hb; /* Addr setup */ struct pico_ip4 addr_1 = { .addr = long_be(0x0a280064) }; struct pico_ip4 addr_2 = { .addr = long_be(0x0a280312) }; /* Case 1: frames are NULL */ a = NULL; b = NULL; fail_if(pico_ipv4_frag_match(a, b) != -1); /* setup */ a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* Case 2: net hdr(s) are NULL */ a->net_hdr = NULL; b->net_hdr = NULL; fail_if(pico_ipv4_frag_match(a, b) != -2); /* Init a frame */ a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv4_hdr); fail_if(pico_ipv4_frag_match(a, b) != -2); /* Init b frame */ b->net_hdr = b->buffer; b->net_len = sizeof(struct pico_ipv4_hdr); /* Init hdrs for rest of tests*/ ha = (struct pico_ipv4_hdr *)a->net_hdr; hb = (struct pico_ipv4_hdr *)b->net_hdr; /* Case 3: src addr are different*/ /* Init a and b net hdr adresses */ ha->src = addr_1; ha->dst = addr_2; hb->src = addr_2; hb->dst = addr_2; fail_if(pico_ipv4_frag_match(a, b) != 1); /* Case 4: dst addr are different*/ /* Init a and b net hdr adresses */ ha->src = addr_1; ha->dst = addr_2; hb->src = addr_1; hb->dst = addr_1; fail_if(pico_ipv4_frag_match(a, b) != 2); /* Case 5: fragments are the same (src and dst are the same)*/ /* Init a and b net hdr adresses */ ha->src = addr_1; ha->dst = addr_2; hb->src = addr_1; hb->dst = addr_2; fail_if(pico_ipv4_frag_match(a, b) != 0); /* Cleanup */ pico_frame_discard(a); pico_frame_discard(b); } END_TEST START_TEST(tc_pico_fragments_get_header_length) { fail_unless(pico_fragments_get_header_length(PICO_PROTO_IPV4) == PICO_SIZE_IP4HDR); fail_unless(pico_fragments_get_header_length(PICO_PROTO_IPV6) == PICO_SIZE_IP6HDR); fail_unless(pico_fragments_get_header_length(1) == 0); } END_TEST START_TEST(tc_pico_fragments_get_more_flag) { struct pico_frame *a = NULL, *b = NULL; a = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); a->net_hdr = a->buffer; a->net_len = sizeof(struct pico_ipv4_hdr); a->buffer[0] = 0x40; /* IPV4 */ a->frag = PICO_IPV4_MOREFRAG; /* Set more flag */ b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); b->net_hdr = a->buffer; b->net_len = sizeof(struct pico_ipv6_hdr); b->buffer[0] = 0x60; /* IPV6 */ b->frag = 0x1; /* set more flag */ fail_unless(pico_fragments_get_more_flag(NULL, PICO_PROTO_IPV4) == 0); fail_unless(pico_fragments_get_more_flag(NULL, PICO_PROTO_IPV6) == 0); /* More flag set in IPV4 */ fail_unless(pico_fragments_get_more_flag(a, PICO_PROTO_IPV4) == 1); /* More flag set in IPV6 */ fail_unless(pico_fragments_get_more_flag(b, PICO_PROTO_IPV6) == 1); /* More flag NOT set in IPV4 */ a->frag = 0; fail_unless(pico_fragments_get_more_flag(a, PICO_PROTO_IPV4) == 0); /* More flag NOT set in IPV6 */ b->frag = 0; fail_unless(pico_fragments_get_more_flag(b, PICO_PROTO_IPV6) == 0); /* Invalid net argument */ fail_unless(pico_fragments_get_more_flag(a, 1) == 0); fail_unless(pico_fragments_get_more_flag(b, 1) == 0); /* Cleanup */ pico_frame_discard(a); pico_frame_discard(b); } END_TEST START_TEST(tc_pico_fragments_get_offset) { struct pico_frame *a=NULL, *b = NULL; b = pico_frame_alloc(sizeof(struct pico_ipv4_hdr)); fail_if(!b); printf("Allocated frame, %p\n", b); /* IPV4 with fragment offset > 0 */ b->frag = 0x20 >> 3u; /* off = 32 */ fail_unless(pico_fragments_get_offset(b, PICO_PROTO_IPV4) == 32); /* IPV4 with fragment offset == 0 */ b->frag = 0; /* off = 0 */ fail_unless(pico_fragments_get_offset(b, PICO_PROTO_IPV4) == 0); /* Invalid net argument */ fail_unless(pico_fragments_get_offset(b, 1) == 0); a = pico_frame_alloc(sizeof(struct pico_ipv6_hdr)); fail_if(!a); printf("Allocated frame, %p\n", a); /* IPV6 with fragment offset > 0 */ a->frag = 0x20; /* off = 32 */ fail_unless(pico_fragments_get_offset(a, PICO_PROTO_IPV6) == 32); /* IPV6 with fragment offset == 0 */ a->frag = 1; /* off = 0 */ fail_unless(pico_fragments_get_offset(a, PICO_PROTO_IPV6) == 0); /* Invalid net argument */ fail_unless(pico_fragments_get_offset(a, 1) == 0); /* Invalid frame argument */ fail_unless(pico_fragments_get_offset(NULL, PICO_PROTO_IPV4) == 0); fail_unless(pico_fragments_get_offset(NULL, PICO_PROTO_IPV6) == 0); fail_unless(pico_fragments_get_offset(NULL, 1) == 0); pico_frame_discard(a); pico_frame_discard(b); } END_TEST START_TEST(tc_pico_fragments_reassemble) { struct pico_frame *a, *b; /* NULL tree */ transport_recv_called = 0; buffer_len_transport_receive = 0; fail_if(pico_fragments_reassemble(NULL, 0, TESTPROTO, PICO_PROTO_IPV4) != -1); fail_if(transport_recv_called); /* Empty tree */ transport_recv_called = 0; buffer_len_transport_receive = 0; fail_if(pico_fragments_reassemble(&ipv4_fragments, 0, TESTPROTO, PICO_PROTO_IPV4) != -2); fail_if(transport_recv_called); /* Empty tree */ transport_recv_called = 0; buffer_len_transport_receive = 0; fail_if(pico_fragments_reassemble(&ipv6_fragments, 0, TESTPROTO, PICO_PROTO_IPV6) != -2); fail_if(transport_recv_called); /* Case 1: IPV4 , everything good */ transport_recv_called = 0; buffer_len_transport_receive = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u; /* off = 32 */ pico_tree_insert(&ipv4_fragments, a); pico_tree_insert(&ipv4_fragments, b); fail_if(pico_fragments_reassemble(&ipv4_fragments, 64, TESTPROTO, PICO_PROTO_IPV4) != 0); fail_if(transport_recv_called != 1); fail_if(buffer_len_transport_receive != 64 + PICO_SIZE_IP4HDR); fail_if(!pico_tree_empty(&ipv4_fragments)); /* Case 2: IPV6 , everything good */ transport_recv_called = 0; buffer_len_transport_receive = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = 1; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20; /* off = 32 */ pico_tree_insert(&ipv6_fragments, a); pico_tree_insert(&ipv6_fragments, b); fail_if(pico_fragments_reassemble(&ipv6_fragments, 64, TESTPROTO, PICO_PROTO_IPV6) != 0); fail_if(transport_recv_called != 1); fail_if(buffer_len_transport_receive != 64 + PICO_SIZE_IP6HDR); fail_if(!pico_tree_empty(&ipv4_fragments)); /* Case 3: IPV4 with mm failure*/ transport_recv_called = 0; buffer_len_transport_receive = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u; /* off = 32 */ pico_tree_insert(&ipv4_fragments, a); pico_tree_insert(&ipv4_fragments, b); pico_set_mm_failure(1); fail_if(pico_fragments_reassemble(&ipv4_fragments, 64, TESTPROTO, PICO_PROTO_IPV4) != 1); fail_if(transport_recv_called == 1); fail_if(buffer_len_transport_receive != 0); fail_if(pico_tree_empty(&ipv4_fragments)); /* Case 4: IPV6 with mm failure */ transport_recv_called = 0; a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = 1; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20; /* off = 32 */ pico_tree_insert(&ipv6_fragments, a); pico_tree_insert(&ipv6_fragments, b); pico_set_mm_failure(1); fail_if(pico_fragments_reassemble(&ipv6_fragments, 64, TESTPROTO, PICO_PROTO_IPV6) != 1); fail_if(transport_recv_called == 1); fail_if(buffer_len_transport_receive != 0); fail_if(pico_tree_empty(&ipv6_fragments)); } END_TEST START_TEST(tc_pico_ipv6_process_frag) { struct pico_ipv6_exthdr *hdr = NULL; struct pico_frame *a = NULL, *b = NULL, *c = NULL; /* NULL args provided */ ipv6_cur_frag_id = 0; timer_add_called = 0; pico_ipv6_process_frag(hdr, a, TESTPROTO); fail_if(ipv6_cur_frag_id != 0); fail_if(timer_add_called != 0); /* init hdr */ hdr = PICO_ZALLOC(sizeof(struct pico_ipv6_exthdr)); hdr->ext.frag.id[0]= 0xF; /* NULL frame provided */ ipv6_cur_frag_id = 0; timer_add_called = 0; pico_ipv6_process_frag(hdr, a, TESTPROTO); fail_if(ipv6_cur_frag_id != 0); fail_if(timer_add_called != 0); /* init frame */ a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); c = pico_frame_alloc(64 + 20); fail_if(!c); printf("Allocated frame, %p\n", c); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = 1; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 | 0x1; /* off = 32 */ c->net_hdr = c->buffer; c->net_len = 20; c->transport_len = 32; c->transport_hdr = c->buffer + 20; c->frag = 0x40; /* off = 64 */ /* Case 1: Empty fragments tree */ ipv6_cur_frag_id = 0; timer_add_called = 0; /* make sure tree is empty */ fail_if(!pico_tree_empty(&ipv6_fragments)); pico_ipv6_process_frag(hdr, a, TESTPROTO); fail_if(ipv6_cur_frag_id != IP6_FRAG_ID(hdr)); fail_if(timer_add_called != 1); fail_if(pico_tree_empty(&ipv6_fragments)); /* make sure we added the fragment to the tree */ fail_if(((struct pico_frame *)pico_tree_first(&ipv6_fragments))->buffer != a->buffer); /* Case 2: Adding second fragment */ timer_add_called = 0; pico_ipv6_process_frag(hdr, b, TESTPROTO); fail_if(ipv6_cur_frag_id != IP6_FRAG_ID(hdr)); fail_if(timer_add_called != 0); fail_if(pico_tree_empty(&ipv6_fragments)); /* make sure we added the fragment to the tree */ fail_if(((struct pico_frame *)pico_tree_last(&ipv6_fragments))->buffer != b->buffer); /* Case 3: Adding final fragment */ timer_cancel_called = 0; transport_recv_called = 0; buffer_len_transport_receive = 0; pico_ipv6_process_frag(hdr, c, TESTPROTO); fail_if(ipv6_cur_frag_id != IP6_FRAG_ID(hdr)); fail_if(timer_cancel_called != 1); fail_if(transport_recv_called != 1); fail_if(buffer_len_transport_receive != 96 + PICO_SIZE_IP6HDR); /* Everything was received, tree should be empty */ fail_if(!pico_tree_empty(&ipv6_fragments)); /* Cleanup */ pico_fragments_empty_tree(&ipv6_fragments); pico_frame_discard(a); pico_frame_discard(b); pico_frame_discard(c); } END_TEST START_TEST(tc_pico_ipv4_process_frag) { struct pico_ipv4_hdr *hdr = NULL; struct pico_frame *a = NULL, *b = NULL, *c = NULL; /* NULL args provided */ ipv4_cur_frag_id = 0; timer_add_called = 0; pico_ipv4_process_frag(hdr, a, TESTPROTO); fail_if(ipv4_cur_frag_id != 0); fail_if(timer_add_called != 0); /* init hdr */ hdr = PICO_ZALLOC(sizeof(struct pico_ipv4_hdr)); hdr->id = TESTID; /* NULL frame provided */ ipv4_cur_frag_id = 0; timer_add_called = 0; pico_ipv4_process_frag(hdr, a, TESTPROTO); fail_if(ipv4_cur_frag_id != 0); fail_if(timer_add_called != 0); /* init frame */ a = pico_frame_alloc(32 + 20); fail_if(!a); printf("Allocated frame, %p\n", a); b = pico_frame_alloc(32 + 20); fail_if(!b); printf("Allocated frame, %p\n", b); c = pico_frame_alloc(64 + 20); fail_if(!c); printf("Allocated frame, %p\n", c); a->net_hdr = a->buffer; a->net_len = 20; a->transport_len = 32; a->transport_hdr = a->buffer + 20; a->frag = PICO_IPV4_MOREFRAG; /* more frags */ b->net_hdr = b->buffer; b->net_len = 20; b->transport_len = 32; b->transport_hdr = b->buffer + 20; b->frag = 0x20 >> 3u | PICO_IPV4_MOREFRAG; /* off = 32 + more frags*/ c->net_hdr = c->buffer; c->net_len = 20; c->transport_len = 32; c->transport_hdr = c->buffer + 20; c->frag = 0x40 >> 3u; /* off = 64 */ /* Case 1: Empty fragments tree */ ipv4_cur_frag_id = 0; timer_add_called = 0; /* make sure tree is empty */ fail_if(!pico_tree_empty(&ipv4_fragments)); pico_ipv4_process_frag(hdr, a, TESTPROTO); fail_if(ipv4_cur_frag_id != TESTID); fail_if(timer_add_called != 1); fail_if(pico_tree_empty(&ipv4_fragments)); /* make sure we added the fragment to the tree */ fail_if(((struct pico_frame *)pico_tree_first(&ipv4_fragments))->buffer != a->buffer); /* Case 2: Adding second fragment */ timer_add_called = 0; pico_ipv4_process_frag(hdr, b, TESTPROTO); fail_if(ipv4_cur_frag_id != TESTID); fail_if(timer_add_called != 0); fail_if(pico_tree_empty(&ipv4_fragments)); /* make sure we added the fragment to the tree */ fail_if(((struct pico_frame *)pico_tree_last(&ipv4_fragments))->buffer != b->buffer); /* Case 3: Adding final fragment */ timer_cancel_called = 0; transport_recv_called = 0; buffer_len_transport_receive = 0; pico_ipv4_process_frag(hdr, c, TESTPROTO); fail_if(ipv4_cur_frag_id != TESTID); fail_if(timer_cancel_called != 1); fail_if(transport_recv_called != 1); fail_if(buffer_len_transport_receive != 96 + PICO_SIZE_IP4HDR); /* Everything was received, tree should be empty */ fail_if(!pico_tree_empty(&ipv4_fragments)); /* Cleanup */ pico_fragments_empty_tree(&ipv4_fragments); pico_frame_discard(a); pico_frame_discard(b); pico_frame_discard(c); } END_TEST Suite *pico_suite(void) { Suite *s = suite_create("PicoTCP"); TCase *TCase_pico_ipv6_process_frag = tcase_create("Unit test for pico_ipv6_process_frag"); TCase *TCase_pico_ipv4_process_frag = tcase_create("Unit test for pico_ipv4_process_frag"); TCase *TCase_pico_fragments_reassemble = tcase_create("Unit test for pico_fragments_reassemble"); TCase *TCase_pico_fragments_get_offset = tcase_create("Unit test for pico_fragments_get_offset"); TCase *TCase_pico_fragments_get_more_flag = tcase_create("Unit test for pico_fragments_get_more_flag"); TCase *TCase_pico_fragments_get_header_length = tcase_create("Unit test for pico_fragments_get_header_length"); TCase *TCase_pico_fragments_empty_tree = tcase_create("Unit test for pico_fragments_empty_tree"); TCase *TCase_pico_fragments_send_notify = tcase_create("Unit test for pico_fragments_send_notify"); TCase *TCase_pico_ipv6_frag_compare = tcase_create("Unit test for pico_ipv6_frag_compare"); TCase *TCase_pico_ipv4_frag_compare = tcase_create("Unit test for pico_ipv4_frag_compare"); TCase *TCase_pico_ipv6_fragments_complete = tcase_create("Unit test for pico_ipv6_fragments_complete"); TCase *TCase_pico_ipv4_fragments_complete = tcase_create("Unit test for pico_ipv4_fragments_complete"); TCase *TCase_pico_fragments_complete = tcase_create("Unit test for pico_fragments_complete"); TCase *TCase_pico_fragments_check_complete = tcase_create("Unit test for pico_fragments_check_complete"); TCase *TCase_pico_frag_expire = tcase_create("Unit test for pico_frag_expire"); TCase *TCase_pico_ipv6_frag_timer_on = tcase_create("Unit test for pico_ipv6_frag_timer_on"); TCase *TCase_pico_ipv4_frag_timer_on = tcase_create("Unit test for pico_ipv4_frag_timer_on"); TCase *TCase_pico_ipv6_frag_match = tcase_create("Unit test for pico_ipv6_frag_match"); TCase *TCase_pico_ipv4_frag_match = tcase_create("Unit test for pico_ipv4_frag_match"); tcase_add_test(TCase_pico_ipv4_process_frag, tc_pico_ipv4_process_frag); suite_add_tcase(s, TCase_pico_ipv4_process_frag); tcase_add_test(TCase_pico_ipv6_process_frag, tc_pico_ipv6_process_frag); suite_add_tcase(s, TCase_pico_ipv6_process_frag); tcase_add_test(TCase_pico_fragments_reassemble, tc_pico_fragments_reassemble); suite_add_tcase(s, TCase_pico_fragments_reassemble); tcase_add_test(TCase_pico_fragments_get_offset, tc_pico_fragments_get_offset); suite_add_tcase(s, TCase_pico_fragments_get_offset); tcase_add_test(TCase_pico_fragments_get_more_flag, tc_pico_fragments_get_more_flag); suite_add_tcase(s, TCase_pico_fragments_get_more_flag); tcase_add_test(TCase_pico_fragments_get_header_length, tc_pico_fragments_get_header_length); suite_add_tcase(s, TCase_pico_fragments_get_header_length); tcase_add_test(TCase_pico_fragments_send_notify, tc_pico_fragments_send_notify); suite_add_tcase(s, TCase_pico_fragments_send_notify); tcase_add_test(TCase_pico_fragments_empty_tree, tc_pico_fragments_empty_tree); suite_add_tcase(s, TCase_pico_fragments_empty_tree); tcase_add_test(TCase_pico_ipv6_frag_compare, tc_pico_ipv6_frag_compare); suite_add_tcase(s, TCase_pico_ipv6_frag_compare); tcase_add_test(TCase_pico_ipv4_frag_compare, tc_pico_ipv4_frag_compare); suite_add_tcase(s, TCase_pico_ipv4_frag_compare); tcase_add_test(TCase_pico_ipv6_fragments_complete, tc_pico_ipv6_fragments_complete); suite_add_tcase(s, TCase_pico_ipv6_fragments_complete); tcase_add_test(TCase_pico_ipv4_fragments_complete, tc_pico_ipv4_fragments_complete); suite_add_tcase(s, TCase_pico_ipv4_fragments_complete); tcase_add_test(TCase_pico_fragments_complete, tc_pico_fragments_complete); suite_add_tcase(s, TCase_pico_fragments_complete); tcase_add_test(TCase_pico_fragments_check_complete, tc_pico_fragments_check_complete); suite_add_tcase(s, TCase_pico_fragments_check_complete); tcase_add_test(TCase_pico_frag_expire, tc_pico_frag_expire); suite_add_tcase(s, TCase_pico_frag_expire); tcase_add_test(TCase_pico_ipv6_frag_timer_on, tc_pico_ipv6_frag_timer_on); suite_add_tcase(s, TCase_pico_ipv6_frag_timer_on); tcase_add_test(TCase_pico_ipv4_frag_timer_on, tc_pico_ipv4_frag_timer_on); suite_add_tcase(s, TCase_pico_ipv4_frag_timer_on); tcase_add_test(TCase_pico_ipv6_frag_match, tc_pico_ipv6_frag_match); suite_add_tcase(s, TCase_pico_ipv6_frag_match); tcase_add_test(TCase_pico_ipv4_frag_match, tc_pico_ipv4_frag_match); suite_add_tcase(s, TCase_pico_ipv4_frag_match); return s; } int main(void) { int fails; Suite *s = pico_suite(); SRunner *sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); fails = srunner_ntests_failed(sr); srunner_free(sr); return fails; }