#include "gtest_utils.h"

/*
 * Frame 4: 60 bytes on wire (480 bits), 60 bytes captured (480 bits)
 * Ethernet II, Src: Fortinet_cc:87:22 (e8:1c:ba:cc:87:22), Dst: EvocInte_2f:35:b8 (00:22:46:2f:35:b8)
 *     Destination: EvocInte_2f:35:b8 (00:22:46:2f:35:b8)
 *         Address: EvocInte_2f:35:b8 (00:22:46:2f:35:b8)
 *         .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
 *         .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
 *     Source: Fortinet_cc:87:22 (e8:1c:ba:cc:87:22)
 *         Address: Fortinet_cc:87:22 (e8:1c:ba:cc:87:22)
 *         .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
 *         .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
 *     Type: IPv4 (0x0800)
 *     Padding: 0000
 * Internet Protocol Version 4, Src: 192.168.36.103, Dst: 192.168.40.137
 *     0100 .... = Version: 4
 *     .... 0101 = Header Length: 20 bytes (5)
 *     Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
 *         0000 00.. = Differentiated Services Codepoint: Default (0)
 *         .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
 *     Total Length: 44
 *     Identification: 0xffff (65535)
 *     001. .... = Flags: 0x1, More fragments
 *         0... .... = Reserved bit: Not set
 *         .0.. .... = Don't fragment: Not set
 *         ..1. .... = More fragments: Set
 *     ...0 0000 0000 0000 = Fragment Offset: 0
 *     Time to Live: 127
 *     Protocol: TCP (6)
 *     Header Checksum: 0x4d8b [correct]
 *     [Header checksum status: Good]
 *     [Calculated Checksum: 0x4d8b]
 *     Source Address: 192.168.36.103
 *     Destination Address: 192.168.40.137
 *     [Reassembled IPv4 in frame: 5]
 * Data (24 bytes)
 *     Data: f4a5270f9107248703d518e75018ff005e9200003132330a
 *     [Length: 24]
 */

unsigned char frag1[] = {
    /* ETH */
    0x00, 0x22, 0x46, 0x2f, 0x35, 0xb8, 0xe8, 0x1c, 0xba, 0xcc, 0x87, 0x22, 0x08, 0x00,
    /* IP */
    0x45, 0x00,             // version & hdr len & tos
    0x00, 0x2c,             // total length
    0xff, 0xff,             // ip id
    0x20, 0x00,             // flags & frag offset
    0x7f, 0x06,             // ttl & protocol
    0x4d, 0x8b,             // checksum
    0xc0, 0xa8, 0x24, 0x67, // src addr
    0xc0, 0xa8, 0x28, 0x89, // dst addr
    /* TCP */
    0xf4, 0xa5,             // src port
    0x27, 0x0f,             // dst port
    0x91, 0x07, 0x24, 0x87, // seq
    0x03, 0xd5, 0x18, 0xe7, // ack
    0x50, 0x18,             // data offset & flags
    0xff, 0x00,             // windows
    0x5e, 0x92,             // checksum
    0x00, 0x00,             // urgent pointer
    /* DATA */
    0x31, 0x32, 0x33, 0x0a,
    /* Padding */
    0x00, 0x00};

/*
 * Frame 5: 60 bytes on wire (480 bits), 60 bytes captured (480 bits)
 * Ethernet II, Src: Fortinet_cc:87:22 (e8:1c:ba:cc:87:22), Dst: EvocInte_2f:35:b8 (00:22:46:2f:35:b8)
 *     Destination: EvocInte_2f:35:b8 (00:22:46:2f:35:b8)
 *         Address: EvocInte_2f:35:b8 (00:22:46:2f:35:b8)
 *         .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
 *         .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
 *     Source: Fortinet_cc:87:22 (e8:1c:ba:cc:87:22)
 *         Address: Fortinet_cc:87:22 (e8:1c:ba:cc:87:22)
 *         .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
 *         .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
 *     Type: IPv4 (0x0800)
 *     Padding: 0000
 * Internet Protocol Version 4, Src: 192.168.36.103, Dst: 192.168.40.137
 *     0100 .... = Version: 4
 *     .... 0101 = Header Length: 20 bytes (5)
 *     Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
 *         0000 00.. = Differentiated Services Codepoint: Default (0)
 *         .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
 *     Total Length: 44
 *     Identification: 0xffff (65535)
 *     000. .... = Flags: 0x0
 *         0... .... = Reserved bit: Not set
 *         .0.. .... = Don't fragment: Not set
 *         ..0. .... = More fragments: Not set
 *     ...0 0000 0000 0011 = Fragment Offset: 24
 *     Time to Live: 127
 *     Protocol: TCP (6)
 *     Header Checksum: 0x6d88 [correct]
 *     [Header checksum status: Good]
 *     [Calculated Checksum: 0x6d88]
 *     Source Address: 192.168.36.103
 *     Destination Address: 192.168.40.137
 *     [2 IPv4 Fragments (48 bytes): #4(24), #5(24)]
 *         [Frame: 4, payload: 0-23 (24 bytes)]
 *         [Frame: 5, payload: 24-47 (24 bytes)]
 *         [Fragment count: 2]
 *         [Reassembled IPv4 length: 48]
 *         [Reassembled IPv4 data: f4a5270f9107248703d518e75018ff005e9200003132330af4a5270f9107248b03d518e7…]
 * Transmission Control Protocol, Src Port: 62629, Dst Port: 9999, Seq: 1, Ack: 1, Len: 28
 *     Source Port: 62629
 *     Destination Port: 9999
 *     [Stream index: 0]
 *     [Conversation completeness: Complete, WITH_DATA (31)]
 *     [TCP Segment Len: 28]
 *     Sequence Number: 1    (relative sequence number)
 *     Sequence Number (raw): 2433164423
 *     [Next Sequence Number: 29    (relative sequence number)]
 *     Acknowledgment Number: 1    (relative ack number)
 *     Acknowledgment number (raw): 64297191
 *     0101 .... = Header Length: 20 bytes (5)
 *     Flags: 0x018 (PSH, ACK)
 *         000. .... .... = Reserved: Not set
 *         ...0 .... .... = Accurate ECN: Not set
 *         .... 0... .... = Congestion Window Reduced: Not set
 *         .... .0.. .... = ECN-Echo: Not set
 *         .... ..0. .... = Urgent: Not set
 *         .... ...1 .... = Acknowledgment: Set
 *         .... .... 1... = Push: Set
 *         .... .... .0.. = Reset: Not set
 *         .... .... ..0. = Syn: Not set
 *         .... .... ...0 = Fin: Not set
 *         [TCP Flags: ·······AP···]
 *     Window: 65280
 *     [Calculated window size: 65280]
 *     [Window size scaling factor: -2 (no window scaling used)]
 *     Checksum: 0x5e92 [correct]
 *     [Checksum Status: Good]
 *     [Calculated Checksum: 0x5e92]
 *     Urgent Pointer: 0
 *     [Timestamps]
 *         [Time since first frame in this TCP stream: 6.525912000 seconds]
 *         [Time since previous frame in this TCP stream: 6.525083000 seconds]
 *     [SEQ/ACK analysis]
 *         [iRTT: 0.000829000 seconds]
 *         [Bytes in flight: 28]
 *         [Bytes sent since last PSH flag: 28]
 *     TCP payload (28 bytes)
 * Data (28 bytes)
 *     Data: 3132330af4a5270f9107248b03d518e75018ff00301600006162630a
 *     [Length: 28]
 */

unsigned char frag2[] = {
    /* ETH */
    0x00, 0x22, 0x46, 0x2f, 0x35, 0xb8, 0xe8, 0x1c, 0xba, 0xcc, 0x87, 0x22, 0x08, 0x00,
    /* IP */
    0x45, 0x00,             // version & hdr len & tos
    0x00, 0x2c,             // total length
    0xff, 0xff,             // ip id
    0x00, 0x03,             // flags & frag offset
    0x7f, 0x06,             // ttl & protocol
    0x6d, 0x88,             // checksum
    0xc0, 0xa8, 0x24, 0x67, // src addr
    0xc0, 0xa8, 0x28, 0x89, // dst addr
    /* DATA */
    0xf4, 0xa5, 0x27, 0x0f, 0x91, 0x07, 0x24, 0x8b, 0x03, 0xd5, 0x18, 0xe7, 0x50, 0x18, 0xff, 0x00, 0x30, 0x16, 0x00, 0x00, 0x61, 0x62, 0x63, 0x0a,
    /* Padding */
    0x00, 0x00};

unsigned char expect[] = {
    /* ETH */
    0x00, 0x22, 0x46, 0x2f, 0x35, 0xb8, 0xe8, 0x1c, 0xba, 0xcc, 0x87, 0x22, 0x08, 0x00,
    /* IP */
    0x45, 0x00,             // version & hdr len & tos
    0x00, 0x44,             // total length         --------- need update ---------
    0xff, 0xff,             // ip id
    0x00, 0x00,             // flags & frag offset  --------- need update ---------
    0x7f, 0x06,             // ttl & protocol
    0x6d, 0x73,             // checksum             --------- need update ---------
    0xc0, 0xa8, 0x24, 0x67, // src addr
    0xc0, 0xa8, 0x28, 0x89, // dst addr
    /* TCP */
    0xf4, 0xa5,             // src port
    0x27, 0x0f,             // dst port
    0x91, 0x07, 0x24, 0x87, // seq
    0x03, 0xd5, 0x18, 0xe7, // ack
    0x50, 0x18,             // data offset & flags
    0xff, 0x00,             // windows
    0x5e, 0x92,             // checksum
    0x00, 0x00,             // urgent pointer
    /* DATA */
    0x31, 0x32, 0x33, 0x0a,                                                                                                                        // data from frag1
    0xf4, 0xa5, 0x27, 0x0f, 0x91, 0x07, 0x24, 0x8b, 0x03, 0xd5, 0x18, 0xe7, 0x50, 0x18, 0xff, 0x00, 0x30, 0x16, 0x00, 0x00, 0x61, 0x62, 0x63, 0x0a // data from frag2
};

#if 1
TEST(IPV4_REASSEMBLE, PADDING_ORDER)
{
    struct packet pkt;
    struct packet *new_pkt;
    const struct layer_private *layer;
    struct ip_reassembly *assy;
    struct ip_reassembly_options opts = {
        .enable = true,
        .timeout = 1,
        .bucket_entries = 16,
        .bucket_num = 8,
    };

    assy = ip_reassembly_new(&opts);
    EXPECT_TRUE(assy != NULL);

    check_stat(ip_reassembly_stat(assy),
               0, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag1
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               1, 0, 1, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag2
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt);

    check_stat(ip_reassembly_stat(assy),
               1, 1, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               2, 2, 2, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // check packet
    packet_print(new_pkt);
    EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
    EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);

    // check IPv4
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_IPV4);
    EXPECT_TRUE(layer);
    struct ip *hdr = (struct ip *)layer->hdr_ptr;
    EXPECT_TRUE(ip4_hdr_get_version(hdr) == 4);
    EXPECT_TRUE(ip4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
    EXPECT_TRUE(ip4_hdr_get_tos(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(ip4_hdr_get_ipid(hdr) == 0xffff);
    EXPECT_TRUE(ip4_hdr_get_flags(hdr) == 0x0);
    EXPECT_TRUE(ip4_hdr_get_frag_offset(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_ttl(hdr) == 127);
    EXPECT_TRUE(ip4_hdr_get_proto(hdr) == 6);
    EXPECT_TRUE(ip4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
    EXPECT_TRUE(ip4_hdr_get_src_addr(hdr) == 0xc0a82467);
    EXPECT_TRUE(ip4_hdr_get_dst_addr(hdr) == 0xc0a82889);
    EXPECT_TRUE(ip4_hdr_get_opt_len(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_opt_data(hdr) == NULL);

    // check TCP
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_TCP);
    EXPECT_TRUE(layer);
    struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
    EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
    EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
    EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
    EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
    EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
    EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
    EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
    EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
    EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);

    // free packet
    packet_free(new_pkt);

    ip_reassembly_free(assy);
}
#endif

#if 1
TEST(IPV4_REASSEMBLE, PADDING_UNORDER)
{
    struct packet pkt;
    struct packet *new_pkt;
    const struct layer_private *layer;
    struct ip_reassembly *assy;
    struct ip_reassembly_options opts = {
        .enable = true,
        .timeout = 1,
        .bucket_entries = 16,
        .bucket_num = 8,
    };

    assy = ip_reassembly_new(&opts);
    EXPECT_TRUE(assy != NULL);

    check_stat(ip_reassembly_stat(assy),
               0, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag2
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               1, 0, 1, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag1
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt);

    check_stat(ip_reassembly_stat(assy),
               1, 1, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               2, 2, 2, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // check packet
    packet_print(new_pkt);
    EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
    EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);

    // check IPv4
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_IPV4);
    EXPECT_TRUE(layer);
    struct ip *hdr = (struct ip *)layer->hdr_ptr;
    EXPECT_TRUE(ip4_hdr_get_version(hdr) == 4);
    EXPECT_TRUE(ip4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
    EXPECT_TRUE(ip4_hdr_get_tos(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(ip4_hdr_get_ipid(hdr) == 0xffff);
    EXPECT_TRUE(ip4_hdr_get_flags(hdr) == 0x0);
    EXPECT_TRUE(ip4_hdr_get_frag_offset(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_ttl(hdr) == 127);
    EXPECT_TRUE(ip4_hdr_get_proto(hdr) == 6);
    EXPECT_TRUE(ip4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
    EXPECT_TRUE(ip4_hdr_get_src_addr(hdr) == 0xc0a82467);
    EXPECT_TRUE(ip4_hdr_get_dst_addr(hdr) == 0xc0a82889);
    EXPECT_TRUE(ip4_hdr_get_opt_len(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_opt_data(hdr) == NULL);

    // check TCP
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_TCP);
    EXPECT_TRUE(layer);
    struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
    EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
    EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
    EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
    EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
    EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
    EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
    EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
    EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
    EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);

    // free packet
    packet_free(new_pkt);

    ip_reassembly_free(assy);
}
#endif

#if 1
TEST(IPV4_REASSEMBLE, EXPIRE)
{
    struct packet pkt;
    struct packet *new_pkt;
    struct ip_reassembly *assy;
    struct ip_reassembly_options opts = {
        .enable = true,
        .timeout = 1,
        .bucket_entries = 16,
        .bucket_num = 8,
    };

    assy = ip_reassembly_new(&opts);
    EXPECT_TRUE(assy != NULL);

    check_stat(ip_reassembly_stat(assy),
               0, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag1
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               1, 0, 1, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag2
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
    new_pkt = ip_reassembly_packet(assy, &pkt, 2);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               2, 0, 1, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               2, 1, 2, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // free packet
    packet_free(new_pkt);

    ip_reassembly_free(assy);
}
#endif

#if 1
TEST(IPV4_REASSEMBLE, DUP_FIRST_FRAG)
{
    struct packet pkt;
    struct packet *new_pkt;
    const struct layer_private *layer;
    struct ip_reassembly *assy;
    struct ip_reassembly_options opts = {
        .enable = true,
        .timeout = 1,
        .bucket_entries = 16,
        .bucket_num = 8,
    };

    assy = ip_reassembly_new(&opts);
    EXPECT_TRUE(assy != NULL);

    check_stat(ip_reassembly_stat(assy),
               0, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag1
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               1, 0, 1, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag1
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               2, 0, 1, 0, 1, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag2
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt);

    check_stat(ip_reassembly_stat(assy),
               1, 1, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               3, 2, 2, 0, 1, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // check packet
    packet_print(new_pkt);
    EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
    EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);

    // check IPv4
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_IPV4);
    EXPECT_TRUE(layer);
    struct ip *hdr = (struct ip *)layer->hdr_ptr;
    EXPECT_TRUE(ip4_hdr_get_version(hdr) == 4);
    EXPECT_TRUE(ip4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
    EXPECT_TRUE(ip4_hdr_get_tos(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(ip4_hdr_get_ipid(hdr) == 0xffff);
    EXPECT_TRUE(ip4_hdr_get_flags(hdr) == 0x0);
    EXPECT_TRUE(ip4_hdr_get_frag_offset(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_ttl(hdr) == 127);
    EXPECT_TRUE(ip4_hdr_get_proto(hdr) == 6);
    EXPECT_TRUE(ip4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
    EXPECT_TRUE(ip4_hdr_get_src_addr(hdr) == 0xc0a82467);
    EXPECT_TRUE(ip4_hdr_get_dst_addr(hdr) == 0xc0a82889);
    EXPECT_TRUE(ip4_hdr_get_opt_len(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_opt_data(hdr) == NULL);

    // check TCP
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_TCP);
    EXPECT_TRUE(layer);
    struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
    EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
    EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
    EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
    EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
    EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
    EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
    EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
    EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
    EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);

    // free packet
    packet_free(new_pkt);

    ip_reassembly_free(assy);
}
#endif

#if 1
TEST(IPV4_REASSEMBLE, DUP_LAST_FRAG)
{
    struct packet pkt;
    struct packet *new_pkt;
    const struct layer_private *layer;
    struct ip_reassembly *assy;
    struct ip_reassembly_options opts = {
        .enable = true,
        .timeout = 1,
        .bucket_entries = 16,
        .bucket_num = 8,
    };

    assy = ip_reassembly_new(&opts);
    EXPECT_TRUE(assy != NULL);

    check_stat(ip_reassembly_stat(assy),
               0, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag2
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               1, 0, 1, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag2
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               2, 0, 1, 0, 0, 1,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // frag1
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt);

    check_stat(ip_reassembly_stat(assy),
               1, 1, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               3, 2, 2, 0, 0, 1,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // check packet
    packet_print(new_pkt);
    EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
    EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);

    // check IPv4
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_IPV4);
    EXPECT_TRUE(layer);
    struct ip *hdr = (struct ip *)layer->hdr_ptr;
    EXPECT_TRUE(ip4_hdr_get_version(hdr) == 4);
    EXPECT_TRUE(ip4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
    EXPECT_TRUE(ip4_hdr_get_tos(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
    EXPECT_TRUE(ip4_hdr_get_ipid(hdr) == 0xffff);
    EXPECT_TRUE(ip4_hdr_get_flags(hdr) == 0x0);
    EXPECT_TRUE(ip4_hdr_get_frag_offset(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_ttl(hdr) == 127);
    EXPECT_TRUE(ip4_hdr_get_proto(hdr) == 6);
    EXPECT_TRUE(ip4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
    EXPECT_TRUE(ip4_hdr_get_src_addr(hdr) == 0xc0a82467);
    EXPECT_TRUE(ip4_hdr_get_dst_addr(hdr) == 0xc0a82889);
    EXPECT_TRUE(ip4_hdr_get_opt_len(hdr) == 0);
    EXPECT_TRUE(ip4_hdr_get_opt_data(hdr) == NULL);

    // check TCP
    layer = packet_get_innermost_layer(new_pkt, LAYER_PROTO_TCP);
    EXPECT_TRUE(layer);
    struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
    EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
    EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
    EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
    EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
    EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
    EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
    EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
    EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
    EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
    EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);

    // free packet
    packet_free(new_pkt);

    ip_reassembly_free(assy);
}
#endif

#if 1
TEST(IPV4_REASSEMBLE, FULL)
{
    struct packet pkt;
    struct packet *new_pkt;
    struct ip_reassembly *assy;
    struct ip_reassembly_options opts = {
        .enable = true,
        .timeout = 1,
        .bucket_entries = 1,
        .bucket_num = 1,
    };

    assy = ip_reassembly_new(&opts);
    EXPECT_TRUE(assy != NULL);

    check_stat(ip_reassembly_stat(assy),
               0, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    char dup_frag[sizeof(frag1)] = {0};
    memcpy(dup_frag, frag1, sizeof(frag1));
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)dup_frag, sizeof(dup_frag));

    // flow1
    packet_set_ipv4_src_addr(&pkt, 1);
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               1, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               1, 0, 1, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // flow2
    packet_set_ipv4_src_addr(&pkt, 2);
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               2, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               2, 0, 2, 0, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // flow3
    packet_set_ipv4_src_addr(&pkt, 3);
    new_pkt = ip_reassembly_packet(assy, &pkt, 1);
    EXPECT_TRUE(new_pkt == NULL);

    check_stat(ip_reassembly_stat(assy),
               2, 0, 0, 0, 0, 0,  // ip4: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               3, 0, 2, 1, 0, 0,  // ip4: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag
               0, 0, 0, 0, 0, 0,  // ip6: defrags_expected, defrags_succeed, defrags_failed_timeout, defrags_failed_invalid_length, defrags_failed_overlap, defrags_failed_too_many_frag
               0, 0, 0, 0, 0, 0); // ip6: frags, frags_freed, frags_buffered, frags_bypass_no_buffer, frags_bypass_dup_fist_frag, frags_bypass_dup_last_frag

    // free packet
    packet_free(new_pkt);

    ip_reassembly_free(assy);
}
#endif

#if 1
TEST(IPV4_REASSEMBLE, OVERLAP)
{
    // TEST ON IPv6
}
#endif

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
