static int TCPGetSackTest01(void)
{
    int retval = 0;
    static uint8_t raw_tcp[] = {
        0x00, 0x50, 0x06, 0xa6, 0xfa, 0x87, 0x0b, 0xf5,
        0xf1, 0x59, 0x02, 0xe0, 0xa0, 0x10, 0x3e, 0xbc,
        0x1d, 0xe7, 0x00, 0x00, 0x01, 0x01, 0x05, 0x12,
        0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64,
        0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 };
    static uint8_t raw_tcp_sack[] = {
        0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64,
        0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 };
    Packet *p = PacketGetFromAlloc();
    if (unlikely(p == NULL))
        return 0;
    IPV4Hdr ip4h;
    ThreadVars tv;
    DecodeThreadVars dtv;

    memset(&tv, 0, sizeof(ThreadVars));
    memset(&dtv, 0, sizeof(DecodeThreadVars));
    memset(&ip4h, 0, sizeof(IPV4Hdr));

    p->src.family = AF_INET;
    p->dst.family = AF_INET;
    p->ip4h = &ip4h;

    FlowInitConfig(FLOW_QUIET);
    DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp));

    if (p->tcph == NULL) {
        printf("tcp packet decode failed: ");
        goto end;
    }

    if (!TCP_HAS_SACK(p)) {
        printf("tcp packet sack not decoded: ");
        goto end;
    }

    int sack = TCP_GET_SACK_CNT(p);
    if (sack != 2) {
        printf("expected 2 sack records, got %u: ", TCP_GET_SACK_CNT(p));
        goto end;
    }

    const uint8_t *sackptr = TCP_GET_SACK_PTR(p);
    if (sackptr == NULL) {
        printf("no sack data: ");
        goto end;
    }

    if (memcmp(sackptr, raw_tcp_sack, 16) != 0) {
        printf("malformed sack data: ");
        goto end;
    }

    retval = 1;
end:
    PACKET_RECYCLE(p);
    FlowShutdown();
    SCFree(p);
    return retval;
}
static int TCPGetSackTest01(void)
{
    int retval = 0;
    static uint8_t raw_tcp[] = {
        0x00, 0x50, 0x06, 0xa6, 0xfa, 0x87, 0x0b, 0xf5,
        0xf1, 0x59, 0x02, 0xe0, 0xa0, 0x10, 0x3e, 0xbc,
        0x1d, 0xe7, 0x00, 0x00, 0x01, 0x01, 0x05, 0x12,
        0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64,
        0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 };
    static uint8_t raw_tcp_sack[] = {
        0xf1, 0x59, 0x13, 0xfc, 0xf1, 0x59, 0x1f, 0x64,
        0xf1, 0x59, 0x08, 0x94, 0xf1, 0x59, 0x0e, 0x48 };
    Packet *p = PacketGetFromAlloc();
    if (unlikely(p == NULL))
        return 0;
    IPV4Hdr ip4h;
    ThreadVars tv;
    DecodeThreadVars dtv;

    memset(&tv, 0, sizeof(ThreadVars));
    memset(&dtv, 0, sizeof(DecodeThreadVars));
    memset(&ip4h, 0, sizeof(IPV4Hdr));

    p->src.family = AF_INET;
    p->dst.family = AF_INET;
    p->ip4h = &ip4h;

    FlowInitConfig(FLOW_QUIET);
    DecodeTCP(&tv, &dtv, p, raw_tcp, sizeof(raw_tcp));

    if (p->tcph == NULL) {
        printf("tcp packet decode failed: ");
        goto end;
    }

    if (!TCP_HAS_SACK(p)) {
        printf("tcp packet sack not decoded: ");
        goto end;
    }

    int sack = TCP_GET_SACK_CNT(p);
    if (sack != 2) {
        printf("expected 2 sack records, got %u: ", TCP_GET_SACK_CNT(p));
        goto end;
    }

    const uint8_t *sackptr = TCP_GET_SACK_PTR(p);
    if (sackptr == NULL) {
        printf("no sack data: ");
        goto end;
    }

    if (memcmp(sackptr, raw_tcp_sack, 16) != 0) {
        printf("malformed sack data: ");
        goto end;
    }

    retval = 1;
end:
    PACKET_RECYCLE(p);
    FlowShutdown();
    SCFree(p);
    return retval;
}