]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tcp: streaming implementation
authorVictor Julien <victor@inliniac.net>
Tue, 22 Dec 2015 09:26:04 +0000 (10:26 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 20 Apr 2017 15:41:11 +0000 (17:41 +0200)
Make stream engine use the streaming buffer API for it's data storage.

This means that the data is stored in a single reassembled sliding
buffer. The subleties of the reassembly, e.g. overlap handling, are
taken care of at segment insertion.

The TcpSegments now have a StreamingBufferSegment that contains an
offset and a length. Using this the segment data can be retrieved
per segment.

Redo segment insertion. The insertion code is moved to it's own file
and is simplified a lot.

A major difference with the previous implementation is that the segment
list now contains overlapping segments if the traffic is that way.
Previously there could be more and smaller segments in the memory list
than what was seen on the wire.

Due to the matching of in memory segments and on the wire segments,
the overlap with different data detection (potential mots attacks)
is much more accurate.

Raw and App reassembly progress is no longer tracked per segment using
flags, but there is now a progress tracker in the TcpStream for each.

When pruning we make sure we don't slide beyond in-use segments. When
both app-layer and raw inspection are beyond the start of the segment
list, the segments might not be freed even though the data in the
streaming buffer is already gone. This is caused by the 'in-use' status
that the segments can implicitly have. This patch accounts for that
when calculating the 'left_edge' of the streaming window.

Raw reassembly still sets up 'StreamMsg' objects for content
inspection. They are set up based on either the full StreamingBuffer,
or based on the StreamingBufferBlocks if there are gaps in the data.

Reworked 'stream needs work' logic. When a flow times out the flow
engine checks whether a TCP flow still needs work. The
StreamNeedsReassembly function is used to test if a stream still has
unreassembled segments or uninspected stream chunks.

This patch updates the function to consider the app and/or raw
progress. It also cleans the function up and adds more meaningful
debug messages. Finally it makes it non-inline.

Unittests have been overhauled, and partly moved into their own files.

Remove lots of dead code.

17 files changed:
src/Makefile.am
src/detect.c
src/flow-manager.c
src/flow-timeout.c
src/output-streaming.c
src/stream-tcp-inline.c
src/stream-tcp-inline.h
src/stream-tcp-list.c [new file with mode: 0644]
src/stream-tcp-list.h [new file with mode: 0644]
src/stream-tcp-private.h
src/stream-tcp-reassemble.c
src/stream-tcp-reassemble.h
src/stream-tcp-util.c
src/stream-tcp-util.h
src/stream-tcp.c
src/stream-tcp.h
src/tests/stream-tcp-list.c [new file with mode: 0644]

index a67d5761f4b4ca1f4ed314d29b7f1608dc0d709d..8dcb24585be51ccf33199dbcc3731459cbadd249 100644 (file)
@@ -337,6 +337,7 @@ source-pfring.c source-pfring.h \
 stream.c stream.h \
 stream-tcp.c stream-tcp.h stream-tcp-private.h \
 stream-tcp-inline.c stream-tcp-inline.h \
+stream-tcp-list.c stream-tcp-list.h \
 stream-tcp-reassemble.c stream-tcp-reassemble.h \
 stream-tcp-sack.c stream-tcp-sack.h \
 stream-tcp-util.c stream-tcp-util.h \
index 728c5c5bbfd6f09645151c2a47043bf6a9bdffea..6edede544241be6f7f6fdfa1d8d5327016f5e6ed 100644 (file)
@@ -665,6 +665,8 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
                 ssn->toserver_smsg_tail = NULL;
 
                 SCLogDebug("to_server smsg %p at stream eof", smsg);
+                if (smsg)
+                    SCLogDebug("to_server smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
             } else {
                 smsg = ssn->toclient_smsg_head;
                 /* deref from the ssn */
@@ -672,6 +674,8 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
                 ssn->toclient_smsg_tail = NULL;
 
                 SCLogDebug("to_client smsg %p at stream eof", smsg);
+                if (smsg)
+                    SCLogDebug("to_client smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
             }
         } else {
             if (p->flowflags & FLOW_PKT_TOSERVER) {
@@ -694,7 +698,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
                 ssn->toserver_smsg_head = NULL;
                 ssn->toserver_smsg_tail = NULL;
 
-                SCLogDebug("to_server smsg %p", smsg);
+                SCLogDebug("to_server smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
             } else {
                 StreamMsg *head = ssn->toclient_smsg_head;
                 if (unlikely(head == NULL))
@@ -713,12 +717,22 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
                 ssn->toclient_smsg_head = NULL;
                 ssn->toclient_smsg_tail = NULL;
 
-                SCLogDebug("to_client smsg %p", smsg);
+                SCLogDebug("to_client smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
             }
         }
     }
 
 end:
+#ifdef DEBUG
+    if (SCLogDebugEnabled()) {
+        StreamMsg *m = smsg;
+        while(m) {
+            SCLogDebug("m %p size %u, SEQ %u", m, m->data_len, m->seq);
+            PrintRawDataFp(stdout, m->data, m->data_len);
+            m = m->next;
+        }
+    }
+#endif
     SCReturnPtr(smsg, "StreamMsg");
 }
 
index 4f92ec2c12ad13470330b42248169d1c0ec3b6c4..2d0323707bc596083ffe97d10a3c8a7538c82d2c 100644 (file)
@@ -1200,7 +1200,6 @@ static int FlowMgrTest02 (void)
     struct timeval ts;
     TcpSegment seg;
     TcpStream client;
-    uint8_t payload[3] = {0x41, 0x41, 0x41};
 
     FlowQueueInit(&flow_spare_q);
 
@@ -1216,8 +1215,7 @@ static int FlowMgrTest02 (void)
     f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE;
 
     TimeGet(&ts);
-    seg.payload = payload;
-    seg.payload_len = 3;
+    TCP_SEG_LEN(&seg) = 3;
     seg.next = NULL;
     seg.prev = NULL;
     client.seg_list = &seg;
@@ -1308,7 +1306,6 @@ static int FlowMgrTest04 (void)
     struct timeval ts;
     TcpSegment seg;
     TcpStream client;
-    uint8_t payload[3] = {0x41, 0x41, 0x41};
 
     FlowQueueInit(&flow_spare_q);
 
@@ -1324,8 +1321,7 @@ static int FlowMgrTest04 (void)
     f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE;
 
     TimeGet(&ts);
-    seg.payload = payload;
-    seg.payload_len = 3;
+    TCP_SEG_LEN(&seg) = 3;
     seg.next = NULL;
     seg.prev = NULL;
     client.seg_list = &seg;
index eb1400022f894dd3abd8a5e95df8913d699544a8..7daf316b5213a0d206c4243b0683dbe9893c8679 100644 (file)
@@ -220,7 +220,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p,
         } else {
             p->tcph->th_seq = htonl(ssn->client.next_seq);
             p->tcph->th_ack = htonl(ssn->server.seg_list_tail->seq +
-                                    ssn->server.seg_list_tail->payload_len);
+                                    TCP_SEG_LEN(ssn->server.seg_list_tail));
         }
 
         /* to client */
@@ -234,7 +234,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p,
         } else {
             p->tcph->th_seq = htonl(ssn->server.next_seq);
             p->tcph->th_ack = htonl(ssn->client.seg_list_tail->seq +
-                                    ssn->client.seg_list_tail->payload_len);
+                                    TCP_SEG_LEN(ssn->client.seg_list_tail));
         }
     }
 
index aae5ec55013662b03cccfcff9c144e8f62b1db60..48c6abd57c0594556fa3e85b2d36f030aea98fe1 100644 (file)
@@ -266,7 +266,7 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t
                 continue;
             }
 
-            if (SEQ_GT(seg->seq + seg->payload_len, stream->last_ack)) {
+            if (SEQ_GT(seg->seq + TCP_SEG_LEN(seg), stream->last_ack)) {
                 SCLogDebug("seg not (fully) acked yet");
                 break;
             }
@@ -278,7 +278,11 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t
             if (close && seg->next == NULL)
                 flags |= OUTPUT_STREAMING_FLAG_CLOSE;
 
-            Streamer(cbdata, f, seg->payload, (uint32_t)seg->payload_len, 0, flags);
+            const uint8_t *seg_data;
+            uint32_t seg_datalen;
+            StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
+
+            Streamer(cbdata, f, seg_data, seg_datalen, 0, flags);
 
             seg->flags |= SEGMENTTCP_FLAG_LOGAPI_PROCESSED;
 
index 97f8555d3c6518cf649bb373f6554cf21197091c..429a4ea85ae0247261eb84f66fec369f0d0b221d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2011 Open Information Security Foundation
+/* Copyright (C) 2007-2016 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -24,6 +24,7 @@
  */
 
 #include "suricata-common.h"
+#include "stream-tcp-private.h"
 #include "stream-tcp-inline.h"
 
 #include "util-memcmp.h"
@@ -57,66 +58,52 @@ int StreamTcpInlineMode(void)
  *  \retval 0 shared data is the same (or no data is shared)
  *  \retval 1 shared data is different
  */
-int StreamTcpInlineSegmentCompare(TcpSegment *seg1, TcpSegment *seg2)
+int StreamTcpInlineSegmentCompare(TcpStream *stream, Packet *p, TcpSegment *seg)
 {
     SCEnter();
 
-    if (seg1 == NULL || seg2 == NULL) {
+    if (p == NULL || seg == NULL) {
         SCReturnInt(0);
     }
 
-    if (SEQ_EQ(seg1->seq, seg2->seq) && seg1->payload_len == seg2->payload_len) {
-        int r = SCMemcmp(seg1->payload, seg2->payload, seg1->payload_len);
-#if 0
-        if (r) {
-            PrintRawDataFp(stdout,seg1->payload,seg1->payload_len);
-            PrintRawDataFp(stdout,seg2->payload,seg2->payload_len);
-        }
-#endif
+    const uint8_t *seg_data;
+    uint32_t seg_datalen;
+    StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
+
+    const uint32_t pkt_seq = TCP_GET_SEQ(p);
+
+    if (SEQ_EQ(pkt_seq, seg->seq) && p->payload_len == seg_datalen) {
+        int r = SCMemcmp(p->payload, seg_data, seg_datalen);
         SCReturnInt(r);
-    } else if (SEQ_GT(seg1->seq, (seg2->seq + seg2->payload_len))) {
+    } else if (SEQ_GT(pkt_seq, (seg->seq + seg_datalen))) {
         SCReturnInt(0);
-    } else if (SEQ_GT(seg2->seq, (seg1->seq + seg1->payload_len))) {
+    } else if (SEQ_GT(seg->seq, (pkt_seq + p->payload_len))) {
         SCReturnInt(0);
     } else {
-        SCLogDebug("seg1 %u (%u), seg2 %u (%u)", seg1->seq,
-                seg1->payload_len, seg2->seq, seg2->payload_len);
-
-        uint32_t seg1_end = seg1->seq + seg1->payload_len;
-        uint32_t seg2_end = seg2->seq + seg2->payload_len;
-        SCLogDebug("seg1_end %u, seg2_end %u", seg1_end, seg2_end);
-#if 0
-        SCLogDebug("seg1");
-        PrintRawDataFp(stdout,seg1->payload,seg1->payload_len);
-        SCLogDebug("seg2");
-        PrintRawDataFp(stdout,seg2->payload,seg2->payload_len);
-#endif
+        SCLogDebug("p %u (%u), seg2 %u (%u)", pkt_seq,
+                p->payload_len, seg->seq, seg_datalen);
+
+        uint32_t pkt_end = pkt_seq + p->payload_len;
+        uint32_t seg_end = seg->seq + seg_datalen;
+        SCLogDebug("pkt_end %u, seg_end %u", pkt_end, seg_end);
+
         /* get the minimal seg*_end */
-        uint32_t end = (SEQ_GT(seg1_end, seg2_end)) ? seg2_end : seg1_end;
+        uint32_t end = (SEQ_GT(pkt_end, seg_end)) ? seg_end : pkt_end;
         /* and the max seq */
-        uint32_t seq = (SEQ_LT(seg1->seq, seg2->seq)) ? seg2->seq : seg1->seq;
+        uint32_t seq = (SEQ_LT(pkt_seq, seg->seq)) ? seg->seq : pkt_seq;
 
         SCLogDebug("seq %u, end %u", seq, end);
 
-        uint16_t seg1_off = seq - seg1->seq;
-        uint16_t seg2_off = seq - seg2->seq;
-        SCLogDebug("seg1_off %u, seg2_off %u", seg1_off, seg2_off);
+        uint16_t pkt_off = seq - pkt_seq;
+        uint16_t seg_off = seq - seg->seq;
+        SCLogDebug("pkt_off %u, seg_off %u", pkt_off, seg_off);
 
         uint32_t range = end - seq;
         SCLogDebug("range %u", range);
         BUG_ON(range > 65536);
 
         if (range) {
-            int r = SCMemcmp(seg1->payload+seg1_off, seg2->payload+seg2_off, range);
-#if 0
-            if (r) {
-                PrintRawDataFp(stdout,seg1->payload+seg1_off,range);
-                PrintRawDataFp(stdout,seg2->payload+seg2_off,range);
-
-                PrintRawDataFp(stdout,seg1->payload,seg1->payload_len);
-                PrintRawDataFp(stdout,seg2->payload,seg2->payload_len);
-            }
-#endif
+            int r = SCMemcmp(p->payload + pkt_off, seg_data + seg_off, range);
             SCReturnInt(r);
         }
         SCReturnInt(0);
@@ -133,7 +120,7 @@ int StreamTcpInlineSegmentCompare(TcpSegment *seg1, TcpSegment *seg2)
  *  \todo What about reassembled fragments?
  *  \todo What about unwrapped tunnel packets?
  */
-void StreamTcpInlineSegmentReplacePacket(Packet *p, TcpSegment *seg)
+void StreamTcpInlineSegmentReplacePacket(TcpStream *stream, Packet *p, TcpSegment *seg)
 {
     SCEnter();
 
@@ -141,505 +128,169 @@ void StreamTcpInlineSegmentReplacePacket(Packet *p, TcpSegment *seg)
     uint32_t tseq = seg->seq;
 
     /* check if segment is within the packet */
-    if (tseq + seg->payload_len < pseq) {
+    if (tseq + TCP_SEG_LEN(seg) < pseq) {
         SCReturn;
     } else if (pseq + p->payload_len < tseq) {
         SCReturn;
-    } else {
-        /** \todo review logic */
-        uint32_t pend = pseq + p->payload_len;
-        uint32_t tend = tseq + seg->payload_len;
-        SCLogDebug("pend %u, tend %u", pend, tend);
+    }
 
-        //SCLogDebug("packet");
-        //PrintRawDataFp(stdout,p->payload,p->payload_len);
-        //SCLogDebug("seg");
-        //PrintRawDataFp(stdout,seg->payload,seg->payload_len);
+    const uint8_t *seg_data;
+    uint32_t seg_datalen;
+    StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
 
-        /* get the minimal seg*_end */
-        uint32_t end = (SEQ_GT(pend, tend)) ? tend : pend;
-        /* and the max seq */
-        uint32_t seq = (SEQ_LT(pseq, tseq)) ? tseq : pseq;
+    uint32_t pend = pseq + p->payload_len;
+    uint32_t tend = tseq + seg_datalen;
+    SCLogDebug("pend %u, tend %u", pend, tend);
 
-        SCLogDebug("seq %u, end %u", seq, end);
+    /* get the minimal seg*_end */
+    uint32_t end = (SEQ_GT(pend, tend)) ? tend : pend;
+    /* and the max seq */
+    uint32_t seq = (SEQ_LT(pseq, tseq)) ? tseq : pseq;
+    SCLogDebug("seq %u, end %u", seq, end);
 
-        uint16_t poff = seq - pseq;
-        uint16_t toff = seq - tseq;
-        SCLogDebug("poff %u, toff %u", poff, toff);
+    uint16_t poff = seq - pseq;
+    uint16_t toff = seq - tseq;
+    SCLogDebug("poff %u, toff %u", poff, toff);
 
-        uint32_t range = end - seq;
-        SCLogDebug("range %u", range);
-        BUG_ON(range > 65536);
+    uint32_t range = end - seq;
+    SCLogDebug("range %u", range);
+    BUG_ON(range > 65536);
 
-        if (range) {
-            /* update the packets payload. As payload is a ptr to either
-             * p->pkt or p->ext_pkt that is updated as well */
-            memcpy(p->payload+poff, seg->payload+toff, range);
+    if (range) {
+        /* update the packets payload. As payload is a ptr to either
+         * p->pkt or p->ext_pkt that is updated as well */
+        memcpy(p->payload+poff, seg_data+toff, range);
 
-            /* flag as modified so we can reinject / replace after
-             * recalculating the checksum */
-            p->flags |= PKT_STREAM_MODIFIED;
-        }
+        /* flag as modified so we can reinject / replace after
+         * recalculating the checksum */
+        p->flags |= PKT_STREAM_MODIFIED;
     }
 }
 
 #ifdef UNITTESTS
 
-/** \test full overlap */
-static int StreamTcpInlineTest01(void)
-{
-    SCEnter();
-
-    uint8_t payload1[] = "AAC"; /* packet */
-    uint8_t payload2[] = "ABC"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000000UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000000UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (!(p->flags & PKT_STREAM_MODIFIED)) {
-        printf("PKT_STREAM_MODIFIED pkt flag not set: ");
-        goto end;
-    }
+#include "stream-tcp-util.h"
 
-    if (memcmp(p->payload, t->payload, p->payload_len) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,t->payload,t->payload_len);
-        printf("payloads didn't match: ");
-        goto end;
+static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
+{
+    if (StreamingBufferCompareRawData(stream->sb,
+                data, data_len) == 0)
+    {
+        SCReturnInt(0);
     }
+    SCLogInfo("OK");
+    PrintRawDataFp(stdout, data, data_len);
+    return 1;
+}
 
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
-    if (memcmp(pkt,payload2,sizeof(payload2)-1) != 0) {
-        PrintRawDataFp(stdout,pkt,3);
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        goto end;
-    }
+#define INLINE_START(isn)                      \
+    Packet *p;                                  \
+    TcpReassemblyThreadCtx *ra_ctx = NULL;      \
+    TcpSession ssn;                             \
+    ThreadVars tv;                              \
+    memset(&tv, 0, sizeof(tv));                 \
+    \
+    StreamTcpUTInit(&ra_ctx);                   \
+    StreamTcpUTInitInline();                    \
+    \
+    StreamTcpUTSetupSession(&ssn);              \
+    StreamTcpUTSetupStream(&ssn.server, (isn)); \
+    StreamTcpUTSetupStream(&ssn.client, (isn)); \
+    \
+    TcpStream *stream = &ssn.client;
+
+#define INLINE_END                             \
+    StreamTcpUTClearSession(&ssn);              \
+    StreamTcpUTDeinit(ra_ctx);                  \
+    PASS
+
+#define INLINE_STEP(rseq, seg, seglen, buf, buflen, packet, packetlen) \
+    p = UTHBuildPacketReal((uint8_t *)(seg), (seglen), IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);    \
+    FAIL_IF(p == NULL); \
+    p->tcph->th_seq = htonl(stream->isn + (rseq)); \
+    p->tcph->th_ack = htonl(31);  \
+    FAIL_IF (StreamTcpReassembleHandleSegmentHandleData(&tv, ra_ctx, &ssn, stream, p) < 0);   \
+    FAIL_IF (memcmp(p->payload, packet, MIN((packetlen),p->payload_len)) != 0); \
+    UTHFreePacket(p);   \
+    FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
 
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+/** \test full overlap */
+static int StreamTcpInlineTest01(void)
+{
+    INLINE_START(0);
+    INLINE_STEP(1, "AAC", 3, "AAC", 3, "AAC", 3);
+    INLINE_STEP(1, "ABC", 3, "AAC", 3, "AAC", 3);
+    INLINE_END;
 }
 
 /** \test full overlap */
 static int StreamTcpInlineTest02(void)
 {
-    SCEnter();
-
-    uint8_t payload1[] = "xxx"; /* packet */
-    uint8_t payload2[] = "ABCDE"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000001UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000000UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (!(p->flags & PKT_STREAM_MODIFIED)) {
-        printf("PKT_STREAM_MODIFIED pkt flag not set: ");
-        goto end;
-    }
-
-    if (memcmp(p->payload, t->payload+1, p->payload_len) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,t->payload,t->payload_len);
-        printf("payloads didn't match: ");
-        goto end;
-    }
-
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
-    if (memcmp(pkt,payload2+1,sizeof(payload2)-3) != 0) {
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,payload2+1,sizeof(payload2)-3);
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,pkt,3);
-        printf("Packet (full):\n");
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        printf("packet data doesn't match: ");
-        goto end;
-    }
-
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+    INLINE_START(0);
+    INLINE_STEP(1, "ABCDE", 5, "ABCDE", 5, "ABCDE", 5);
+    INLINE_STEP(2, "xxx", 3, "ABCDE", 5, "BCD", 3);
+    INLINE_END;
 }
 
 /** \test partial overlap */
 static int StreamTcpInlineTest03(void)
 {
-    SCEnter();
-
-    uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
-    uint8_t payload2[] = "ABCDE"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000000UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000003UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (!(p->flags & PKT_STREAM_MODIFIED)) {
-        printf("PKT_STREAM_MODIFIED pkt flag not set: ");
-        goto end;
-    }
-
-    if (memcmp(p->payload+3, t->payload, t->payload_len) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,t->payload,t->payload_len);
-        printf("payloads didn't match: ");
-        goto end;
-    }
-
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1 + 3);
-    if (memcmp(pkt,payload2,sizeof(payload2)-1) != 0) {
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,payload2+1,sizeof(payload2)-3);
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,pkt,3);
-        printf("Packet (full):\n");
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        printf("packet data doesn't match: ");
-        goto end;
-    }
-
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+    INLINE_START(0);
+    INLINE_STEP(1, "ABCDE", 5, "ABCDE", 5, "ABCDE", 5);
+    INLINE_STEP(3, "xxxxx", 5, "ABCDExx", 7, "CDExx", 5);
+    INLINE_END;
 }
 
 /** \test partial overlap */
 static int StreamTcpInlineTest04(void)
 {
-    SCEnter();
-
-    uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
-    uint8_t payload2[] = "ABCDE"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000003UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000000UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (!(p->flags & PKT_STREAM_MODIFIED)) {
-        printf("PKT_STREAM_MODIFIED pkt flag not set: ");
-        goto end;
-    }
-
-    if (memcmp(p->payload, t->payload+3, 2) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,t->payload,t->payload_len);
-        printf("payloads didn't match: ");
-        goto end;
-    }
-
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
-    if (memcmp(pkt,payload2+3,2) != 0) {
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,payload2+3,2);
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,pkt,3);
-        printf("Packet (full):\n");
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        printf("packet data doesn't match: ");
-        goto end;
-    }
-
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+    INLINE_START(0);
+    INLINE_STEP(3, "ABCDE", 5, "\0\0ABCDE", 7, "ABCDE", 5);
+    INLINE_STEP(1, "xxxxx", 5, "xxABCDE", 7, "xxABC", 5);
+    INLINE_END;
 }
-/** \test partial overlap */
+
+/** \test no overlap */
 static int StreamTcpInlineTest05(void)
 {
-    SCEnter();
-
-    uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
-    uint8_t payload2[] = "ABCDE"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000000UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000010UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (!(p->flags & PKT_STREAM_MODIFIED)) {
-        printf("PKT_STREAM_MODIFIED pkt flag not set: ");
-        goto end;
-    }
-
-    if (memcmp(p->payload+10, t->payload, 2) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,t->payload,t->payload_len);
-        printf("payloads didn't match: ");
-        goto end;
-    }
-
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
-    if (memcmp(pkt+10,payload2,2) != 0) {
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,payload2,2);
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,pkt,3);
-        printf("Packet (full):\n");
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        printf("packet data doesn't match: ");
-        goto end;
-    }
-
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+    INLINE_START(0);
+    INLINE_STEP(8, "ABCDE", 5, "\0\0\0\0\0\0\0ABCDE", 12, "ABCDE", 5);
+    INLINE_STEP(1, "xxxxx", 5, "xxxxx\0\0ABCDE", 12, "xxxxx", 5);
+    INLINE_END;
 }
 
-/** \test no overlap */
+/** \test multiple overlaps */
 static int StreamTcpInlineTest06(void)
 {
-    SCEnter();
-
-    uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
-    uint8_t payload2[] = "ABCDE"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000020UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000000UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (p->flags & PKT_STREAM_MODIFIED) {
-        printf("PKT_STREAM_MODIFIED pkt flag set, but it shouldn't: ");
-        goto end;
-    }
-
-    if (memcmp(p->payload, payload1, sizeof(payload1)-1) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Original payload:\n");
-        PrintRawDataFp(stdout,payload1,sizeof(payload1)-1);
-        printf("payloads didn't match: ");
-        goto end;
-    }
-
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
-    if (memcmp(pkt,payload1,sizeof(payload1)-1) != 0) {
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,payload2,2);
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,pkt,3);
-        printf("Packet (full):\n");
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        printf("packet data doesn't match: ");
-        goto end;
-    }
-
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+    INLINE_START(0);
+    INLINE_STEP(2, "A", 1, "\0A", 2, "A", 1);
+    INLINE_STEP(4, "A", 1, "\0A\0A", 4, "A", 1);
+    INLINE_STEP(6, "A", 1, "\0A\0A\0A", 6, "A", 1);
+    INLINE_STEP(8, "A", 1, "\0A\0A\0A\0A", 8, "A", 1);
+    INLINE_STEP(1, "xxxxxxxxx", 9, "xAxAxAxAx", 9, "xAxAxAxAx", 9);
+    INLINE_END;
 }
 
-/** \test no overlap */
+/** \test overlap, data not different */
 static int StreamTcpInlineTest07(void)
 {
-    SCEnter();
-
-    uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
-    uint8_t payload2[] = "ABCDE"; /* segment */
-    int result = 0;
-    TcpSegment *t = NULL;
-
-    Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
-    if (p == NULL || p->tcph == NULL) {
-        printf("generating test packet failed: ");
-        goto end;
-    }
-    p->tcph->th_seq = htonl(10000000UL);
-
-    t = SCMalloc(sizeof(TcpSegment));
-    if (unlikely(t == NULL)) {
-        printf("alloc TcpSegment failed: ");
-        goto end;
-    }
-    memset(t, 0x00, sizeof(TcpSegment));
-    t->payload = payload2;
-    t->payload_len = sizeof(payload2)-1;
-    t->seq = 10000020UL;
-
-    StreamTcpInlineSegmentReplacePacket(p, t);
-
-    if (p->flags & PKT_STREAM_MODIFIED) {
-        printf("PKT_STREAM_MODIFIED pkt flag set, but it shouldn't: ");
-        goto end;
-    }
-
-    if (memcmp(p->payload, payload1, sizeof(payload1)-1) != 0) {
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,p->payload,p->payload_len);
-        printf("Original payload:\n");
-        PrintRawDataFp(stdout,payload1,sizeof(payload1)-1);
-        printf("payloads didn't match: ");
-        goto end;
-    }
-
-    uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
-    if (memcmp(pkt,payload1,sizeof(payload1)-1) != 0) {
-        printf("Segment:\n");
-        PrintRawDataFp(stdout,payload2,2);
-        printf("Packet:\n");
-        PrintRawDataFp(stdout,pkt,3);
-        printf("Packet (full):\n");
-        PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
-        printf("packet data doesn't match: ");
-        goto end;
-    }
+    INLINE_START(0);
+    INLINE_STEP(3, "ABCDE", 5, "\0\0ABCDE", 7, "ABCDE", 5);
+    INLINE_STEP(1, "XXABC", 5, "XXABCDE", 7, "XXABC", 5);
+    INLINE_END;
+}
 
-    result = 1;
-end:
-    if (p != NULL) {
-        UTHFreePacket(p);
-    }
-    if (t != NULL) {
-        SCFree(t);
-    }
-    SCReturnInt(result);
+static int StreamTcpInlineTest08(void)
+{
+    INLINE_START(0);
+    INLINE_STEP(1, "AAAAA", 5, "AAAAA", 5, "AAAAA", 5);
+    INLINE_STEP(1, "BBBBB", 5, "AAAAA", 5, "AAAAA", 5);
+    INLINE_STEP(1, "CCCCCCCCCC", 10, "AAAAACCCCC", 10, "AAAAACCCCC", 10);
+    INLINE_STEP(10, "X", 1, "AAAAACCCCC", 10, "C", 1);
+    INLINE_STEP(11, "X", 1, "AAAAACCCCCX", 11, "X", 1);
+    INLINE_END;
 }
+
 #endif /* UNITTESTS */
 
 void StreamTcpInlineRegisterTests(void)
@@ -652,6 +303,7 @@ void StreamTcpInlineRegisterTests(void)
     UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05);
     UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06);
     UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07);
+    UtRegisterTest("StreamTcpInlineTest08", StreamTcpInlineTest08);
 #endif /* UNITTESTS */
 }
 
index 49d49781761fa0b38b4343d3f67727c47c3721f5..ad37d25143522ade6a1f75be7144d1b1127cec33 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2011 Open Information Security Foundation
+/* Copyright (C) 2007-2016 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -27,8 +27,8 @@
 #include "stream-tcp-private.h"
 
 int StreamTcpInlineMode(void);
-int StreamTcpInlineSegmentCompare(TcpSegment *, TcpSegment *);
-void StreamTcpInlineSegmentReplacePacket(Packet *, TcpSegment *);
+int StreamTcpInlineSegmentCompare(TcpStream *, Packet *, TcpSegment *);
+void StreamTcpInlineSegmentReplacePacket(TcpStream *, Packet *, TcpSegment *);
 
 void StreamTcpInlineRegisterTests(void);
 
diff --git a/src/stream-tcp-list.c b/src/stream-tcp-list.c
new file mode 100644 (file)
index 0000000..ba0fd6c
--- /dev/null
@@ -0,0 +1,883 @@
+/* Copyright (C) 2007-2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/** \file
+ *
+ *  Segment list functions for insertions, overlap handling, removal and
+ *  more.
+ */
+
+#include "suricata-common.h"
+#include "stream-tcp-private.h"
+#include "stream-tcp.h"
+#include "stream-tcp-reassemble.h"
+#include "stream-tcp-inline.h"
+#include "stream-tcp-list.h"
+#include "util-streaming-buffer.h"
+#include "util-print.h"
+
+//static void PrintList2(TcpSegment *seg);
+
+static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg);
+
+static int check_overlap_different_data = 0;
+
+void StreamTcpReassembleConfigEnableOverlapCheck(void)
+{
+    check_overlap_different_data = 1;
+}
+
+/*
+ *  Inserts and overlap handling
+ */
+
+
+/** \internal
+ *  \brief insert segment data into the streaming buffer
+ *  \param seg segment to store stream offset in
+ *  \param data segment data after overlap handling (if any)
+ *  \param data_len data length
+ */
+static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, uint8_t *data, uint16_t data_len)
+{
+    uint64_t stream_offset;
+    uint16_t data_offset;
+
+    if (likely(SEQ_GEQ(seg->seq, stream->base_seq))) {
+        stream_offset = stream->base_seq_offset + (seg->seq - stream->base_seq);
+        data_offset = 0;
+    } else {
+        /* segment is partly before base_seq */
+        data_offset = stream->base_seq - seg->seq;
+        stream_offset = stream->base_seq_offset;
+    }
+
+    SCLogDebug("stream %p buffer %p, stream_offset %"PRIu64", "
+               "data_offset %"PRIu16", SEQ %u BASE %u, data_len %u",
+               stream, stream->sb, stream_offset,
+               data_offset, seg->seq, stream->base_seq, data_len);
+    BUG_ON(data_offset > data_len);
+    if (data_len == data_offset) {
+        SCReturnInt(0);
+    }
+
+    if (StreamingBufferInsertAt(stream->sb, &seg->sbseg,
+                data + data_offset,
+                data_len - data_offset,
+                stream_offset) != 0) {
+        SCReturnInt(-1);
+    }
+#ifdef DEBUG
+    {
+        const uint8_t *mydata;
+        uint32_t mydata_len;
+        uint64_t mydata_offset;
+        StreamingBufferGetData(stream->sb, &mydata, &mydata_len, &mydata_offset);
+
+        SCLogDebug("stream %p seg %p data in buffer %p of len %u and offset %u",
+                stream, seg, stream->sb, mydata_len, (uint)mydata_offset);
+        //PrintRawDataFp(stdout, mydata, mydata_len);
+    }
+#endif
+    SCReturnInt(0);
+}
+
+/** \internal
+ *  \brief insert the segment into the proper place in the list
+ *         don't worry about the data or overlaps
+ *
+ *         If seq is equal to list seq, keep sorted by insert time.
+ *         1. seg 123 len 12
+ *         2. seg 123 len 14
+ *         3. seg 124 len 1
+ *
+ *  \retval 1 inserted with overlap detected
+ *  \retval 0 inserted, no overlap
+ *  \retval -1 error
+ */
+static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, Packet *p)
+{
+    if (unlikely(stream->sb == NULL)) {
+        stream->sb = StreamingBufferInit(&stream_config.sbcnf);
+        if (stream->sb == NULL) {
+            return -1;
+        }
+    }
+
+    /* before our base_seq we don't insert it in our list */
+    if (SEQ_LEQ((seg->seq + TCP_SEG_LEN(seg)), stream->base_seq))
+    {
+        SCLogDebug("not inserting: SEQ+payload %"PRIu32", last_ack %"PRIu32", "
+                "base_seq %"PRIu32, (seg->seq + TCP_SEG_LEN(seg)),
+                stream->last_ack, stream->base_seq);
+        StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ);
+        return -1;
+    }
+
+    /* fast track */
+    if (stream->seg_list == NULL) {
+        SCLogDebug("empty list, inserting seg %p seq %" PRIu32 ", "
+                   "len %" PRIu32 "", seg, seg->seq, TCP_SEG_LEN(seg));
+        stream->seg_list = seg;
+        seg->prev = NULL;
+        stream->seg_list_tail = seg;
+        return 0;
+    }
+
+    /* insert the segment in the stream list using this fast track, if seg->seq
+       is equal or higher than stream->seg_list_tail.*/
+    if (SEQ_GEQ(seg->seq, (stream->seg_list_tail->seq +
+                    TCP_SEG_LEN(stream->seg_list_tail))))
+    {
+        SCLogDebug("seg beyond list tail, append");
+        stream->seg_list_tail->next = seg;
+        seg->prev = stream->seg_list_tail;
+        stream->seg_list_tail = seg;
+        return 0;
+    }
+
+    /* walk the list to see where we can insert the segment.
+     * Check if a segment overlaps with us, if so we return 1 to indicate
+     * to the caller that we need to handle overlaps. */
+    TcpSegment *list_seg;
+    for (list_seg = stream->seg_list; list_seg != NULL; list_seg = list_seg->next)
+    {
+        if (SEQ_LT(seg->seq, list_seg->seq)) {
+            if (list_seg->prev != NULL) {
+                list_seg->prev->next = seg;
+            } else {
+                stream->seg_list = seg;
+            }
+            seg->prev = list_seg->prev;
+            seg->next = list_seg;
+            list_seg->prev = seg;
+
+            SCLogDebug("inserted %u before %p seq %u", seg->seq, list_seg, list_seg->seq);
+
+            if (seg->prev != NULL) {
+                SCLogDebug("previous %u", seg->prev->seq);
+            }
+            if (seg->next != NULL) {
+                SCLogDebug("next %u", seg->next->seq);
+            }
+            if (seg->prev != NULL && SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg->prev), seg->seq)) {
+                SCLogDebug("seg inserted with overlap (before)");
+                return 1;
+            }
+            else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), seg->next->seq)) {
+                SCLogDebug("seg inserted with overlap (after)");
+                return 1;
+            }
+
+            return 0;
+        }
+    }
+    /* if we got here we didn't insert. Append */
+    seg->prev = stream->seg_list_tail;
+    stream->seg_list_tail->next = seg;
+    stream->seg_list_tail = seg;
+
+    if (seg->prev != NULL && SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg->prev), seg->seq)) {
+        SCLogDebug("seg inserted with overlap (before)");
+        return 1;
+    }
+
+    SCLogDebug("default: append");
+    return 0;
+}
+
+/** \internal
+ *  \brief handle overlap per list segment
+ *
+ *  For a list segment handle the overlap according to the policy.
+ *
+ *  The 'buf' parameter points to the memory that will be inserted into
+ *  the stream after the overlap checks are complete. As it will
+ *  unconditionally overwrite whats in the stream now, the overlap
+ *  policies are applied to this buffer. It starts with the 'new' data,
+ *  so when the policy states 'old' data has to be used, 'buf' is
+ *  updated to contain the 'old' data here.
+ *
+ *  \param buf stack allocated buffer sized p->payload_len that will be
+ *             inserted into the stream buffer
+ */
+static int DoHandleDataOverlap(TcpStream *stream, TcpSegment *list, TcpSegment *seg, uint8_t *buf, Packet *p)
+{
+    SCLogDebug("handle overlap for segment %p seq %u len %u re %u, "
+            "list segment %p seq %u len %u re %u", seg, seg->seq, p->payload_len, SEG_SEQ_RIGHT_EDGE(seg),
+            list, list->seq, TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list));
+
+    int data_is_different = 0;
+    int use_new_data = 0;
+
+    if (StreamTcpInlineMode()) {
+        SCLogDebug("inline mode");
+        if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) {
+            SCLogDebug("already accepted data not the same as packet data, rewrite packet");
+            StreamTcpInlineSegmentReplacePacket(stream, p, list);
+            data_is_different = 1;
+
+            /* in inline mode we check for different data unconditionally,
+             * but setting events still depends on config */
+            if (check_overlap_different_data) {
+                StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
+            }
+        }
+
+    /* IDS mode */
+    } else {
+        if (check_overlap_different_data) {
+            if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) {
+                SCLogDebug("data is different from what is in the list");
+                data_is_different = 1;
+                StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
+            }
+        } else {
+            /* if we're not checking, assume it's different */
+            data_is_different = 1;
+        }
+
+        /* apply overlap policies */
+
+        if (stream->os_policy == OS_POLICY_LAST) {
+            /* buf will start with LAST data (from the segment),
+             * so if policy is LAST we're now done here. */
+            return 0;
+        }
+
+        /* start at the same seq */
+        if (SEQ_EQ(seg->seq, list->seq)) {
+            SCLogDebug("seg starts at list segment");
+
+            if (SEQ_LT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
+                SCLogDebug("seg ends before list end, end overlapped by list");
+            } else {
+                if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
+                    SCLogDebug("seg ends beyond list end, list overlapped and more");
+                    switch (stream->os_policy) {
+                        case OS_POLICY_LINUX:
+                            if (data_is_different) {
+                                use_new_data = 1;
+                            }
+                            break;
+                    }
+                } else {
+                    SCLogDebug("full overlap");
+                }
+
+                switch (stream->os_policy) {
+                    case OS_POLICY_OLD_LINUX:
+                    case OS_POLICY_SOLARIS:
+                    case OS_POLICY_HPUX11:
+                        if (data_is_different) {
+                            use_new_data = 1;
+                        }
+                        break;
+                }
+            }
+
+            /* new seg starts before list segment */
+        } else if (SEQ_LT(seg->seq, list->seq)) {
+            SCLogDebug("seg starts before list segment");
+
+            if (SEQ_LT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
+                SCLogDebug("seg ends before list end, end overlapped by list");
+            } else {
+                if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
+                    SCLogDebug("seg starts before and fully overlaps list and beyond");
+                } else {
+                    SCLogDebug("seg starts before and fully overlaps list");
+                }
+
+                switch (stream->os_policy) {
+                    case OS_POLICY_SOLARIS:
+                    case OS_POLICY_HPUX11:
+                        if (data_is_different) {
+                            use_new_data = 1;
+                        }
+                        break;
+                }
+            }
+
+            switch (stream->os_policy) {
+                case OS_POLICY_BSD:
+                case OS_POLICY_HPUX10:
+                case OS_POLICY_IRIX:
+                case OS_POLICY_WINDOWS:
+                case OS_POLICY_WINDOWS2K3:
+                case OS_POLICY_OLD_LINUX:
+                case OS_POLICY_LINUX:
+                case OS_POLICY_MACOS:
+                    if (data_is_different) {
+                        use_new_data = 1;
+                    }
+                    break;
+            }
+
+            /* new seg starts after list segment */
+        } else { //if (SEQ_GT(seg->seq, list->seq)) {
+            SCLogDebug("seg starts after list segment");
+
+            if (SEQ_EQ(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
+                SCLogDebug("seg after and is fully overlapped by list");
+            } else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
+                SCLogDebug("seg starts after list and ends after list");
+
+                switch (stream->os_policy) {
+                    case OS_POLICY_SOLARIS:
+                    case OS_POLICY_HPUX11:
+                        if (data_is_different) {
+                            use_new_data = 1;
+                        }
+                        break;
+                }
+            } else {
+                SCLogDebug("seg starts after list and ends before list end");
+
+            }
+        }
+    }
+
+    SCLogDebug("data_is_different %s, use_new_data %s",
+        data_is_different ? "yes" : "no",
+        use_new_data ? "yes" : "no");
+
+    /* if the data is different and we don't want to use the new (seg)
+     * data, we have to update buf with the list data */
+    if (data_is_different && !use_new_data) {
+        /* we need to copy list into seg */
+        uint16_t list_offset = 0;
+        uint16_t seg_offset = 0;
+        uint32_t list_len;
+        uint16_t seg_len = p->payload_len;
+        uint32_t list_seq = list->seq;
+
+        const uint8_t *list_data;
+        StreamingBufferSegmentGetData(stream->sb, &list->sbseg, &list_data, &list_len);
+        if (list_data == NULL || list_len == 0)
+            return 0;
+        BUG_ON(list_len > USHRT_MAX);
+
+        /* if list seg is partially before base_seq, list_len (from stream) and
+         * TCP_SEG_LEN(list) will not be the same */
+        if (SEQ_GEQ(list->seq, stream->base_seq)) {
+            ;
+        } else {
+            list_seq = stream->base_seq;
+            list_len = SEG_SEQ_RIGHT_EDGE(list) - stream->base_seq;
+        }
+
+        if (SEQ_LT(seg->seq, list_seq)) {
+            seg_offset = list_seq - seg->seq;
+            seg_len -= seg_offset;
+        } else if (SEQ_GT(seg->seq, list_seq)) {
+            list_offset = seg->seq - list_seq;
+            list_len -= list_offset;
+        }
+
+        if (SEQ_LT(seg->seq + seg_offset + seg_len, list_seq + list_offset + list_len)) {
+            list_len -= (list_seq + list_offset + list_len) - (seg->seq + seg_offset + seg_len);
+        }
+        SCLogDebug("here goes nothing: list %u %u, seg %u %u", list_offset, list_len, seg_offset, seg_len);
+
+        //PrintRawDataFp(stdout, list_data + list_offset, list_len);
+        //PrintRawDataFp(stdout, buf + seg_offset, seg_len);
+
+        memcpy(buf + seg_offset, list_data + list_offset, list_len);
+        //PrintRawDataFp(stdout, buf, p->payload_len);
+    }
+    return 0;
+}
+
+#define MAX_IP_DATA (uint32_t)(65536 - 40) // min ip header and min tcp header
+
+/** \internal
+ *  \brief walk segment list backwards to see if there are overlaps
+ *
+ *  Walk back from the current segment which is already in the list.
+ *  We walk until we can't possibly overlap anymore.
+ */
+static int DoHandleDataCheckBackwards(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p)
+{
+    SCLogDebug("check list backwards: insert data for segment %p seq %u len %u re %u",
+            seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
+
+    TcpSegment *list = seg->prev;
+    do {
+        int overlap = 0;
+        if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(list), stream->base_seq)) {
+            // segment entirely before base_seq
+            ;
+        } else if (SEQ_LEQ(list->seq + MAX_IP_DATA, seg->seq)) {
+            SCLogDebug("list segment too far to the left, no more overlap will be found");
+            break;
+        } else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(list), seg->seq)) {
+            overlap = 1;
+        }
+
+        SCLogDebug("(back) list seg %u len %u re %u overlap? %s", list->seq, TCP_SEG_LEN(list),
+                SEG_SEQ_RIGHT_EDGE(list), overlap ? "yes" : "no");
+
+        if (overlap) {
+            DoHandleDataOverlap(stream, list, seg, buf, p);
+        }
+
+        list = list->prev;
+    } while (list != NULL);
+
+    return 0;
+}
+
+/** \internal
+ *  \brief walk segment list in forward direction to see if there are overlaps
+ *
+ *  Walk forward from the current segment which is already in the list.
+ *  We walk until the next segs start with a SEQ beyond our right edge.
+ */
+static int DoHandleDataCheckForward(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p)
+{
+    uint32_t seg_re = SEG_SEQ_RIGHT_EDGE(seg);
+
+    SCLogDebug("check list forward: insert data for segment %p seq %u len %u re %u",
+            seg, seg->seq, TCP_SEG_LEN(seg), seg_re);
+
+    TcpSegment *list = seg->next;
+    do {
+        int overlap = 0;
+        if (SEQ_GT(seg_re, list->seq))
+            overlap = 1;
+        else if (SEQ_LEQ(seg_re, list->seq)) {
+            SCLogDebug("list segment %u too far ahead, "
+                    "no more overlaps can happen", list->seq);
+            break;
+        }
+
+        SCLogDebug("(fwd) list seg %u len %u re %u overlap? %s", list->seq,
+                TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list), overlap ? "yes" : "no");
+
+        if (overlap) {
+            DoHandleDataOverlap(stream, list, seg, buf, p);
+        }
+
+        list = list->next;
+    } while (list != NULL);
+
+    return 0;
+}
+
+static int DoHandleData(TcpStream *stream, TcpSegment *seg, Packet *p)
+{
+    SCLogDebug("insert data for segment %p seq %u len %u re %u",
+            seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
+
+    /* create temporary buffer to contain the data we will insert. Overlap
+     * handling may update it. By using this we don't have to track whether
+     * parts of the data are already inserted or not. */
+    uint8_t buf[p->payload_len];
+    memcpy(buf, p->payload, p->payload_len);
+
+    /* new list head  */
+    if (seg->next != NULL && seg->prev == NULL) {
+        DoHandleDataCheckForward(stream, seg, buf, p);
+
+    /* new list tail */
+    } else if (seg->next == NULL && seg->prev != NULL) {
+        DoHandleDataCheckBackwards(stream, seg, buf, p);
+
+    /* middle of the list */
+    } else if (seg->next != NULL && seg->prev != NULL) {
+        DoHandleDataCheckBackwards(stream, seg, buf, p);
+        DoHandleDataCheckForward(stream, seg, buf, p);
+    }
+
+    /* insert the temp buffer now that we've (possibly) updated
+     * it to account for the overlap policies */
+    if (InsertSegmentDataCustom(stream, seg, buf, p->payload_len) < 0) {
+        return -1;
+    }
+
+    return 0;
+
+}
+
+/**
+ *  \retval -1 segment not inserted
+ *
+ *  \param seg segment, this function takes total ownership
+ *
+ *  In case of error, this function returns the segment to the pool
+ */
+int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+        TcpStream *stream, TcpSegment *seg, Packet *p, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen)
+{
+    /* insert segment into list. Note: doesn't handle the data */
+#ifdef DEBUG
+    SCLogDebug("pre insert");
+    PrintList(stream->seg_list);
+#endif
+
+    int r = DoInsertSegment (stream, seg, p);
+
+#ifdef DEBUG
+    SCLogDebug("post insert");
+    PrintList(stream->seg_list);
+#endif
+
+    if (likely(r == 0)) {
+        /* no overlap, straight data insert */
+        int res = InsertSegmentDataCustom(stream, seg, pkt_data, pkt_datalen);
+        if (res < 0) {
+            StreamTcpRemoveSegmentFromStream(stream, seg);
+            StreamTcpSegmentReturntoPool(seg);
+            SCReturnInt(-1);
+        }
+
+    } else if (r == 1) {
+        /* now let's consider the data in the overlap case */
+        int res = DoHandleData(stream, seg, p);
+        if (res < 0) {
+            StreamTcpRemoveSegmentFromStream(stream, seg);
+            StreamTcpSegmentReturntoPool(seg);
+            SCReturnInt(-1);
+        }
+
+    } else if (r < 0) {
+        StreamTcpSegmentReturntoPool(seg);
+        SCReturnInt(-1);
+    }
+
+    SCReturnInt(0);
+}
+
+
+/*
+ * Pruning & removal
+ */
+
+
+static inline int SegmentInUse(TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
+{
+    if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) {
+        /* not (seg is entirely before first smsg, skip) */
+        if (!(SEQ_LEQ(seg->seq + TCP_SEG_LEN(seg), ssn->toserver_smsg_head->seq))) {
+            SCReturnInt(1);
+        }
+    } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) {
+        /* not (seg is entirely before first smsg, skip) */
+        if (!(SEQ_LEQ(seg->seq + TCP_SEG_LEN(seg), ssn->toclient_smsg_head->seq))) {
+            SCReturnInt(1);
+        }
+    }
+
+    /* if proto detect isn't done, we're not returning */
+    if (!(stream->flags & STREAMTCP_STREAM_FLAG_GAP)) {
+        if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) {
+            SCReturnInt(1);
+        }
+    }
+
+    SCReturnInt(0);
+}
+
+
+/** \internal
+ *  \brief check if we can remove a segment from our segment list
+ *
+ *  If a segment is entirely before the oldest smsg, we can discard it. Otherwise
+ *  we keep it around to be able to log it.
+ *
+ *  \retval 1 yes
+ *  \retval 0 no
+ */
+static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
+{
+    if (SegmentInUse(ssn, stream, seg)) {
+        SCReturnInt(0);
+    }
+
+    if (!(StreamingBufferSegmentIsBeforeWindow(stream->sb, &seg->sbseg))) {
+        SCReturnInt(0);
+    }
+
+    SCReturnInt(1);
+}
+
+static inline uint64_t GetLeftEdge(TcpSession *ssn, TcpStream *stream)
+{
+    int use_app = 1;
+    int use_raw = 1;
+
+    uint64_t left_edge = 0;
+    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
+          (stream->flags & STREAMTCP_STREAM_FLAG_GAP))
+    {
+        // app is dead
+        use_app = 0;
+    }
+
+    if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) {
+        // raw is dead
+        use_raw = 0;
+    }
+
+    if (use_app && use_raw) {
+        left_edge = MIN(stream->app_progress, stream->raw_progress);
+        SCLogDebug("left_edge %"PRIu64", using both app:%"PRIu64", raw:%"PRIu64,
+                left_edge, stream->app_progress, stream->raw_progress);
+    } else if (use_app) {
+        left_edge = stream->app_progress;
+        SCLogDebug("left_edge %"PRIu64", using app:%"PRIu64,
+                left_edge, stream->app_progress);
+    } else if (use_raw) {
+        left_edge = stream->raw_progress;
+        SCLogDebug("left_edge %"PRIu64", using raw:%"PRIu64,
+                left_edge, stream->raw_progress);
+    } else {
+        SCLogDebug("left_edge 0, none");
+    }
+
+    if (left_edge > 0) {
+        /* we know left edge based on the progress values now,
+         * lets adjust it to make sure in-use segments still have
+         * data */
+        TcpSegment *seg;
+        for (seg = stream->seg_list; seg != NULL; seg = seg->next)
+        {
+            if (TCP_SEG_OFFSET(seg) > left_edge) {
+                SCLogDebug("seg beyond left_edge, we're done");
+                break;
+            }
+
+            if (SegmentInUse(ssn, stream, seg)) {
+                left_edge = TCP_SEG_OFFSET(seg);
+                SCLogDebug("in-use seg before left_edge, adjust to %"PRIu64" and bail", left_edge);
+                break;
+            }
+        }
+    }
+
+    return left_edge;
+}
+
+static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg)
+{
+    if (seg->prev == NULL) {
+        stream->seg_list = seg->next;
+        if (stream->seg_list != NULL)
+            stream->seg_list->prev = NULL;
+    } else {
+        seg->prev->next = seg->next;
+        if (seg->next != NULL)
+            seg->next->prev = seg->prev;
+    }
+
+    if (stream->seg_list_tail == seg)
+        stream->seg_list_tail = seg->prev;
+}
+
+/** \brief Remove idle TcpSegments from TcpSession
+ *
+ *  \param f flow
+ *  \param flags direction flags
+ */
+void StreamTcpPruneSession(Flow *f, uint8_t flags)
+{
+    SCEnter();
+
+    if (f == NULL || f->protoctx == NULL) {
+        SCReturn;
+    }
+
+    TcpSession *ssn = f->protoctx;
+    TcpStream *stream = NULL;
+
+    if (flags & STREAM_TOSERVER) {
+        stream = &ssn->client;
+    } else if (flags & STREAM_TOCLIENT) {
+        stream = &ssn->server;
+    } else {
+        SCReturn;
+    }
+
+    uint64_t left_edge = GetLeftEdge(ssn, stream);
+    if (left_edge) {
+        /* in IPS mode we consider the chunk_size when sliding */
+        if (StreamTcpInlineMode() == TRUE) {
+            uint32_t chunk_size = (flags & STREAM_TOSERVER) ?
+                stream_config.reassembly_toserver_chunk_size :
+                stream_config.reassembly_toclient_chunk_size;
+            if ((uint64_t)chunk_size >= left_edge) {
+                left_edge = 0;
+            } else {
+                left_edge -= chunk_size;
+            }
+        }
+
+        if (left_edge > stream->base_seq_offset) {
+            uint32_t slide = left_edge - stream->base_seq_offset;
+            SCLogDebug("buffer sliding %u to offset %"PRIu64, slide, left_edge);
+            StreamingBufferSlideToOffset(stream->sb, left_edge);
+            stream->base_seq_offset += slide;
+            stream->base_seq += slide;
+            SCLogDebug("stream base_seq %u at stream offset %"PRIu64,
+                    stream->base_seq, stream->base_seq_offset);
+        }
+    }
+
+    /* loop through the segments and fill one or more msgs */
+    TcpSegment *seg = stream->seg_list;
+
+    while (seg != NULL)
+    {
+        SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", FLAGS %02x",
+                seg, seg->seq, TCP_SEG_LEN(seg),
+                (uint32_t)(seg->seq + TCP_SEG_LEN(seg)), seg->flags);
+
+        if (StreamTcpReturnSegmentCheck(f, ssn, stream, seg) == 0) {
+            SCLogDebug("not removing segment");
+            break;
+        }
+
+        TcpSegment *next_seg = seg->next;
+        StreamTcpRemoveSegmentFromStream(stream, seg);
+        StreamTcpSegmentReturntoPool(seg);
+        seg = next_seg;
+        SCLogDebug("removed segment");
+        continue;
+    }
+#ifdef DEBUG
+    PrintList(stream->seg_list);
+#endif
+    SCReturn;
+}
+
+/*
+ *  Utils
+ */
+
+#if 0
+void PrintList2(TcpSegment *seg)
+{
+    TcpSegment *prev_seg = NULL;
+
+    if (seg == NULL)
+        return;
+
+    uint32_t next_seq = seg->seq;
+
+    while (seg != NULL) {
+        if (SEQ_LT(next_seq,seg->seq)) {
+            SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
+                        (seg->seq - next_seq));
+        }
+
+        SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p",
+                    seg->seq, TCP_SEG_LEN(seg), seg, seg->prev, seg->next);
+
+        if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
+            /* check for SEQ_LT cornercase where a - b is exactly 2147483648,
+             * which makes the marco return TRUE in both directions. This is
+             * a hack though, we're going to check next how we end up with
+             * a segment list with seq differences that big */
+            if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
+                SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) =="
+                        " TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 ""
+                        "", seg->seq, seg->prev->seq);
+            }
+        }
+
+        if (SEQ_LT(seg->seq,next_seq)) {
+            SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
+                       "seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
+                       next_seq);
+        }
+
+        if (prev_seg != seg->prev) {
+            SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
+                        prev_seg, seg->prev);
+        }
+
+        next_seq = seg->seq + TCP_SEG_LEN(seg);
+        SCLogDebug("next_seq is now %"PRIu32"", next_seq);
+        prev_seg = seg;
+        seg = seg->next;
+    }
+}
+#endif
+
+void PrintList(TcpSegment *seg)
+{
+    TcpSegment *prev_seg = NULL;
+//    TcpSegment *head_seg = seg;
+
+    if (seg == NULL)
+        return;
+
+    uint32_t next_seq = seg->seq;
+
+    while (seg != NULL) {
+        if (SEQ_LT(next_seq,seg->seq)) {
+            SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
+                        (seg->seq - next_seq));
+        }
+
+        SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p, flags 0x%02x",
+                    seg->seq, TCP_SEG_LEN(seg), seg, seg->prev, seg->next, seg->flags);
+
+        if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
+            /* check for SEQ_LT cornercase where a - b is exactly 2147483648,
+             * which makes the marco return TRUE in both directions. This is
+             * a hack though, we're going to check next how we end up with
+             * a segment list with seq differences that big */
+            if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
+                SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) == "
+                        "TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "",
+                        seg->seq, seg->prev->seq);
+//                PrintList2(head_seg);
+//                abort();
+            }
+        }
+
+        if (SEQ_LT(seg->seq,next_seq)) {
+            SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
+                       "seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
+                       next_seq);
+//            PrintList2(head_seg);
+//            abort();
+        }
+
+        if (prev_seg != seg->prev) {
+            SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
+                       prev_seg, seg->prev);
+//            PrintList2(head_seg);
+            abort();
+        }
+
+        next_seq = seg->seq + TCP_SEG_LEN(seg);
+        SCLogDebug("next_seq is now %"PRIu32"", next_seq);
+        prev_seg = seg;
+        seg = seg->next;
+    }
+}
+
+/*
+ *  unittests
+ */
+
+#ifdef UNITTESTS
+#include "tests/stream-tcp-list.c"
+#endif
diff --git a/src/stream-tcp-list.h b/src/stream-tcp-list.h
new file mode 100644 (file)
index 0000000..28c7947
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2007-2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ */
+
+#ifndef __STREAM_TCP_LIST_H__
+#define __STREAM_TCP_LIST_H__
+
+#include "stream-tcp-private.h"
+
+void PrintList(TcpSegment *);
+
+#ifdef UNITTESTS
+void StreamTcpListRegisterTests(void);
+#endif
+
+#endif /* __STREAM_TCP_LIST_H__ */
index c13da86671738f44efad72b419c33c92c3c39ec3..773e74d7d5d29fedcb724e0161ae704b99f0caeb 100644 (file)
@@ -27,6 +27,7 @@
 #include "decode.h"
 #include "util-pool.h"
 #include "util-pool-thread.h"
+#include "util-streaming-buffer.h"
 
 #define STREAMTCP_QUEUE_FLAG_TS     0x01
 #define STREAMTCP_QUEUE_FLAG_WS     0x02
@@ -51,7 +52,7 @@ typedef struct StreamTcpSackRecord_ {
 } StreamTcpSackRecord;
 
 typedef struct TcpSegment_ {
-    uint8_t *payload;
+    StreamingBufferSegment sbseg;
     uint16_t payload_len;       /**< actual size of the payload */
     uint16_t pool_size;         /**< size of the memory */
     uint32_t seq;
@@ -61,6 +62,11 @@ typedef struct TcpSegment_ {
     uint8_t flags;
 } TcpSegment;
 
+#define TCP_SEG_LEN(seg)        (seg)->payload_len
+#define TCP_SEG_OFFSET(seg)     (seg)->sbseg.stream_offset
+
+#define SEG_SEQ_RIGHT_EDGE(seg) ((seg)->seq + TCP_SEG_LEN((seg)))
+
 typedef struct TcpStream_ {
     uint16_t flags:12;              /**< Flag specific to the stream e.g. Timestamp */
     /* coccinelle: TcpStream:flags:STREAMTCP_STREAM_FLAG_ */
@@ -79,8 +85,12 @@ typedef struct TcpStream_ {
                                          This will be used to validate the last_ts, when connection has been idle for
                                          longer time.(RFC 1323)*/
     /* reassembly */
-    uint32_t ra_app_base_seq;       /**< reassembled seq. We've reassembled up to this point. */
-    uint32_t ra_raw_base_seq;       /**< reassembled seq. We've reassembled up to this point. */
+    uint32_t base_seq;              /**< seq where we are left with reassebly */
+    uint64_t base_seq_offset;       /**< offset from the start of the stream (== 0) of the current
+                                     *   base seq */
+    StreamingBuffer *sb;
+    uint64_t app_progress;
+    uint64_t raw_progress;
 
     TcpSegment *seg_list;           /**< list of TCP segments that are not yet (fully) used in reassembly */
     TcpSegment *seg_list_tail;      /**< Last segment in the reassembled stream seg list*/
@@ -176,12 +186,6 @@ enum
 /*
  * Per SEGMENT flags
  */
-/** Flag to indicate that the current segment has been processed by the
- *  reassembly code and should be deleted after app layer protocol has been
- *  detected. */
-#define SEGMENTTCP_FLAG_RAW_PROCESSED       0x01
-/** App Layer reassembly code is done with this segment */
-#define SEGMENTTCP_FLAG_APPLAYER_PROCESSED  0x02
 /** Log API (streaming) has processed this segment */
 #define SEGMENTTCP_FLAG_LOGAPI_PROCESSED    0x04
 
@@ -203,8 +207,7 @@ enum
 
 #define STREAMTCP_SET_RA_BASE_SEQ(stream, seq) { \
     do { \
-        (stream)->ra_raw_base_seq = (seq); \
-        (stream)->ra_app_base_seq = (seq); \
+        (stream)->base_seq = (seq) + 1;    \
     } while(0); \
 }
 
index 9632c116bd99511fd406a928ff03a17c9c9749ec..c613d8ea5154eaee2dc97f67bea7251250c6329f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2016 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -51,6 +51,7 @@
 #include "stream-tcp-private.h"
 #include "stream-tcp-reassemble.h"
 #include "stream-tcp-inline.h"
+#include "stream-tcp-list.h"
 #include "stream-tcp-util.h"
 
 #include "stream.h"
@@ -64,8 +65,6 @@
 
 #include "util-profiling.h"
 
-#define PSEUDO_PACKET_PAYLOAD_SIZE  65416 /* 64 Kb minus max IP and TCP header */
-
 #ifdef DEBUG
 static SCMutex segment_pool_memuse_mutex;
 static uint64_t segment_pool_memuse = 0;
@@ -87,30 +86,14 @@ static uint64_t segment_pool_cnt = 0;
 #endif
 /* index to the right pool for all packet sizes. */
 static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */
-static int check_overlap_different_data = 0;
 
 /* Memory use counter */
 SC_ATOMIC_DECLARE(uint64_t, ra_memuse);
 
 /* prototypes */
-static int HandleSegmentStartsBeforeListSegment(ThreadVars *, TcpReassemblyThreadCtx *,
-                                    TcpStream *, TcpSegment *, TcpSegment *, Packet *);
-static int HandleSegmentStartsAtSameListSegment(ThreadVars *, TcpReassemblyThreadCtx *,
-                                    TcpStream *, TcpSegment *, TcpSegment *, Packet *);
-static int HandleSegmentStartsAfterListSegment(ThreadVars *, TcpReassemblyThreadCtx *,
-                                    TcpStream *, TcpSegment *, TcpSegment *, Packet *);
-void StreamTcpSegmentDataReplace(TcpSegment *, TcpSegment *, uint32_t, uint16_t);
-void StreamTcpSegmentDataCopy(TcpSegment *, TcpSegment *);
 TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *, uint16_t);
 void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);
 void StreamTcpReassemblePseudoPacketCreate(TcpStream *, Packet *, PacketQueue *);
-static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg,
-                                 uint32_t start_point, uint16_t len);
-
-void StreamTcpReassembleConfigEnableOverlapCheck(void)
-{
-    check_overlap_different_data = 1;
-}
 
 /**
  *  \brief  Function to Increment the memory usage counter for the TCP reassembly
@@ -187,16 +170,16 @@ int TcpSegmentPoolInit(void *data, void *payload_len)
     }
 
     seg->pool_size = size;
-    seg->payload_len = seg->pool_size;
-
-    seg->payload = SCMalloc(seg->payload_len);
-    if (seg->payload == NULL) {
+    TCP_SEG_LEN(seg) = seg->pool_size;
+#if 0
+    TCP_SEG_PAYLOAD(seg) = SCMalloc(TCP_SEG_LEN(seg));
+    if (TCP_SEG_PAYLOAD(seg) == NULL) {
         return 0;
     }
-
+#endif
 #ifdef DEBUG
     SCMutexLock(&segment_pool_memuse_mutex);
-    segment_pool_memuse += seg->payload_len;
+    segment_pool_memuse += TCP_SEG_LEN(seg);
     segment_pool_memcnt++;
     SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
     SCMutexUnlock(&segment_pool_memuse_mutex);
@@ -224,7 +207,7 @@ void TcpSegmentPoolCleanup(void *ptr)
     SCMutexUnlock(&segment_pool_memuse_mutex);
 #endif
 
-    SCFree(seg->payload);
+    //SCFree(TCP_SEG_PAYLOAD(seg));
     return;
 }
 
@@ -278,6 +261,25 @@ void StreamTcpReturnStreamSegments (TcpStream *stream)
     stream->seg_list_tail = NULL;
 }
 
+static inline bool STREAM_LASTACK_GT_BASESEQ(const TcpStream *stream)
+{
+    /* last ack not yet initialized */
+    if (stream->base_seq_offset == 0 && stream->last_ack == 0)
+        return false;
+    if (SEQ_GT(stream->last_ack, stream->base_seq))
+        return true;
+    return false;
+}
+
+/** \internal
+ *  \brief check if segments falls before stream 'offset' */
+static inline int SEGMENT_BEFORE_OFFSET(TcpStream *stream, TcpSegment *seg, uint64_t offset)
+{
+    if (seg->sbseg.stream_offset + seg->sbseg.segment_len <= offset)
+        return 1;
+    return 0;
+}
+
 /** \param f locked flow */
 void StreamTcpDisableAppLayer(Flow *f)
 {
@@ -513,6 +515,9 @@ int StreamTcpReassemblyConfig(char quiet)
     if (!quiet)
         SCLogConfig("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size);
 
+    stream_config.sbcnf.flags = STREAMING_BUFFER_NOFLAGS;
+    stream_config.sbcnf.buf_size = 2048;
+
     return 0;
 }
 
@@ -533,11 +538,6 @@ int StreamTcpReassembleInit(char quiet)
     return 0;
 }
 
-#ifdef DEBUG
-static uint32_t dbg_app_layer_gap;
-static uint32_t dbg_app_layer_gap_candidate;
-#endif
-
 void StreamTcpReassembleFree(char quiet)
 {
     uint16_t u16 = 0;
@@ -578,8 +578,6 @@ void StreamTcpReassembleFree(char quiet)
     SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
     SCMutexDestroy(&segment_pool_memuse_mutex);
     SCMutexDestroy(&segment_pool_cnt_mutex);
-    SCLogPerf("dbg_app_layer_gap %u", dbg_app_layer_gap);
-    SCLogPerf("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate);
 #endif
 }
 
@@ -609,5196 +607,1537 @@ void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
     SCReturn;
 }
 
-void PrintList2(TcpSegment *seg)
-{
-    TcpSegment *prev_seg = NULL;
-
-    if (seg == NULL)
-        return;
-
-    uint32_t next_seq = seg->seq;
-
-    while (seg != NULL) {
-        if (SEQ_LT(next_seq,seg->seq)) {
-            SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
-                        (seg->seq - next_seq));
-        }
-
-        SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p",
-                    seg->seq, seg->payload_len, seg, seg->prev, seg->next);
-
-        if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
-            /* check for SEQ_LT cornercase where a - b is exactly 2147483648,
-             * which makes the marco return TRUE in both directions. This is
-             * a hack though, we're going to check next how we end up with
-             * a segment list with seq differences that big */
-            if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
-                SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) =="
-                        " TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 ""
-                        "", seg->seq, seg->prev->seq);
-            }
-        }
-
-        if (SEQ_LT(seg->seq,next_seq)) {
-            SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
-                       "seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
-                       next_seq);
-        }
-
-        if (prev_seg != seg->prev) {
-            SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
-                        prev_seg, seg->prev);
-        }
-
-        next_seq = seg->seq + seg->payload_len;
-        SCLogDebug("next_seq is now %"PRIu32"", next_seq);
-        prev_seg = seg;
-        seg = seg->next;
-    }
-}
-
-void PrintList(TcpSegment *seg)
-{
-    TcpSegment *prev_seg = NULL;
-    TcpSegment *head_seg = seg;
-
-    if (seg == NULL)
-        return;
-
-    uint32_t next_seq = seg->seq;
-
-    while (seg != NULL) {
-        if (SEQ_LT(next_seq,seg->seq)) {
-            SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
-                        (seg->seq - next_seq));
-        }
-
-        SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p, flags 0x%02x",
-                    seg->seq, seg->payload_len, seg, seg->prev, seg->next, seg->flags);
-
-        if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
-            /* check for SEQ_LT cornercase where a - b is exactly 2147483648,
-             * which makes the marco return TRUE in both directions. This is
-             * a hack though, we're going to check next how we end up with
-             * a segment list with seq differences that big */
-            if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
-                SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) == "
-                        "TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "",
-                        seg->seq, seg->prev->seq);
-                PrintList2(head_seg);
-                abort();
-            }
-        }
-
-        if (SEQ_LT(seg->seq,next_seq)) {
-            SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
-                       "seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
-                       next_seq);
-            PrintList2(head_seg);
-            abort();
-        }
-
-        if (prev_seg != seg->prev) {
-            SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
-                       prev_seg, seg->prev);
-            PrintList2(head_seg);
-            abort();
-        }
-
-        next_seq = seg->seq + seg->payload_len;
-        SCLogDebug("next_seq is now %"PRIu32"", next_seq);
-        prev_seg = seg;
-        seg = seg->next;
-    }
-}
-
 /**
- *  \internal
- *  \brief Get the active ra_base_seq, considering stream gaps
+ *  \brief check if stream in pkt direction has depth reached
+ *
+ *  \param p packet with *LOCKED* flow
  *
- *  \retval seq the active ra_base_seq
+ *  \retval 1 stream has depth reached
+ *  \retval 0 stream does not have depth reached
  */
-static inline uint32_t StreamTcpReassembleGetRaBaseSeq(TcpStream *stream)
+int StreamTcpReassembleDepthReached(Packet *p)
 {
-    if (!(stream->flags & STREAMTCP_STREAM_FLAG_GAP)) {
-        SCReturnUInt(stream->ra_app_base_seq);
-    } else {
-        SCReturnUInt(stream->ra_raw_base_seq);
+    if (p->flow != NULL && p->flow->protoctx != NULL) {
+        TcpSession *ssn = p->flow->protoctx;
+        TcpStream *stream;
+        if (p->flowflags & FLOW_PKT_TOSERVER) {
+            stream = &ssn->client;
+        } else {
+            stream = &ssn->server;
+        }
+
+        return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
     }
+
+    return 0;
 }
 
 /**
  *  \internal
- *  \brief  Function to handle the insertion newly arrived segment,
- *          The packet is handled based on its target OS.
+ *  \brief Function to Check the reassembly depth valuer against the
+ *        allowed max depth of the stream reassmbly for TCP streams.
  *
- *  \param  stream  The given TCP stream to which this new segment belongs
- *  \param  seg     Newly arrived segment
- *  \param  p       received packet
+ *  \param stream stream direction
+ *  \param seq sequence number where "size" starts
+ *  \param size size of the segment that is added
  *
- *  \retval 0  success
- *  \retval -1 error -- either we hit a memory issue (OOM/memcap) or we received
- *             a segment before ra_base_seq.
+ *  \retval size Part of the size that fits in the depth, 0 if none
  */
-int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-        TcpStream *stream, TcpSegment *seg, Packet *p)
+static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
+        uint32_t seq, uint32_t size)
 {
     SCEnter();
 
-    TcpSegment *list_seg = stream->seg_list;
-    TcpSegment *next_list_seg = NULL;
-
-#if DEBUG
-    PrintList(stream->seg_list);
-#endif
-
-    int ret_value = 0;
-    char return_seg = FALSE;
-
-    /* before our ra_app_base_seq we don't insert it in our list,
-     * or ra_raw_base_seq if in stream gap state */
-    if (SEQ_LT((TCP_GET_SEQ(p)+p->payload_len),(StreamTcpReassembleGetRaBaseSeq(stream)+1)))
-    {
-        SCLogDebug("not inserting: SEQ+payload %"PRIu32", last_ack %"PRIu32", "
-                "ra_(app|raw)_base_seq %"PRIu32, (TCP_GET_SEQ(p)+p->payload_len),
-                stream->last_ack, StreamTcpReassembleGetRaBaseSeq(stream)+1);
-        return_seg = TRUE;
-        ret_value = -1;
-
-        StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ);
-        goto end;
+    /* if the configured depth value is 0, it means there is no limit on
+       reassembly depth. Otherwise carry on my boy ;) */
+    if (ssn->reassembly_depth == 0) {
+        SCReturnUInt(size);
     }
 
-    SCLogDebug("SEQ %"PRIu32", SEQ+payload %"PRIu32", last_ack %"PRIu32", "
-            "ra_app_base_seq %"PRIu32, TCP_GET_SEQ(p), (TCP_GET_SEQ(p)+p->payload_len),
-            stream->last_ack, stream->ra_app_base_seq);
-
-    if (seg == NULL) {
-        goto end;
+    /* if the final flag is set, we're not accepting anymore */
+    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
+        SCReturnUInt(0);
     }
 
-    /* fast track */
-    if (list_seg == NULL) {
-        SCLogDebug("empty list, inserting seg %p seq %" PRIu32 ", "
-                   "len %" PRIu32 "", seg, seg->seq, seg->payload_len);
-        stream->seg_list = seg;
-        seg->prev = NULL;
-        stream->seg_list_tail = seg;
-        goto end;
+    uint64_t seg_depth;
+    if (SEQ_GT(stream->base_seq, seq)) {
+        if (SEQ_LEQ(seq+size, stream->base_seq)) {
+            SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u",
+                    stream->base_seq, seq, seq+size);
+            SCReturnUInt(0);
+        }
+
+        seg_depth = stream->base_seq_offset + size - (stream->base_seq - seq);
+    } else {
+        seg_depth = stream->base_seq_offset + ((seq + size) - stream->base_seq);
     }
 
-    /* insert the segment in the stream list using this fast track, if seg->seq
-       is equal or higher than stream->seg_list_tail.*/
-    if (SEQ_GEQ(seg->seq, (stream->seg_list_tail->seq +
-            stream->seg_list_tail->payload_len)))
-    {
-        stream->seg_list_tail->next = seg;
-        seg->prev = stream->seg_list_tail;
-        stream->seg_list_tail = seg;
+    /* if the base_seq has moved passed the depth window we stop
+     * checking and just reject the rest of the packets including
+     * retransmissions. Saves us the hassle of dealing with sequence
+     * wraps as well */
+    SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size),
+            stream->base_seq, seg_depth,
+            stream_config.reassembly_depth);
 
-        goto end;
+    if (seg_depth > (uint64_t)stream_config.reassembly_depth) {
+        SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
+        stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
+        SCReturnUInt(0);
     }
+    SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
+    SCLogDebug("%"PRIu64" <= %u", seg_depth, stream_config.reassembly_depth);
+#if 0
+    SCLogDebug("full depth not yet reached: %"PRIu64" <= %"PRIu32,
+            (stream->base_seq_offset + stream->base_seq + size),
+            (stream->isn + stream_config.reassembly_depth));
+#endif
+    if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + stream_config.reassembly_depth))) {
+        /* packet (partly?) fits the depth window */
 
-    /* If the OS policy is not set then set the OS policy for this stream */
-    if (stream->os_policy == 0) {
-        StreamTcpSetOSPolicy(stream, p);
+        if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) {
+            /* complete fit */
+            SCReturnUInt(size);
+        } else {
+            stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
+            /* partial fit, return only what fits */
+            uint32_t part = (stream->isn + 1 + ssn->reassembly_depth) - seq;
+#if DEBUG
+            BUG_ON(part > size);
+#else
+            if (part > size)
+                part = size;
+#endif
+            SCReturnUInt(part);
+        }
     }
 
-    for (; list_seg != NULL; list_seg = next_list_seg) {
-        next_list_seg = list_seg->next;
-
-        SCLogDebug("seg %p, list_seg %p, list_prev %p list_seg->next %p, "
-                   "segment length %" PRIu32 "", seg, list_seg, list_seg->prev,
-                   list_seg->next, seg->payload_len);
-        SCLogDebug("seg->seq %"PRIu32", list_seg->seq %"PRIu32"",
-                   seg->seq, list_seg->seq);
-
-        /* segment starts before list */
-        if (SEQ_LT(seg->seq, list_seg->seq)) {
-            /* seg is entirely before list_seg */
-            if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->seq)) {
-                SCLogDebug("before list seg: seg->seq %" PRIu32 ", list_seg->seq"
-                           " %" PRIu32 ", list_seg->payload_len %" PRIu32 ", "
-                           "list_seg->prev %p", seg->seq, list_seg->seq,
-                           list_seg->payload_len, list_seg->prev);
-                seg->next = list_seg;
-                if (list_seg->prev == NULL) {
-                    stream->seg_list = seg;
-                }
-                if (list_seg->prev != NULL) {
-                    list_seg->prev->next = seg;
-                    seg->prev = list_seg->prev;
-                }
-                list_seg->prev = seg;
+    SCReturnUInt(0);
+}
 
-                goto end;
+static void StreamTcpStoreStreamChunk(TcpSession *ssn, StreamMsg *smsg, const Packet *p, int streaminline)
+{
+    uint8_t direction = 0;
 
-            /* seg overlap with next seg(s) */
-            } else {
-                ret_value = HandleSegmentStartsBeforeListSegment(tv, ra_ctx, stream, list_seg, seg, p);
-                if (ret_value == 1) {
-                    ret_value = 0;
-                    return_seg = TRUE;
-                    goto end;
-                } else if (ret_value == -1) {
-                    SCLogDebug("HandleSegmentStartsBeforeListSegment failed");
-                    ret_value = -1;
-                    return_seg = TRUE;
-                    goto end;
-                }
-            }
+    if ((!streaminline && (p->flowflags & FLOW_PKT_TOSERVER)) ||
+        ( streaminline && (p->flowflags & FLOW_PKT_TOCLIENT)))
+    {
+        direction = STREAM_TOCLIENT;
+        SCLogDebug("stream chunk is to_client");
+    } else {
+        direction = STREAM_TOSERVER;
+        SCLogDebug("stream chunk is to_server");
+    }
 
-        /* seg starts at same sequence number as list_seg */
-        } else if (SEQ_EQ(seg->seq, list_seg->seq)) {
-            ret_value = HandleSegmentStartsAtSameListSegment(tv, ra_ctx, stream, list_seg, seg, p);
-            if (ret_value == 1) {
-                ret_value = 0;
-                return_seg = TRUE;
-                goto end;
-            } else if (ret_value == -1) {
-                SCLogDebug("HandleSegmentStartsAtSameListSegment failed");
-                ret_value = -1;
-                return_seg = TRUE;
-                goto end;
-            }
+    /* store the smsg in the tcp stream */
+    if (direction == STREAM_TOSERVER) {
+        SCLogDebug("storing smsg in the to_server");
 
-        /* seg starts at sequence number higher than list_seg */
-        } else if (SEQ_GT(seg->seq, list_seg->seq)) {
-            if (((SEQ_GEQ(seg->seq, (list_seg->seq + list_seg->payload_len))))
-                    && SEQ_GT((seg->seq + seg->payload_len),
-                    (list_seg->seq + list_seg->payload_len)))
-            {
-                SCLogDebug("starts beyond list end, ends after list end: "
-                           "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ", "
-                           "list_seg->payload_len %" PRIu32 " (%" PRIu32 ")",
-                           seg->seq, list_seg->seq, list_seg->payload_len,
-                           list_seg->seq + list_seg->payload_len);
-
-                if (list_seg->next == NULL) {
-                    list_seg->next = seg;
-                    seg->prev = list_seg;
-                    stream->seg_list_tail = seg;
-                    goto end;
-                }
-            } else {
-                ret_value = HandleSegmentStartsAfterListSegment(tv, ra_ctx, stream, list_seg, seg, p);
-                if (ret_value == 1) {
-                    ret_value = 0;
-                    return_seg = TRUE;
-                    goto end;
-                } else if (ret_value == -1) {
-                    SCLogDebug("HandleSegmentStartsAfterListSegment failed");
-                    ret_value = -1;
-                    return_seg = TRUE;
-                    goto end;
-                }
-            }
+        /* put the smsg in the stream list */
+        if (ssn->toserver_smsg_head == NULL) {
+            ssn->toserver_smsg_head = smsg;
+            ssn->toserver_smsg_tail = smsg;
+            smsg->next = NULL;
+            smsg->prev = NULL;
+        } else {
+            StreamMsg *cur = ssn->toserver_smsg_tail;
+            cur->next = smsg;
+            smsg->prev = cur;
+            smsg->next = NULL;
+            ssn->toserver_smsg_tail = smsg;
         }
-    }
+    } else {
+        SCLogDebug("storing smsg in the to_client");
 
-end:
-    if (return_seg == TRUE && seg != NULL) {
-        StreamTcpSegmentReturntoPool(seg);
+        /* put the smsg in the stream list */
+        if (ssn->toclient_smsg_head == NULL) {
+            ssn->toclient_smsg_head = smsg;
+            ssn->toclient_smsg_tail = smsg;
+            smsg->next = NULL;
+            smsg->prev = NULL;
+        } else {
+            StreamMsg *cur = ssn->toclient_smsg_tail;
+            cur->next = smsg;
+            smsg->prev = cur;
+            smsg->next = NULL;
+            ssn->toclient_smsg_tail = smsg;
+        }
     }
-
-#ifdef DEBUG
-    PrintList(stream->seg_list);
-#endif
-    SCReturnInt(ret_value);
 }
 
 /**
- *  \brief Function to handle the newly arrived segment, when newly arrived
- *         starts with the sequence number lower than the original segment and
- *         ends at different position relative to original segment.
- *         The packet is handled based on its target OS.
+ *  \brief Insert a packets TCP data into the stream reassembly engine.
+ *
+ *  \retval 0 good segment, as far as we checked.
+ *  \retval -1 badness, reason to drop in inline mode
  *
- *  \param list_seg Original Segment in the stream
- *  \param seg      Newly arrived segment
- *  \param prev_seg Previous segment in the stream segment list
- *  \param p        Packet
+ *  If the retval is 0 the segment is inserted correctly, or overlap is handled,
+ *  or it wasn't added because of reassembly depth.
  *
- *  \retval 1 success and done
- *  \retval 0 success, but not done yet
- *  \retval -1 error, will *only* happen on memory errors
  */
-
-static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-        TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p)
+int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+                                TcpSession *ssn, TcpStream *stream, Packet *p)
 {
     SCEnter();
 
-    uint16_t overlap = 0;
-    uint16_t packet_length = 0;
-    uint32_t overlap_point = 0;
-    char end_before = FALSE;
-    char end_after = FALSE;
-    char end_same = FALSE;
-    char return_after = FALSE;
-    uint8_t os_policy = stream->os_policy;
-#ifdef DEBUG
-    SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 "", seg->seq,
-                seg->payload_len);
-    PrintList(stream->seg_list);
-#endif
+    if (ssn->data_first_seen_dir == 0) {
+        if (PKT_IS_TOSERVER(p)) {
+            ssn->data_first_seen_dir = STREAM_TOSERVER;
+        } else {
+            ssn->data_first_seen_dir = STREAM_TOCLIENT;
+        }
+    }
 
-    if (SEQ_GT((seg->seq + seg->payload_len), list_seg->seq) &&
-        SEQ_LT((seg->seq + seg->payload_len),(list_seg->seq +
-                                                        list_seg->payload_len)))
-    {
-        /* seg starts before list seg, ends beyond it but before list end */
-        end_before = TRUE;
-
-        /* [aaaa[abab]bbbb] a = seg, b = list_seg, overlap is the part [abab]
-         * We know seg->seq + seg->payload_len is bigger than list_seg->seq */
-        overlap = (seg->seq + seg->payload_len) - list_seg->seq;
-        overlap_point = list_seg->seq;
-        SCLogDebug("starts before list seg, ends before list end: seg->seq "
-                   "%" PRIu32 ", list_seg->seq %" PRIu32 ", "
-                   "list_seg->payload_len %" PRIu16 " overlap is %" PRIu32 ", "
-                   "overlap point %"PRIu32"", seg->seq, list_seg->seq,
-                   list_seg->payload_len, overlap, overlap_point);
-    } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq +
-                                                        list_seg->payload_len)))
-    {
-        /* seg fully overlaps list_seg, starts before, at end point
-         * [aaa[ababab]] where a = seg, b = list_seg
-         * overlap is [ababab], which is list_seg->payload_len */
-        overlap = list_seg->payload_len;
-        end_same = TRUE;
-        overlap_point = list_seg->seq;
-        SCLogDebug("starts before list seg, ends at list end: list prev %p"
-                   "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ","
-                   "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32 "",
-                   list_seg->prev, seg->seq, list_seg->seq,
-                   list_seg->payload_len, overlap);
-        /* seg fully overlaps list_seg, starts before, ends after list endpoint */
-    } else if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq +
-                                                        list_seg->payload_len)))
-    {
-        /* seg fully overlaps list_seg, starts before, ends after list endpoint
-         * [aaa[ababab]aaa] where a = seg, b = list_seg
-         * overlap is [ababab] which is list_seg->payload_len */
-        overlap = list_seg->payload_len;
-        end_after = TRUE;
-        overlap_point = list_seg->seq;
-        SCLogDebug("starts before list seg, ends after list end: seg->seq "
-                   "%" PRIu32 ", seg->payload_len %"PRIu32" list_seg->seq "
-                   "%" PRIu32 ", list_seg->payload_len %" PRIu32 " overlap is"
-                   " %" PRIu32 "", seg->seq, seg->payload_len,
-                   list_seg->seq, list_seg->payload_len, overlap);
-    }
-
-    if (overlap > 0) {
-        /* handle the case where we need to fill a gap before list_seg first */
-        if (list_seg->prev != NULL && SEQ_LT((list_seg->prev->seq + list_seg->prev->payload_len), list_seg->seq)) {
-            SCLogDebug("GAP to fill before list segment, size %u", list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len));
-
-            uint32_t new_seq = (list_seg->prev->seq + list_seg->prev->payload_len);
-            if (SEQ_GT(seg->seq, new_seq)) {
-                new_seq = seg->seq;
-            }
+    /* If the OS policy is not set then set the OS policy for this stream */
+    if (stream->os_policy == 0) {
+        StreamTcpSetOSPolicy(stream, p);
+    }
 
-            packet_length = list_seg->seq - new_seq;
-            if (packet_length > seg->payload_len) {
-                packet_length = seg->payload_len;
-            }
+    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
+        (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) {
+        SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
+        SCReturnInt(0);
+    }
 
-            TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-            if (new_seg == NULL) {
-                SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+    /* If we have reached the defined depth for either of the stream, then stop
+       reassembling the TCP session */
+    uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len);
+    SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
 
-                StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                SCReturnInt(-1);
-            }
-            new_seg->payload_len = packet_length;
+    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
+        /* increment stream depth counter */
+        StatsIncr(tv, ra_ctx->counter_tcp_stream_depth);
 
-            new_seg->seq = new_seq;
+        stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY;
+        SCLogDebug("ssn %p: reassembly depth reached, "
+                "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn);
+    }
+    if (size == 0) {
+        SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
+        SCReturnInt(0);
+    }
 
-            SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
-                    "%" PRIu16"", new_seg->seq, new_seg->payload_len);
+#if DEBUG
+    BUG_ON(size > p->payload_len);
+#else
+    if (size > p->payload_len)
+        size = p->payload_len;
+#endif
 
-            new_seg->next = list_seg;
-            new_seg->prev = list_seg->prev;
-            list_seg->prev->next = new_seg;
-            list_seg->prev = new_seg;
-
-            /* create a new seg, copy the list_seg data over */
-            StreamTcpSegmentDataCopy(new_seg, seg);
-
-#ifdef DEBUG
-            PrintList(stream->seg_list);
-#endif
-        }
+    TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx, size);
+    if (seg == NULL) {
+        SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[size]);
 
-        /* Handling case when the segment starts before the first segment in
-         * the list */
-        if (list_seg->prev == NULL) {
-            if (end_after == TRUE && list_seg->next != NULL &&
-                    SEQ_LT(list_seg->next->seq, (seg->seq + seg->payload_len)))
-            {
-                packet_length = (list_seg->seq - seg->seq) + list_seg->payload_len;
-            } else {
-                packet_length = seg->payload_len + (list_seg->payload_len - overlap);
-                return_after = TRUE;
-            }
+        StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
+        SCReturnInt(-1);
+    }
 
-            SCLogDebug("entered here packet_length %" PRIu32 ", seg->payload_len"
-                       " %" PRIu32 ", list->payload_len %" PRIu32 "",
-                       packet_length, seg->payload_len, list_seg->payload_len);
+    TCP_SEG_LEN(seg) = size;
+    seg->seq = TCP_GET_SEQ(p);
 
-            TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-            if (new_seg == NULL) {
-                SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+    /* proto detection skipped, but now we do get data. Set event. */
+    if (stream->seg_list == NULL &&
+        stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) {
 
-                StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                SCReturnInt(-1);
-            }
-            new_seg->payload_len = packet_length;
-            new_seg->seq = seg->seq;
-            new_seg->next = list_seg->next;
-            new_seg->prev = list_seg->prev;
+        AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
+                APPLAYER_PROTO_DETECTION_SKIPPED);
+    }
 
-            StreamTcpSegmentDataCopy(new_seg, list_seg);
+    if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p, TCP_GET_SEQ(p), p->payload, p->payload_len) != 0) {
+        SCLogDebug("StreamTcpReassembleInsertSegment failed");
+        SCReturnInt(-1);
+    }
+    SCReturnInt(0);
+}
 
-            /* first the data before the list_seg->seq */
-            uint16_t replace = (uint16_t) (list_seg->seq - seg->seq);
-            SCLogDebug("copying %"PRIu16" bytes to new_seg", replace);
-            StreamTcpSegmentDataReplace(new_seg, seg, seg->seq, replace);
+static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
+                                      Packet *p)
+{
+    uint8_t flag = 0;
 
-            /* if any, data after list_seg->seq + list_seg->payload_len */
-            if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq +
-                    list_seg->payload_len)) && return_after == TRUE)
-            {
-                replace = (uint16_t)(((seg->seq + seg->payload_len) -
-                                             (list_seg->seq +
-                                              list_seg->payload_len)));
-                SCLogDebug("replacing %"PRIu16"", replace);
-                StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq +
-                                             list_seg->payload_len), replace);
-            }
+    if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {
+        flag |= STREAM_START;
+    }
 
-            /* update the stream last_seg in case of removal of list_seg */
-            if (stream->seg_list_tail == list_seg)
-                stream->seg_list_tail = new_seg;
+    if (ssn->state == TCP_CLOSED) {
+        flag |= STREAM_EOF;
+    }
+    if (p->flags & PKT_PSEUDO_STREAM_END) {
+        flag |= STREAM_EOF;
+    }
 
-            StreamTcpSegmentReturntoPool(list_seg);
-            list_seg = new_seg;
-            if (new_seg->prev != NULL) {
-                new_seg->prev->next = new_seg;
-            }
-            if (new_seg->next != NULL) {
-                new_seg->next->prev = new_seg;
-            }
+    if (StreamTcpInlineMode() == 0) {
+        if (p->flowflags & FLOW_PKT_TOSERVER) {
+            flag |= STREAM_TOCLIENT;
+        } else {
+            flag |= STREAM_TOSERVER;
+        }
+    } else {
+        if (p->flowflags & FLOW_PKT_TOSERVER) {
+            flag |= STREAM_TOSERVER;
+        } else {
+            flag |= STREAM_TOCLIENT;
+        }
+    }
 
-            stream->seg_list = new_seg;
-            SCLogDebug("list_seg now %p, stream->seg_list now %p", list_seg,
-                        stream->seg_list);
+    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
+        flag |= STREAM_DEPTH;
+    }
+    return flag;
+}
 
-        } else if (end_before == TRUE || end_same == TRUE) {
-            /* Handling overlapping with more than one segment and filling gap */
-            if (SEQ_GT(list_seg->seq, (list_seg->prev->seq +
-                                   list_seg->prev->payload_len)))
-            {
-                SCLogDebug("list_seg->prev %p list_seg->prev->seq %"PRIu32" "
-                           "list_seg->prev->payload_len %"PRIu16"",
-                            list_seg->prev, list_seg->prev->seq,
-                            list_seg->prev->payload_len);
-                if (SEQ_LT(list_seg->prev->seq, seg->seq)) {
-                    packet_length = list_seg->payload_len + (list_seg->seq -
-                                                                    seg->seq);
-                } else {
-                    packet_length = list_seg->payload_len + (list_seg->seq -
-                           (list_seg->prev->seq + list_seg->prev->payload_len));
-                }
+/**
+ *  \brief Check the minimum size limits for reassembly.
+ *
+ *  \retval 0 don't reassemble yet
+ *  \retval 1 do reassemble
+ */
+static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream,
+                                         Packet *p)
+{
+    SCEnter();
 
-                TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-                if (new_seg == NULL) {
-                    SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+    if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+        SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NOREASSEMBLY is set, so not expecting any new packets");
+        SCReturnInt(1);
+    }
 
-                    StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                    SCReturnInt(-1);
-                }
+    if (ssn->flags & STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY) {
+        SCLogDebug("reassembling now as STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY is set");
+        ssn->flags &= ~STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
+        SCReturnInt(1);
+    }
 
-                new_seg->payload_len = packet_length;
-                if (SEQ_GT((list_seg->prev->seq + list_seg->prev->payload_len),
-                        seg->seq))
-                {
-                    new_seg->seq = (list_seg->prev->seq +
-                                    list_seg->prev->payload_len);
-                } else {
-                    new_seg->seq = seg->seq;
-                }
-                SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
-                           "%" PRIu16"", new_seg->seq, new_seg->payload_len);
-                new_seg->next = list_seg->next;
-                new_seg->prev = list_seg->prev;
-
-                StreamTcpSegmentDataCopy(new_seg, list_seg);
-
-                uint16_t copy_len = (uint16_t) (list_seg->seq - seg->seq);
-                SCLogDebug("copy_len %" PRIu32 " (%" PRIu32 " - %" PRIu32 ")",
-                            copy_len, list_seg->seq, seg->seq);
-                StreamTcpSegmentDataReplace(new_seg, seg, seg->seq, copy_len);
-
-                /*update the stream last_seg in case of removal of list_seg*/
-                if (stream->seg_list_tail == list_seg)
-                    stream->seg_list_tail = new_seg;
-
-                StreamTcpSegmentReturntoPool(list_seg);
-                list_seg = new_seg;
-                if (new_seg->prev != NULL) {
-                    new_seg->prev->next = new_seg;
-                }
-                if (new_seg->next != NULL) {
-                    new_seg->next->prev = new_seg;
-                }
-            }
-        } else if (end_after == TRUE) {
-            if (list_seg->next != NULL) {
-                if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->next->seq))
-                {
-                    if (SEQ_GT(seg->seq, (list_seg->prev->seq +
-                                list_seg->prev->payload_len)))
-                    {
-                        packet_length = list_seg->payload_len + (list_seg->seq -
-                                                                 seg->seq);
-                    } else {
-                        packet_length = list_seg->payload_len + (list_seg->seq -
-                                                (list_seg->prev->seq +
-                                                 list_seg->prev->payload_len));
-                    }
-
-                    packet_length += (seg->seq + seg->payload_len) -
-                                        (list_seg->seq + list_seg->payload_len);
-
-                    TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-                    if (new_seg == NULL) {
-                        SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
-
-                        StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                        SCReturnInt(-1);
-                    }
-                    new_seg->payload_len = packet_length;
-                    if (SEQ_GT((list_seg->prev->seq +
-                                    list_seg->prev->payload_len), seg->seq))
-                    {
-                        new_seg->seq = (list_seg->prev->seq +
-                                            list_seg->prev->payload_len);
-                    } else {
-                        new_seg->seq = seg->seq;
-                    }
-                    SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
-                           "%" PRIu16"", new_seg->seq, new_seg->payload_len);
-                    new_seg->next = list_seg->next;
-                    new_seg->prev = list_seg->prev;
-
-                    /* create a new seg, copy the list_seg data over */
-                    StreamTcpSegmentDataCopy(new_seg, list_seg);
-
-                    /* copy the part before list_seg */
-                    uint16_t copy_len = list_seg->seq - new_seg->seq;
-                    StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
-                                                copy_len);
-
-                    /* copy the part after list_seg */
-                    copy_len = (seg->seq + seg->payload_len) -
-                                    (list_seg->seq + list_seg->payload_len);
-                    StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq +
-                                              list_seg->payload_len), copy_len);
-
-                    if (new_seg->prev != NULL) {
-                        new_seg->prev->next = new_seg;
-                    }
-                    if (new_seg->next != NULL) {
-                        new_seg->next->prev = new_seg;
-                    }
-                    /*update the stream last_seg in case of removal of list_seg*/
-                    if (stream->seg_list_tail == list_seg)
-                        stream->seg_list_tail = new_seg;
-
-                    StreamTcpSegmentReturntoPool(list_seg);
-                    list_seg = new_seg;
-                    return_after = TRUE;
-                }
-            /* Handle the case, when list_seg is the end of segment list, but
-               seg is ending after the list_seg. So we need to copy the data
-               from newly received segment. After copying return the newly
-               received seg to pool */
-            } else {
-                if (SEQ_GT(seg->seq, (list_seg->prev->seq +
-                                list_seg->prev->payload_len)))
-                {
-                    packet_length = list_seg->payload_len + (list_seg->seq -
-                            seg->seq);
-                } else {
-                    packet_length = list_seg->payload_len + (list_seg->seq -
-                            (list_seg->prev->seq +
-                             list_seg->prev->payload_len));
-                }
+    if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
+        SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
+                "so no new segments will be considered");
+        SCReturnInt(1);
+    }
 
-                packet_length += (seg->seq + seg->payload_len) -
-                    (list_seg->seq + list_seg->payload_len);
+    /* some states mean we reassemble no matter how much data we have */
+    if (ssn->state >= TCP_TIME_WAIT)
+        SCReturnInt(1);
 
-                TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-                if (new_seg == NULL) {
-                    SCLogDebug("segment_pool[%"PRIu16"] is empty",
-                            segment_pool_idx[packet_length]);
+    if (p->flags & PKT_PSEUDO_STREAM_END)
+        SCReturnInt(1);
 
-                    StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                    SCReturnInt(-1);
-                }
-                new_seg->payload_len = packet_length;
+    /* check if we have enough data to do raw reassembly */
+    if (p->flowflags & FLOW_PKT_TOCLIENT) {
+        SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOSERVER) %"PRIu32,
+                StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
 
-                if (SEQ_GT((list_seg->prev->seq +
-                                list_seg->prev->payload_len), seg->seq))
-                {
-                    new_seg->seq = (list_seg->prev->seq +
-                            list_seg->prev->payload_len);
-                } else {
-                    new_seg->seq = seg->seq;
-                }
-                SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
-                        "%" PRIu16"", new_seg->seq, new_seg->payload_len);
-                new_seg->next = list_seg->next;
-                new_seg->prev = list_seg->prev;
-
-                /* create a new seg, copy the list_seg data over */
-                StreamTcpSegmentDataCopy(new_seg, list_seg);
-
-                /* copy the part before list_seg */
-                uint16_t copy_len = list_seg->seq - new_seg->seq;
-                StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
-                        copy_len);
-
-                /* copy the part after list_seg */
-                copy_len = (seg->seq + seg->payload_len) -
-                    (list_seg->seq + list_seg->payload_len);
-                StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq +
-                            list_seg->payload_len), copy_len);
-
-                if (new_seg->prev != NULL) {
-                    new_seg->prev->next = new_seg;
-                }
+        uint32_t delta = stream->last_ack - stream->base_seq;
+        /* get max absolute offset */
+        uint64_t max_offset = stream->base_seq_offset + delta;
 
-                /*update the stream last_seg in case of removal of list_seg*/
-                if (stream->seg_list_tail == list_seg)
-                    stream->seg_list_tail = new_seg;
+        int64_t diff = max_offset - stream->raw_progress;
 
-                StreamTcpSegmentReturntoPool(list_seg);
-                list_seg = new_seg;
-                return_after = TRUE;
-            }
+        if ((int64_t)StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER) >
+                diff) {
+            SCLogDebug("toserver min chunk len not yet reached: "
+                    "last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < "
+                    "%"PRIu32"", stream->last_ack, stream->base_seq,
+                    (stream->last_ack - stream->base_seq),
+                    StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
+            SCReturnInt(0);
         }
+    } else {
+        SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOCLIENT) %"PRIu32,
+                StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
 
-        if (check_overlap_different_data &&
-                !StreamTcpSegmentDataCompare(seg, list_seg, list_seg->seq, overlap)) {
-            /* interesting, overlap with different data */
-            StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
-        }
+        uint32_t delta = stream->last_ack - stream->base_seq;
+        /* get max absolute offset */
+        uint64_t max_offset = stream->base_seq_offset + delta;
 
-        if (StreamTcpInlineMode()) {
-            if (StreamTcpInlineSegmentCompare(seg, list_seg) != 0) {
-                StreamTcpInlineSegmentReplacePacket(p, list_seg);
-            }
-        } else {
-            switch (os_policy) {
-                case OS_POLICY_SOLARIS:
-                case OS_POLICY_HPUX11:
-                    if (end_after == TRUE || end_same == TRUE) {
-                        StreamTcpSegmentDataReplace(list_seg, seg, overlap_point,
-                                overlap);
-                    } else {
-                        SCLogDebug("using old data in starts before list case, "
-                                "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                                "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                                overlap);
-                    }
-                    break;
-                case OS_POLICY_VISTA:
-                case OS_POLICY_FIRST:
-                    SCLogDebug("using old data in starts before list case, "
-                            "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                            "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                            overlap);
-                    break;
-                case OS_POLICY_BSD:
-                case OS_POLICY_HPUX10:
-                case OS_POLICY_IRIX:
-                case OS_POLICY_WINDOWS:
-                case OS_POLICY_WINDOWS2K3:
-                case OS_POLICY_OLD_LINUX:
-                case OS_POLICY_LINUX:
-                case OS_POLICY_MACOS:
-                case OS_POLICY_LAST:
-                default:
-                    SCLogDebug("replacing old data in starts before list seg "
-                            "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                            "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                            overlap);
-                    StreamTcpSegmentDataReplace(list_seg, seg, overlap_point,
-                            overlap);
-                    break;
-            }
-        }
-        /* To return from for loop as seg is finished with current list_seg
-           no need to check further (improve performance) */
-        if (end_before == TRUE || end_same == TRUE || return_after == TRUE) {
-            SCReturnInt(1);
+        int64_t diff = max_offset - stream->raw_progress;
+
+        if ((int64_t)StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT) >
+                diff) {
+            SCLogDebug("toclient min chunk len not yet reached: "
+                    "last_ack %"PRIu32", base_seq %"PRIu32",  %"PRIu32" < "
+                    "%"PRIu32"", stream->last_ack, stream->base_seq,
+                    (stream->last_ack - stream->base_seq),
+                    StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
+            SCReturnInt(0);
         }
     }
 
-    SCReturnInt(0);
+    SCReturnInt(1);
 }
 
 /**
- *  \brief  Function to handle the newly arrived segment, when newly arrived
- *          starts with the same sequence number as the original segment and
- *          ends at different position relative to original segment.
- *          The packet is handled based on its target OS.
- *
- *  \param  list_seg    Original Segment in the stream
- *  \param  seg         Newly arrived segment
- *  \param  prev_seg    Previous segment in the stream segment list
- *
- *  \retval 1 success and done
- *  \retval 0 success, but not done yet
- *  \retval -1 error, will *only* happen on memory errors
+ *  \brief see what if any work the TCP session still needs
  */
-
-static int HandleSegmentStartsAtSameListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-        TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p)
+int StreamNeedsReassembly(TcpSession *ssn, int direction)
 {
-    uint16_t overlap = 0;
-    uint16_t packet_length;
-    char end_before = FALSE;
-    char end_after = FALSE;
-    char end_same = FALSE;
-    char handle_beyond = FALSE;
-    uint8_t os_policy = stream->os_policy;
-
-    if (SEQ_LT((seg->seq + seg->payload_len), (list_seg->seq +
-                                               list_seg->payload_len)))
-    {
-        /* seg->seg == list_seg->seq and list_seg->payload_len > seg->payload_len
-         * [[ababab]bbbb] where a = seg, b = list_seg
-         * overlap is the [ababab] part, which equals seg->payload_len. */
-        overlap = seg->payload_len;
-        end_before = TRUE;
-        SCLogDebug("starts at list seq, ends before list end: seg->seq "
-                   "%" PRIu32 ", list_seg->seq %" PRIu32 ", "
-                   "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32,
-                   seg->seq, list_seg->seq, list_seg->payload_len, overlap);
-
-    } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq +
-                                                        list_seg->payload_len)))
-    {
-        /* seg starts at seq, ends at seq, retransmission.
-         * both segments are the same, so overlap is either
-         * seg->payload_len or list_seg->payload_len */
-
-        /* check csum, ack, other differences? */
-        overlap = seg->payload_len;
-        end_same = TRUE;
-        SCLogDebug("(retransmission) starts at list seq, ends at list end: "
-                   "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ", "
-                   "list_seg->payload_len %" PRIu32 " overlap is %"PRIu32"",
-                   seg->seq, list_seg->seq, list_seg->payload_len, overlap);
-
-    } else if (SEQ_GT((seg->seq + seg->payload_len),
-            (list_seg->seq + list_seg->payload_len))) {
-        /* seg starts at seq, ends beyond seq. */
-        /* seg->seg == list_seg->seq and seg->payload_len > list_seg->payload_len
-         * [[ababab]aaaa] where a = seg, b = list_seg
-         * overlap is the [ababab] part, which equals list_seg->payload_len. */
-        overlap = list_seg->payload_len;
-        end_after = TRUE;
-        SCLogDebug("starts at list seq, ends beyond list end: seg->seq "
-                   "%" PRIu32 ", list_seg->seq %" PRIu32 ", "
-                   "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32 "",
-                   seg->seq, list_seg->seq, list_seg->payload_len, overlap);
-    }
-    if (overlap > 0) {
-        /*Handle the case when newly arrived segment ends after original
-          segment and original segment is the last segment in the list
-          or the next segment in the list starts after the end of new segment*/
-        if (end_after == TRUE) {
-            char fill_gap = FALSE;
-
-            if (list_seg->next != NULL) {
-                /* first see if we have space left to fill up */
-                if (SEQ_LT((list_seg->seq + list_seg->payload_len),
-                            list_seg->next->seq))
-                {
-                    fill_gap = TRUE;
-                }
-
-                /* then see if we overlap (partly) with the next seg */
-                if (SEQ_GT((seg->seq + seg->payload_len), list_seg->next->seq))
-                {
-                    handle_beyond = TRUE;
-                }
-            /* Handle the case, when list_seg is the end of segment list, but
-               seg is ending after the list_seg. So we need to copy the data
-               from newly received segment. After copying return the newly
-               received seg to pool */
-            } else {
-                fill_gap = TRUE;
-            }
+    TcpStream *stream = NULL;
+    StreamMsg *head = NULL;
+#ifdef DEBUG
+    char *dirstr = NULL;
+#endif
+    /* TODO use STREAM_TOCLIENT/STREAM_TOSERVER */
+    if (direction == 0) {
+        stream = &ssn->client;
+        head = ssn->toserver_smsg_head;
+#ifdef DEBUG
+        dirstr = "client";
+#endif
+    } else {
+        stream = &ssn->server;
+        head = ssn->toclient_smsg_head;
+#ifdef DEBUG
+        dirstr = "server";
+#endif
+    }
 
-            SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE",
-                        handle_beyond?"TRUE":"FALSE");
-
-            if (fill_gap == TRUE) {
-                /* if there is a gap after this list_seg we fill it now with a
-                 * new seg */
-                SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"",
-                            list_seg->next?list_seg->next->seq:0);
-                if (handle_beyond == TRUE) {
-                    packet_length = list_seg->next->seq -
-                                        (list_seg->seq + list_seg->payload_len);
-                } else {
-                    packet_length = seg->payload_len - list_seg->payload_len;
-                }
+    int use_app = 1;
+    int use_raw = 1;
 
-                SCLogDebug("packet_length %"PRIu16"", packet_length);
+    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
+          (stream->flags & STREAMTCP_STREAM_FLAG_GAP))
+    {
+        // app is dead
+        use_app = 0;
+    }
 
-                TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-                if (new_seg == NULL) {
-                    SCLogDebug("egment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+    if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) {
+        // raw is dead
+        use_raw = 0;
+    }
 
-                    StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                    return -1;
-                }
-                new_seg->payload_len = packet_length;
-                new_seg->seq = list_seg->seq + list_seg->payload_len;
-                new_seg->next = list_seg->next;
-                if (new_seg->next != NULL)
-                    new_seg->next->prev = new_seg;
-                new_seg->prev = list_seg;
-                list_seg->next = new_seg;
-                SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, "
-                           "list_seg->next %p", new_seg, new_seg->next,
-                           new_seg->prev, list_seg->next);
-                StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
-                                            new_seg->payload_len);
-
-                /*update the stream last_seg in case of removal of list_seg*/
-                if (stream->seg_list_tail == list_seg)
-                    stream->seg_list_tail = new_seg;
-            }
-        }
+    if (stream->seg_list_tail != NULL) {
+        uint64_t right_edge = TCP_SEG_OFFSET(stream->seg_list_tail) +
+                              TCP_SEG_LEN(stream->seg_list_tail);
 
-        if (check_overlap_different_data &&
-                !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) {
-            /* interesting, overlap with different data */
-            StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
-        }
+        SCLogDebug("%s: list %p app %"PRIu64" (use: %s), raw %"PRIu64" (use: %s). Stream right edge: %"PRIu64,
+                dirstr,
+                stream->seg_list,
+                stream->app_progress, use_app ? "yes" : "no",
+                stream->raw_progress, use_raw ? "yes" : "no",
+                right_edge);
 
-        if (StreamTcpInlineMode()) {
-            if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) {
-                StreamTcpInlineSegmentReplacePacket(p, list_seg);
-            }
-        } else {
-            switch (os_policy) {
-                case OS_POLICY_OLD_LINUX:
-                case OS_POLICY_SOLARIS:
-                case OS_POLICY_HPUX11:
-                    if (end_after == TRUE || end_same == TRUE) {
-                        StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
-                    } else {
-                        SCLogDebug("using old data in starts at list case, "
-                                "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                                "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                                overlap);
-                    }
-                    break;
-                case OS_POLICY_LAST:
-                    StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
-                    break;
-                case OS_POLICY_LINUX:
-                    if (end_after == TRUE) {
-                        StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
-                    } else {
-                        SCLogDebug("using old data in starts at list case, "
-                                "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                                "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                                overlap);
-                    }
-                    break;
-                case OS_POLICY_BSD:
-                case OS_POLICY_HPUX10:
-                case OS_POLICY_IRIX:
-                case OS_POLICY_WINDOWS:
-                case OS_POLICY_WINDOWS2K3:
-                case OS_POLICY_VISTA:
-                case OS_POLICY_MACOS:
-                case OS_POLICY_FIRST:
-                default:
-                    SCLogDebug("using old data in starts at list case, list_seg->seq"
-                            " %" PRIu32 " policy %" PRIu32 " overlap %" PRIu32 "",
-                            list_seg->seq, os_policy, overlap);
-                    break;
+        if (use_raw) {
+            if (right_edge > stream->raw_progress) {
+                SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY", dirstr);
+                return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
             }
         }
-
-        /* return 1 if we're done */
-        if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) {
-            return 1;
+        if (use_app) {
+            if (right_edge > stream->app_progress) {
+                SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY", dirstr);
+                return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
+            }
         }
+    } else {
+        SCLogDebug("%s: no list", dirstr);
     }
-    return 0;
-}
 
-/**
- *  \internal
- *  \brief  Function to handle the newly arrived segment, when newly arrived
- *          starts with the sequence number higher than the original segment and
- *          ends at different position relative to original segment.
- *          The packet is handled based on its target OS.
- *
- *  \param  list_seg    Original Segment in the stream
- *  \param  seg         Newly arrived segment
- *  \param  prev_seg    Previous segment in the stream segment list
+    if (head != NULL) {
+        SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
+        return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
+    }
 
- *  \retval 1 success and done
- *  \retval 0 success, but not done yet
- *  \retval -1 error, will *only* happen on memory errors
- */
+    SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
+    return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
+}
 
-static int HandleSegmentStartsAfterListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-        TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p)
+#ifdef DEBUG
+static uint64_t GetStreamSize(TcpStream *stream)
 {
-    SCEnter();
-    uint16_t overlap = 0;
-    uint16_t packet_length;
-    char end_before = FALSE;
-    char end_after = FALSE;
-    char end_same = FALSE;
-    char handle_beyond = FALSE;
-    uint8_t os_policy = stream->os_policy;
-
-    if (SEQ_LT((seg->seq + seg->payload_len), (list_seg->seq +
-                list_seg->payload_len)))
-    {
-        /* seg starts after list, ends before list end
-         * [bbbb[ababab]bbbb] where a = seg, b = list_seg
-         * overlap is the part [ababab] which is seg->payload_len */
-        overlap = seg->payload_len;
-        end_before = TRUE;
-
-        SCLogDebug("starts beyond list seq, ends before list end: seg->seq"
-            " %" PRIu32 ", list_seg->seq %" PRIu32 ", list_seg->payload_len "
-            "%" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq,
-            list_seg->payload_len, overlap);
-
-    } else if (SEQ_EQ((seg->seq + seg->payload_len),
-            (list_seg->seq + list_seg->payload_len))) {
-        /* seg starts after seq, before end, ends at seq
-         * [bbbb[ababab]] where a = seg, b = list_seg
-         * overlapping part is [ababab], thus seg->payload_len */
-        overlap = seg->payload_len;
-        end_same = TRUE;
-
-        SCLogDebug("starts beyond list seq, ends at list end: seg->seq"
-            " %" PRIu32 ", list_seg->seq %" PRIu32 ", list_seg->payload_len "
-            "%" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq,
-            list_seg->payload_len, overlap);
-
-    } else if (SEQ_LT(seg->seq, list_seg->seq + list_seg->payload_len) &&
-               SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq +
-                       list_seg->payload_len)))
-    {
-        /* seg starts after seq, before end, ends beyond seq.
-         *
-         * [bbb[ababab]aaa] where a = seg, b = list_seg.
-         * overlap is the [ababab] part, which can be get using:
-         * (list_seg->seq + list_seg->payload_len) - seg->seg */
-        overlap = (list_seg->seq + list_seg->payload_len) - seg->seq;
-        end_after = TRUE;
-
-        SCLogDebug("starts beyond list seq, ends after list seq end: "
-            "seg->seq %" PRIu32 ", seg->payload_len %"PRIu16" (%"PRIu32") "
-            "list_seg->seq %" PRIu32 ", list_seg->payload_len %" PRIu32 " "
-            "(%"PRIu32") overlap is %" PRIu32 "", seg->seq, seg->payload_len,
-            seg->seq + seg->payload_len, list_seg->seq, list_seg->payload_len,
-            list_seg->seq + list_seg->payload_len, overlap);
-    }
-    if (overlap > 0) {
-        /*Handle the case when newly arrived segment ends after original
-          segment and original segment is the last segment in the list*/
-        if (end_after == TRUE) {
-            char fill_gap = FALSE;
-
-            if (list_seg->next != NULL) {
-                /* first see if we have space left to fill up */
-                if (SEQ_LT((list_seg->seq + list_seg->payload_len),
-                            list_seg->next->seq))
-                {
-                    fill_gap = TRUE;
-                }
+    if (stream) {
+        uint64_t size = 0;
+        uint32_t cnt = 0;
 
-                /* then see if we overlap (partly) with the next seg */
-                if (SEQ_GT((seg->seq + seg->payload_len), list_seg->next->seq))
-                {
-                    handle_beyond = TRUE;
-                }
-            } else {
-                fill_gap = TRUE;
-            }
+        TcpSegment *seg = stream->seg_list;
+        while (seg) {
+            cnt++;
+            size += (uint64_t)TCP_SEG_LEN(seg);
 
-            SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE",
-                        handle_beyond?"TRUE":"FALSE");
+            seg = seg->next;
+        }
 
-            if (fill_gap == TRUE) {
-                /* if there is a gap after this list_seg we fill it now with a
-                 * new seg */
-                if (list_seg->next != NULL) {
-                    SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"",
-                            list_seg->next?list_seg->next->seq:0);
+        SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
+        return size;
+    }
+    return (uint64_t)0;
+}
 
-                    packet_length = list_seg->next->seq - (list_seg->seq +
-                            list_seg->payload_len);
-                } else {
-                    packet_length = seg->payload_len - overlap;
-                }
-                if (packet_length > (seg->payload_len - overlap)) {
-                    packet_length = seg->payload_len - overlap;
-                }
-                SCLogDebug("packet_length %"PRIu16"", packet_length);
+static void GetSessionSize(TcpSession *ssn, Packet *p)
+{
+    uint64_t size = 0;
+    if (ssn) {
+        size = GetStreamSize(&ssn->client);
+        size += GetStreamSize(&ssn->server);
+
+        //if (size > 900000)
+        //    SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
+        SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
+    }
+}
+#endif
 
-                TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
-                if (new_seg == NULL) {
-                    SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+/** \internal
+ *
+ *  Get buffer, or first part of the buffer if data gaps exist.
+ *
+ *  \brief get stream data from offset
+ *  \param offset stream offset */
+static void GetAppBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_len, uint64_t offset)
+{
+    const uint8_t *mydata;
+    uint32_t mydata_len;
 
-                    StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-                    SCReturnInt(-1);
-                }
-                new_seg->payload_len = packet_length;
-                new_seg->seq = list_seg->seq + list_seg->payload_len;
-                new_seg->next = list_seg->next;
-                if (new_seg->next != NULL)
-                    new_seg->next->prev = new_seg;
-                new_seg->prev = list_seg;
-                list_seg->next = new_seg;
-
-                SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, "
-                           "list_seg->next %p new_seg->seq %"PRIu32"", new_seg,
-                            new_seg->next, new_seg->prev, list_seg->next,
-                            new_seg->seq);
-
-                StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
-                                            new_seg->payload_len);
-
-                /* update the stream last_seg in case of removal of list_seg */
-                if (stream->seg_list_tail == list_seg)
-                    stream->seg_list_tail = new_seg;
-            }
-        }
+    if (stream->sb->block_list == NULL) {
+        SCLogDebug("getting one blob");
 
-        if (check_overlap_different_data &&
-                !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) {
-            /* interesting, overlap with different data */
-            StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
-        }
+        StreamingBufferGetDataAtOffset(stream->sb, &mydata, &mydata_len, offset);
 
-        if (StreamTcpInlineMode()) {
-            if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) {
-                StreamTcpInlineSegmentReplacePacket(p, list_seg);
-            }
+        *data = mydata;
+        *data_len = mydata_len;
+    } else {
+        StreamingBufferBlock *blk = stream->sb->block_list;
+
+        if (blk->offset > offset) {
+            SCLogDebug("gap, want data at offset %"PRIu64", got data at %"PRIu64,
+                    offset, blk->offset);
+            *data = NULL;
+            *data_len = 0;
+
+        } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
+            SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
+                    offset, blk->offset, blk->len);
+            StreamingBufferSBBGetDataAtOffset(stream->sb, blk, data, data_len, offset);
+            SCLogDebug("data %p, data_len %u", *data, *data_len);
         } else {
-            switch (os_policy) {
-                case OS_POLICY_SOLARIS:
-                case OS_POLICY_HPUX11:
-                    if (end_after == TRUE) {
-                        StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
-                    } else {
-                        SCLogDebug("using old data in starts beyond list case, "
-                                "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                                "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                                overlap);
-                    }
-                    break;
-                case OS_POLICY_LAST:
-                    StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
-                    break;
-                case OS_POLICY_BSD:
-                case OS_POLICY_HPUX10:
-                case OS_POLICY_IRIX:
-                case OS_POLICY_WINDOWS:
-                case OS_POLICY_WINDOWS2K3:
-                case OS_POLICY_VISTA:
-                case OS_POLICY_OLD_LINUX:
-                case OS_POLICY_LINUX:
-                case OS_POLICY_MACOS:
-                case OS_POLICY_FIRST:
-                default: /* DEFAULT POLICY */
-                    SCLogDebug("using old data in starts beyond list case, "
-                            "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
-                            "overlap %" PRIu32 "", list_seg->seq, os_policy,
-                            overlap);
-                    break;
-            }
-        }
-        if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) {
-            SCReturnInt(1);
+            StreamingBufferSBBGetData(stream->sb, blk, data, data_len);
         }
     }
-    SCReturnInt(0);
 }
 
-/**
- *  \brief check if stream in pkt direction has depth reached
- *
- *  \param p packet with *LOCKED* flow
- *
- *  \retval 1 stream has depth reached
- *  \retval 0 stream does not have depth reached
+/** \internal
+ *  \brief get stream buffer and update the app-layer
+ *  \retval 0 success
  */
-int StreamTcpReassembleDepthReached(Packet *p)
+static int ReassembleUpdateAppLayer (ThreadVars *tv,
+        TcpReassemblyThreadCtx *ra_ctx,
+        TcpSession *ssn, TcpStream *stream,
+        Packet *p)
 {
-    if (p->flow != NULL && p->flow->protoctx != NULL) {
-        TcpSession *ssn = p->flow->protoctx;
-        TcpStream *stream;
-        if (p->flowflags & FLOW_PKT_TOSERVER) {
-            stream = &ssn->client;
-        } else {
-            stream = &ssn->server;
+    const uint64_t app_progress = stream->app_progress;
+    uint64_t last_ack_abs = app_progress; /* absolute right edge of ack'd data */
+
+    SCLogDebug("app progress %"PRIu64, stream->app_progress);
+    SCLogDebug("last_ack %u, base_seq %u", stream->last_ack, stream->base_seq);
+
+    if (STREAM_LASTACK_GT_BASESEQ(stream)) {
+        /* get window of data that is acked */
+        uint32_t delta = stream->last_ack - stream->base_seq;
+        /* get max absolute offset */
+        last_ack_abs += delta;
+    }
+
+    const uint8_t *mydata;
+    uint32_t mydata_len;
+    GetAppBuffer(stream, &mydata, &mydata_len, stream->app_progress);
+    //PrintRawDataFp(stdout, mydata, mydata_len);
+
+    SCLogDebug("stream %p data in buffer %p of len %u and offset %u",
+            stream, stream->sb, mydata_len, (uint)stream->app_progress);
+
+    /* get window of data that is acked */
+    if (StreamTcpInlineMode() == 0 && (p->flags & PKT_PSEUDO_STREAM_END)) {
+        //
+    } else if (StreamTcpInlineMode() == 0) {
+        /* see if the buffer contains unack'd data as well */
+        if (stream->app_progress + mydata_len > last_ack_abs) {
+            mydata_len = last_ack_abs - stream->app_progress;
+            SCLogDebug("data len adjusted to %u to make sure only ACK'd "
+                    "data is considered", mydata_len);
         }
+    }
 
-        return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
+    /* update the app-layer */
+    int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+            (uint8_t *)mydata, mydata_len,
+            StreamGetAppLayerFlags(ssn, stream, p));
+
+    /* see if we can update the progress */
+    if (r == 0 && StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
+        if (mydata_len > 0) {
+            SCLogDebug("app progress %"PRIu64" increasing with data len %u to %"PRIu64,
+                    stream->app_progress, mydata_len, stream->app_progress + mydata_len);
+
+            stream->app_progress += mydata_len;
+            SCLogDebug("app progress now %"PRIu64, stream->app_progress);
+        }
+    } else {
+        SCLogDebug("NOT UPDATED app progress now %"PRIu64, stream->app_progress);
     }
 
-    return 0;
+    SCReturnInt(0);
 }
 
 /**
- *  \internal
- *  \brief Function to Check the reassembly depth valuer against the
- *        allowed max depth of the stream reassmbly for TCP streams.
+ *  \brief Update the stream reassembly upon receiving an ACK packet.
  *
- *  \param stream stream direction
- *  \param seq sequence number where "size" starts
- *  \param size size of the segment that is added
+ *  Stream is in the opposite direction of the packet, as the ACK-packet
+ *  is ACK'ing the stream.
  *
- *  \retval size Part of the size that fits in the depth, 0 if none
+ *  One of the utilities call by this function AppLayerHandleTCPData(),
+ *  has a feature where it will call this very same function for the
+ *  stream opposing the stream it is called with.  This shouldn't cause
+ *  any issues, since processing of each stream is independent of the
+ *  other stream.
+ *
+ *  \todo this function is too long, we need to break it up. It needs it BAD
  */
-static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
-        uint32_t seq, uint32_t size)
+int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+                                 TcpSession *ssn, TcpStream *stream,
+                                 Packet *p)
 {
     SCEnter();
 
-    /* if the configured depth value is 0, it means there is no limit on
-       reassembly depth. Otherwise carry on my boy ;) */
-    if (ssn->reassembly_depth == 0) {
-        SCReturnUInt(size);
+    /* this function can be directly called by app layer protocol
+     * detection. */
+    if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+        SCLogDebug("stream no reassembly flag set.  Mostly called via "
+                   "app proto detection.");
+        SCReturnInt(0);
     }
 
-    /* if the final flag is set, we're not accepting anymore */
-    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
-        SCReturnUInt(0);
-    }
+    SCLogDebug("stream->seg_list %p", stream->seg_list);
+#ifdef DEBUG
+    PrintList(stream->seg_list);
+    GetSessionSize(ssn, p);
+#endif
 
-    /* if the ra_base_seq has moved passed the depth window we stop
-     * checking and just reject the rest of the packets including
-     * retransmissions. Saves us the hassle of dealing with sequence
-     * wraps as well */
-    if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + ssn->reassembly_depth))) {
-        stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
-        SCReturnUInt(0);
-    }
+    /* Check if we have a gap at the start of the stream. 2 conditions:
+     * 1. no segments, but last_ack moved fwd
+     * 2. segments, but clearly some missing: if last_ack is
+     *    bigger than the list start and the list start is bigger than
+     *    next_seq, we know we are missing data that has been ack'd. That
+     *    won't get retransmitted, so it's a data gap.
+     */
+    if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
+        int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1;
+        if ((stream->seg_list == NULL && /*1*/
+                    stream->base_seq == stream->isn+1 &&
+                    SEQ_GT(stream->last_ack, stream->isn + ackadd))
+                ||
+            (stream->seg_list != NULL && /*2*/
+                    SEQ_GT(stream->seg_list->seq, stream->base_seq) &&
+                    SEQ_LT(stream->seg_list->seq, stream->last_ack)))
+        {
+            if (stream->seg_list == NULL) {
+                SCLogDebug("no segs, last_ack moved fwd so GAP "
+                        "(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64,
+                        stream->base_seq, stream->isn, stream->last_ack,
+                        stream->last_ack - (stream->isn + ackadd), p->pcap_cnt);
+            }
+
+            /* send gap signal */
+            SCLogDebug("sending GAP to app-layer");
+            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+                    NULL, 0,
+                    StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
+            AppLayerProfilingStore(ra_ctx->app_tctx, p);
 
-    SCLogDebug("full Depth not yet reached: %"PRIu32" <= %"PRIu32,
-            (StreamTcpReassembleGetRaBaseSeq(stream)+1),
-            (stream->isn + ssn->reassembly_depth));
+            /* set a GAP flag and make sure not bothering this stream anymore */
+            SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
+            stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
 
-    if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) {
-        /* packet (partly?) fits the depth window */
+            StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
+            StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
 
-        if (SEQ_LEQ((seq + size),(stream->isn + ssn->reassembly_depth))) {
-            /* complete fit */
-            SCReturnUInt(size);
-        } else {
-            stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
-            /* partial fit, return only what fits */
-            uint32_t part = (stream->isn + ssn->reassembly_depth) - seq;
-#if DEBUG
-            BUG_ON(part > size);
-#else
-            if (part > size)
-                part = size;
-#endif
-            SCReturnUInt(part);
+            SCReturnInt(0);
         }
     }
 
-    SCReturnUInt(0);
-}
+    /* if no segments are in the list or all are already processed,
+     * and state is beyond established, we send an empty msg */
+    TcpSegment *seg_tail = stream->seg_list_tail;
+    if (seg_tail == NULL ||
+            SEGMENT_BEFORE_OFFSET(stream, seg_tail, stream->app_progress))
+    {
+        /* send an empty EOF msg if we have no segments but TCP state
+         * is beyond ESTABLISHED */
+        if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
+            SCLogDebug("sending empty eof message");
+            /* send EOF to app layer */
+            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+                                  NULL, 0,
+                                  StreamGetAppLayerFlags(ssn, stream, p));
+            AppLayerProfilingStore(ra_ctx->app_tctx, p);
 
-static void StreamTcpStoreStreamChunk(TcpSession *ssn, StreamMsg *smsg, const Packet *p, int streaminline)
-{
-    uint8_t direction = 0;
+            SCReturnInt(0);
+        }
+    }
 
-    if ((!streaminline && (p->flowflags & FLOW_PKT_TOSERVER)) ||
-        ( streaminline && (p->flowflags & FLOW_PKT_TOCLIENT)))
-    {
-        direction = STREAM_TOCLIENT;
-        SCLogDebug("stream chunk is to_client");
-    } else {
-        direction = STREAM_TOSERVER;
-        SCLogDebug("stream chunk is to_server");
+    /* no segments, nothing to do */
+    if (stream->seg_list == NULL) {
+        SCLogDebug("no segments in the list to reassemble");
+        SCReturnInt(0);
     }
 
-    /* store the smsg in the tcp stream */
-    if (direction == STREAM_TOSERVER) {
-        SCLogDebug("storing smsg in the to_server");
+    if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) {
+        SCReturnInt(0);
+    }
 
-        /* put the smsg in the stream list */
-        if (ssn->toserver_smsg_head == NULL) {
-            ssn->toserver_smsg_head = smsg;
-            ssn->toserver_smsg_tail = smsg;
-            smsg->next = NULL;
-            smsg->prev = NULL;
-        } else {
-            StreamMsg *cur = ssn->toserver_smsg_tail;
-            cur->next = smsg;
-            smsg->prev = cur;
-            smsg->next = NULL;
-            ssn->toserver_smsg_tail = smsg;
+    /* with all that out of the way, lets update the app-layer */
+    ReassembleUpdateAppLayer(tv, ra_ctx, ssn, stream, p);
+
+    SCReturnInt(0);
+}
+
+/** \internal
+ *  \brief get stream data from offset
+ *  \param offset stream offset */
+static int GetRawBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_len,
+        StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
+{
+    const uint8_t *mydata;
+    uint32_t mydata_len;
+    if (stream->sb->block_list == NULL) {
+        SCLogDebug("getting one blob");
+
+        uint64_t roffset = offset;
+        if (offset)
+            StreamingBufferGetDataAtOffset(stream->sb, &mydata, &mydata_len, offset);
+        else {
+            StreamingBufferGetData(stream->sb, &mydata, &mydata_len, &roffset);
         }
+
+        *data = mydata;
+        *data_len = mydata_len;
+        *data_offset = roffset;
     } else {
-        SCLogDebug("storing smsg in the to_client");
+        if (*iter == NULL)
+            *iter = stream->sb->block_list;
+        if (*iter == NULL) {
+            *data = NULL;
+            *data_len = 0;
+            return 0;
+        }
+
+        if (offset) {
+            while (*iter && ((*iter)->offset + (*iter)->len < offset))
+                *iter = (*iter)->next;
+            if (*iter == NULL) {
+                *data = NULL;
+                *data_len = 0;
+                *data_offset = 0;
+                return 0;
+            }
+        }
+
+        SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u (next? %s)", *iter, (*iter)->offset, (*iter)->len, (*iter)->next ? "yes":"no");
+
+        StreamingBufferSBBGetData(stream->sb, (*iter), &mydata, &mydata_len);
+
+        if ((*iter)->offset < offset) {
+            uint64_t delta = offset - (*iter)->offset;
+            if (delta < mydata_len) {
+                *data = mydata + delta;
+                *data_len = mydata_len - delta;
+                *data_offset = offset;
+            } else {
+                *data = NULL;
+                *data_len = 0;
+                *data_offset = 0;
+            }
 
-        /* put the smsg in the stream list */
-        if (ssn->toclient_smsg_head == NULL) {
-            ssn->toclient_smsg_head = smsg;
-            ssn->toclient_smsg_tail = smsg;
-            smsg->next = NULL;
-            smsg->prev = NULL;
         } else {
-            StreamMsg *cur = ssn->toclient_smsg_tail;
-            cur->next = smsg;
-            smsg->prev = cur;
-            smsg->next = NULL;
-            ssn->toclient_smsg_tail = smsg;
+            *data = mydata;
+            *data_len = mydata_len;
+            *data_offset = (*iter)->offset;
         }
+
+        *iter = (*iter)->next;
     }
+    return 0;
 }
 
-/**
- *  \brief Insert a packets TCP data into the stream reassembly engine.
- *
- *  \retval 0 good segment, as far as we checked.
- *  \retval -1 badness, reason to drop in inline mode
- *
- *  If the retval is 0 the segment is inserted correctly, or overlap is handled,
- *  or it wasn't added because of reassembly depth.
- *
+/** \internal
+ *  \brief based on the data in the streaming buffer setup StreamMsgs
  */
-int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-                                TcpSession *ssn, TcpStream *stream, Packet *p)
+static int ReassembleRaw(TcpSession *ssn, TcpStream *stream, Packet *p)
 {
     SCEnter();
 
-    if (ssn->data_first_seen_dir == 0) {
-        if (p->flowflags & FLOW_PKT_TOSERVER) {
-            ssn->data_first_seen_dir = STREAM_TOSERVER;
-        } else {
-            ssn->data_first_seen_dir = STREAM_TOCLIENT;
+    StreamingBufferBlock *iter = NULL;
+    uint64_t progress = stream->raw_progress;
+    uint64_t last_ack_abs = 0; /* absolute right edge of ack'd data */
+    uint64_t right_edge_abs = 0;
+
+    /* get window of data that is acked */
+    SCLogDebug("last_ack %u, base_seq %u", stream->last_ack, stream->base_seq);
+    uint32_t delta = stream->last_ack - stream->base_seq;
+    /* get max absolute offset */
+    last_ack_abs = stream->base_seq_offset + delta;
+    right_edge_abs = last_ack_abs;
+
+    if (StreamTcpInlineMode() == TRUE) {
+        uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
+            stream_config.reassembly_toserver_chunk_size :
+            stream_config.reassembly_toclient_chunk_size;
+        SCLogDebug("pkt SEQ %u, payload_len %u; base_seq %u => base_seq_offset %"PRIu64,
+                TCP_GET_SEQ(p), p->payload_len,
+                stream->base_seq, stream->base_seq_offset);
+
+        SCLogDebug("progress before adjust %"PRIu64", chunk_size %"PRIu32, progress, chunk_size);
+
+        /* determine the left edge and right edge */
+        uint32_t rel_right_edge = TCP_GET_SEQ(p) + p->payload_len;
+        uint32_t rel_left_edge = rel_right_edge - chunk_size;
+        SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32", chunk_size %u", rel_left_edge, rel_right_edge, chunk_size);
+
+        if (SEQ_LT(rel_left_edge, stream->base_seq)) {
+            rel_left_edge = stream->base_seq;
+            rel_right_edge = rel_left_edge + chunk_size;
+            SCLogDebug("adjusting left_edge to not be before base_seq: left_edge %u", rel_left_edge);
         }
-    }
 
-    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
-        (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) {
-        SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
-        SCReturnInt(0);
+        progress = stream->base_seq_offset + (rel_left_edge - stream->base_seq);
+        right_edge_abs = progress + chunk_size;
+        SCLogDebug("working with progress %"PRIu64, progress);
+
+        SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, rel_left_edge, rel_right_edge);
     }
 
-    /* If we have reached the defined depth for either of the stream, then stop
-       reassembling the TCP session */
-    uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len);
-    SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
+    /* loop through available buffers. On no packet loss we'll have a single
+     * iteration. On missing data we'll walk the blocks */
+    while (1) {
+        const uint8_t *mydata;
+        uint32_t mydata_len;
+        uint64_t mydata_offset = 0;
 
-    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
-        /* increment stream depth counter */
-        StatsIncr(tv, ra_ctx->counter_tcp_stream_depth);
+        GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
+        if (mydata_len == 0)
+            break;
+        //PrintRawDataFp(stdout, mydata, mydata_len);
 
-        stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY;
-        SCLogDebug("ssn %p: reassembly depth reached, "
-                "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn);
-    }
-    if (size == 0) {
-        SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
-        SCReturnInt(0);
-    }
+        SCLogDebug("raw progress %"PRIu64, progress);
+        SCLogDebug("stream %p data in buffer %p of len %u and offset %u",
+                stream, stream->sb, mydata_len, (uint)progress);
 
-#if DEBUG
-    BUG_ON(size > p->payload_len);
-#else
-    if (size > p->payload_len)
-        size = p->payload_len;
-#endif
+        if (StreamTcpInlineMode() == 0 && (p->flags & PKT_PSEUDO_STREAM_END)) {
+            //
+        } else if (StreamTcpInlineMode() == FALSE) {
+            if (right_edge_abs < progress) {
+                SCLogDebug("nothing to do");
+                goto end;
+            }
 
-    TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx, size);
-    if (seg == NULL) {
-        SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[size]);
+            SCLogDebug("delta %u, right_edge_abs %"PRIu64", raw_progress %"PRIu64, delta, right_edge_abs, progress);
+            SCLogDebug("raw_progress + mydata_len %"PRIu64", right_edge_abs %"PRIu64, progress + mydata_len, right_edge_abs);
 
-        StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
-        SCReturnInt(-1);
-    }
+            /* see if the buffer contains unack'd data as well */
+            if (progress + mydata_len > last_ack_abs) {
+                mydata_len = last_ack_abs - progress;
+                SCLogDebug("data len adjusted to %u to make sure only ACK'd "
+                        "data is considered", mydata_len);
+            }
 
-    memcpy(seg->payload, p->payload, size);
-    seg->payload_len = size;
-    seg->seq = TCP_GET_SEQ(p);
+        /* StreamTcpInlineMode() == TRUE */
+        } else {
+            if (progress + mydata_len > right_edge_abs) {
+                uint32_t delta = (progress + mydata_len) - right_edge_abs;
+                SCLogDebug("adjusting mydata_len %u to subtract %u", mydata_len, delta);
+                mydata_len -= delta;
+            }
+        }
+        if (mydata_len == 0)
+            break;
 
-    if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)
-        seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
+        SCLogDebug("data %p len %u", mydata, mydata_len);
+
+        /*
+        [buffer with segment data]
+        ^
+        |
+        base_seq_offset (0 on start start)
+        base_seq (ISN on start start)
+
+        going from 'progress' to SEQ => (progress - base_seq_offset) + base_seq;
+        */
+#define GET_SEQ_FOR_PROGRESS(stream, progress) \
+            (((progress) - (stream)->base_seq_offset) + (stream->base_seq))
+
+        /* we have data. Use it to setup StreamMsg(s) */
+        StreamMsg *smsg = NULL;
+        uint32_t data_offset = 0;
+        uint32_t data_left = mydata_len;
+        while (data_left) {
+            smsg = StreamMsgGetFromPool();
+            if (smsg == NULL)
+                break;
 
-    /* if raw reassembly is disabled for new segments, flag each
-     * segment as complete for raw before insert */
-    if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
-        seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
-        SCLogDebug("segment %p flagged with SEGMENTTCP_FLAG_RAW_PROCESSED, "
-                   "flags %02x", seg, seg->flags);
-    }
+            uint32_t copy_len = (data_left > smsg->data_size) ? smsg->data_size : data_left;
+            SCLogDebug("copy_len %u, data_left %u", copy_len, data_left);
 
-    /* proto detection skipped, but now we do get data. Set event. */
-    if (stream->seg_list == NULL &&
-        stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) {
+            memcpy(smsg->data, mydata + data_offset, copy_len);
+            smsg->data_len = copy_len;
+            smsg->seq = GET_SEQ_FOR_PROGRESS(stream, (mydata_offset + data_offset));
+            SCLogDebug("smsg %p seq %u", smsg, smsg->seq);
 
-        AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
-                APPLAYER_PROTO_DETECTION_SKIPPED);
-    }
+            BUG_ON(copy_len > data_left);
+            data_left -= copy_len;
+            BUG_ON(data_left > mydata_len);
+            data_offset += copy_len;
 
-    if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p) != 0) {
-        SCLogDebug("StreamTcpReassembleInsertSegment failed");
-        SCReturnInt(-1);
-    }
+            SCLogDebug("smsg %p %u/%u", smsg, smsg->data_len, smsg->data_size);
+            //PrintRawDataFp(stdout, smsg->data, smsg->data_len);
 
-    SCReturnInt(0);
-}
+            StreamTcpStoreStreamChunk(ssn, smsg, p, StreamTcpInlineMode());
+        }
 
-static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
-                                      Packet *p)
-{
-    uint8_t flag = 0;
+        if (mydata_offset == progress) {
+            SCLogDebug("raw progress %"PRIu64" increasing with data len %u to %"PRIu64,
+                    progress, mydata_len, stream->raw_progress + mydata_len);
 
-    if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {
-        flag |= STREAM_START;
-    }
+            //if (StreamTcpInlineMode() == TRUE) {
+            //progress = right_edge_abs;
+            //} else {
+            progress += mydata_len;
+            //}
+            SCLogDebug("raw progress now %"PRIu64, progress);
 
-    if (ssn->state == TCP_CLOSED) {
-        flag |= STREAM_EOF;
-    }
-    if (p->flags & PKT_PSEUDO_STREAM_END) {
-        flag |= STREAM_EOF;
-    }
+        /* data is beyond the progress we'd like, and before last ack. Gap. */
+        } else if (mydata_offset > progress && mydata_offset < last_ack_abs) {
+            SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
+            SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
+            progress = mydata_offset;
+            SCLogDebug("raw progress now %"PRIu64, progress);
 
-    if (StreamTcpInlineMode() == 0) {
-        if (p->flowflags & FLOW_PKT_TOSERVER) {
-            flag |= STREAM_TOCLIENT;
-        } else {
-            flag |= STREAM_TOSERVER;
-        }
-    } else {
-        if (p->flowflags & FLOW_PKT_TOSERVER) {
-            flag |= STREAM_TOSERVER;
         } else {
-            flag |= STREAM_TOCLIENT;
+            SCLogDebug("not increasing progress, data gap => mydata_offset "
+                       "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
         }
-    }
 
-    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
-        flag |= STREAM_DEPTH;
+        if (iter == NULL)
+            break;
     }
-    return flag;
+end:
+    stream->raw_progress = progress;
+    SCLogDebug("stream raw progress now %"PRIu64, stream->raw_progress);
+    return 0;
 }
 
-static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p,
-                              StreamMsg *smsg)
+/**
+ *  \brief Update the stream reassembly upon receiving an ACK packet.
+ *  \todo this function is too long, we need to break it up. It needs it BAD
+ */
+int StreamTcpReassembleRaw (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+        TcpSession *ssn, TcpStream *stream, Packet *p)
 {
     SCEnter();
-    smsg->data_len = 0;
-    SCLogDebug("smsg %p", smsg);
-    SCReturn;
+    SCLogDebug("start p %p", p);
+
+    if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW)
+        SCReturnInt(0);
+
+    if (stream->seg_list == NULL) {
+        SCLogDebug("no segments in the list to reassemble");
+        SCReturnInt(0);
+    }
+
+#if 0
+    if (ssn->state <= TCP_ESTABLISHED &&
+        !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
+        SCLogDebug("only starting raw reassembly after app layer protocol "
+                "detection has completed.");
+        SCReturnInt(0);
+    }
+#endif
+    /* check if we have enough data */
+    if (StreamTcpInlineMode() == FALSE &&
+            StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0)
+    {
+        SCLogDebug("not yet reassembling");
+        SCReturnInt(0);
+    }
+
+    /* take the data we have, and turn it into StreamMsgs */
+    ReassembleRaw(ssn, stream, p);
+    SCReturnInt(0);
 }
 
-/**
- *  \brief Check the minimum size limits for reassembly.
+/** \brief update app layer and raw reassembly
  *
- *  \retval 0 don't reassemble yet
- *  \retval 1 do reassemble
+ *  \retval r 0 on success, -1 on error
  */
-static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream,
-                                         Packet *p)
+int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
+        TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
 {
     SCEnter();
 
-    if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
-        SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NOREASSEMBLY is set, so not expecting any new packets");
-        SCReturnInt(1);
+    SCLogDebug("stream->seg_list %p", stream->seg_list);
+
+    int r = 0;
+    if (!(StreamTcpInlineMode())) {
+        if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
+            r = -1;
+        if (StreamTcpReassembleRaw(tv, ra_ctx, ssn, stream, p) < 0)
+            r = -1;
     }
 
-    if (ssn->flags & STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY) {
-        SCLogDebug("reassembling now as STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY is set");
-        ssn->flags &= ~STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
-        SCReturnInt(1);
+    SCLogDebug("stream->seg_list %p", stream->seg_list);
+    SCReturnInt(r);
+}
+
+int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+                                     TcpSession *ssn, TcpStream *stream,
+                                     Packet *p, PacketQueue *pq)
+{
+    SCEnter();
+    SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
+                ssn, stream, p, p->payload_len);
+
+    /* we need to update the opposing stream in
+     * StreamTcpReassembleHandleSegmentUpdateACK */
+    TcpStream *opposing_stream = NULL;
+    if (stream == &ssn->client) {
+        opposing_stream = &ssn->server;
+    } else {
+        opposing_stream = &ssn->client;
     }
 
-    if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
-        SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
-                "so no new segments will be considered");
-        SCReturnInt(1);
+    /* handle ack received */
+    if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0)
+    {
+        SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
+        SCReturnInt(-1);
     }
 
-    /* some states mean we reassemble no matter how much data we have */
-    if (ssn->state >= TCP_TIME_WAIT)
-        SCReturnInt(1);
+    /* If no stream reassembly/application layer protocol inspection, then
+       simple return */
+    if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
+        SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
 
-    if (p->flags & PKT_PSEUDO_STREAM_END)
-        SCReturnInt(1);
+        if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
+            SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
+            SCReturnInt(-1);
+        }
 
-    /* check if we have enough data to send to L7 */
-    if (p->flowflags & FLOW_PKT_TOCLIENT) {
-        SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOSERVER) %"PRIu32,
-                StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
+        p->flags |= PKT_STREAM_ADD;
+    }
 
-        if (StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER) >
-                (stream->last_ack - stream->ra_raw_base_seq)) {
-            SCLogDebug("toserver min chunk len not yet reached: "
-                    "last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < "
-                    "%"PRIu32"", stream->last_ack, stream->ra_raw_base_seq,
-                    (stream->last_ack - stream->ra_raw_base_seq),
-                    StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
-            SCReturnInt(0);
-        }
-    } else {
-        SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOCLIENT) %"PRIu32,
-                StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
+    /* in stream inline mode even if we have no data we call the reassembly
+     * functions to handle EOF */
+    if (StreamTcpInlineMode()) {
+        int r = 0;
+        if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
+            r = -1;
+        if (StreamTcpReassembleRaw(tv, ra_ctx, ssn, stream, p) < 0)
+            r = -1;
 
-        if (StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT) >
-                (stream->last_ack - stream->ra_raw_base_seq)) {
-            SCLogDebug("toclient min chunk len not yet reached: "
-                    "last_ack %"PRIu32", ra_base_seq %"PRIu32",  %"PRIu32" < "
-                    "%"PRIu32"", stream->last_ack, stream->ra_raw_base_seq,
-                    (stream->last_ack - stream->ra_raw_base_seq),
-                    StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
-            SCReturnInt(0);
+        if (r < 0) {
+            SCReturnInt(-1);
         }
     }
 
-    SCReturnInt(1);
+    SCReturnInt(0);
 }
 
 /**
- *  \brief see if app layer is done with a segment
- *
- *  \retval 1 app layer is done with this segment
- *  \retval 0 not done yet
- */
-#define StreamTcpAppLayerSegmentProcessed(ssn, stream, segment) \
-    (( ( (ssn)->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || \
-       ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \
-       ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 ))
-
-/** \internal
- *  \brief check if we can remove a segment from our segment list
+ *  \brief   Function to get the segment of required length from the pool.
  *
- *  If a segment is entirely before the oldest smsg, we can discard it. Otherwise
- *  we keep it around to be able to log it.
+ *  \param   len    Length which tells the required size of needed segment.
  *
- *  \retval 1 yes
- *  \retval 0 no
+ *  \retval seg Segment from the pool or NULL
  */
-static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
+TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint16_t len)
 {
-    if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) {
-        /* not (seg is entirely before first smsg, skip) */
-        if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) {
-            SCReturnInt(0);
-        }
-    } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) {
-        /* not (seg is entirely before first smsg, skip) */
-        if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) {
-            SCReturnInt(0);
-        }
-    }
-
-    /* if proto detect isn't done, we're not returning */
-    if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) {
-        SCReturnInt(0);
-    }
-
-    /* check app layer conditions */
-    if (!(StreamTcpAppLayerSegmentProcessed(ssn, stream, seg))) {
-        SCReturnInt(0);
-    }
+    uint16_t idx = segment_pool_idx[len];
+    SCLogDebug("segment_pool_idx %" PRIu32 " for payload_len %" PRIu32 "",
+                idx, len);
 
-    /* check raw reassembly conditions */
-    if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) {
-        SCReturnInt(0);
-    }
+    SCMutexLock(&segment_pool_mutex[idx]);
+    TcpSegment *seg = (TcpSegment *) PoolGet(segment_pool[idx]);
 
-    SCReturnInt(1);
-}
+    SCLogDebug("segment_pool[%u]->empty_stack_size %u, segment_pool[%u]->alloc_"
+               "list_size %u, alloc %u", idx, segment_pool[idx]->empty_stack_size,
+               idx, segment_pool[idx]->alloc_stack_size,
+               segment_pool[idx]->allocated);
+    SCMutexUnlock(&segment_pool_mutex[idx]);
 
-static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg)
-{
-    if (seg->prev == NULL) {
-        stream->seg_list = seg->next;
-        if (stream->seg_list != NULL)
-            stream->seg_list->prev = NULL;
+    SCLogDebug("seg we return is %p", seg);
+    if (seg == NULL) {
+        SCLogDebug("segment_pool[%u]->empty_stack_size %u, "
+                   "alloc %u", idx, segment_pool[idx]->empty_stack_size,
+                   segment_pool[idx]->allocated);
+        /* Increment the counter to show that we are not able to serve the
+           segment request due to memcap limit */
+        StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
     } else {
-        seg->prev->next = seg->next;
-        if (seg->next != NULL)
-            seg->next->prev = seg->prev;
+        seg->flags = stream_config.segment_init_flags;
+        seg->next = NULL;
+        seg->prev = NULL;
+
+        memset(&seg->sbseg, 0, sizeof(seg->sbseg));
     }
 
-    if (stream->seg_list_tail == seg)
-        stream->seg_list_tail = seg->prev;
+#ifdef DEBUG
+    SCMutexLock(&segment_pool_cnt_mutex);
+    segment_pool_cnt++;
+    SCMutexUnlock(&segment_pool_cnt_mutex);
+#endif
+
+    return seg;
 }
 
 /**
- *  \brief Update the stream reassembly upon receiving a data segment
- *
- *  | left edge        | right edge based on sliding window size
- *  [aaa]
- *  [aaabbb]
- *  ...
- *  [aaabbbcccdddeeefff]
- *  [bbbcccdddeeefffggg] <- cut off aaa to adhere to the window size
+ *  \brief Trigger RAW stream reassembly
  *
- *  GAP situation: each chunk that is uninterrupted has it's own smsg
- *  [aaabbb].[dddeeefff]
- *  [aaa].[ccc].[eeefff]
+ *  Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
+ *  reassembly from the applayer, for example upon completion of a
+ *  HTTP request.
  *
- *  A flag will be set to indicate where the *NEW* payload starts. This
- *  is to aid the detection code for alert only sigs.
+ *  Works by setting a flag in the TcpSession that is unset as soon
+ *  as it's checked. Since everything happens when operating under
+ *  a single lock period, no side effects are expected.
  *
- *  \todo this function is too long, we need to break it up. It needs it BAD
+ *  \param ssn TcpSession
  */
-static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx,
-        TcpSession *ssn, TcpStream *stream, Packet *p)
+void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn)
 {
-    SCEnter();
-    SCLogDebug("start p %p, seq %"PRIu32, p, TCP_GET_SEQ(p));
+#ifdef DEBUG
+    BUG_ON(ssn == NULL);
+#endif
 
-    if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW)
-        SCReturnInt(0);
-    if (stream->seg_list == NULL) {
-        SCReturnInt(0);
+    if (ssn != NULL) {
+        SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
+        ssn->flags |= STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
     }
+}
 
-    uint32_t ra_base_seq = stream->ra_raw_base_seq;
-    StreamMsg *smsg = NULL;
-    uint32_t smsg_offset = 0;
-    uint16_t payload_offset = 0;
-    uint16_t payload_len = 0;
-    TcpSegment *seg = stream->seg_list;
-    uint32_t next_seq = ra_base_seq + 1;
-    int gap = 0;
+#ifdef UNITTESTS
+/** unit tests and it's support functions below */
 
-    uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
-        stream_config.reassembly_toserver_chunk_size :
-        stream_config.reassembly_toclient_chunk_size;
+#define SET_ISN(stream, setseq)             \
+    (stream)->isn = (setseq);               \
+    (stream)->base_seq = (setseq) + 1
 
-    /* determine the left edge and right edge */
-    uint32_t right_edge = TCP_GET_SEQ(p) + p->payload_len;
-    uint32_t left_edge = right_edge - chunk_size;
+static int UtTestSmsg(StreamMsg *smsg, const uint8_t *buf, uint32_t buf_len)
+{
+    if (smsg == NULL)
+        return 0;
 
-    /* shift the window to the right if the left edge doesn't cover segments */
-    if (SEQ_GT(seg->seq,left_edge)) {
-        right_edge += (seg->seq - left_edge);
-        left_edge = seg->seq;
+    if (smsg->data_len != buf_len) {
+        printf("Got: data_len %u, expected %u\n", smsg->data_len, buf_len);
+        PrintRawDataFp(stdout, smsg->data, smsg->data_len);
+        return 0;
     }
 
-    SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, left_edge, right_edge);
-
-    /* loop through the segments and fill one or more msgs */
-    for (; seg != NULL && SEQ_LT(seg->seq, right_edge); ) {
-        SCLogDebug("seg %p", seg);
+    if (!(memcmp(buf, smsg->data, buf_len) == 0)) {
+        printf("data is not what we expected:\nExpected:\n");
+        PrintRawDataFp(stdout, (uint8_t *)buf, buf_len);
+        printf("Got:\n");
+        PrintRawDataFp(stdout, smsg->data, smsg->data_len);
+        return 0;
+    }
+    return 1;
+}
 
-        /* If packets are fully before ra_base_seq, skip them. We do this
-         * because we've reassembled up to the ra_base_seq point already,
-         * so we won't do anything with segments before it anyway. */
-        SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32""
-                   " len %"PRIu16", combined %"PRIu32" and right_edge "
-                   "%"PRIu32"", ra_base_seq, seg, seg->seq,
-                    seg->payload_len, seg->seq+seg->payload_len, right_edge);
+static uint32_t UtSsnSmsgCnt(TcpSession *ssn, uint8_t direction)
+{
+    uint32_t cnt = 0;
+    StreamMsg *smsg = (direction == STREAM_TOSERVER) ?
+                            ssn->toserver_smsg_head :
+                            ssn->toclient_smsg_head;
+    while (smsg) {
+        cnt++;
+        smsg = smsg->next;
+    }
+    return cnt;
+}
 
-        /* Remove the segments which are completely before the ra_base_seq */
-        if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size)))
-        {
-            SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32""
-                        " len %"PRIu16"", ra_base_seq, seg, seg->seq,
-                        seg->payload_len);
-
-            /* only remove if app layer reassembly is ready too */
-            if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) {
-                TcpSegment *next_seg = seg->next;
-                StreamTcpRemoveSegmentFromStream(stream, seg);
-                StreamTcpSegmentReturntoPool(seg);
-                seg = next_seg;
-            /* otherwise, just flag it for removal */
-            } else {
-                seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
-                seg = seg->next;
-            }
-            continue;
-        }
-
-        /* if app layer protocol has been detected, then remove all the segments
-         * which has been previously processed and reassembled
-         *
-         * If the stream is in GAP state the app layer flag won't be set */
-        if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) &&
-                (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) &&
-                StreamTcpAppLayerSegmentProcessed(ssn, stream, seg))
-        {
-            SCLogDebug("segment(%p) of length %"PRIu16" has been processed,"
-                    " so return it to pool", seg, seg->payload_len);
-            TcpSegment *next_seg = seg->next;
-            StreamTcpRemoveSegmentFromStream(stream, seg);
-            StreamTcpSegmentReturntoPool(seg);
-            seg = next_seg;
-            continue;
-        }
-
-        /* we've run into a sequence gap, wrap up any existing smsg and
-         * queue it so the next chunk (if any) is in a new smsg */
-        if (SEQ_GT(seg->seq, next_seq)) {
-            /* pass on pre existing smsg (if any) */
-            if (smsg != NULL && smsg->data_len > 0) {
-                StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
-                stream->ra_raw_base_seq = ra_base_seq;
-                smsg = NULL;
-            }
-
-            gap = 1;
-        }
-
-        /* if the segment ends beyond left_edge we need to consider it */
-        if (SEQ_GT((seg->seq + seg->payload_len), left_edge)) {
-            SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", "
-                       "left_edge %" PRIu32 "", seg->seq,
-                       seg->payload_len, left_edge);
-
-            /* handle segments partly before ra_base_seq */
-            if (SEQ_GT(left_edge, seg->seq)) {
-                payload_offset = left_edge - seg->seq;
-
-                if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) {
-                    payload_len = (right_edge - seg->seq) - payload_offset;
-                } else {
-                    payload_len = seg->payload_len - payload_offset;
-                }
-
-                if (SCLogDebugEnabled()) {
-                    BUG_ON(payload_offset > seg->payload_len);
-                    BUG_ON((payload_len + payload_offset) > seg->payload_len);
-                }
-            } else {
-                payload_offset = 0;
-
-                if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) {
-                    payload_len = right_edge - seg->seq;
-                } else {
-                    payload_len = seg->payload_len;
-                }
-            }
-            SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
-                       " and stream->last_ack is %"PRIu32"", payload_offset,
-                        payload_len, stream->last_ack);
-
-            if (payload_len == 0) {
-                SCLogDebug("no payload_len, so bail out");
-                break;
-            }
-
-            if (smsg == NULL) {
-                smsg = StreamMsgGetFromPool();
-                if (smsg == NULL) {
-                    SCLogDebug("stream_msg_pool is empty");
-                    return -1;
-                }
-
-                smsg_offset = 0;
-
-                StreamTcpSetupMsg(ssn, stream, p, smsg);
-                smsg->seq = ra_base_seq + 1;
-            }
-
-            /* copy the data into the smsg */
-            uint32_t copy_size = smsg->data_size - smsg_offset;
-            if (copy_size > payload_len) {
-                copy_size = payload_len;
-            }
-            if (SCLogDebugEnabled()) {
-                BUG_ON(copy_size > smsg->data_size);
-            }
-            SCLogDebug("copy_size is %"PRIu16"", copy_size);
-            memcpy(smsg->data + smsg_offset, seg->payload + payload_offset,
-                    copy_size);
-            smsg_offset += copy_size;
-
-            SCLogDebug("seg total %u, seq %u off %u copy %u, ra_base_seq %u",
-                    (seg->seq + payload_offset + copy_size), seg->seq,
-                    payload_offset, copy_size, ra_base_seq);
-            if (gap == 0 && SEQ_GT((seg->seq + payload_offset + copy_size),ra_base_seq+1)) {
-                ra_base_seq += copy_size;
-            }
-            SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq);
-
-            smsg->data_len += copy_size;
-
-            /* queue the smsg if it's full */
-            if (smsg->data_len == smsg->data_size) {
-                StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
-                stream->ra_raw_base_seq = ra_base_seq;
-                smsg = NULL;
-            }
-
-            /* if the payload len is bigger than what we copied, we handle the
-             * rest of the payload next... */
-            if (copy_size < payload_len) {
-                SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size,
-                            payload_len);
-                payload_offset += copy_size;
-                payload_len -= copy_size;
-                SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is "
-                           "%"PRIu16" and stream->last_ack is %"PRIu32"",
-                            payload_offset, seg->payload_len, stream->last_ack);
-                if (SCLogDebugEnabled()) {
-                    BUG_ON(payload_offset > seg->payload_len);
-                }
-
-                /* we need a while loop here as the packets theoretically can be
-                 * 64k */
-                char segment_done = FALSE;
-                while (segment_done == FALSE) {
-                    SCLogDebug("new msg at offset %" PRIu32 ", payload_len "
-                               "%" PRIu32 "", payload_offset, payload_len);
-
-                    /* get a new message
-                       XXX we need a setup function */
-                    smsg = StreamMsgGetFromPool();
-                    if (smsg == NULL) {
-                        SCLogDebug("stream_msg_pool is empty");
-                        SCReturnInt(-1);
-                    }
-                    smsg_offset = 0;
-
-                    StreamTcpSetupMsg(ssn, stream,p,smsg);
-                    smsg->seq = ra_base_seq + 1;
-
-                    copy_size = smsg->data_size - smsg_offset;
-                    if ((int32_t)copy_size > (seg->payload_len - payload_offset)) {
-                        copy_size = (seg->payload_len - payload_offset);
-                    }
-                    if (SCLogDebugEnabled()) {
-                        BUG_ON(copy_size > smsg->data_size);
-                    }
-
-                    SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset "
-                                "%" PRIu32 ", copy_size %" PRIu32 "",
-                                payload_offset, smsg_offset, copy_size);
-                    memcpy(smsg->data + smsg_offset, seg->payload +
-                            payload_offset, copy_size);
-                    smsg_offset += copy_size;
-                    if (gap == 0 && SEQ_GT((seg->seq + payload_offset + copy_size),ra_base_seq+1)) {
-                        ra_base_seq += copy_size;
-                    }
-                    SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq);
-                    smsg->data_len += copy_size;
-                    SCLogDebug("copied payload_offset %" PRIu32 ", "
-                               "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "",
-                               payload_offset, smsg_offset, copy_size);
-                    if (smsg->data_len == smsg->data_size) {
-                        StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
-                        stream->ra_raw_base_seq = ra_base_seq;
-                        smsg = NULL;
-                    }
-
-                    /* see if we have segment payload left to process */
-                    if ((copy_size + payload_offset) < seg->payload_len) {
-                        payload_offset += copy_size;
-                        payload_len -= copy_size;
-
-                        if (SCLogDebugEnabled()) {
-                            BUG_ON(payload_offset > seg->payload_len);
-                        }
-                    } else {
-                        payload_offset = 0;
-                        segment_done = TRUE;
-                    }
-                }
-            }
-        }
-
-        /* done with this segment, return it to the pool */
-        TcpSegment *next_seg = seg->next;
-        next_seq = seg->seq + seg->payload_len;
-
-        if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size))) {
-            if (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED) {
-                StreamTcpRemoveSegmentFromStream(stream, seg);
-                SCLogDebug("removing seg %p, seg->next %p", seg, seg->next);
-                StreamTcpSegmentReturntoPool(seg);
-            } else {
-                seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
-            }
-        }
-        seg = next_seg;
-    }
-
-    /* put the partly filled smsg in the queue */
-    if (smsg != NULL) {
-        StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
-        smsg = NULL;
-        stream->ra_raw_base_seq = ra_base_seq;
-    }
-
-    /* see if we can clean up some segments */
-    left_edge = (ra_base_seq + 1) - chunk_size;
-    SCLogDebug("left_edge %"PRIu32", ra_base_seq %"PRIu32, left_edge, ra_base_seq);
-
-    /* loop through the segments to remove unneeded segments */
-    for (seg = stream->seg_list; seg != NULL && SEQ_LEQ((seg->seq + p->payload_len), left_edge); ) {
-        SCLogDebug("seg %p seq %"PRIu32", len %"PRIu16", sum %"PRIu32, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len);
-
-        /* only remove if app layer reassembly is ready too */
-        if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) {
-            TcpSegment *next_seg = seg->next;
-            StreamTcpRemoveSegmentFromStream(stream, seg);
-            StreamTcpSegmentReturntoPool(seg);
-            seg = next_seg;
-        } else {
-            break;
-        }
-    }
-    SCLogDebug("stream->ra_raw_base_seq %u", stream->ra_raw_base_seq);
-    SCReturnInt(0);
-}
-
-/** \brief Remove idle TcpSegments from TcpSession
- *
- *  \param f flow
- *  \param flags direction flags
- */
-void StreamTcpPruneSession(Flow *f, uint8_t flags)
-{
-    if (f == NULL || f->protoctx == NULL)
-        return;
-
-    TcpSession *ssn = f->protoctx;
-    TcpStream *stream = NULL;
-
-    if (flags & STREAM_TOSERVER) {
-        stream = &ssn->client;
-    } else if (flags & STREAM_TOCLIENT) {
-        stream = &ssn->server;
-    } else {
-        return;
-    }
-
-    /* loop through the segments and fill one or more msgs */
-    TcpSegment *seg = stream->seg_list;
-
-    for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);)
-    {
-        SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", FLAGS %02x",
-                seg, seg->seq, seg->payload_len,
-                (uint32_t)(seg->seq + seg->payload_len), seg->flags);
-
-        if (StreamTcpReturnSegmentCheck(f, ssn, stream, seg) == 0) {
-            break;
-        }
-
-        TcpSegment *next_seg = seg->next;
-        StreamTcpRemoveSegmentFromStream(stream, seg);
-        StreamTcpSegmentReturntoPool(seg);
-        seg = next_seg;
-        continue;
-    }
-}
-
-#ifdef DEBUG
-static uint64_t GetStreamSize(TcpStream *stream)
-{
-    if (stream) {
-        uint64_t size = 0;
-        uint32_t cnt = 0;
-
-        TcpSegment *seg = stream->seg_list;
-        while (seg) {
-            cnt++;
-            size += (uint64_t)seg->payload_len;
-
-            seg = seg->next;
-        }
-
-        SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
-        return size;
-    }
-    return (uint64_t)0;
-}
-
-static void GetSessionSize(TcpSession *ssn, Packet *p)
-{
-    uint64_t size = 0;
-    if (ssn) {
-        size = GetStreamSize(&ssn->client);
-        size += GetStreamSize(&ssn->server);
-
-        //if (size > 900000)
-        //    SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
-        SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
-    }
-}
-#endif
-
-typedef struct ReassembleData_ {
-    uint32_t ra_base_seq;
-    uint32_t data_len;
-    uint8_t data[4096];
-    int partial;        /* last segment was processed only partially */
-    uint32_t data_sent; /* data passed on this run */
-} ReassembleData;
-
-/** \internal
- *  \brief test if segment follows a gap. If so, handle the gap
- *
- *  If in inline mode, segment may be un-ack'd. In this case we
- *  consider it a gap, but it's not 'final' yet.
- *
- *  \retval bool 1 gap 0 no gap
- */
-int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-                 TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd,
-                 Packet *p, uint32_t next_seq)
-{
-    if (unlikely(SEQ_GT(seg->seq, next_seq))) {
-        /* we've run into a sequence gap */
-
-        if (StreamTcpInlineMode()) {
-            /* don't conclude it's a gap until we see that the data
-             * that is missing was acked. */
-            if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED)
-                return 1;
-        }
-
-        /* first, pass on data before the gap */
-        if (rd->data_len > 0) {
-            SCLogDebug("pre GAP data");
-
-            /* process what we have so far */
-            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                    rd->data, rd->data_len,
-                    StreamGetAppLayerFlags(ssn, stream, p));
-            AppLayerProfilingStore(ra_ctx->app_tctx, p);
-            rd->data_sent += rd->data_len;
-            rd->data_len = 0;
-        }
-
-#ifdef DEBUG
-        uint32_t gap_len = seg->seq - next_seq;
-        SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , "
-                "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"",
-                next_seq, seg->seq, stream->last_ack, gap_len);
-#endif
-        /* We have missed the packet and end host has ack'd it, so
-         * IDS should advance it's ra_base_seq and should not consider this
-         * packet any longer, even if it is retransmitted, as end host will
-         * drop it anyway */
-        rd->ra_base_seq = seg->seq - 1;
-
-        /* send gap "signal" */
-        AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
-        AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
-        /* set a GAP flag and make sure not bothering this stream anymore */
-        SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
-        stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
-
-        StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
-        StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
-#ifdef DEBUG
-        dbg_app_layer_gap++;
-#endif
-        return 1;
-    }
-    return 0;
-}
-
-static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-                 TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd,
-                 Packet *p)
-{
-    /* fast paths: send data directly into the app layer, w/o first doing
-     * a copy step. However, don't use the fast path until protocol detection
-     * has been completed
-     * TODO if initial data is big enough for proto detect, we could do the
-     *      fast path anyway. */
-    if (stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) {
-        /* fast path 1: segment is exactly what we need */
-        if (likely(rd->data_len == 0 &&
-                    SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
-                    SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len))))
-        {
-            /* process single segment directly */
-            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                    seg->payload, seg->payload_len,
-                    StreamGetAppLayerFlags(ssn, stream, p));
-            AppLayerProfilingStore(ra_ctx->app_tctx, p);
-            rd->data_sent += seg->payload_len;
-            rd->ra_base_seq += seg->payload_len;
-#ifdef DEBUG
-            ra_ctx->fp1++;
-#endif
-            /* if after the first data chunk we have no alproto yet,
-             * there is no point in continueing here. */
-            if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-                SCLogDebug("no alproto after first data chunk");
-                return 0;
-            }
-            return 1;
-            /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */
-        } else if (rd->data_len == 0 &&
-                SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
-                SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) &&
-                seg->payload_len >= stream_config.zero_copy_size)
-        {
-            /* process single segment directly */
-            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                    seg->payload, seg->payload_len,
-                    StreamGetAppLayerFlags(ssn, stream, p));
-            AppLayerProfilingStore(ra_ctx->app_tctx, p);
-            rd->data_sent += seg->payload_len;
-            rd->ra_base_seq += seg->payload_len;
-#ifdef DEBUG
-            ra_ctx->fp2++;
-#endif
-            /* if after the first data chunk we have no alproto yet,
-             * there is no point in continueing here. */
-            if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-                SCLogDebug("no alproto after first data chunk");
-                return 0;
-            }
-            return 1;
-        }
-    }
-#ifdef DEBUG
-    ra_ctx->sp++;
-#endif
-    uint16_t payload_offset = 0;
-    uint16_t payload_len = 0;
-
-    /* start clean */
-    rd->partial = FALSE;
-
-    /* if the segment ends beyond ra_base_seq we need to consider it */
-    if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) {
-        SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", "
-                "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq,
-                seg->payload_len, rd->ra_base_seq, stream->last_ack);
-
-        if (StreamTcpInlineMode() == 0) {
-            /* handle segments partly before ra_base_seq */
-            if (SEQ_GT(rd->ra_base_seq, seg->seq)) {
-                payload_offset = (rd->ra_base_seq + 1) - seg->seq;
-                SCLogDebug("payload_offset %u", payload_offset);
-
-                if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
-                    if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) {
-                        return 1;
-                    } else {
-                        payload_len = (stream->last_ack - seg->seq) - payload_offset;
-                        SCLogDebug("payload_len %u", payload_len);
-                    }
-                    rd->partial = TRUE;
-                } else {
-                    payload_len = seg->payload_len - payload_offset;
-                    SCLogDebug("payload_len %u", payload_len);
-                }
-
-                if (SCLogDebugEnabled()) {
-                    BUG_ON(payload_offset > seg->payload_len);
-                    BUG_ON((payload_len + payload_offset) > seg->payload_len);
-                }
-            } else {
-                payload_offset = 0;
-
-                if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
-                    payload_len = stream->last_ack - seg->seq;
-                    SCLogDebug("payload_len %u", payload_len);
-
-                    rd->partial = TRUE;
-                } else {
-                    payload_len = seg->payload_len;
-                    SCLogDebug("payload_len %u", payload_len);
-                }
-            }
-        /* inline mode, don't consider last_ack as we process un-ACK'd segments */
-        } else {
-            /* handle segments partly before ra_base_seq */
-            if (SEQ_GT(rd->ra_base_seq, seg->seq)) {
-                payload_offset = rd->ra_base_seq - seg->seq - 1;
-                payload_len = seg->payload_len - payload_offset;
-
-                if (SCLogDebugEnabled()) {
-                    BUG_ON(payload_offset > seg->payload_len);
-                    BUG_ON((payload_len + payload_offset) > seg->payload_len);
-                }
-            } else {
-                payload_offset = 0;
-                payload_len = seg->payload_len;
-            }
-        }
-        SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
-                " and stream->last_ack is %"PRIu32"", payload_offset,
-                payload_len, stream->last_ack);
-
-        if (payload_len == 0) {
-            SCLogDebug("no payload_len, so bail out");
-            return 0;
-        }
-
-        /* copy the data into the buffer */
-        uint16_t copy_size = sizeof(rd->data) - rd->data_len;
-        if (copy_size + payload_offset > seg->payload_len) {
-            copy_size = seg->payload_len - payload_offset;
-        }
-        if (copy_size > payload_len) {
-            copy_size = payload_len;
-        }
-        if (SCLogDebugEnabled()) {
-            BUG_ON(copy_size > sizeof(rd->data));
-            BUG_ON(copy_size+payload_offset > seg->payload_len);
-            BUG_ON(copy_size+payload_offset > seg->pool_size);
-        }
-
-        SCLogDebug("copy_size is %"PRIu16"", copy_size);
-        memcpy(rd->data + rd->data_len, seg->payload + payload_offset, copy_size);
-        rd->data_len += copy_size;
-        rd->ra_base_seq += copy_size;
-        SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, rd->ra_base_seq, rd->data_len);
-
-        /* queue the smsg if it's full */
-        if (rd->data_len == sizeof(rd->data)) {
-            /* process what we have so far */
-            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                    rd->data, rd->data_len,
-                    StreamGetAppLayerFlags(ssn, stream, p));
-            AppLayerProfilingStore(ra_ctx->app_tctx, p);
-            rd->data_sent += rd->data_len;
-            rd->data_len = 0;
-
-            /* if after the first data chunk we have no alproto yet,
-             * there is no point in continueing here. */
-            if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-                SCLogDebug("no alproto after first data chunk");
-                return 0;
-            }
-        }
-
-        /* if the payload len is bigger than what we copied, we handle the
-         * rest of the payload next... */
-        if (copy_size < payload_len) {
-            SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size,
-                    payload_len);
-
-            payload_offset += copy_size;
-            payload_len -= copy_size;
-            SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is "
-                    "%"PRIu16" and stream->last_ack is %"PRIu32"",
-                    payload_offset, seg->payload_len, stream->last_ack);
-            if (SCLogDebugEnabled()) {
-                BUG_ON(payload_offset > seg->payload_len);
-            }
-
-            /* we need a while loop here as the packets theoretically can be
-             * 64k */
-            char segment_done = FALSE;
-            while (segment_done == FALSE) {
-                SCLogDebug("new msg at offset %" PRIu32 ", payload_len "
-                        "%" PRIu32 "", payload_offset, payload_len);
-                rd->data_len = 0;
-
-                copy_size = sizeof(rd->data) - rd->data_len;
-                if (copy_size > (seg->payload_len - payload_offset)) {
-                    copy_size = (seg->payload_len - payload_offset);
-                }
-                if (SCLogDebugEnabled()) {
-                    BUG_ON(copy_size > sizeof(rd->data));
-                }
-
-                SCLogDebug("copy payload_offset %" PRIu32 ", data_len "
-                        "%" PRIu32 ", copy_size %" PRIu32 "",
-                        payload_offset, rd->data_len, copy_size);
-                memcpy(rd->data + rd->data_len, seg->payload +
-                        payload_offset, copy_size);
-                rd->data_len += copy_size;
-                rd->ra_base_seq += copy_size;
-                SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq);
-                SCLogDebug("copied payload_offset %" PRIu32 ", "
-                        "data_len %" PRIu32 ", copy_size %" PRIu32 "",
-                        payload_offset, rd->data_len, copy_size);
-
-                if (rd->data_len == sizeof(rd->data)) {
-                    /* process what we have so far */
-                    AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                            rd->data, rd->data_len,
-                            StreamGetAppLayerFlags(ssn, stream, p));
-                    AppLayerProfilingStore(ra_ctx->app_tctx, p);
-                    rd->data_sent += rd->data_len;
-                    rd->data_len = 0;
-
-                    /* if after the first data chunk we have no alproto yet,
-                     * there is no point in continueing here. */
-                    if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-                        SCLogDebug("no alproto after first data chunk");
-                        return 0;
-                    }
-                }
-
-                /* see if we have segment payload left to process */
-                if ((copy_size + payload_offset) < seg->payload_len) {
-                    payload_offset += copy_size;
-                    payload_len -= copy_size;
-
-                    if (SCLogDebugEnabled()) {
-                        BUG_ON(payload_offset > seg->payload_len);
-                    }
-                } else {
-                    payload_offset = 0;
-                    segment_done = TRUE;
-                }
-            }
-        }
-    }
-
-    return 1;
-}
-
-/**
- *  \brief Update the stream reassembly upon receiving an ACK packet.
- *
- *  Stream is in the opposite direction of the packet, as the ACK-packet
- *  is ACK'ing the stream.
- *
- *  One of the utilities call by this function AppLayerHandleTCPData(),
- *  has a feature where it will call this very same function for the
- *  stream opposing the stream it is called with.  This shouldn't cause
- *  any issues, since processing of each stream is independent of the
- *  other stream.
- *
- *  \todo this function is too long, we need to break it up. It needs it BAD
- */
-int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-                                 TcpSession *ssn, TcpStream *stream,
-                                 Packet *p)
-{
-    SCEnter();
-
-    /* this function can be directly called by app layer protocol
-     * detection. */
-    if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_GAP)) {
-        SCLogDebug("stream no reassembly flag set.  Mostly called via "
-                   "app proto detection.");
-        SCReturnInt(0);
-    }
-
-    SCLogDebug("stream->seg_list %p", stream->seg_list);
-#ifdef DEBUG
-    PrintList(stream->seg_list);
-    GetSessionSize(ssn, p);
-#endif
-
-    /* Check if we have a gap at the start of the stream. 2 conditions:
-     * 1. no segments, but last_ack moved fwd
-     * 2. segments, but clearly some missing: if last_ack is
-     *    bigger than the list start and the list start is bigger than
-     *    next_seq, we know we are missing data that has been ack'd. That
-     *    won't get retransmitted, so it's a data gap.
-     */
-    if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
-        int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1;
-        if ((stream->seg_list == NULL && /*1*/
-                    stream->ra_app_base_seq == stream->isn &&
-                    SEQ_GT(stream->last_ack, stream->isn + ackadd))
-                ||
-            (stream->seg_list != NULL && /*2*/
-                    SEQ_GT(stream->seg_list->seq, stream->ra_app_base_seq+1) &&
-                    SEQ_LT(stream->seg_list->seq, stream->last_ack)))
-        {
-            if (stream->seg_list == NULL) {
-                SCLogDebug("no segs, last_ack moved fwd so GAP "
-                        "(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64,
-                        stream->ra_app_base_seq, stream->isn, stream->last_ack,
-                        stream->last_ack - (stream->isn + ackadd), p->pcap_cnt);
-            }
-
-            /* send gap signal */
-            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                    NULL, 0,
-                    StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
-            AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
-            /* set a GAP flag and make sure not bothering this stream anymore */
-            SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
-            stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
-
-            StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
-            StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
-#ifdef DEBUG
-            dbg_app_layer_gap++;
-#endif
-            SCReturnInt(0);
-        }
-    }
-
-    /* if no segments are in the list or all are already processed,
-     * and state is beyond established, we send an empty msg */
-    TcpSegment *seg_tail = stream->seg_list_tail;
-    if (seg_tail == NULL ||
-            (seg_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
-    {
-        /* send an empty EOF msg if we have no segments but TCP state
-         * is beyond ESTABLISHED */
-        if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
-            SCLogDebug("sending empty eof message");
-            /* send EOF to app layer */
-            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                                  NULL, 0,
-                                  StreamGetAppLayerFlags(ssn, stream, p));
-            AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
-            SCReturnInt(0);
-        }
-    }
-
-    /* no segments, nothing to do */
-    if (stream->seg_list == NULL) {
-        SCLogDebug("no segments in the list to reassemble");
-        SCReturnInt(0);
-    }
-
-
-    if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) {
-        SCReturnInt(0);
-    }
-
-    /* stream->ra_app_base_seq remains at stream->isn until protocol is
-     * detected. */
-    ReassembleData rd;
-    rd.ra_base_seq = stream->ra_app_base_seq;
-    rd.data_len = 0;
-    rd.data_sent = 0;
-    rd.partial = FALSE;
-    uint32_t next_seq = rd.ra_base_seq + 1;
-
-    SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32,
-            rd.ra_base_seq, stream->last_ack, next_seq);
-
-    /* loop through the segments and fill one or more msgs */
-    TcpSegment *seg = stream->seg_list;
-    SCLogDebug("pre-loop seg %p", seg);
-#ifdef DEBUG_VALIDATION
-    uint64_t bytes = 0;
-#endif
-    for (; seg != NULL; )
-    {
-#ifdef DEBUG_VALIDATION
-        bytes += seg->payload_len;
-#endif
-        /* if in inline mode, we process all segments regardless of whether
-         * they are ack'd or not. In non-inline, we process only those that
-         * are at least partly ack'd. */
-        if (StreamTcpInlineMode() == 0 && SEQ_GEQ(seg->seq, stream->last_ack))
-            break;
-
-        SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32,
-                seg, seg->seq, seg->payload_len,
-                (uint32_t)(seg->seq + seg->payload_len));
-
-        if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) {
-            SCLogDebug("removing segment");
-            TcpSegment *next_seg = seg->next;
-            StreamTcpRemoveSegmentFromStream(stream, seg);
-            StreamTcpSegmentReturntoPool(seg);
-            seg = next_seg;
-            continue;
-        } else if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) {
-            TcpSegment *next_seg = seg->next;
-            seg = next_seg;
-            continue;
-        }
-
-        /* check if we have a sequence gap and if so, handle it */
-        if (DoHandleGap(tv, ra_ctx, ssn, stream, seg, &rd, p, next_seq) == 1)
-            break;
-
-        /* process this segment */
-        if (DoReassemble(tv, ra_ctx, ssn, stream, seg, &rd, p) == 0)
-            break;
-
-        /* done with this segment, return it to the pool */
-        TcpSegment *next_seg = seg->next;
-        next_seq = seg->seq + seg->payload_len;
-        if (rd.partial == FALSE) {
-            SCLogDebug("fully done with segment in app layer reassembly (seg %p seq %"PRIu32")",
-                    seg, seg->seq);
-            seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
-            SCLogDebug("flags now %02x", seg->flags);
-        } else {
-            SCLogDebug("not yet fully done with segment in app layer reassembly");
-        }
-        seg = next_seg;
-    }
-#ifdef DEBUG_VALIDATION /* we should never have this much data queued */
-    BUG_ON(bytes > 1000000ULL && bytes > (stream->window * 1.5));
-#endif
-
-    /* put the partly filled smsg in the queue to the l7 handler */
-    if (rd.data_len > 0) {
-        SCLogDebug("data_len > 0, %u", rd.data_len);
-        /* process what we have so far */
-        BUG_ON(rd.data_len > sizeof(rd.data));
-        AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                              rd.data, rd.data_len,
-                              StreamGetAppLayerFlags(ssn, stream, p));
-        AppLayerProfilingStore(ra_ctx->app_tctx, p);
-    }
-
-    /* if no data was sent to the applayer, we send it a empty 'nudge'
-     * when in inline mode */
-    if (StreamTcpInlineMode() && rd.data_sent == 0 && ssn->state > TCP_ESTABLISHED) {
-        SCLogDebug("sending empty eof message");
-        /* send EOF to app layer */
-        AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                NULL, 0, StreamGetAppLayerFlags(ssn, stream, p));
-        AppLayerProfilingStore(ra_ctx->app_tctx, p);
-    }
-
-    /* store ra_base_seq in the stream */
-    if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-        stream->ra_app_base_seq = rd.ra_base_seq;
-    } else {
-        TcpSegment *tmp_seg = stream->seg_list;
-        while (tmp_seg != NULL) {
-            if (!(tmp_seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
-                break;
-            tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
-            tmp_seg = tmp_seg->next;
-        }
-    }
-    SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq);
-    SCReturnInt(0);
-}
-
-typedef struct ReassembleRawData_ {
-    uint32_t ra_base_seq;
-    int partial;        /* last segment was processed only partially */
-    StreamMsg *smsg;
-    uint32_t smsg_offset; // TODO diff with smsg->data_len?
-} ReassembleRawData;
-
-static void DoHandleRawGap(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p,
-        ReassembleRawData *rd, uint32_t next_seq)
-{
-    /* we've run into a sequence gap */
-    if (SEQ_GT(seg->seq, next_seq)) {
-        /* pass on pre existing smsg (if any) */
-        if (rd->smsg != NULL && rd->smsg->data_len > 0) {
-            /* if app layer protocol has not been detected till yet,
-               then check did we have sent message to app layer already
-               or not. If not then sent the message and set flag that first
-               message has been sent. No more data till proto has not
-               been detected */
-            StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0);
-            stream->ra_raw_base_seq = rd->ra_base_seq;
-            rd->smsg = NULL;
-        }
-
-        /* see what the length of the gap is, gap length is seg->seq -
-         * (ra_base_seq +1) */
-#ifdef DEBUG
-        uint32_t gap_len = seg->seq - next_seq;
-        SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , "
-                "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"",
-                next_seq, seg->seq, stream->last_ack, gap_len);
-#endif
-        stream->ra_raw_base_seq = rd->ra_base_seq;
-
-        /* We have missed the packet and end host has ack'd it, so
-         * IDS should advance it's ra_base_seq and should not consider this
-         * packet any longer, even if it is retransmitted, as end host will
-         * drop it anyway */
-        rd->ra_base_seq = seg->seq - 1;
-    }
-}
-
-static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p,
-    ReassembleRawData *rd)
-{
-    uint16_t payload_offset = 0;
-    uint16_t payload_len = 0;
-
-    /* start clean */
-    rd->partial = FALSE;
-
-    /* if the segment ends beyond ra_base_seq we need to consider it */
-    if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) {
-        SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", "
-                "ra_base_seq %" PRIu32 "", seg->seq,
-                seg->payload_len, rd->ra_base_seq);
-
-        /* handle segments partly before ra_base_seq */
-        if (SEQ_GT(rd->ra_base_seq, seg->seq)) {
-            payload_offset = rd->ra_base_seq - seg->seq;
-
-            if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
-
-                if (SEQ_LT(stream->last_ack, rd->ra_base_seq)) {
-                    return 1;
-                } else {
-                    payload_len = (stream->last_ack - seg->seq) - payload_offset;
-                }
-                rd->partial = TRUE;
-            } else {
-                payload_len = seg->payload_len - payload_offset;
-            }
-
-            if (SCLogDebugEnabled()) {
-                BUG_ON(payload_offset > seg->payload_len);
-                BUG_ON((payload_len + payload_offset) > seg->payload_len);
-            }
-        } else {
-            payload_offset = 0;
-
-            if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
-                payload_len = stream->last_ack - seg->seq;
-                rd->partial = TRUE;
-            } else {
-                payload_len = seg->payload_len;
-            }
-        }
-        SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
-                " and stream->last_ack is %"PRIu32"", payload_offset,
-                payload_len, stream->last_ack);
-
-        if (payload_len == 0) {
-            SCLogDebug("no payload_len, so bail out");
-            return 1; // TODO
-        }
-
-        if (rd->smsg == NULL) {
-            rd->smsg = StreamMsgGetFromPool();
-            if (rd->smsg == NULL) {
-                SCLogDebug("stream_msg_pool is empty");
-                return -1;
-            }
-
-            rd->smsg_offset = 0;
-
-            StreamTcpSetupMsg(ssn, stream, p, rd->smsg);
-            rd->smsg->seq = rd->ra_base_seq + 1;
-            SCLogDebug("smsg->seq %u", rd->smsg->seq);
-        }
-
-        /* copy the data into the smsg */
-        uint32_t copy_size = rd->smsg->data_size - rd->smsg_offset;
-        if (copy_size + payload_offset > seg->payload_len) {
-            copy_size = seg->payload_len - payload_offset;
-        }
-        if (copy_size > payload_len) {
-            copy_size = payload_len;
-        }
-        if (SCLogDebugEnabled()) {
-            BUG_ON(copy_size > rd->smsg->data_size);
-        }
-        SCLogDebug("copy_size is %"PRIu16"", copy_size);
-        memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + payload_offset,
-                copy_size);
-        rd->smsg_offset += copy_size;
-        rd->ra_base_seq += copy_size;
-        SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq);
-
-        rd->smsg->data_len += copy_size;
-
-        /* queue the smsg if it's full */
-        if (rd->smsg->data_len == rd->smsg->data_size) {
-            StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0);
-            stream->ra_raw_base_seq = rd->ra_base_seq;
-            rd->smsg = NULL;
-        }
-
-        /* if the payload len is bigger than what we copied, we handle the
-         * rest of the payload next... */
-        if (copy_size < payload_len) {
-            SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size,
-                    payload_len);
-
-            payload_offset += copy_size;
-            payload_len -= copy_size;
-            SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is "
-                    "%"PRIu16" and stream->last_ack is %"PRIu32"",
-                    payload_offset, seg->payload_len, stream->last_ack);
-            if (SCLogDebugEnabled()) {
-                BUG_ON(payload_offset > seg->payload_len);
-            }
-
-            /* we need a while loop here as the packets theoretically can be
-             * 64k */
-            char segment_done = FALSE;
-            while (segment_done == FALSE) {
-                SCLogDebug("new msg at offset %" PRIu32 ", payload_len "
-                        "%" PRIu32 "", payload_offset, payload_len);
-
-                /* get a new message
-                   XXX we need a setup function */
-                rd->smsg = StreamMsgGetFromPool();
-                if (rd->smsg == NULL) {
-                    SCLogDebug("stream_msg_pool is empty");
-                    SCReturnInt(-1);
-                }
-                rd->smsg_offset = 0;
-
-                StreamTcpSetupMsg(ssn, stream, p, rd->smsg);
-                rd->smsg->seq = rd->ra_base_seq + 1;
-
-                copy_size = rd->smsg->data_size - rd->smsg_offset;
-                if (copy_size > payload_len) {
-                    copy_size = payload_len;
-                }
-                if (SCLogDebugEnabled()) {
-                    BUG_ON(copy_size > rd->smsg->data_size);
-                }
-
-                SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset "
-                        "%" PRIu32 ", copy_size %" PRIu32 "",
-                        payload_offset, rd->smsg_offset, copy_size);
-                memcpy(rd->smsg->data + rd->smsg_offset, seg->payload +
-                        payload_offset, copy_size);
-                rd->smsg_offset += copy_size;
-                rd->ra_base_seq += copy_size;
-                SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq);
-                rd->smsg->data_len += copy_size;
-                SCLogDebug("copied payload_offset %" PRIu32 ", "
-                        "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "",
-                        payload_offset, rd->smsg_offset, copy_size);
-                if (rd->smsg->data_len == rd->smsg->data_size) {
-                    StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0);
-                    stream->ra_raw_base_seq = rd->ra_base_seq;
-                    rd->smsg = NULL;
-                }
-
-                /* see if we have segment payload left to process */
-                if (copy_size < payload_len) {
-                    payload_offset += copy_size;
-                    payload_len -= copy_size;
-
-                    if (SCLogDebugEnabled()) {
-                        BUG_ON(payload_offset > seg->payload_len);
-                    }
-                } else {
-                    payload_offset = 0;
-                    segment_done = TRUE;
-                }
-            }
-        }
-    }
-    return 1;
-}
-
-/**
- *  \brief Update the stream reassembly upon receiving an ACK packet.
- *  \todo this function is too long, we need to break it up. It needs it BAD
- */
-static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx,
-        TcpSession *ssn, TcpStream *stream, Packet *p)
-{
-    SCEnter();
-    SCLogDebug("start p %p", p);
-
-    if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW)
-        SCReturnInt(0);
-
-    if (stream->seg_list == NULL) {
-        SCLogDebug("no segments in the list to reassemble");
-        SCReturnInt(0);
-    }
-
-#if 0
-    if (ssn->state <= TCP_ESTABLISHED &&
-        !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-        SCLogDebug("only starting raw reassembly after app layer protocol "
-                "detection has completed.");
-        SCReturnInt(0);
-    }
-#endif
-    /* check if we have enough data */
-    if (StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0) {
-        SCLogDebug("not yet reassembling");
-        SCReturnInt(0);
-    }
-
-    TcpSegment *seg = stream->seg_list;
-    ReassembleRawData rd;
-    rd.smsg = NULL;
-    rd.ra_base_seq = stream->ra_raw_base_seq;
-    rd.smsg_offset = 0;
-    uint32_t next_seq = rd.ra_base_seq + 1;
-
-    SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32,
-            rd.ra_base_seq, stream->last_ack, next_seq);
-
-    /* loop through the segments and fill one or more msgs */
-    for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);)
-    {
-        SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", flags %02x",
-                seg, seg->seq, seg->payload_len,
-                (uint32_t)(seg->seq + seg->payload_len), seg->flags);
-
-        if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) {
-            SCLogDebug("removing segment");
-            TcpSegment *next_seg = seg->next;
-            StreamTcpRemoveSegmentFromStream(stream, seg);
-            StreamTcpSegmentReturntoPool(seg);
-            seg = next_seg;
-            continue;
-        } else if(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) {
-            TcpSegment *next_seg = seg->next;
-            seg = next_seg;
-            continue;
-        }
-
-        DoHandleRawGap(ssn, stream, seg, p, &rd, next_seq);
-
-        if (DoRawReassemble(ssn, stream, seg, p, &rd) == 0)
-            break;
-
-        /* done with this segment, return it to the pool */
-        TcpSegment *next_seg = seg->next;
-        next_seq = seg->seq + seg->payload_len;
-        if (rd.partial == FALSE) {
-            SCLogDebug("fully done with segment in raw reassembly (seg %p seq %"PRIu32")",
-                    seg, seg->seq);
-            seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
-            SCLogDebug("flags now %02x", seg->flags);
-        } else {
-            SCLogDebug("not yet fully done with segment in raw reassembly");
-        }
-        seg = next_seg;
-    }
-
-    /* put the partly filled smsg in the queue to the l7 handler */
-    if (rd.smsg != NULL) {
-        StreamTcpStoreStreamChunk(ssn, rd.smsg, p, 0);
-        rd.smsg = NULL;
-        stream->ra_raw_base_seq = rd.ra_base_seq;
-    }
-
-    SCReturnInt(0);
-}
-
-/** \brief update app layer and raw reassembly
- *
- *  \retval r 0 on success, -1 on error
- */
-int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
-        TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
-{
-    SCEnter();
-
-    SCLogDebug("stream->seg_list %p", stream->seg_list);
-
-    int r = 0;
-    if (!(StreamTcpInlineMode())) {
-        if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
-            r = -1;
-        if (StreamTcpReassembleRaw(ra_ctx, ssn, stream, p) < 0)
-            r = -1;
-    }
-
-    SCLogDebug("stream->seg_list %p", stream->seg_list);
-    SCReturnInt(r);
-}
-
-int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
-                                     TcpSession *ssn, TcpStream *stream,
-                                     Packet *p, PacketQueue *pq)
-{
-    SCEnter();
-    SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
-                ssn, stream, p, p->payload_len);
-
-    /* we need to update the opposing stream in
-     * StreamTcpReassembleHandleSegmentUpdateACK */
-    TcpStream *opposing_stream = NULL;
-    if (stream == &ssn->client) {
-        opposing_stream = &ssn->server;
-    } else {
-        opposing_stream = &ssn->client;
-    }
-
-    /* handle ack received */
-    if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0)
-    {
-        SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
-        SCReturnInt(-1);
-    }
-
-    /* If no stream reassembly/application layer protocol inspection, then
-       simple return */
-    if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
-        SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
-
-        if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
-            SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
-            SCReturnInt(-1);
-        }
-
-        p->flags |= PKT_STREAM_ADD;
-    }
-
-    /* in stream inline mode even if we have no data we call the reassembly
-     * functions to handle EOF */
-    if (StreamTcpInlineMode()) {
-        int r = 0;
-        if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
-            r = -1;
-        if (StreamTcpReassembleInlineRaw(ra_ctx, ssn, stream, p) < 0)
-            r = -1;
-
-        if (r < 0) {
-            SCReturnInt(-1);
-        }
-    }
-
-    SCReturnInt(0);
-}
-
-/**
- *  \brief  Function to replace the data from a specific point up to given length.
- *
- *  \param  dst_seg     Destination segment to replace the data
- *  \param  src_seg     Source segment of which data is to be written to destination
- *  \param  start_point Starting point to replace the data onwards
- *  \param  len         Length up to which data is need to be replaced
- *
- *  \todo VJ We can remove the abort()s later.
- *  \todo VJ Why not memcpy?
- */
-void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg,
-                                 uint32_t start_point, uint16_t len)
-{
-    uint32_t seq;
-    uint16_t src_pos = 0;
-    uint16_t dst_pos = 0;
-
-    SCLogDebug("start_point %u", start_point);
-
-    if (SEQ_GT(start_point, dst_seg->seq)) {
-        dst_pos = start_point - dst_seg->seq;
-    } else if (SEQ_LT(start_point, dst_seg->seq)) {
-        dst_pos = dst_seg->seq - start_point;
-    }
-
-    if (SCLogDebugEnabled()) {
-        BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len);
-    } else {
-        if (((len + dst_pos) - 1) > dst_seg->payload_len)
-            return;
-    }
-
-    src_pos = (uint16_t)(start_point - src_seg->seq);
-
-    SCLogDebug("Replacing data from dst_pos %"PRIu16"", dst_pos);
-
-    for (seq = start_point; SEQ_LT(seq, (start_point + len)) &&
-            src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len;
-            seq++, dst_pos++, src_pos++)
-    {
-        dst_seg->payload[dst_pos] = src_seg->payload[src_pos];
-    }
-
-    SCLogDebug("Replaced data of size %"PRIu16" up to src_pos %"PRIu16
-            " dst_pos %"PRIu16, len, src_pos, dst_pos);
-}
-
-/**
- *  \brief  Function to compare the data from a specific point up to given length.
- *
- *  \param  dst_seg     Destination segment to compare the data
- *  \param  src_seg     Source segment of which data is to be compared to destination
- *  \param  start_point Starting point to compare the data onwards
- *  \param  len         Length up to which data is need to be compared
- *
- *  \retval 1 same
- *  \retval 0 different
- */
-static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg,
-                                 uint32_t start_point, uint16_t len)
-{
-    uint32_t seq;
-    uint16_t src_pos = 0;
-    uint16_t dst_pos = 0;
-
-    SCLogDebug("start_point %u dst_seg %u src_seg %u", start_point, dst_seg->seq, src_seg->seq);
-
-    if (SEQ_GT(start_point, dst_seg->seq)) {
-        SCLogDebug("start_point %u > dst %u", start_point, dst_seg->seq);
-        dst_pos = start_point - dst_seg->seq;
-    } else if (SEQ_LT(start_point, dst_seg->seq)) {
-        SCLogDebug("start_point %u < dst %u", start_point, dst_seg->seq);
-        dst_pos = dst_seg->seq - start_point;
-    }
-
-    if (SCLogDebugEnabled()) {
-        BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len);
-    } else {
-        if (((len + dst_pos) - 1) > dst_seg->payload_len)
-            return 1;
-    }
-
-    src_pos = (uint16_t)(start_point - src_seg->seq);
-
-    SCLogDebug("Comparing data from dst_pos %"PRIu16", src_pos %u", dst_pos, src_pos);
-
-    for (seq = start_point; SEQ_LT(seq, (start_point + len)) &&
-            src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len;
-            seq++, dst_pos++, src_pos++)
-    {
-        if (dst_seg->payload[dst_pos] != src_seg->payload[src_pos]) {
-            SCLogDebug("data is different %02x != %02x, dst_pos %u, src_pos %u", dst_seg->payload[dst_pos], src_seg->payload[src_pos], dst_pos, src_pos);
-            return 0;
-        }
-    }
-
-    SCLogDebug("Compared data of size %"PRIu16" up to src_pos %"PRIu16
-            " dst_pos %"PRIu16, len, src_pos, dst_pos);
-    return 1;
-}
-
-/**
- *  \brief  Function to copy the data from src_seg to dst_seg.
- *
- *  \param  dst_seg     Destination segment for copying the contents
- *  \param  src_seg     Source segment to copy its contents
- *
- *  \todo VJ wouldn't a memcpy be more appropriate here?
- *
- *  \warning Both segments need to be properly initialized.
- */
-
-void StreamTcpSegmentDataCopy(TcpSegment *dst_seg, TcpSegment *src_seg)
-{
-    uint32_t u;
-    uint16_t dst_pos = 0;
-    uint16_t src_pos = 0;
-    uint32_t seq;
-
-    if (SEQ_GT(dst_seg->seq, src_seg->seq)) {
-        src_pos = dst_seg->seq - src_seg->seq;
-        seq = dst_seg->seq;
-    } else {
-        dst_pos = src_seg->seq - dst_seg->seq;
-        seq = src_seg->seq;
-    }
-
-    SCLogDebug("Copying data from seq %"PRIu32"", seq);
-    for (u = seq;
-            (SEQ_LT(u, (src_seg->seq + src_seg->payload_len)) &&
-             SEQ_LT(u, (dst_seg->seq + dst_seg->payload_len))); u++)
-    {
-        //SCLogDebug("u %"PRIu32, u);
-
-        dst_seg->payload[dst_pos] = src_seg->payload[src_pos];
-
-        dst_pos++;
-        src_pos++;
-    }
-    SCLogDebug("Copyied data of size %"PRIu16" up to dst_pos %"PRIu16"",
-                src_pos, dst_pos);
-}
-
-/**
- *  \brief   Function to get the segment of required length from the pool.
- *
- *  \param   len    Length which tells the required size of needed segment.
- *
- *  \retval seg Segment from the pool or NULL
- */
-TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint16_t len)
-{
-    uint16_t idx = segment_pool_idx[len];
-    SCLogDebug("segment_pool_idx %" PRIu32 " for payload_len %" PRIu32 "",
-                idx, len);
-
-    SCMutexLock(&segment_pool_mutex[idx]);
-    TcpSegment *seg = (TcpSegment *) PoolGet(segment_pool[idx]);
-
-    SCLogDebug("segment_pool[%u]->empty_stack_size %u, segment_pool[%u]->alloc_"
-               "list_size %u, alloc %u", idx, segment_pool[idx]->empty_stack_size,
-               idx, segment_pool[idx]->alloc_stack_size,
-               segment_pool[idx]->allocated);
-    SCMutexUnlock(&segment_pool_mutex[idx]);
-
-    SCLogDebug("seg we return is %p", seg);
-    if (seg == NULL) {
-        SCLogDebug("segment_pool[%u]->empty_stack_size %u, "
-                   "alloc %u", idx, segment_pool[idx]->empty_stack_size,
-                   segment_pool[idx]->allocated);
-        /* Increment the counter to show that we are not able to serve the
-           segment request due to memcap limit */
-        StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
-    } else {
-        seg->flags = stream_config.segment_init_flags;
-        seg->next = NULL;
-        seg->prev = NULL;
-    }
-
-#ifdef DEBUG
-    SCMutexLock(&segment_pool_cnt_mutex);
-    segment_pool_cnt++;
-    SCMutexUnlock(&segment_pool_cnt_mutex);
-#endif
-
-    return seg;
-}
-
-/**
- *  \brief Trigger RAW stream reassembly
- *
- *  Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
- *  reassembly from the applayer, for example upon completion of a
- *  HTTP request.
- *
- *  Works by setting a flag in the TcpSession that is unset as soon
- *  as it's checked. Since everything happens when operating under
- *  a single lock period, no side effects are expected.
- *
- *  \param ssn TcpSession
- */
-void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn)
-{
-#ifdef DEBUG
-    BUG_ON(ssn == NULL);
-#endif
-
-    if (ssn != NULL) {
-        SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
-        ssn->flags |= STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
-    }
-}
-
-#ifdef UNITTESTS
-/** unit tests and it's support functions below */
-
-static int UtTestSmsg(StreamMsg *smsg, const uint8_t *buf, uint32_t buf_len)
-{
-    if (smsg == NULL)
-        return 0;
-
-    if (smsg->data_len != buf_len) {
-        return 0;
-    }
-
-    if (!(memcmp(buf, smsg->data, buf_len) == 0)) {
-        printf("data is not what we expected:\nExpected:\n");
-        PrintRawDataFp(stdout, (uint8_t *)buf, buf_len);
-        printf("Got:\n");
-        PrintRawDataFp(stdout, smsg->data, smsg->data_len);
-        return 0;
-    }
-    return 1;
-}
-
-static uint32_t UtSsnSmsgCnt(TcpSession *ssn, uint8_t direction)
-{
-    uint32_t cnt = 0;
-    StreamMsg *smsg = (direction == STREAM_TOSERVER) ?
-                            ssn->toserver_smsg_head :
-                            ssn->toclient_smsg_head;
-    while (smsg) {
-        cnt++;
-        smsg = smsg->next;
-    }
-    return cnt;
-}
-
-/** \brief  The Function tests the reassembly engine working for different
- *          OSes supported. It includes all the OS cases and send
- *          crafted packets to test the reassembly.
- *
- *  \param  stream  The stream which will contain the reassembled segments
- */
-
-static int StreamTcpReassembleStreamTest(TcpStream *stream)
-{
-
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow f;
-    uint8_t payload[4];
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
-
-    StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
-    p->tcph->th_seq = htonl(12);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
-    p->tcph->th_seq = htonl(16);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
-    p->tcph->th_seq = htonl(18);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/
-    p->tcph->th_seq = htonl(22);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/
-    p->tcph->th_seq = htonl(25);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/
-    p->tcph->th_seq = htonl(27);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/
-    p->tcph->th_seq = htonl(30);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/
-    p->tcph->th_seq = htonl(32);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/
-    p->tcph->th_seq = htonl(34);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/
-    p->tcph->th_seq = htonl(13);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 4;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/
-    p->tcph->th_seq = htonl(18);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/
-    p->tcph->th_seq = htonl(21);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/
-    p->tcph->th_seq = htonl(24);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/
-    p->tcph->th_seq = htonl(28);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/
-    p->tcph->th_seq = htonl(31);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/
-    p->tcph->th_seq = htonl(32);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/
-    p->tcph->th_seq = htonl(34);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x30, 1, 4); /*0*/
-    p->tcph->th_seq = htonl(11);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-
-    SCFree(p);
-    return 1;
-}
-
-/** \brief  The Function to create the packet with given payload, which is used
- *          to test the reassembly of the engine.
- *
- *  \param  payload     The variable used to store the payload contents of the
- *                      current packet.
- *  \param  value       The value which current payload will have for this packet
- *  \param  payload_len The length of the filed payload for current packet.
- *  \param  len         Length of the payload array
- */
-
-void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
-                               uint8_t payload_len, uint8_t len)
-{
-    uint8_t i;
-    for (i = 0; i < payload_len; i++)
-        payload[i] = value;
-    for (; i < len; i++)
-        payload = NULL;
-}
-
-/** \brief  The Function Checks the reassembled stream contents against predefined
- *          stream contents according to OS policy used.
- *
- *  \param  stream_policy   Predefined value of stream for different OS policies
- *  \param  stream          Reassembled stream returned from the reassembly functions
- */
-
-int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
-{
-    TcpSegment *temp;
-    uint16_t i = 0;
-    uint8_t j;
-
-#ifdef DEBUG
-    if (SCLogDebugEnabled()) {
-        TcpSegment *temp1;
-        for (temp1 = stream->seg_list; temp1 != NULL; temp1 = temp1->next)
-            PrintRawDataFp(stdout, temp1->payload, temp1->payload_len);
-
-        PrintRawDataFp(stdout, stream_policy, sp_size);
-    }
-#endif
-
-    for (temp = stream->seg_list; temp != NULL; temp = temp->next) {
-        j = 0;
-        for (; j < temp->payload_len; j++) {
-            SCLogDebug("i %"PRIu16", len %"PRIu32", stream %"PRIx32" and temp is %"PRIx8"",
-                i, temp->payload_len, stream_policy[i], temp->payload[j]);
-
-            if (stream_policy[i] == temp->payload[j]) {
-                i++;
-                continue;
-            } else
-                return 0;
-        }
-    }
-    return 1;
-}
-
-/** \brief  The Function Checks the Stream Queue contents against predefined
- *          stream contents.
- *
- *  \param  stream_contents     Predefined value of stream contents
- *  \param  stream              Queue which has the stream contents
- *
- *  \retval On success the function returns 1, on failure 0.
- */
-static int StreamTcpCheckChunks (TcpSession *ssn, uint8_t *stream_contents)
-{
-    SCEnter();
-
-    StreamMsg *msg;
-    uint16_t i = 0;
-    uint8_t j;
-    uint8_t cnt = 0;
-
-    if (ssn == NULL) {
-        printf("ssn == NULL, ");
-        SCReturnInt(0);
-    }
-
-    if (ssn->toserver_smsg_head == NULL) {
-        printf("ssn->toserver_smsg_head == NULL, ");
-        SCReturnInt(0);
-    }
-
-    msg = ssn->toserver_smsg_head;
-    while(msg != NULL) {
-        cnt++;
-        j = 0;
-        for (; j < msg->data_len; j++) {
-            SCLogDebug("i is %" PRIu32 " and len is %" PRIu32 "  and temp is %" PRIx32 "", i, msg->data_len, msg->data[j]);
-
-            if (stream_contents[i] == msg->data[j]) {
-                i++;
-                continue;
-            } else {
-                SCReturnInt(0);
-            }
-        }
-        msg = msg->next;
-    }
-    SCReturnInt(1);
-}
-
-/* \brief           The function craft packets to test the overlapping, where
- *                  new segment stats before the list segment.
- *
- *  \param  stream  The stream which will contain the reassembled segments and
- *                  also tells the OS policy used for reassembling the segments.
- */
-
-static int StreamTcpTestStartsBeforeListSegment(TcpStream *stream) {
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow f;
-    uint8_t payload[4];
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
-
-    StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
-    p->tcph->th_seq = htonl(16);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/
-    p->tcph->th_seq = htonl(22);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/
-    p->tcph->th_seq = htonl(25);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
-    p->tcph->th_seq = htonl(15);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/
-    p->tcph->th_seq = htonl(14);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 4;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    SCLogDebug("sending segment with SEQ 21, len 3");
-    StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/
-    p->tcph->th_seq = htonl(21);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/
-    p->tcph->th_seq = htonl(24);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    SCFree(p);
-    return 1;
-}
-
-/* \brief           The function craft packets to test the overlapping, where
- *                  new segment stats at the same seq no. as the list segment.
- *
- *  \param  stream  The stream which will contain the reassembled segments and
- *                  also tells the OS policy used for reassembling the segments.
- */
-
-static int StreamTcpTestStartsAtSameListSegment(TcpStream *stream)
-{
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow f;
-    uint8_t payload[4];
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
-
-    StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
-    p->tcph->th_seq = htonl(18);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/
-    p->tcph->th_seq = htonl(32);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/
-    p->tcph->th_seq = htonl(34);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/
-    p->tcph->th_seq = htonl(18);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4c, 4, 4); /*LLLL*/
-    p->tcph->th_seq = htonl(18);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 4;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/
-    p->tcph->th_seq = htonl(32);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/
-    p->tcph->th_seq = htonl(34);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    SCFree(p);
-    return 1;
-}
-
-/* \brief           The function craft packets to test the overlapping, where
- *                  new segment stats after the list segment.
- *
- *  \param  stream  The stream which will contain the reassembled segments and
- *                  also tells the OS policy used for reassembling the segments.
- */
-
-
-static int StreamTcpTestStartsAfterListSegment(TcpStream *stream)
-{
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow f;
-    uint8_t payload[4];
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
-
-    StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
-    p->tcph->th_seq = htonl(12);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/
-    p->tcph->th_seq = htonl(27);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 3;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/
-    p->tcph->th_seq = htonl(30);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4a, 2, 4); /*JJ*/
-    p->tcph->th_seq = htonl(13);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 2;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/
-    p->tcph->th_seq = htonl(31);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/
-    p->tcph->th_seq = htonl(28);
-    p->tcph->th_ack = htonl(31);
-    p->payload = payload;
-    p->payload_len = 1;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
-
-    SCFree(p);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              before the list segment and BSD policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest01(void)
-{
-    TcpStream stream;
-    uint8_t stream_before_bsd[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
-                                      0x4c, 0x4d, 0x4d, 0x4d};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_before_bsd,sizeof(stream_before_bsd), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              at the same seq no. as the list segment and BSD policy is used
- *              to reassemble segments.
- */
-
-static int StreamTcpReassembleTest02(void)
-{
-    TcpStream stream;
-    uint8_t stream_same_bsd[8] = {0x43, 0x43, 0x43, 0x4c, 0x48, 0x48,
-                                    0x49, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_same_bsd, sizeof(stream_same_bsd), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              after the list segment and BSD policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest03(void)
-{
-    TcpStream stream;
-    uint8_t stream_after_bsd[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
-                                     0x47, 0x47};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_after_bsd, sizeof(stream_after_bsd), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly engine for all the case
- *              before, same and after overlapping and BSD policy is used to
- *              reassemble segments.
- */
-
-static int StreamTcpReassembleTest04(void)
-{
-    TcpStream stream;
-    uint8_t stream_bsd[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x43,
-                               0x43, 0x43, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
-                               0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpReassembleStreamTest(&stream) == 0) {
-        printf("failed in segments reassembly: ");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_bsd, sizeof(stream_bsd), &stream) == 0) {
-        printf("failed in stream matching: ");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              before the list segment and VISTA policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest05(void)
-{
-    TcpStream stream;
-    uint8_t stream_before_vista[10] = {0x4a, 0x41, 0x42, 0x4a, 0x4c, 0x44,
-                                        0x4c, 0x4d, 0x45, 0x45};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_VISTA;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_before_vista, sizeof(stream_before_vista), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              at the same seq no. as the list segment and VISTA policy is used
- *              to reassemble segments.
- */
-
-static int StreamTcpReassembleTest06(void)
-{
-    TcpStream stream;
-    uint8_t stream_same_vista[8] = {0x43, 0x43, 0x43, 0x4c, 0x48, 0x48,
-                                     0x49, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_VISTA;
-
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_same_vista, sizeof(stream_same_vista), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              after the list segment and BSD policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest07(void)
-{
-    TcpStream stream;
-    uint8_t stream_after_vista[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
-                                      0x47, 0x47};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_VISTA;
-
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_after_vista, sizeof(stream_after_vista), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly engine for all the case
- *              before, same and after overlapping and VISTA policy is used to
- *              reassemble segments.
- */
-
-static int StreamTcpReassembleTest08(void)
-{
-    TcpStream stream;
-    uint8_t stream_vista[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x42, 0x42, 0x43,
-                                 0x43, 0x43, 0x4c, 0x44, 0x4c, 0x4d, 0x45, 0x45,
-                                 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_VISTA;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpReassembleStreamTest(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_vista, sizeof(stream_vista), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              before the list segment and LINUX policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest09(void)
-{
-    TcpStream stream;
-    uint8_t stream_before_linux[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
-                                        0x4c, 0x4d, 0x4d, 0x4d};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_before_linux, sizeof(stream_before_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              at the same seq no. as the list segment and LINUX policy is used
- *              to reassemble segments.
- */
-
-static int StreamTcpReassembleTest10(void)
-{
-    TcpStream stream;
-    uint8_t stream_same_linux[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48,
-                                     0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_same_linux, sizeof(stream_same_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              after the list segment and LINUX policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest11(void)
-{
-    TcpStream stream;
-    uint8_t stream_after_linux[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
-                                      0x47, 0x47};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_after_linux, sizeof(stream_after_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly engine for all the case
- *              before, same and after overlapping and LINUX policy is used to
- *              reassemble segments.
- */
-
-static int StreamTcpReassembleTest12(void)
-{
-    TcpStream stream;
-    uint8_t stream_linux[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x43,
-                                 0x43, 0x43, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
-                                 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpReassembleStreamTest(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_linux, sizeof(stream_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              before the list segment and OLD_LINUX policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest13(void)
-{
-    TcpStream stream;
-    uint8_t stream_before_old_linux[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
-                                            0x4c, 0x4d, 0x4d, 0x4d};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_OLD_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_before_old_linux, sizeof(stream_before_old_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              at the same seq no. as the list segment and OLD_LINUX policy is
- *              used to reassemble segments.
- */
-
-static int StreamTcpReassembleTest14(void)
-{
-    TcpStream stream;
-    uint8_t stream_same_old_linux[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48,
-                                         0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_OLD_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_same_old_linux, sizeof(stream_same_old_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              after the list segment and OLD_LINUX policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest15(void)
-{
-    TcpStream stream;
-    uint8_t stream_after_old_linux[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
-                                          0x47, 0x47};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_OLD_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_after_old_linux, sizeof(stream_after_old_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly engine for all the case
- *              before, same and after overlapping and OLD_LINUX policy is used to
- *              reassemble segments.
- */
-
-static int StreamTcpReassembleTest16(void)
-{
-    TcpStream stream;
-    uint8_t stream_old_linux[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x4b,
-                                     0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
-                                     0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_OLD_LINUX;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpReassembleStreamTest(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_old_linux, sizeof(stream_old_linux), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              before the list segment and SOLARIS policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest17(void)
-{
-    TcpStream stream;
-    uint8_t stream_before_solaris[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
-                                          0x4c, 0x4d, 0x4d, 0x4d};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_SOLARIS;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_before_solaris, sizeof(stream_before_solaris), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              at the same seq no. as the list segment and SOLARIS policy is used
- *              to reassemble segments.
- */
-
-static int StreamTcpReassembleTest18(void)
-{
-    TcpStream stream;
-    uint8_t stream_same_solaris[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48,
-                                       0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_SOLARIS;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_same_solaris, sizeof(stream_same_solaris), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              after the list segment and SOLARIS policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest19(void)
-{
-    TcpStream stream;
-    uint8_t stream_after_solaris[8] = {0x41, 0x4a, 0x4a, 0x46, 0x46, 0x46,
-                                        0x47, 0x47};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_SOLARIS;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        StreamTcpFreeConfig(TRUE);
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_after_solaris, sizeof(stream_after_solaris), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        StreamTcpFreeConfig(TRUE);
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly engine for all the case
- *              before, same and after overlapping and SOLARIS policy is used to
- *              reassemble segments.
- */
-
-static int StreamTcpReassembleTest20(void)
-{
-    TcpStream stream;
-    uint8_t stream_solaris[25] = {0x30, 0x41, 0x4a, 0x4a, 0x4a, 0x42, 0x42, 0x4b,
-                                   0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
-                                   0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_SOLARIS;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpReassembleStreamTest(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        StreamTcpFreeConfig(TRUE);
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_solaris, sizeof(stream_solaris), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        StreamTcpFreeConfig(TRUE);
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              before the list segment and LAST policy is used to reassemble
- *              segments.
- */
-
-static int StreamTcpReassembleTest21(void)
-{
-    TcpStream stream;
-    uint8_t stream_before_last[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
-                                       0x4c, 0x4d, 0x4d, 0x4d};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_LAST;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_before_last, sizeof(stream_before_last), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              at the same seq no. as the list segment and LAST policy is used
- *              to reassemble segments.
- */
-
-static int StreamTcpReassembleTest22(void)
-{
-    TcpStream stream;
-    uint8_t stream_same_last[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x50, 0x48,
-                                    0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_LAST;
-    StreamTcpInitConfig(TRUE);
-    if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_same_last, sizeof(stream_same_last), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly when new segment starts
- *              after the list segment and LAST policy is used to reassemble
- *              segments.
- */
-static int StreamTcpReassembleTest23(void)
-{
-    TcpStream stream;
-    uint8_t stream_after_last[8] = {0x41, 0x4a, 0x4a, 0x46, 0x4e, 0x46, 0x47, 0x4f};
-    memset(&stream, 0, sizeof (TcpStream));
-
-    stream.os_policy = OS_POLICY_LAST;
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
-        printf("failed in segments reassembly!!\n");
-        return 0;
-    }
-    if (StreamTcpCheckStreamContents(stream_after_last, sizeof(stream_after_last), &stream) == 0) {
-        printf("failed in stream matching!!\n");
-        return 0;
-    }
-    StreamTcpFreeConfig(TRUE);
-    return 1;
-}
-
-/** \brief      The Function to test the reassembly engine for all the case
- *              before, same and after overlapping and LAST policy is used to
- *              reassemble segments.
- */
-
-static int StreamTcpReassembleTest24(void)
-{
-    int ret = 0;
-    TcpStream stream;
-    uint8_t stream_last[25] = {0x30, 0x41, 0x4a, 0x4a, 0x4a, 0x4a, 0x42, 0x4b,
-                               0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
-                               0x46, 0x4e, 0x46, 0x47, 0x4f, 0x50, 0x48, 0x51, 0x51};
-    memset(&stream, 0, sizeof (TcpStream));
-
-    stream.os_policy = OS_POLICY_LAST;
-    StreamTcpInitConfig(TRUE);
-
-    if (StreamTcpReassembleStreamTest(&stream) == 0)  {
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-    if (StreamTcpCheckStreamContents(stream_last, sizeof(stream_last), &stream) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/** \brief  The Function to test the missed packets handling with given payload,
- *          which is used to test the reassembly of the engine.
- *
- *  \param  stream      Stream which contain the packets
- *  \param  seq         Sequence number of the packet
- *  \param  ack         Acknowledgment number of the packet
- *  \param  payload     The variable used to store the payload contents of the
- *                      current packet.
- *  \param  len         The length of the payload for current packet.
- *  \param  th_flag     The TCP flags
- *  \param  flowflags   The packet flow direction
- *  \param  state       The TCP session state
- *
- *  \retval On success it returns 0 and on failure it return -1.
- */
-
-static int StreamTcpTestMissedPacket (TcpReassemblyThreadCtx *ra_ctx,
-        TcpSession *ssn, uint32_t seq, uint32_t ack, uint8_t *payload,
-        uint16_t len, uint8_t th_flags, uint8_t flowflags, uint8_t state)
-{
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return -1;
-    Flow f;
-    TCPHdr tcph;
-    Port sp;
-    Port dp;
-    struct in_addr in;
-    ThreadVars tv;
-    PacketQueue pq;
-
-    memset(&pq,0,sizeof(PacketQueue));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    memset(&tv, 0, sizeof (ThreadVars));
-
-    sp = 200;
-    dp = 220;
-
-    FLOW_INITIALIZE(&f);
-    if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) {
-        SCFree(p);
-        return -1;
-    }
-    f.src.addr_data32[0] = in.s_addr;
-    if (inet_pton(AF_INET, "1.2.3.5", &in) != 1) {
-        SCFree(p);
-        return -1;
-    }
-    f.dst.addr_data32[0] = in.s_addr;
-    f.flags |= FLOW_IPV4;
-    f.sp = sp;
-    f.dp = dp;
-    f.protoctx = ssn;
-    f.proto = IPPROTO_TCP;
-    p->flow = &f;
-
-    tcph.th_win = htons(5480);
-    tcph.th_seq = htonl(seq);
-    tcph.th_ack = htonl(ack);
-    tcph.th_flags = th_flags;
-    p->tcph = &tcph;
-    p->flowflags = flowflags;
-
-    p->payload = payload;
-    p->payload_len = len;
-    ssn->state = state;
-
-    TcpStream *s = NULL;
-    if (flowflags & FLOW_PKT_TOSERVER) {
-        s = &ssn->server;
-    } else {
-        s = &ssn->client;
-    }
-
-    FLOWLOCK_WRLOCK(&f);
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, ssn, s, p, &pq) == -1) {
-        FLOWLOCK_UNLOCK(&f);
-        SCFree(p);
-        return -1;
-    }
-
-    FLOWLOCK_UNLOCK(&f);
-    SCFree(p);
-    return 0;
-}
-
-/**
- *  \test   Test the handling of packets missed by both IDS and the end host.
- *          The packet is missed in the starting of the stream.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest25 (void)
-{
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    TcpSession ssn;
-    uint8_t th_flag;
-    uint8_t flowflags;
-    uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43};
-
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    memset(&ssn, 0, sizeof (TcpSession));
-
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-    ack = 20;
-    StreamTcpInitConfig(TRUE);
-
-    StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
-    seq = 10;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/
-    seq = 12;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-    ssn.server.next_seq = 14;
-    StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
-    seq = 7;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test the handling of packets missed by both IDS and the end host.
- *          The packet is missed in the middle of the stream.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest26 (void)
-{
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    TcpSession ssn;
-    uint8_t th_flag;
-    uint8_t flowflags;
-    uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43};
-    memset(&ssn, 0, sizeof (TcpSession));
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-    ack = 20;
-    StreamTcpInitConfig(TRUE);
-
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
-    StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
-    seq = 10;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/
-    seq = 15;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
-    seq = 13;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test the handling of packets missed by both IDS and the end host.
- *          The packet is missed in the end of the stream.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest27 (void)
-{
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    TcpSession ssn;
-    uint8_t th_flag;
-    uint8_t flowflags;
-    uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43};
-    memset(&ssn, 0, sizeof (TcpSession));
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-    ack = 20;
-    StreamTcpInitConfig(TRUE);
-
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
-    StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
-    seq = 10;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
-    seq = 13;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/
-    seq = 15;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test the handling of packets missed by IDS, but the end host has
- *          received it and send the acknowledgment of it. The packet is missed
- *          in the starting of the stream.
+#if 0
+/** \brief  The Function tests the reassembly engine working for different
+ *          OSes supported. It includes all the OS cases and send
+ *          crafted packets to test the reassembly.
  *
- *  \retval On success it returns 1 and on failure 0.
+ *  \param  stream  The stream which will contain the reassembled segments
  */
 
-static int StreamTcpReassembleTest28 (void)
+static int StreamTcpReassembleStreamTest(TcpStream *stream)
 {
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    uint8_t th_flag;
-    uint8_t th_flags;
-    uint8_t flowflags;
-    uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42};
+
     TcpSession ssn;
-    memset(&ssn, 0, sizeof (TcpSession));
+    Packet *p = PacketGetFromAlloc();
+    if (unlikely(p == NULL))
+        return 0;
+    Flow f;
+    uint8_t payload[4];
+    TCPHdr tcph;
     TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
 
-    StreamTcpInitConfig(TRUE);
+    /* prevent L7 from kicking in */
     StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
     StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
+    PacketQueue pq;
+    memset(&pq,0,sizeof(PacketQueue));
 
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-    th_flags = TH_ACK;
-
-    ssn.server.last_ack = 22;
-    ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 6;
-    ssn.server.isn = 6;
-
-    StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
-    seq = 10;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly (1): ");
-        goto end;
-    }
-
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 12;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly (2): ");
-        goto end;
-    }
-
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
-    seq = 12;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly (4): ");
-        goto end;
-    }
-
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 15;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_TIME_WAIT) == -1) {
-        printf("failed in segments reassembly (5): ");
-        goto end;
-    }
-
-    if (StreamTcpCheckChunks(&ssn, check_contents) == 0) {
-        printf("failed in stream matching (6): ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test the handling of packets missed by IDS, but the end host has
- *          received it and send the acknowledgment of it. The packet is missed
- *          in the middle of the stream.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest29 (void)
-{
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    uint8_t th_flag;
-    uint8_t th_flags;
-    uint8_t flowflags;
-    uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42};
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    TcpSession ssn;
-    memset(&ssn, 0, sizeof (TcpSession));
-
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-    th_flags = TH_ACK;
-
-    ssn.server.last_ack = 22;
-    ssn.server.ra_raw_base_seq = 9;
-    ssn.server.isn = 9;
-    StreamTcpInitConfig(TRUE);
-
-    StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
-    seq = 10;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 15;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
-    seq = 15;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 18;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_TIME_WAIT) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
-    }
-
-    if (StreamTcpCheckChunks(&ssn, check_contents) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test the handling of packets missed by IDS, but the end host has
- *          received it and send the acknowledgment of it. The packet is missed
- *          at the end of the stream.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest30 (void)
-{
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    uint8_t th_flag;
-    uint8_t th_flags;
-    uint8_t flowflags;
-    uint8_t check_contents[6] = {0x41, 0x41, 0x42, 0x42, 0x42, 0x00};
-    TcpSession ssn;
     memset(&ssn, 0, sizeof (TcpSession));
+    memset(&f, 0, sizeof (Flow));
+    memset(&tcph, 0, sizeof (TCPHdr));
+    ThreadVars tv;
+    memset(&tv, 0, sizeof (ThreadVars));
+    FLOW_INITIALIZE(&f);
+    f.protoctx = &ssn;
+    f.proto = IPPROTO_TCP;
+    p->src.family = AF_INET;
+    p->dst.family = AF_INET;
+    p->proto = IPPROTO_TCP;
+    p->flow = &f;
+    tcph.th_win = 5480;
+    tcph.th_flags = TH_PUSH | TH_ACK;
+    p->tcph = &tcph;
+    p->flowflags = FLOW_PKT_TOSERVER;
+    SET_ISN(&ssn.client, 10);
+    SET_ISN(&ssn.server, 10);
 
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-    th_flags = TH_ACK;
-
-    ssn.client.last_ack = 2;
-    ssn.client.isn = 1;
-
-    ssn.server.last_ack = 22;
-    ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
-    ssn.server.isn = 9;
-
-    StreamTcpInitConfig(TRUE);
-    StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
-    seq = 10;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
+    p->tcph->th_seq = htonl(12);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 3;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 12;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
+    p->tcph->th_seq = htonl(16);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 2;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
-    seq = 12;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
+    p->tcph->th_seq = htonl(18);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 3;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 18;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/
+    p->tcph->th_seq = htonl(22);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 1;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    th_flag = TH_FIN|TH_ACK;
-    seq = 18;
-    ack = 20;
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x00, 1, 4);
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/
+    p->tcph->th_seq = htonl(25);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 2;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOCLIENT;
-    StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
-    seq = 20;
-    ack = 18;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flag, flowflags, TCP_TIME_WAIT) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/
+    p->tcph->th_seq = htonl(27);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 3;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    if (StreamTcpCheckChunks(&ssn, check_contents) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/
+    p->tcph->th_seq = htonl(30);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 2;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test to reassemble the packets using the fast track method, as most
- *          packets arrives in order.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest31 (void)
-{
-    int ret = 0;
-    uint8_t payload[4];
-    uint32_t seq;
-    uint32_t ack;
-    uint8_t th_flag;
-    uint8_t flowflags;
-    uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42};
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    TcpSession ssn;
-    memset(&ssn, 0, sizeof (TcpSession));
-
-    flowflags = FLOW_PKT_TOSERVER;
-    th_flag = TH_ACK|TH_PUSH;
-
-    ssn.server.ra_raw_base_seq = 9;
-    ssn.server.isn = 9;
-    StreamTcpInitConfig(TRUE);
-
-    StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
-    seq = 10;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/
+    p->tcph->th_seq = htonl(32);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 2;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
-    seq = 15;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/
+    p->tcph->th_seq = htonl(34);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 1;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
-    seq = 12;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/
+    p->tcph->th_seq = htonl(13);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 4;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    flowflags = FLOW_PKT_TOSERVER;
-    StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
-    seq = 16;
-    ack = 20;
-    if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
-        printf("failed in segments reassembly: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/
+    p->tcph->th_seq = htonl(18);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 3;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    if (StreamTcpCheckStreamContents(check_contents, 5, &ssn.server) == 0) {
-        printf("failed in stream matching: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/
+    p->tcph->th_seq = htonl(21);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 3;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    if (ssn.server.seg_list_tail->seq != 16) {
-        printf("failed in fast track handling: ");
-        goto end;
+    StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/
+    p->tcph->th_seq = htonl(24);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 3;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-static int StreamTcpReassembleTest32(void)
-{
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
+    StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/
+    p->tcph->th_seq = htonl(28);
+    p->tcph->th_ack = htonl(31);
+    p->payload = payload;
+    p->payload_len = 1;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
         return 0;
-    Flow f;
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    TcpStream stream;
-    uint8_t ret = 0;
-    uint8_t check_contents[35] = {0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
-                                 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
-                                 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42,
-                                 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
-                                 0x43, 0x43, 0x43};
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-    uint8_t payload[20] = "";
-
-    StreamTcpInitConfig(TRUE);
-
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
+    }
 
-    p->tcph->th_seq = htonl(10);
+    StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/
+    p->tcph->th_seq = htonl(31);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 10;
-    StreamTcpCreateTestPacket(payload, 0x41, 10, 20); /*AA*/
     p->payload = payload;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
-        goto end;
+    p->payload_len = 1;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
+    }
 
-    p->tcph->th_seq = htonl(20);
+    StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/
+    p->tcph->th_seq = htonl(32);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 10;
-    StreamTcpCreateTestPacket(payload, 0x42, 10, 20); /*BB*/
     p->payload = payload;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
-        goto end;
+    p->payload_len = 1;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
+    }
 
-    p->tcph->th_seq = htonl(40);
+    StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/
+    p->tcph->th_seq = htonl(34);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 10;
-    StreamTcpCreateTestPacket(payload, 0x43, 10, 20); /*CC*/
     p->payload = payload;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
-        goto end;
+    p->payload_len = 2;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
+    }
 
-    p->tcph->th_seq = htonl(5);
+    StreamTcpCreateTestPacket(payload, 0x30, 1, 4); /*0*/
+    p->tcph->th_seq = htonl(11);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 20;
-    StreamTcpCreateTestPacket(payload, 0x41, 20, 20); /*AA*/
     p->payload = payload;
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
-        goto end;
-
-    if (StreamTcpCheckStreamContents(check_contents, 35, &stream) != 0) {
-        ret = 1;
-    } else {
-        printf("failed in stream matching: ");
+    p->payload_len = 1;
+    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+        SCFree(p);
+        return 0;
     }
 
+    StreamTcpReassembleFreeThreadCtx(ra_ctx);
 
-end:
-    StreamTcpFreeConfig(TRUE);
     SCFree(p);
-    return ret;
+    return 1;
 }
+#endif
 
-static int StreamTcpReassembleTest33(void)
+/** \brief  The Function to create the packet with given payload, which is used
+ *          to test the reassembly of the engine.
+ *
+ *  \param  payload     The variable used to store the payload contents of the
+ *                      current packet.
+ *  \param  value       The value which current payload will have for this packet
+ *  \param  payload_len The length of the filed payload for current packet.
+ *  \param  len         Length of the payload array
+ */
+
+void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
+                               uint8_t payload_len, uint8_t len)
 {
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
+    uint8_t i;
+    for (i = 0; i < payload_len; i++)
+        payload[i] = value;
+    for (; i < len; i++)
+        payload = NULL;
+}
+
+/** \brief  The Function Checks the reassembled stream contents against predefined
+ *          stream contents according to OS policy used.
+ *
+ *  \param  stream_policy   Predefined value of stream for different OS policies
+ *  \param  stream          Reassembled stream returned from the reassembly functions
+ */
+
+int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
+{
+    if (StreamingBufferCompareRawData(stream->sb, stream_policy,(uint32_t)sp_size) == 0)
+    {
+        //PrintRawDataFp(stdout, stream_policy, sp_size);
         return 0;
-    Flow f;
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    TcpStream stream;
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-    uint8_t packet[1460] = "";
+    }
+    return 1;
+}
 
-    StreamTcpInitConfig(TRUE);
+static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
+{
+    if (StreamingBufferCompareRawData(stream->sb,
+                data, data_len) == 0)
+    {
+        SCReturnInt(0);
+    }
+    SCLogInfo("OK");
+    PrintRawDataFp(stdout, data, data_len);
+    return 1;
+}
 
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
+#define MISSED_START(isn)                       \
+    TcpReassemblyThreadCtx *ra_ctx = NULL;      \
+    TcpSession ssn;                             \
+    ThreadVars tv;                              \
+    memset(&tv, 0, sizeof(tv));                 \
+                                                \
+    StreamTcpUTInit(&ra_ctx);                   \
+                                                \
+    StreamTcpUTSetupSession(&ssn);              \
+    StreamTcpUTSetupStream(&ssn.server, (isn)); \
+    StreamTcpUTSetupStream(&ssn.client, (isn)); \
+                                                \
+    TcpStream *stream = &ssn.client;
+
+#define MISSED_END                             \
+    PASS
+
+#define MISSED_STEP(seq, seg, seglen, buf, buflen) \
+    StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));    \
+    FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
 
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
-    p->payload = packet;
+/**
+ *  \test   Test the handling of packets missed by both IDS and the end host.
+ *          The packet is missed in the starting of the stream.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
 
-    p->tcph->th_seq = htonl(10);
-    p->tcph->th_ack = htonl(31);
-    p->payload_len = 10;
+static int StreamTcpReassembleTest25 (void)
+{
+    MISSED_START(6);
+    MISSED_STEP(10, "BB", 2, "\0\0\0BB", 5);
+    MISSED_STEP(12, "CC", 2, "\0\0\0BBCC", 7);
+    MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
+    MISSED_END;
+}
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
+/**
+ *  \test   Test the handling of packets missed by both IDS and the end host.
+ *          The packet is missed in the middle of the stream.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
 
-    p->tcph->th_seq = htonl(20);
-    p->tcph->th_ack = htonl(31);
-    p->payload_len = 10;
+static int StreamTcpReassembleTest26 (void)
+{
+    MISSED_START(9);
+    MISSED_STEP(10, "AAA", 3, "AAA", 3);
+    MISSED_STEP(15, "CC", 2, "AAA\0\0CC", 7);
+    MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
+    MISSED_END;
+}
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
+/**
+ *  \test   Test the handling of packets missed by both IDS and the end host.
+ *          The packet is missed in the end of the stream.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
 
-    p->tcph->th_seq = htonl(40);
-    p->tcph->th_ack = htonl(31);
-    p->payload_len = 10;
+static int StreamTcpReassembleTest27 (void)
+{
+    MISSED_START(9);
+    MISSED_STEP(10, "AAA", 3, "AAA", 3);
+    MISSED_STEP(13, "BB", 2, "AAABB", 5);
+    MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
+    MISSED_END;
+}
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
+/**
+ *  \test   Test the handling of packets missed by IDS, but the end host has
+ *          received it and send the acknowledgment of it. The packet is missed
+ *          in the starting of the stream.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
 
-    p->tcph->th_seq = htonl(5);
-    p->tcph->th_ack = htonl(31);
-    p->payload_len = 30;
+static int StreamTcpReassembleTest28 (void)
+{
+    MISSED_START(6);
+    MISSED_STEP(10, "AAA", 3, "\0\0\0AAA", 6);
+    MISSED_STEP(13, "BB", 2, "\0\0\0AAABB", 8);
+    ssn.state = TCP_TIME_WAIT;
+    MISSED_STEP(15, "CC", 2, "\0\0\0AAABBCC", 10);
+    MISSED_END;
+}
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
-        SCFree(p);
-        return 0;
-    }
+/**
+ *  \test   Test the handling of packets missed by IDS, but the end host has
+ *          received it and send the acknowledgment of it. The packet is missed
+ *          in the middle of the stream.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
 
-    StreamTcpFreeConfig(TRUE);
-    SCFree(p);
-    return 1;
+static int StreamTcpReassembleTest29 (void)
+{
+    MISSED_START(9);
+    MISSED_STEP(10, "AAA", 3, "AAA", 3);
+    ssn.state = TCP_TIME_WAIT;
+    MISSED_STEP(15, "CC", 2, "AAA\0\0CC", 7);
+    MISSED_END;
 }
 
-static int StreamTcpReassembleTest34(void)
+static int StreamTcpReassembleTest33(void)
 {
     TcpSession ssn;
     Packet *p = PacketGetFromAlloc();
@@ -5838,36 +2177,36 @@ static int StreamTcpReassembleTest34(void)
     p->flowflags = FLOW_PKT_TOSERVER;
     p->payload = packet;
 
-    p->tcph->th_seq = htonl(857961230);
+    p->tcph->th_seq = htonl(10);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 304;
+    p->payload_len = 10;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
         return 0;
     }
 
-    p->tcph->th_seq = htonl(857961534);
+    p->tcph->th_seq = htonl(20);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 1460;
+    p->payload_len = 10;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
         return 0;
     }
 
-    p->tcph->th_seq = htonl(857963582);
+    p->tcph->th_seq = htonl(40);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 1460;
+    p->payload_len = 10;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
         return 0;
     }
 
-    p->tcph->th_seq = htonl(857960946);
+    p->tcph->th_seq = htonl(5);
     p->tcph->th_ack = htonl(31);
-    p->payload_len = 1460;
+    p->payload_len = 30;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
@@ -5879,8 +2218,7 @@ static int StreamTcpReassembleTest34(void)
     return 1;
 }
 
-/** \test Test the bug 56 condition */
-static int StreamTcpReassembleTest35(void)
+static int StreamTcpReassembleTest34(void)
 {
     TcpSession ssn;
     Packet *p = PacketGetFromAlloc();
@@ -5897,8 +2235,8 @@ static int StreamTcpReassembleTest35(void)
     StreamTcpInitConfig(TRUE);
 
     /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10);
+    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
+    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
 
     PacketQueue pq;
     memset(&pq,0,sizeof(PacketQueue));
@@ -5919,92 +2257,38 @@ static int StreamTcpReassembleTest35(void)
     p->tcph = &tcph;
     p->flowflags = FLOW_PKT_TOSERVER;
     p->payload = packet;
+    SET_ISN(&stream, 857961230);
 
-    p->tcph->th_seq = htonl(2257022155UL);
-    p->tcph->th_ack = htonl(1374943142);
-    p->payload_len = 142;
-    stream.last_ack = 2257022285UL;
-    stream.ra_raw_base_seq = 2257022172UL;
-    stream.ra_app_base_seq = 2257022172UL;
+    p->tcph->th_seq = htonl(857961230);
+    p->tcph->th_ack = htonl(31);
+    p->payload_len = 304;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
         return 0;
     }
 
-    p->tcph->th_seq = htonl(2257022285UL);
-    p->tcph->th_ack = htonl(1374943142);
-    p->payload_len = 34;
-    stream.last_ack = 2257022285UL;
-    stream.ra_raw_base_seq = 2257022172UL;
+    p->tcph->th_seq = htonl(857961534);
+    p->tcph->th_ack = htonl(31);
+    p->payload_len = 1460;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
         return 0;
     }
 
-    StreamTcpFreeConfig(TRUE);
-    SCFree(p);
-    return 1;
-}
-
-/** \test Test the bug 57 condition */
-static int StreamTcpReassembleTest36(void)
-{
-    TcpSession ssn;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow f;
-    TCPHdr tcph;
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-    TcpStream stream;
-    memset(&stream, 0, sizeof (TcpStream));
-    stream.os_policy = OS_POLICY_BSD;
-    uint8_t packet[1460] = "";
-
-    StreamTcpInitConfig(TRUE);
-
-    /* prevent L7 from kicking in */
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10);
-    StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10);
-
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-    memset(&ssn, 0, sizeof (TcpSession));
-    memset(&f, 0, sizeof (Flow));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-    FLOW_INITIALIZE(&f);
-    f.protoctx = &ssn;
-    f.proto = IPPROTO_TCP;
-    p->src.family = AF_INET;
-    p->dst.family = AF_INET;
-    p->proto = IPPROTO_TCP;
-    p->flow = &f;
-    tcph.th_win = 5480;
-    tcph.th_flags = TH_PUSH | TH_ACK;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOSERVER;
-    p->payload = packet;
-
-    p->tcph->th_seq = htonl(1549588966);
-    p->tcph->th_ack = htonl(4162241372UL);
-    p->payload_len = 204;
-    stream.last_ack = 1549589007;
-    stream.ra_raw_base_seq = 1549589101;
+    p->tcph->th_seq = htonl(857963582);
+    p->tcph->th_ack = htonl(31);
+    p->payload_len = 1460;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
         return 0;
     }
 
-    p->tcph->th_seq = htonl(1549589007);
-    p->tcph->th_ack = htonl(4162241372UL);
-    p->payload_len = 23;
-    stream.last_ack = 1549589007;
-    stream.ra_raw_base_seq = 1549589101;
+    p->tcph->th_seq = htonl(857960946);
+    p->tcph->th_ack = htonl(31);
+    p->payload_len = 1460;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
@@ -6063,8 +2347,7 @@ static int StreamTcpReassembleTest37(void)
     p->tcph->th_ack = htonl(1729548549UL);
     p->payload_len = 1391;
     stream.last_ack = 3061091137UL;
-    stream.ra_raw_base_seq = 3061091309UL;
-    stream.ra_app_base_seq = 3061091309UL;
+    SET_ISN(&stream, 3061091309UL);
 
     /* pre base_seq, so should be rejected */
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) != -1) {
@@ -6076,8 +2359,6 @@ static int StreamTcpReassembleTest37(void)
     p->tcph->th_ack = htonl(1729548549UL);
     p->payload_len = 1391;
     stream.last_ack = 3061091137UL;
-    stream.ra_raw_base_seq = 3061091309UL;
-    stream.ra_app_base_seq = 3061091309UL;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
@@ -6088,8 +2369,6 @@ static int StreamTcpReassembleTest37(void)
     p->tcph->th_ack = htonl(1729548549UL);
     p->payload_len = 1391;
     stream.last_ack = 3061091137UL;
-    stream.ra_raw_base_seq = 3061091309UL;
-    stream.ra_app_base_seq = 3061091309UL;
 
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
         SCFree(p);
@@ -6106,14 +2385,6 @@ static int StreamTcpReassembleTest37(void)
  *          until the app layer protocol has been detected and one smsg from
  *          toserver side has been sent to app layer.
  *
- * Unittest modified by commit -
- *
- * commit bab1636377bb4f1b7b889f4e3fd594795085eaa4
- * Author: Anoop Saldanha <anoopsaldanha@gmail.com>
- * Date:   Fri Feb 15 18:58:33 2013 +0530
- *
- *     Improved app protocol detection.
- *
  *  \retval On success it returns 1 and on failure 0.
  */
 static int StreamTcpReassembleTest38 (void)
@@ -6155,11 +2426,9 @@ static int StreamTcpReassembleTest38 (void)
     sp = 200;
     dp = 220;
 
-    ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
-    ssn.server.isn = 9;
+    SET_ISN(&ssn.server, 9);
     ssn.server.last_ack = 60;
-    ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
-    ssn.client.isn = 9;
+    SET_ISN(&ssn.client, 9);
     ssn.client.last_ack = 9;
     f.alproto = ALPROTO_UNKNOWN;
 
@@ -6482,6 +2751,7 @@ static int StreamTcpReassembleTest39 (void)
     p->flowflags = FLOW_PKT_TOCLIENT;
     p->payload_len = sizeof(response);
     p->payload = response;
+
     if (StreamTcpPacket(&tv, p, stt, &pq) == -1)
         goto end;
     if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
@@ -6742,22 +3012,34 @@ static int StreamTcpReassembleTest39 (void)
     p->payload = NULL;
     if (StreamTcpPacket(&tv, p, stt, &pq) == -1)
         goto end;
+
+    SCLogDebug("StreamTcpIsSetStreamFlagAppProtoDetectionCompleted %s, "
+            "StreamTcpIsSetStreamFlagAppProtoDetectionCompleted %s, "
+            "f.alproto %u f.alproto_ts %u f.alproto_tc %u",
+            StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ? "true" : "false",
+            StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ? "true" : "false",
+            f.alproto, f.alproto_ts, f.alproto_tc);
+
     if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
         !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
         f.alproto != ALPROTO_HTTP ||
         f.alproto_ts != ALPROTO_HTTP ||
-        f.alproto_tc != ALPROTO_HTTP ||
-        ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
-        !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
-        !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
-        ssn->client.seg_list != NULL ||
-        ssn->server.seg_list == NULL ||
-        ssn->server.seg_list->next != NULL ||
-        ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
+        f.alproto_tc != ALPROTO_HTTP)// ||
+        //ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)// ||
+        //!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
+        //!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
+        //ssn->client.seg_list != NULL ||
+        //ssn->server.seg_list == NULL ||
+        //ssn->server.seg_list->next != NULL ||
+        //ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER)
+    {
         printf("failure 15\n");
         goto end;
     }
 
+    StreamTcpPruneSession(&f, STREAM_TOSERVER);
+    StreamTcpPruneSession(&f, STREAM_TOCLIENT);
+
     /* request acking a response */
     p->tcph->th_ack = htonl(328);
     p->tcph->th_seq = htonl(175);
@@ -6767,18 +3049,20 @@ static int StreamTcpReassembleTest39 (void)
     p->payload = NULL;
     if (StreamTcpPacket(&tv, p, stt, &pq) == -1)
         goto end;
-    if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
-        !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
-        f.alproto != ALPROTO_HTTP ||
-        f.alproto_ts != ALPROTO_HTTP ||
-        f.alproto_tc != ALPROTO_HTTP ||
-        ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
+    if (//!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
+        //!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
+        //f.alproto != ALPROTO_HTTP ||
+        //f.alproto_ts != ALPROTO_HTTP ||
+        //f.alproto_tc != ALPROTO_HTTP ||
+        //ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
         !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
         !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
         ssn->client.seg_list != NULL ||
         ssn->server.seg_list != NULL ||
-        ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
-        printf("failure 15\n");
+        ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
+        ) {
+        printf("failure 16\n");
+        abort();
         goto end;
     }
 
@@ -6833,12 +3117,10 @@ static int StreamTcpReassembleTest40 (void)
     uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
     uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
 
-    ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
-    ssn.server.isn = 9;
+    SET_ISN(&ssn.server, 9);
     ssn.server.last_ack = 10;
-    ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
+    SET_ISN(&ssn.client, 9);
     ssn.client.isn = 9;
-    ssn.client.last_ack = 10;
 
     f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
     if (f == NULL)
@@ -6915,7 +3197,8 @@ static int StreamTcpReassembleTest40 (void)
 
     /* check is have the segment in the list and flagged or not */
     if (ssn.client.seg_list == NULL ||
-        (ssn.client.seg_list->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
+        SEGMENT_BEFORE_OFFSET(&ssn.client, ssn.client.seg_list, ssn.client.app_progress))
+//        (ssn.client.seg_list->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
     {
         printf("the list is NULL or the processed segment has not been flaged (7): ");
         goto end;
@@ -7038,10 +3321,10 @@ static int StreamTcpReassembleTest43 (void)
                          "aG9uZT\r\n\r\n";
     uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
 
-    ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
+    ssn.server.base_seq= 10;
     ssn.server.isn = 9;
     ssn.server.last_ack = 600;
-    ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
+    ssn.client.base_seq = 10;
     ssn.client.isn = 9;
     ssn.client.last_ack = 600;
 
@@ -7139,316 +3422,161 @@ static int StreamTcpReassembleTest43 (void)
         goto end;
     }
 
-    p->flowflags = FLOW_PKT_TOCLIENT;
-    p->payload = httpbuf2;
-    p->payload_len = httplen2;
-    tcph.th_seq = htonl(100);
-    tcph.th_ack = htonl(53);
-    s = &ssn.server;
-
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toserver packet (11): ");
-        goto end;
-    }
-    /* the flag should be set, as the smsg scanned size has crossed the max.
-       signature size for app proto detection */
-    if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn.client)) {
-        printf("app layer detected flag is not set, it should be (14): ");
-        goto end;
-    }
-
-    ret = 1;
-end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    SCFree(p);
-    FLOWLOCK_UNLOCK(f);
-    UTHFreeFlow(f);
-    return ret;
-}
-
-/** \test   Test the memcap incrementing/decrementing and memcap check */
-static int StreamTcpReassembleTest44(void)
-{
-    uint8_t ret = 0;
-    StreamTcpInitConfig(TRUE);
-    uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
-
-    StreamTcpReassembleIncrMemuse(500);
-    if (SC_ATOMIC_GET(ra_memuse) != (memuse+500)) {
-        printf("failed in incrementing the memory");
-        goto end;
-    }
-
-    StreamTcpReassembleDecrMemuse(500);
-    if (SC_ATOMIC_GET(ra_memuse) != memuse) {
-        printf("failed in decrementing the memory");
-        goto end;
-    }
-
-    if (StreamTcpReassembleCheckMemcap(500) != 1) {
-        printf("failed in validating the memcap");
-        goto end;
-    }
-
-    if (StreamTcpReassembleCheckMemcap((memuse + stream_config.reassembly_memcap)) != 0) {
-        printf("failed in validating the memcap");
-        goto end;
-    }
-
-    StreamTcpFreeConfig(TRUE);
-
-    if (SC_ATOMIC_GET(ra_memuse) != 0) {
-        printf("failed in clearing the memory");
-        goto end;
-    }
-
-    ret = 1;
-    return ret;
-end:
-    StreamTcpFreeConfig(TRUE);
-    return ret;
-}
-
-/**
- *  \test   Test to make sure that reassembly_depth is enforced.
- *
- *  \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest45 (void)
-{
-    int ret = 0;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow *f = NULL;
-    TCPHdr tcph;
-    TcpSession ssn;
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    memset(&ssn, 0, sizeof(TcpSession));
-    ThreadVars tv;
-    memset(&tv, 0, sizeof (ThreadVars));
-
-    uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0";
-
-    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
-
-    StreamTcpInitConfig(TRUE);
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, 9);
-    ssn.server.isn = 9;
-    ssn.server.last_ack = 60;
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9);
-    ssn.client.isn = 9;
-    ssn.client.last_ack = 9;
-
-    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
-    if (f == NULL)
-        goto end;
-    f->protoctx = &ssn;
-    f->proto = IPPROTO_TCP;
-    p->flow = f;
-
-    tcph.th_win = htons(5480);
-    tcph.th_seq = htonl(10);
-    tcph.th_ack = htonl(20);
-    tcph.th_flags = TH_ACK|TH_PUSH;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOCLIENT;
-
-    p->payload = httpbuf1;
-    p->payload_len = httplen1;
-    ssn.state = TCP_ESTABLISHED;
-
-    /* set the default value of reassembly depth, as there is no config file */
-    ssn.reassembly_depth = httplen1 + 1;
-
-    TcpStream *s = NULL;
+    p->flowflags = FLOW_PKT_TOCLIENT;
+    p->payload = httpbuf2;
+    p->payload_len = httplen2;
+    tcph.th_seq = htonl(100);
+    tcph.th_ack = htonl(53);
     s = &ssn.server;
 
-    FLOWLOCK_WRLOCK(f);
     if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toclient packet: ");
+        printf("failed in segments reassembly, while processing toserver packet (11): ");
         goto end;
     }
-
-    /* Check if we have flags set or not */
-    if (s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
-        printf("there shouldn't be a noreassembly flag be set: ");
+    /* the flag should be set, as the smsg scanned size has crossed the max.
+       signature size for app proto detection */
+    if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn.client)) {
+        printf("app layer detected flag is not set, it should be (14): ");
         goto end;
     }
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, ssn.server.isn + httplen1);
 
-    p->flowflags = FLOW_PKT_TOSERVER;
-    p->payload_len = httplen1;
-    s = &ssn.client;
+    ret = 1;
+end:
+    StreamTcpReassembleFreeThreadCtx(ra_ctx);
+    StreamTcpFreeConfig(TRUE);
+    SCFree(p);
+    SCMutexUnlock(&f->m);
+    UTHFreeFlow(f);
+    return ret;
+}
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toserver packet: ");
+/** \test   Test the memcap incrementing/decrementing and memcap check */
+static int StreamTcpReassembleTest44(void)
+{
+    uint8_t ret = 0;
+    StreamTcpInitConfig(TRUE);
+    uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
+
+    StreamTcpReassembleIncrMemuse(500);
+    if (SC_ATOMIC_GET(ra_memuse) != (memuse+500)) {
+        printf("failed in incrementing the memory");
         goto end;
     }
 
-    /* Check if we have flags set or not */
-    if (s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
-        printf("there shouldn't be a noreassembly flag be set: ");
+    StreamTcpReassembleDecrMemuse(500);
+    if (SC_ATOMIC_GET(ra_memuse) != memuse) {
+        printf("failed in decrementing the memory");
         goto end;
     }
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, ssn.client.isn + httplen1);
 
-    p->flowflags = FLOW_PKT_TOCLIENT;
-    p->payload_len = httplen1;
-    s = &ssn.server;
+    if (StreamTcpReassembleCheckMemcap(500) != 1) {
+        printf("failed in validating the memcap");
+        goto end;
+    }
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toserver packet: ");
+    if (StreamTcpReassembleCheckMemcap((memuse + stream_config.reassembly_memcap)) != 0) {
+        printf("failed in validating the memcap");
         goto end;
     }
 
-    /* Check if we have flags set or not */
-    if (!(s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
-        printf("the noreassembly flags should be set, "
-                "p.payload_len %"PRIu16" stream_config.reassembly_"
-                "depth %"PRIu32": ", p->payload_len,
-                stream_config.reassembly_depth);
+    StreamTcpFreeConfig(TRUE);
+
+    if (SC_ATOMIC_GET(ra_memuse) != 0) {
+        printf("failed in clearing the memory");
         goto end;
     }
 
     ret = 1;
+    return ret;
 end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
     StreamTcpFreeConfig(TRUE);
-    SCFree(p);
-    FLOWLOCK_UNLOCK(f);
-    UTHFreeFlow(f);
     return ret;
 }
 
 /**
- *  \test   Test the undefined config value of reassembly depth.
- *          the default value of 0 will be loaded and stream will be reassembled
- *          until the session ended
+ *  \test   Test to make sure that reassembly_depth is enforced.
  *
  *  \retval On success it returns 1 and on failure 0.
  */
 
-static int StreamTcpReassembleTest46 (void)
+static int StreamTcpReassembleTest45 (void)
 {
-    int ret = 0;
-    Packet *p = PacketGetFromAlloc();
-    if (unlikely(p == NULL))
-        return 0;
-    Flow *f = NULL;
-    TCPHdr tcph;
+    TcpReassemblyThreadCtx *ra_ctx = NULL;
     TcpSession ssn;
     ThreadVars tv;
-    PacketQueue pq;
-    memset(&pq,0,sizeof(PacketQueue));
-    memset(&tcph, 0, sizeof (TCPHdr));
-    memset(&ssn, 0, sizeof(TcpSession));
-    memset(&tv, 0, sizeof (ThreadVars));
-
-    uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0";
-    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
-
-    StreamTcpInitConfig(TRUE);
-    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
+    memset(&tv, 0, sizeof(tv));
+    uint8_t payload[100] = {0};
+    uint16_t payload_size = 100;
 
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, 9);
-    ssn.server.isn = 9;
-    ssn.server.last_ack = 60;
-    ssn.server.next_seq = ssn.server.isn;
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9);
-    ssn.client.isn = 9;
-    ssn.client.last_ack = 9;
-    ssn.client.next_seq = ssn.client.isn;
+    StreamTcpUTInit(&ra_ctx);
+    stream_config.reassembly_depth = 100;
 
-    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
-    if (f == NULL)
-        goto end;
-    f->protoctx = &ssn;
-    f->proto = IPPROTO_TCP;
-    p->flow = f;
+    StreamTcpUTSetupSession(&ssn);
+    ssn.reassembly_depth = 100;
+    StreamTcpUTSetupStream(&ssn.server, 100);
+    StreamTcpUTSetupStream(&ssn.client, 100);
 
-    tcph.th_win = htons(5480);
-    tcph.th_seq = htonl(10);
-    tcph.th_ack = htonl(20);
-    tcph.th_flags = TH_ACK|TH_PUSH;
-    p->tcph = &tcph;
-    p->flowflags = FLOW_PKT_TOCLIENT;
+    int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
+    FAIL_IF(r != 0);
+    FAIL_IF(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY);
 
-    p->payload = httpbuf1;
-    p->payload_len = httplen1;
-    ssn.state = TCP_ESTABLISHED;
+    r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
+    FAIL_IF(r != 0);
+    FAIL_IF(!(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY));
 
-    stream_config.reassembly_depth = 0;
+    StreamTcpUTClearStream(&ssn.server);
+    StreamTcpUTClearStream(&ssn.client);
+    StreamTcpUTClearSession(&ssn);
+    StreamTcpUTDeinit(ra_ctx);
+    PASS;
+}
 
-    TcpStream *s = NULL;
-    s = &ssn.server;
+/**
+ *  \test   Test the unlimited config value of reassembly depth.
+ *
+ *  \retval On success it returns 1 and on failure 0.
+ */
 
-    FLOWLOCK_WRLOCK(f);
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toclient packet\n");
-        goto end;
-    }
+static int StreamTcpReassembleTest46 (void)
+{
+    int result = 0;
+    TcpReassemblyThreadCtx *ra_ctx = NULL;
+    TcpSession ssn;
+    ThreadVars tv;
+    memset(&tv, 0, sizeof(tv));
+    uint8_t payload[100] = {0};
+    uint16_t payload_size = 100;
 
-    /* Check if we have flags set or not */
-    if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
-        (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
-        printf("there shouldn't be any no reassembly flag be set \n");
-        goto end;
-    }
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, ssn.server.isn + httplen1);
+    StreamTcpUTInit(&ra_ctx);
+    stream_config.reassembly_depth = 0;
 
-    p->flowflags = FLOW_PKT_TOSERVER;
-    p->payload_len = httplen1;
-    s = &ssn.client;
+    StreamTcpUTSetupSession(&ssn);
+    StreamTcpUTSetupStream(&ssn.server, 100);
+    StreamTcpUTSetupStream(&ssn.client, 100);
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toserver packet\n");
+    int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
+    if (r != 0)
         goto end;
-    }
-
-    /* Check if we have flags set or not */
-    if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
-        (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
-        printf("there shouldn't be any no reassembly flag be set \n");
+    if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+        printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
         goto end;
     }
-    STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, ssn.client.isn + httplen1);
 
-    p->flowflags = FLOW_PKT_TOCLIENT;
-    p->payload_len = httplen1;
-    tcph.th_seq = htonl(10 + httplen1);
-    tcph.th_ack = htonl(20 + httplen1);
-    s = &ssn.server;
-
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
-        printf("failed in segments reassembly, while processing toserver packet\n");
+    r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
+    if (r != 0)
         goto end;
-    }
-
-    /* Check if we have flags set or not */
-    if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
-        (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
-        printf("the no_reassembly flags should not be set, "
-                "p->payload_len %"PRIu16" stream_config.reassembly_"
-                "depth %"PRIu32": ", p->payload_len,
-                stream_config.reassembly_depth);
+    if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+        printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
         goto end;
     }
 
-    ret = 1;
+    result = 1;
 end:
-    StreamTcpReassembleFreeThreadCtx(ra_ctx);
-    StreamTcpFreeConfig(TRUE);
-    SCFree(p);
-    FLOWLOCK_UNLOCK(f);
-    UTHFreeFlow(f);
-    return ret;
+    StreamTcpUTClearStream(&ssn.server);
+    StreamTcpUTClearStream(&ssn.client);
+    StreamTcpUTClearSession(&ssn);
+    StreamTcpUTDeinit(ra_ctx);
+    return result;
 }
 
 /**
@@ -7484,11 +3612,10 @@ static int StreamTcpReassembleTest47 (void)
     uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
     uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
 
-    ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 572799781UL;
-    ssn.server.isn = 572799781UL;
+    SET_ISN(&ssn.server, 572799781UL);
     ssn.server.last_ack = 572799782UL;
-    ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 4294967289UL;
-    ssn.client.isn = 4294967289UL;
+
+    SET_ISN(&ssn.client, 4294967289UL);
     ssn.client.last_ack = 21;
 
     f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
@@ -7593,16 +3720,13 @@ static int StreamTcpReassembleInlineTest01(void)
     }
     ssn.client.next_seq = 17;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
     }
 
-    if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
-        printf("expected a single stream message: ");
-        goto end;
-    }
+    FAIL_IF(UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1);
 
     StreamMsg *smsg = ssn.toserver_smsg_head;
     if (UtTestSmsg(smsg, stream_payload, 15) == 0)
@@ -7663,7 +3787,7 @@ static int StreamTcpReassembleInlineTest02(void)
     }
     ssn.client.next_seq = 17;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -7684,7 +3808,7 @@ static int StreamTcpReassembleInlineTest02(void)
     }
     ssn.client.next_seq = 22;
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed 2: ");
         goto end;
@@ -7758,14 +3882,14 @@ static int StreamTcpReassembleInlineTest03(void)
     }
     ssn.client.next_seq = 17;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
     }
 
     if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
-        printf("expected a single stream message 1: ");
+        printf("expected a single stream message 1, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER));
         goto end;
     }
 
@@ -7781,7 +3905,7 @@ static int StreamTcpReassembleInlineTest03(void)
 
     p->tcph->th_seq = htonl(17);
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed 2: ");
         goto end;
@@ -7855,7 +3979,7 @@ static int StreamTcpReassembleInlineTest04(void)
     }
     ssn.client.next_seq = 17;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -7878,7 +4002,7 @@ static int StreamTcpReassembleInlineTest04(void)
 
     p->tcph->th_seq = htonl(17);
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed 2: ");
         goto end;
@@ -7949,7 +4073,7 @@ static int StreamTcpReassembleInlineTest05(void)
 
     p->tcph->th_seq = htonl(17);
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -8025,7 +4149,7 @@ static int StreamTcpReassembleInlineTest06(void)
 
     p->tcph->th_seq = htonl(17);
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -8052,7 +4176,7 @@ static int StreamTcpReassembleInlineTest06(void)
 
     p->tcph->th_seq = htonl(12);
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -8128,7 +4252,7 @@ static int StreamTcpReassembleInlineTest07(void)
 
     p->tcph->th_seq = htonl(17);
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -8140,12 +4264,16 @@ static int StreamTcpReassembleInlineTest07(void)
     }
 
     StreamMsg *smsg = ssn.toserver_smsg_head;
-    if (UtTestSmsg(smsg, stream_payload1, 6) == 0)
+    if (UtTestSmsg(smsg, stream_payload1, 6) == 0) {
+        printf("stream_payload1 failed: ");
         goto end;
+    }
 
     smsg = ssn.toserver_smsg_head->next;
-    if (UtTestSmsg(smsg, stream_payload2, 5) == 0)
+    if (UtTestSmsg(smsg, stream_payload2, 5) == 0) {
+        printf("stream_payload2 failed: ");
         goto end;
+    }
 
     if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
         printf("failed to add segment 3: ");
@@ -8155,7 +4283,7 @@ static int StreamTcpReassembleInlineTest07(void)
 
     p->tcph->th_seq = htonl(12);
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -8167,8 +4295,10 @@ static int StreamTcpReassembleInlineTest07(void)
     }
 
     smsg = ssn.toserver_smsg_head->next->next;
-    if (UtTestSmsg(smsg, stream_payload3, 16) == 0)
+    if (UtTestSmsg(smsg, stream_payload3, 16) == 0) {
+        printf("stream_payload3 failed: ");
         goto end;
+    }
 
     ret = 1;
 end:
@@ -8187,14 +4317,11 @@ end:
  */
 static int StreamTcpReassembleInlineTest08(void)
 {
-    int ret = 0;
     TcpReassemblyThreadCtx *ra_ctx = NULL;
     ThreadVars tv;
+    memset(&tv, 0x00, sizeof(tv));
     TcpSession ssn;
     Flow f;
-
-    memset(&tv, 0x00, sizeof(tv));
-
     StreamTcpUTInit(&ra_ctx);
     StreamTcpUTInitInline();
     StreamTcpUTSetupSession(&ssn);
@@ -8203,95 +4330,57 @@ static int StreamTcpReassembleInlineTest08(void)
 
     stream_config.reassembly_toserver_chunk_size = 15;
     ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP;
+    f.protoctx = &ssn;
 
     uint8_t stream_payload1[] = "AAAAABBBBBCCCCC";
     uint8_t stream_payload2[] = "BBBBBCCCCCDDDDD";
     uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
     Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
-    if (p == NULL) {
-        printf("couldn't get a packet: ");
-        goto end;
-    }
+    FAIL_IF(p == NULL);
     p->tcph->th_seq = htonl(12);
     p->flow = &f;
     p->flowflags |= FLOW_PKT_TOSERVER;
 
-    FLOWLOCK_WRLOCK(&f);
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
-        printf("failed to add segment 1: ");
-        goto end;
-    }
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
-        printf("failed to add segment 2: ");
-        goto end;
-    }
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
-        printf("failed to add segment 3: ");
-        goto end;
-    }
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
     ssn.client.next_seq = 17;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
-    if (r < 0) {
-        printf("StreamTcpReassembleInlineRaw failed: ");
-        goto end;
-    }
-
-    if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
-        printf("expected a single stream message: ");
-        goto end;
-    }
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
+    FAIL_IF(r < 0);
 
+    FAIL_IF(UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1);
     StreamMsg *smsg = ssn.toserver_smsg_head;
-    if (UtTestSmsg(smsg, stream_payload1, 15) == 0)
-        goto end;
-
-    if (ssn.client.ra_raw_base_seq != 16) {
-        printf("ra_raw_base_seq %"PRIu32", expected 16: ", ssn.client.ra_raw_base_seq);
-        goto end;
-    }
+    FAIL_IF(UtTestSmsg(smsg, stream_payload1, 15) == 0);
 
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
-        printf("failed to add segment 4: ");
-        goto end;
-    }
+    FAIL_IF(ssn.client.raw_progress != 15);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
     ssn.client.next_seq = 22;
-
     p->tcph->th_seq = htonl(17);
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
-    if (r < 0) {
-        printf("StreamTcpReassembleInlineRaw failed 2: ");
-        goto end;
-    }
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
+    FAIL_IF (r < 0);
 
-    if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) {
-        printf("expected a single stream message, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER));
-        goto end;
-    }
+    FAIL_IF(UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2);
 
     smsg = ssn.toserver_smsg_head->next;
-    if (UtTestSmsg(smsg, stream_payload2, 15) == 0)
-        goto end;
+    FAIL_IF(UtTestSmsg(smsg, stream_payload2, 15) == 0);
 
-    if (ssn.client.ra_raw_base_seq != 21) {
-        printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
-        goto end;
-    }
+    FAIL_IF(ssn.client.raw_progress != 20);
 
-    if (ssn.client.seg_list->seq != 7) {
-        printf("expected segment 2 (seq 7) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq);
-        goto end;
-    }
+    smsg = ssn.toserver_smsg_head;
+    StreamMsgReturnToPool(smsg);
+    ssn.toserver_smsg_head = ssn.toserver_smsg_head->next;
+
+    StreamTcpPruneSession(&f, STREAM_TOSERVER);
+
+    FAIL_IF (ssn.client.seg_list->seq != 2);
 
-    ret = 1;
-end:
-    FLOWLOCK_UNLOCK(&f);
     FLOW_DESTROY(&f);
     UTHFreePacket(p);
     StreamTcpUTClearSession(&ssn);
     StreamTcpUTDeinit(ra_ctx);
-    return ret;
+    PASS;
 }
 
 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
@@ -8345,8 +4434,9 @@ static int StreamTcpReassembleInlineTest09(void)
         goto end;
     }
     ssn.client.next_seq = 12;
+    ssn.client.last_ack = 10;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed: ");
         goto end;
@@ -8365,12 +4455,12 @@ static int StreamTcpReassembleInlineTest09(void)
     if (UtTestSmsg(smsg, stream_payload2, 5) == 0)
         goto end;
 
-    if (ssn.client.ra_raw_base_seq != 11) {
-        printf("ra_raw_base_seq %"PRIu32", expected 11: ", ssn.client.ra_raw_base_seq);
+    if (ssn.client.raw_progress != 10) {
+        printf("raw_progress %"PRIu64", expected 10: ", ssn.client.raw_progress);
         goto end;
     }
 
-    /* close the GAP and see if we properly reassemble and update ra_base_seq */
+    /* close the GAP and see if we properly reassemble and update base_seq */
     if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
         printf("failed to add segment 4: ");
         goto end;
@@ -8379,7 +4469,7 @@ static int StreamTcpReassembleInlineTest09(void)
 
     p->tcph->th_seq = htonl(12);
 
-    r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+    r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
     if (r < 0) {
         printf("StreamTcpReassembleInlineRaw failed 2: ");
         goto end;
@@ -8394,8 +4484,8 @@ static int StreamTcpReassembleInlineTest09(void)
     if (UtTestSmsg(smsg, stream_payload3, 20) == 0)
         goto end;
 
-    if (ssn.client.ra_raw_base_seq != 21) {
-        printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
+    if (ssn.client.raw_progress != 20) {
+        printf("raw_progress %"PRIu64", expected 20: ", ssn.client.raw_progress);
         goto end;
     }
 
@@ -8468,8 +4558,8 @@ static int StreamTcpReassembleInlineTest10(void)
     }
 
     /* ssn.server.ra_app_base_seq should be isn here. */
-    if (ssn.server.ra_app_base_seq != 1 || ssn.server.ra_app_base_seq != ssn.server.isn) {
-        printf("expected ra_app_base_seq 1, got %u: ", ssn.server.ra_app_base_seq);
+    if (ssn.server.base_seq != 2 || ssn.server.base_seq != ssn.server.isn+1) {
+        printf("expected ra_app_base_seq 1, got %u: ", ssn.server.base_seq);
         goto end;
     }
 
@@ -8489,8 +4579,9 @@ static int StreamTcpReassembleInlineTest10(void)
         goto end;
     }
 
-    if (ssn.server.ra_app_base_seq != 18) {
-        printf("expected ra_app_base_seq 18, got %u: ", ssn.server.ra_app_base_seq);
+    if (ssn.server.app_progress != 17) {
+        printf("expected ssn.server.app_progress == 17got %"PRIu64": ",
+                ssn.server.app_progress);
         goto end;
     }
 
@@ -8508,7 +4599,6 @@ end:
  */
 static int StreamTcpReassembleInsertTest01(void)
 {
-    int ret = 0;
     TcpReassemblyThreadCtx *ra_ctx = NULL;
     ThreadVars tv;
     TcpSession ssn;
@@ -8519,68 +4609,35 @@ static int StreamTcpReassembleInsertTest01(void)
     StreamTcpUTInit(&ra_ctx);
     StreamTcpUTSetupSession(&ssn);
     StreamTcpUTSetupStream(&ssn.client, 1);
+    ssn.client.os_policy = OS_POLICY_LAST;
     FLOW_INITIALIZE(&f);
 
     uint8_t stream_payload1[] = "AAAAABBBBBCCCCCDDDDD";
     uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
     Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
-    if (p == NULL) {
-        printf("couldn't get a packet: ");
-        goto end;
-    }
+    FAIL_IF(p == NULL);
     p->tcph->th_seq = htonl(12);
     p->flow = &f;
 
-    FLOWLOCK_WRLOCK(&f);
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
-        printf("failed to add segment 1: ");
-        goto end;
-    }
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
-        printf("failed to add segment 2: ");
-        goto end;
-    }
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1) {
-        printf("failed to add segment 3: ");
-        goto end;
-    }
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1) {
-        printf("failed to add segment 4: ");
-        goto end;
-    }
-    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
-        printf("failed to add segment 5: ");
-        goto end;
-    }
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
+    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
     ssn.client.next_seq = 21;
 
-    int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
-    if (r < 0) {
-        printf("StreamTcpReassembleInlineRaw failed: ");
-        goto end;
-    }
-
-    if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
-        printf("expected a single stream message: ");
-        goto end;
-    }
-
+    int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
+    FAIL_IF (r < 0);
+    FAIL_IF (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1);
     StreamMsg *smsg = ssn.toserver_smsg_head;
-    if (UtTestSmsg(smsg, stream_payload1, 20) == 0)
-        goto end;
+    FAIL_IF(UtTestSmsg(smsg, stream_payload1, 20) == 0);
+    FAIL_IF(ssn.client.raw_progress != 20);
 
-    if (ssn.client.ra_raw_base_seq != 21) {
-        printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
-        goto end;
-    }
-    ret = 1;
-end:
-    FLOWLOCK_UNLOCK(&f);
     FLOW_DESTROY(&f);
     UTHFreePacket(p);
     StreamTcpUTClearSession(&ssn);
     StreamTcpUTDeinit(ra_ctx);
-    return ret;
+    PASS;
 }
 
 /** \test test insert with overlaps
@@ -8678,54 +4735,6 @@ end:
 void StreamTcpReassembleRegisterTests(void)
 {
 #ifdef UNITTESTS
-    UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test",
-                   StreamTcpReassembleTest01);
-    UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test",
-                   StreamTcpReassembleTest02);
-    UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test",
-                   StreamTcpReassembleTest03);
-    UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test",
-                   StreamTcpReassembleTest04);
-    UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test",
-                   StreamTcpReassembleTest05);
-    UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test",
-                   StreamTcpReassembleTest06);
-    UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test",
-                   StreamTcpReassembleTest07);
-    UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test",
-                   StreamTcpReassembleTest08);
-    UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test",
-                   StreamTcpReassembleTest09);
-    UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test",
-                   StreamTcpReassembleTest10);
-    UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test",
-                   StreamTcpReassembleTest11);
-    UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test",
-                   StreamTcpReassembleTest12);
-    UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test",
-                   StreamTcpReassembleTest13);
-    UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test",
-                   StreamTcpReassembleTest14);
-    UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test",
-                   StreamTcpReassembleTest15);
-    UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test",
-                   StreamTcpReassembleTest16);
-    UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test",
-                   StreamTcpReassembleTest17);
-    UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test",
-                   StreamTcpReassembleTest18);
-    UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test",
-                   StreamTcpReassembleTest19);
-    UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test",
-                   StreamTcpReassembleTest20);
-    UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test",
-                   StreamTcpReassembleTest21);
-    UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test",
-                   StreamTcpReassembleTest22);
-    UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test",
-                   StreamTcpReassembleTest23);
-    UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test",
-                   StreamTcpReassembleTest24);
     UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
                    StreamTcpReassembleTest25);
     UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
@@ -8736,20 +4745,10 @@ void StreamTcpReassembleRegisterTests(void)
                    StreamTcpReassembleTest28);
     UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
                    StreamTcpReassembleTest29);
-    UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test",
-                   StreamTcpReassembleTest30);
-    UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test",
-                   StreamTcpReassembleTest31);
-    UtRegisterTest("StreamTcpReassembleTest32 -- Bug test",
-                   StreamTcpReassembleTest32);
     UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
                    StreamTcpReassembleTest33);
     UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
                    StreamTcpReassembleTest34);
-    UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test",
-                   StreamTcpReassembleTest35);
-    UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test",
-                   StreamTcpReassembleTest36);
     UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test",
                    StreamTcpReassembleTest37);
     UtRegisterTest("StreamTcpReassembleTest38 -- app proto test",
@@ -8800,5 +4799,6 @@ void StreamTcpReassembleRegisterTests(void)
 
     StreamTcpInlineRegisterTests();
     StreamTcpUtilRegisterTests();
+    StreamTcpListRegisterTests();
 #endif /* UNITTESTS */
 }
index 0dcea133bfbfea9993a5adfe21c28b5f192d5a37..b0026484a5c4007c8286253b1eee7f9d077181f2 100644 (file)
@@ -90,7 +90,7 @@ int StreamTcpCheckStreamContents(uint8_t *, uint16_t , TcpStream *);
 
 int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
         TcpSession *ssn, TcpStream *stream, Packet *p);
-int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, Packet *);
+int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, Packet *, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen);
 TcpSegment* StreamTcpGetSegment(ThreadVars *, TcpReassemblyThreadCtx *, uint16_t);
 
 void StreamTcpReturnStreamSegments(TcpStream *);
index bdd5d7327f84cf5dc2463d0e92f257675782ef1a..a810de519ae6108cb325ac62f4518511a633ed22 100644 (file)
@@ -77,6 +77,7 @@ void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn)
 
     s->isn = isn;
     STREAMTCP_SET_RA_BASE_SEQ(s, isn);
+    s->base_seq = isn+1;
 }
 
 void StreamTcpUTClearStream(TcpStream *s)
@@ -109,16 +110,15 @@ int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
     }
 
     s->seq = seq;
-    s->payload_len = len;
-    memcpy(s->payload, payload, len);
+    TCP_SEG_LEN(s) = len;
 
-    Packet *p = UTHBuildPacketReal(s->payload, s->payload_len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
+    Packet *p = UTHBuildPacketReal(payload, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
     if (p == NULL) {
         return -1;
     }
     p->tcph->th_seq = htonl(seq);
 
-    if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p) < 0)
+    if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0)
         return -1;
 
     UTHFreePacket(p);
@@ -133,16 +133,17 @@ int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx
     }
 
     s->seq = seq;
-    s->payload_len = len;
-    memset(s->payload, byte, len);
+    TCP_SEG_LEN(s) = len;
+    uint8_t buf[len];
+    memset(buf, byte, len);
 
-    Packet *p = UTHBuildPacketReal(s->payload, s->payload_len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
+    Packet *p = UTHBuildPacketReal(buf, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
     if (p == NULL) {
         return -1;
     }
     p->tcph->th_seq = htonl(seq);
 
-    if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p) < 0)
+    if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0)
         return -1;
     UTHFreePacket(p);
     return 0;
index 8067d5ac4c7189c97582224091129fe21b595235..fe05537e33efd948748d8e98393484ec75d89079 100644 (file)
@@ -25,6 +25,7 @@
 #define __STREAM_TCP_UTIL_H__
 
 #include "stream-tcp-private.h"
+#include "stream-tcp-reassemble.h"
 
 void StreamTcpUTInit(TcpReassemblyThreadCtx **);
 void StreamTcpUTDeinit(TcpReassemblyThreadCtx *);
index 022dca19917822b7380600881ad61680eae33c14..466c982ab40aaad43c347d570e320df89ac9d814 100644 (file)
@@ -154,6 +154,8 @@ void StreamTcpStreamCleanup(TcpStream *stream)
     if (stream != NULL) {
         StreamTcpSackFreeList(stream);
         StreamTcpReturnStreamSegments(stream);
+        StreamingBufferFree(stream->sb);
+        stream->sb = NULL;
     }
 }
 
@@ -570,7 +572,8 @@ void StreamTcpInitConfig(char quiet)
     if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
         if (!enable_raw) {
             stream_config.ssn_init_flags = STREAMTCP_FLAG_DISABLE_RAW;
-            stream_config.segment_init_flags = SEGMENTTCP_FLAG_RAW_PROCESSED;
+// TODO how to handle this now?
+//            stream_config.segment_init_flags = SEGMENTTCP_FLAG_RAW_PROCESSED;
         }
     } else {
         enable_raw = 1;
@@ -2262,9 +2265,9 @@ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
     uint32_t ack = seq;
 
     if (stream->seg_list_tail != NULL) {
-        if (SEQ_GT((stream->seg_list_tail->seq + stream->seg_list_tail->payload_len), ack))
+        if (SEQ_GT((stream->seg_list_tail->seq + TCP_SEG_LEN(stream->seg_list_tail)), ack))
         {
-            ack = stream->seg_list_tail->seq + stream->seg_list_tail->payload_len;
+            ack = stream->seg_list_tail->seq + TCP_SEG_LEN(stream->seg_list_tail);
         }
     }
 
@@ -5791,7 +5794,11 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback
     for (; seg != NULL &&
             (stream_inline || SEQ_LT(seg->seq, stream->last_ack));)
     {
-        ret = CallbackFunc(p, data, seg->payload, seg->payload_len);
+        const uint8_t *seg_data;
+        uint32_t seg_datalen;
+        StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
+
+        ret = CallbackFunc(p, data, seg_data, seg_datalen);
         if (ret != 1) {
             SCLogDebug("Callback function has failed");
             return -1;
@@ -5818,6 +5825,10 @@ void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
 
 #ifdef UNITTESTS
 
+#define SET_ISN(stream, setseq)             \
+    (stream)->isn = (setseq);               \
+    (stream)->base_seq = (setseq) + 1
+
 /**
  *  \test   Test the allocation of TCP session for a given packet from the
  *          ssn_pool.
@@ -5878,28 +5889,32 @@ static int StreamTcpTest02 (void)
     Packet *p = SCMalloc(SIZE_OF_PACKET);
     if (unlikely(p == NULL))
         return 0;
+    int ret = 0;
     Flow f;
     ThreadVars tv;
     StreamTcpThread stt;
     uint8_t payload[4];
+    TcpReassemblyThreadCtx *ra_ctx = NULL;;
     TCPHdr tcph;
-    TcpReassemblyThreadCtx ra_ctx;
     PacketQueue pq;
     memset(&pq,0,sizeof(PacketQueue));
-    memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
     memset(p, 0, SIZE_OF_PACKET);
     memset (&f, 0, sizeof(Flow));
     memset(&tv, 0, sizeof (ThreadVars));
     memset(&stt, 0, sizeof (StreamTcpThread));
     memset(&tcph, 0, sizeof (TCPHdr));
+
+    ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
+    if (ra_ctx == NULL) {
+        goto end;
+    }
     FLOW_INITIALIZE(&f);
     p->flow = &f;
     tcph.th_win = htons(5480);
     tcph.th_flags = TH_SYN;
     p->tcph = &tcph;
     p->flowflags = FLOW_PKT_TOSERVER;
-    int ret = 0;
-    stt.ra_ctx = &ra_ctx;
+    stt.ra_ctx = ra_ctx;
 
     StreamTcpInitConfig(TRUE);
 
@@ -8225,12 +8240,10 @@ static int StreamTcpTest23(void)
     TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
     uint8_t packet[1460] = "";
     ThreadVars tv;
-    int result = 1;
     PacketQueue pq;
 
     Packet *p = SCMalloc(SIZE_OF_PACKET);
-    if (unlikely(p == NULL))
-        return 0;
+    FAIL_IF(p == NULL);
 
     memset(&pq,0,sizeof(PacketQueue));
     memset(&ssn, 0, sizeof (TcpSession));
@@ -8257,54 +8270,35 @@ static int StreamTcpTest23(void)
     p->tcph = &tcph;
     p->flowflags = FLOW_PKT_TOSERVER;
     p->payload = packet;
-    ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
+    SET_ISN(&ssn.client, 3184324452UL);
 
     p->tcph->th_seq = htonl(3184324453UL);
     p->tcph->th_ack = htonl(3373419609UL);
     p->payload_len = 2;
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
-        printf("failed in segment reassmebling: ");
-        result &= 0;
-        goto end;
-    }
+    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
 
     p->tcph->th_seq = htonl(3184324455UL);
     p->tcph->th_ack = htonl(3373419621UL);
     p->payload_len = 2;
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
-        printf("failed in segment reassmebling: ");
-        result &= 0;
-        goto end;
-    }
+    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
 
     p->tcph->th_seq = htonl(3184324453UL);
     p->tcph->th_ack = htonl(3373419621UL);
     p->payload_len = 6;
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
-        printf("failed in segment reassmebling: ");
-        result &= 0;
-//        goto end;
-    }
+    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
 
-    if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 4) {
-        printf("failed in segment reassmebling: ");
-        result &= 0;
-    }
+    FAIL_IF(ssn.client.seg_list_tail == NULL);
+    FAIL_IF(TCP_SEG_LEN(ssn.client.seg_list_tail) != 2);
 
-end:
     StreamTcpReturnStreamSegments(&ssn.client);
     StreamTcpFreeConfig(TRUE);
-    if (SC_ATOMIC_GET(st_memuse) == 0) {
-        result &= 1;
-    } else {
-        printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse));
-    }
+    FAIL_IF(SC_ATOMIC_GET(st_memuse) > 0);
     SCFree(p);
     FLOW_DESTROY(&f);
-    return result;
+    PASS;
 }
 
 /** \test   Test the stream mem leaks conditions. */
@@ -8312,14 +8306,12 @@ static int StreamTcpTest24(void)
 {
     TcpSession ssn;
     Packet *p = SCMalloc(SIZE_OF_PACKET);
-    if (unlikely(p == NULL))
-        return 0;
+    FAIL_IF (p == NULL);
     Flow f;
     TCPHdr tcph;
     TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
     uint8_t packet[1460] = "";
     ThreadVars tv;
-    int result = 1;
     PacketQueue pq;
     memset(&pq,0,sizeof(PacketQueue));
 
@@ -8346,54 +8338,36 @@ static int StreamTcpTest24(void)
     p->tcph = &tcph;
     p->flowflags = FLOW_PKT_TOSERVER;
     p->payload = packet;
-    ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
+    //ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
+    SET_ISN(&ssn.client, 3184324453UL);
 
     p->tcph->th_seq = htonl(3184324455UL);
     p->tcph->th_ack = htonl(3373419621UL);
     p->payload_len = 4;
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
-        printf("failed in segment reassmebling\n");
-        result &= 0;
-        goto end;
-    }
+    FAIL_IF (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
 
     p->tcph->th_seq = htonl(3184324459UL);
     p->tcph->th_ack = htonl(3373419633UL);
     p->payload_len = 2;
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
-        printf("failed in segment reassmebling\n");
-        result &= 0;
-        goto end;
-    }
+    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
 
     p->tcph->th_seq = htonl(3184324459UL);
     p->tcph->th_ack = htonl(3373419657UL);
     p->payload_len = 4;
 
-    if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
-        printf("failed in segment reassmebling\n");
-        result &= 0;
-        goto end;
-    }
+    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
 
-    if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 2) {
-        printf("failed in segment reassmebling\n");
-        result &= 0;
-    }
+    FAIL_IF(ssn.client.seg_list_tail == NULL);
+    FAIL_IF(TCP_SEG_LEN(ssn.client.seg_list_tail) != 4);
 
-end:
     StreamTcpReturnStreamSegments(&ssn.client);
     StreamTcpFreeConfig(TRUE);
-    if (SC_ATOMIC_GET(st_memuse) == 0) {
-        result &= 1;
-    } else {
-        printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse));
-    }
+    FAIL_IF(SC_ATOMIC_GET(st_memuse) > 0);
     SCFree(p);
     FLOW_DESTROY(&f);
-    return result;
+    PASS;
 }
 
 /**
@@ -9708,9 +9682,9 @@ static int StreamTcpTest37(void)
         goto end;
     }
 
-    if (((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq != 3) {
-        printf("the ssn->client.next_seq should be 3, but it is %"PRIu32"\n",
-                ((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq);
+    if (((TcpSession *)p->flow->protoctx)->client.raw_progress != 3) {
+        printf("the ssn->client.raw_progress should be 3, but it is %"PRIu64"\n",
+                ((TcpSession *)p->flow->protoctx)->client.raw_progress);
         goto end;
     }
 
index e49ab9a8d3e844f45ebddaebae33090e5eac5d0d..087bc7eb7cf7e0809f2d088e87e34f5928f47e01 100644 (file)
@@ -67,6 +67,8 @@ typedef struct TcpStreamCnf_ {
 
     uint8_t flags;
     uint8_t max_synack_queued;
+
+    StreamingBufferConfig sbcnf;
 } TcpStreamCnf;
 
 typedef struct StreamTcpThread_ {
@@ -185,34 +187,8 @@ enum {
     STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION = 2,
 };
 
-static inline int StreamNeedsReassembly(TcpSession *ssn, int direction)
-{
-    /* server tcp state */
-    if (direction) {
-        if (ssn->server.seg_list != NULL &&
-            (!(ssn->server.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) ||
-             !(ssn->server.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) ) {
-            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
-        } else if (ssn->toclient_smsg_head != NULL) {
-            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
-        } else {
-            return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
-        }
-    } else {
-        if (ssn->client.seg_list != NULL &&
-            (!(ssn->client.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) ||
-             !(ssn->client.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) ) {
-            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
-        } else if (ssn->toserver_smsg_head != NULL) {
-            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
-        } else {
-            return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
-        }
-    }
-}
-
 TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
-void StreamTcpExitPrintStats(ThreadVars *, void *);
+int StreamNeedsReassembly(TcpSession *ssn, int direction);
 TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **);
 TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data);
 void StreamTcpRegisterTests (void);
diff --git a/src/tests/stream-tcp-list.c b/src/tests/stream-tcp-list.c
new file mode 100644 (file)
index 0000000..631ef5b
--- /dev/null
@@ -0,0 +1,733 @@
+/* Copyright (C) 2007-2016 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "../suricata-common.h"
+#include "../stream-tcp-private.h"
+#include "../stream-tcp.h"
+#include "../stream-tcp-reassemble.h"
+#include "../stream-tcp-inline.h"
+#include "../stream-tcp-list.h"
+#include "../stream-tcp-util.h"
+#include "../util-streaming-buffer.h"
+#include "../util-print.h"
+#include "../util-unittest.h"
+
+static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
+{
+    if (StreamingBufferCompareRawData(stream->sb,
+                data, data_len) == 0)
+    {
+        SCReturnInt(0);
+    }
+    SCLogInfo("OK");
+    PrintRawDataFp(stdout, data, data_len);
+    return 1;
+}
+
+#define OVERLAP_START(isn, policy)              \
+    TcpReassemblyThreadCtx *ra_ctx = NULL;      \
+    TcpSession ssn;                             \
+    ThreadVars tv;                              \
+    memset(&tv, 0, sizeof(tv));                 \
+                                                \
+    StreamTcpUTInit(&ra_ctx);                   \
+                                                \
+    StreamTcpUTSetupSession(&ssn);              \
+    StreamTcpUTSetupStream(&ssn.server, (isn)); \
+    StreamTcpUTSetupStream(&ssn.client, (isn)); \
+                                                \
+    TcpStream *stream = &ssn.client;            \
+    stream->os_policy = (policy);
+
+#define OVERLAP_END                             \
+    StreamTcpUTClearSession(&ssn);              \
+    StreamTcpUTDeinit(ra_ctx);                  \
+    PASS
+
+#define OVERLAP_STEP(rseq, seg, seglen, buf, buflen) \
+    StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, stream->isn + (rseq), (uint8_t *)(seg), (seglen));    \
+    FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
+
+static int OverlapBSD(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_BSD);
+
+    OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
+    OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
+    OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
+    OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
+    OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
+    OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
+    OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
+    OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
+    OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* AA not overwritten, gap filled and B overwritten because 'starts before' */
+    OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* no-op, overlaps CCC which takes precedence */
+    OVERLAP_STEP(8, "KKK", 3, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* LLL fills gaps and replaces D as it starts before */
+    OVERLAP_STEP(11, "LLL", 3, "\0AAAJJBCCCLLL\0EEFFFGGHHI", 24);
+    /* MMM fills gap and replaces EE as it starts before */
+    OVERLAP_STEP(14, "MMM", 3, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(18, "N", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(21, "O", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(22, "P", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no replace of I as it starts the same */
+    OVERLAP_STEP(24, "QQ", 2, "\0AAAJJBCCCLLLMMMFFFGGHHIQ", 25);
+    OVERLAP_STEP(1, "0", 1, "0AAAJJBCCCLLLMMMFFFGGHHIQ", 25);
+
+    OVERLAP_END;
+}
+
+static int OverlapBSDBefore(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_BSD);
+
+    OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
+    OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
+    OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
+    OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
+
+    OVERLAP_END;
+}
+
+static int OverlapBSDSame(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_BSD);
+
+    OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
+    OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
+    OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    /* ignored as 'starts the same' */
+    OVERLAP_STEP(1, "KKK", 3, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    /* original data not overwritten as it starts on the same seq */
+    OVERLAP_STEP(1, "LLLL", 4, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "P", 1, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "QQ", 2, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+
+    OVERLAP_END;
+}
+
+static int OverlapBSDAfter(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_BSD);
+
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
+    OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+
+    OVERLAP_END;
+}
+
+static int OverlapVISTA(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_VISTA);
+
+    OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
+    OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
+    OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
+    OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
+    OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
+    OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
+    OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
+    OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
+    OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* AA not overwritten, gap filled and B not overwritten */
+    OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJBBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* no-op, overlaps CCC which takes precedence */
+    OVERLAP_STEP(8, "KKK", 3, "\0AAAJBBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* LLL fills gaps only */
+    OVERLAP_STEP(11, "LLL", 3, "\0AAAJBBCCCLDL\0EEFFFGGHHI", 24);
+    /* MMM fills gap only */
+    OVERLAP_STEP(14, "MMM", 3, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(18, "N", 1, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(21, "O", 1, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(22, "P", 1, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
+    /* no replace of I */
+    OVERLAP_STEP(24, "QQ", 2, "\0AAAJBBCCCLDLMEEFFFGGHHIQ", 25);
+    OVERLAP_STEP(1, "0", 1, "0AAAJBBCCCLDLMEEFFFGGHHIQ", 25);
+
+    OVERLAP_END;
+}
+
+static int OverlapVISTABefore(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_VISTA);
+
+    OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
+    OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
+    OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(2, "AA", 2, "\0AB\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(1, "JJJJ", 4, "JABJ\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(8, "LLL", 3, "JABJ\0\0\0LDL\0EE", 13);
+    OVERLAP_STEP(11,"MMM", 3, "JABJ\0\0\0LDLMEE", 13);
+
+    OVERLAP_END;
+}
+
+static int OverlapVISTASame(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_VISTA);
+
+    OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
+    OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
+    OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "KKK", 3, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "LLLL", 4, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "P", 1, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "QQ", 2, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+
+    OVERLAP_END;
+}
+
+static int OverlapVISTAAfter(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_VISTA);
+
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
+    OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUX(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LINUX);
+
+    OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
+    OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
+    OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
+    OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
+    OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
+    OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
+    OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
+    OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
+    OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* AA not overwritten, gap filled and B not overwritten */
+    OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* no-op, overlaps CCC which takes precedence */
+    OVERLAP_STEP(8, "KKK", 3, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* LLL fills gaps and replaces as begins before */
+    OVERLAP_STEP(11, "LLL", 3, "\0AAAJJBCCCLLL\0EEFFFGGHHI", 24);
+    /* MMM fills gap and replaces EE as it begins before */
+    OVERLAP_STEP(14, "MMM", 3, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(18, "N", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(21, "O", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(22, "P", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
+    /* replaces of I as begins the same, ends after*/
+    OVERLAP_STEP(24, "QQ", 2, "\0AAAJJBCCCLLLMMMFFFGGHHQQ", 25);
+    OVERLAP_STEP(1, "0", 1, "0AAAJJBCCCLLLMMMFFFGGHHQQ", 25);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXBefore(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LINUX);
+
+    OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
+    OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
+    OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
+    OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXSame(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LINUX);
+
+    OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
+    OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
+    OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "KKK", 3, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXAfter(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LINUX);
+
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
+    OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXOLD(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
+
+    OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
+    OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
+    OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
+    OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
+    OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
+    OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
+    OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
+    OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
+    OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* AA not overwritten as it starts before, gap filled and B overwritten */
+    OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* replace CCC */
+    OVERLAP_STEP(8, "KKK", 3, "\0AAAJJBKKK\0D\0\0EEFFFGGHHI", 24);
+    /* LLL fills gaps and replaces as begins before */
+    OVERLAP_STEP(11, "LLL", 3, "\0AAAJJBKKKLLL\0EEFFFGGHHI", 24);
+    /* MMM fills gap and replaces EE as it begins before */
+    OVERLAP_STEP(14, "MMM", 3, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(18, "N", 1, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(21, "O", 1, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(22, "P", 1, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
+    /* replaces of I as begins the same, ends after*/
+    OVERLAP_STEP(24, "QQ", 2, "\0AAAJJBKKKLLLMMMFFFGGHHQQ", 25);
+    OVERLAP_STEP(1, "0", 1, "0AAAJJBKKKLLLMMMFFFGGHHQQ", 25);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXOLDBefore(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
+
+    OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
+    OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
+    OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
+    OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXOLDSame(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
+
+    OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
+    OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
+    OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "KKK", 3, "KKK\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0QQII", 18);
+
+    OVERLAP_END;
+}
+
+static int OverlapLINUXOLDAfter(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
+
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
+    OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+
+    OVERLAP_END;
+}
+
+static int OverlapSOLARIS(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_SOLARIS);
+
+    OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
+    OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
+    OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
+    OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
+    OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
+    OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
+    OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
+    OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
+    OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
+    OVERLAP_STEP(3, "JJJJ", 4, "\0AJJJBBCCC\0D\0\0EEFFFGGHHI", 24);
+    /* replace CCC */
+    OVERLAP_STEP(8, "KKK", 3, "\0AJJJBBKKK\0D\0\0EEFFFGGHHI", 24);
+    /* LLL fills gaps and replaces as begins before */
+    OVERLAP_STEP(11, "LLL", 3, "\0AJJJBBKKKLLL\0EEFFFGGHHI", 24);
+    /* MMM fills gap and replaces EE as it begins before */
+    OVERLAP_STEP(14, "MMM", 3, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(18, "N", 1, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(21, "O", 1, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
+    /* no op */
+    OVERLAP_STEP(22, "P", 1, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
+    /* replaces of I as begins the same, ends after*/
+    OVERLAP_STEP(24, "QQ", 2, "\0AJJJBBKKKLLLMMMFFFGGHHQQ", 25);
+    OVERLAP_STEP(1, "0", 1, "0AJJJBBKKKLLLMMMFFFGGHHQQ", 25);
+
+    OVERLAP_END;
+}
+
+static int OverlapSOLARISBefore(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_SOLARIS);
+
+    OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
+    OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
+    OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
+    OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
+
+    OVERLAP_END;
+}
+
+static int OverlapSOLARISSame(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_SOLARIS);
+
+    OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
+    OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
+    OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "KKK", 3, "KKK\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0QQII", 18);
+
+    OVERLAP_END;
+}
+
+static int OverlapSOLARISAfter(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_SOLARIS);
+
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
+    OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(2, "JJ", 2, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(20, "O", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(17, "N", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+
+    OVERLAP_END;
+}
+
+static int OverlapLAST(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LAST);
+
+    OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
+    OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
+    OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
+    OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
+    OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
+    OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
+    OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
+    OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
+    OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
+    OVERLAP_STEP(3, "JJJJ", 4, "\0AJJJJBCCC\0D\0\0EEFFFGGHHI", 24);
+    OVERLAP_STEP(8, "KKK", 3, "\0AJJJJBKKK\0D\0\0EEFFFGGHHI", 24);
+    OVERLAP_STEP(11, "LLL", 3, "\0AJJJJBKKKLLL\0EEFFFGGHHI", 24);
+    OVERLAP_STEP(14, "MMM", 3, "\0AJJJJBKKKLLLMMMFFFGGHHI", 24);
+    OVERLAP_STEP(18, "N", 1, "\0AJJJJBKKKLLLMMMFNFGGHHI", 24);
+    OVERLAP_STEP(21, "O", 1, "\0AJJJJBKKKLLLMMMFNFGOHHI", 24);
+    OVERLAP_STEP(22, "P", 1, "\0AJJJJBKKKLLLMMMFNFGOPHI", 24);
+    OVERLAP_STEP(24, "QQ", 2, "\0AJJJJBKKKLLLMMMFNFGOPHQQ", 25);
+    OVERLAP_STEP(1, "0", 1, "0AJJJJBKKKLLLMMMFNFGOPHQQ", 25);
+
+    OVERLAP_END;
+}
+
+static int OverlapLASTBefore(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LAST);
+
+    OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
+    OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
+    OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
+    OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
+    OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
+
+    OVERLAP_END;
+}
+
+static int OverlapLASTSame(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LAST);
+
+    OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
+    OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
+    OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "KKK", 3, "KKK\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
+    OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0PHII", 18);
+    OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0QQII", 18);
+
+    OVERLAP_END;
+}
+
+static int OverlapLASTAfter(uint32_t isn)
+{
+    OVERLAP_START(isn, OS_POLICY_LAST);
+
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
+    OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(2, "JJ", 2, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
+    OVERLAP_STEP(20, "O", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGO", 20);
+    OVERLAP_STEP(17, "N", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FNFGO", 20);
+
+    OVERLAP_END;
+}
+
+/** \test BSD policy
+ */
+static int StreamTcpReassembleTest01(void)
+{
+    FAIL_IF(OverlapBSD(0) == 0);
+    OverlapBSDBefore(0);
+    OverlapBSDSame(0);
+    OverlapBSDAfter(0);
+
+    OverlapBSD(1);
+    OverlapBSDBefore(1);
+    OverlapBSDSame(1);
+    OverlapBSDAfter(1);
+
+    OverlapBSD(UINT_MAX);
+    OverlapBSDBefore(UINT_MAX);
+    OverlapBSDSame(UINT_MAX);
+    OverlapBSDAfter(UINT_MAX);
+
+    OverlapBSD(UINT_MAX - 10);
+    OverlapBSDBefore(UINT_MAX - 10);
+    OverlapBSDSame(UINT_MAX - 10);
+    OverlapBSDAfter(UINT_MAX - 10);
+    return 1;
+}
+
+
+/** \test Vista Policy
+ */
+static int StreamTcpReassembleTest02(void)
+{
+    OverlapVISTA(0);
+    OverlapVISTABefore(0);
+    OverlapVISTASame(0);
+    OverlapVISTAAfter(0);
+
+    OverlapVISTA(1);
+    OverlapVISTABefore(1);
+    OverlapVISTASame(1);
+    OverlapVISTAAfter(1);
+
+    OverlapVISTA(UINT_MAX);
+    OverlapVISTABefore(UINT_MAX);
+    OverlapVISTASame(UINT_MAX);
+    OverlapVISTAAfter(UINT_MAX);
+
+    OverlapVISTA(UINT_MAX - 10);
+    OverlapVISTABefore(UINT_MAX - 10);
+    OverlapVISTASame(UINT_MAX - 10);
+    OverlapVISTAAfter(UINT_MAX - 10);
+    return 1;
+}
+
+
+/** \test Linux policy
+ */
+static int StreamTcpReassembleTest03(void)
+{
+    OverlapLINUX(0);
+    OverlapLINUXBefore(0);
+    OverlapLINUXSame(0);
+    OverlapLINUXAfter(0);
+
+    OverlapLINUX(1);
+    OverlapLINUXBefore(1);
+    OverlapLINUXSame(1);
+    OverlapLINUXAfter(1);
+
+    OverlapLINUX(UINT_MAX);
+    OverlapLINUXBefore(UINT_MAX);
+    OverlapLINUXSame(UINT_MAX);
+    OverlapLINUXAfter(UINT_MAX);
+
+    OverlapLINUX(UINT_MAX - 10);
+    OverlapLINUXBefore(UINT_MAX - 10);
+    OverlapLINUXSame(UINT_MAX - 10);
+    OverlapLINUXAfter(UINT_MAX - 10);
+    return 1;
+}
+
+/** \test policy Linux old
+ */
+static int StreamTcpReassembleTest04(void)
+{
+    OverlapLINUXOLD(0);
+    OverlapLINUXOLDBefore(0);
+    OverlapLINUXOLDSame(0);
+    OverlapLINUXOLDAfter(0);
+
+    OverlapLINUXOLD(1);
+    OverlapLINUXOLDBefore(1);
+    OverlapLINUXOLDSame(1);
+    OverlapLINUXOLDAfter(1);
+
+    OverlapLINUXOLD(UINT_MAX);
+    OverlapLINUXOLDBefore(UINT_MAX);
+    OverlapLINUXOLDSame(UINT_MAX);
+    OverlapLINUXOLDAfter(UINT_MAX);
+
+    OverlapLINUXOLD(UINT_MAX - 10);
+    OverlapLINUXOLDBefore(UINT_MAX - 10);
+    OverlapLINUXOLDSame(UINT_MAX - 10);
+    OverlapLINUXOLDAfter(UINT_MAX - 10);
+    return 1;
+}
+
+/** \test Solaris policy
+ */
+static int StreamTcpReassembleTest05(void)
+{
+    OverlapSOLARIS(0);
+    OverlapSOLARISBefore(0);
+    OverlapSOLARISSame(0);
+    OverlapSOLARISAfter(0);
+
+    OverlapSOLARIS(1);
+    OverlapSOLARISBefore(1);
+    OverlapSOLARISSame(1);
+    OverlapSOLARISAfter(1);
+
+    OverlapSOLARIS(UINT_MAX);
+    OverlapSOLARISBefore(UINT_MAX);
+    OverlapSOLARISSame(UINT_MAX);
+    OverlapSOLARISAfter(UINT_MAX);
+
+    OverlapSOLARIS(UINT_MAX - 10);
+    OverlapSOLARISBefore(UINT_MAX - 10);
+    OverlapSOLARISSame(UINT_MAX - 10);
+    OverlapSOLARISAfter(UINT_MAX - 10);
+    return 1;
+}
+
+/** \test policy 'last'
+ */
+static int StreamTcpReassembleTest06(void)
+{
+    OverlapLAST(0);
+    OverlapLASTBefore(0);
+    OverlapLASTSame(0);
+    OverlapLASTAfter(0);
+
+    OverlapLAST(1);
+    OverlapLASTBefore(1);
+    OverlapLASTSame(1);
+    OverlapLASTAfter(1);
+
+    OverlapLAST(UINT_MAX);
+    OverlapLASTBefore(UINT_MAX);
+    OverlapLASTSame(UINT_MAX);
+    OverlapLASTAfter(UINT_MAX);
+
+    OverlapLAST(UINT_MAX - 10);
+    OverlapLASTBefore(UINT_MAX - 10);
+    OverlapLASTSame(UINT_MAX - 10);
+    OverlapLASTAfter(UINT_MAX - 10);
+    return 1;
+}
+
+static int StreamTcpReassembleTest30 (void)
+{
+    OVERLAP_START(9, OS_POLICY_BSD);
+    OVERLAP_STEP(3, "BBB", 3, "\0\0BBB", 5);
+    OVERLAP_STEP(1, "AA", 2, "AABBB", 5);
+    OVERLAP_END;
+}
+
+static int StreamTcpReassembleTest31 (void)
+{
+    OVERLAP_START(9, OS_POLICY_BSD);
+    OVERLAP_STEP(1, "AA", 2, "AA", 2);
+    OVERLAP_STEP(3, "BBB", 3, "AABBB", 5);
+    OVERLAP_END;
+}
+
+static int StreamTcpReassembleTest32(void)
+{
+    OVERLAP_START(0, OS_POLICY_BSD);
+    OVERLAP_STEP(11, "AAAAAAAAAA", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAA", 20);
+    OVERLAP_STEP(21, "BBBBBBBBBB", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB", 30);
+    OVERLAP_STEP(41, "CCCCCCCCCC", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50);
+    OVERLAP_STEP(6,  "aaaaaaaaaaaaaaaaaaaa", 20, "\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50);
+    OVERLAP_STEP(1,  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50);
+    OVERLAP_END;
+}
+
+void StreamTcpListRegisterTests(void)
+{
+    UtRegisterTest("StreamTcpReassembleTest01 -- BSD policy",
+            StreamTcpReassembleTest01);
+    UtRegisterTest("StreamTcpReassembleTest02 -- VISTA policy",
+            StreamTcpReassembleTest02);
+    UtRegisterTest("StreamTcpReassembleTest03 -- LINUX policy",
+            StreamTcpReassembleTest03);
+    UtRegisterTest("StreamTcpReassembleTest04 -- LINUX-OLD policy",
+            StreamTcpReassembleTest04);
+    UtRegisterTest("StreamTcpReassembleTest05 -- SOLARIS policy",
+            StreamTcpReassembleTest05);
+    UtRegisterTest("StreamTcpReassembleTest06 -- LAST policy",
+            StreamTcpReassembleTest06);
+
+    UtRegisterTest("StreamTcpReassembleTest30",
+            StreamTcpReassembleTest30);
+    UtRegisterTest("StreamTcpReassembleTest31",
+            StreamTcpReassembleTest31);
+    UtRegisterTest("StreamTcpReassembleTest32",
+            StreamTcpReassembleTest32);
+
+}