diff --git a/src/flow.h b/src/flow.h
index 9866b5685..357ac5298 100644
--- a/src/flow.h
+++ b/src/flow.h
@@ -46,68 +46,68 @@ typedef struct AppLayerParserState_ AppLayerParserState;
 /* per flow flags */

 /** At least one packet from the source address was seen */
-#define FLOW_TO_SRC_SEEN                BIT_U32(0)
+#define FLOW_TO_SRC_SEEN BIT_U32(0)
 /** At least one packet from the destination address was seen */
-#define FLOW_TO_DST_SEEN                BIT_U32(1)
+#define FLOW_TO_DST_SEEN BIT_U32(1)

 // vacancy

 /** Flow was inspected against IP-Only sigs in the toserver direction */
-#define FLOW_TOSERVER_IPONLY_SET        BIT_U32(3)
+#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3)
 /** Flow was inspected against IP-Only sigs in the toclient direction */
-#define FLOW_TOCLIENT_IPONLY_SET        BIT_U32(4)
+#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4)

 /** Packet belonging to this flow should not be inspected at all */
-#define FLOW_NOPACKET_INSPECTION        BIT_U32(5)
+#define FLOW_NOPACKET_INSPECTION BIT_U32(5)
 /** Packet payloads belonging to this flow should not be inspected */
-#define FLOW_NOPAYLOAD_INSPECTION       BIT_U32(6)
+#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6)

 /** All packets in this flow should be dropped */
-#define FLOW_ACTION_DROP                BIT_U32(7)
+#define FLOW_ACTION_DROP BIT_U32(7)

 /** Sgh for toserver direction set (even if it's NULL) */
-#define FLOW_SGH_TOSERVER               BIT_U32(8)
+#define FLOW_SGH_TOSERVER BIT_U32(8)
 /** Sgh for toclient direction set (even if it's NULL) */
-#define FLOW_SGH_TOCLIENT               BIT_U32(9)
+#define FLOW_SGH_TOCLIENT BIT_U32(9)

 /** packet to server direction has been logged in drop file (only in IPS mode) */
-#define FLOW_TOSERVER_DROP_LOGGED       BIT_U32(10)
+#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10)
 /** packet to client direction has been logged in drop file (only in IPS mode) */
-#define FLOW_TOCLIENT_DROP_LOGGED       BIT_U32(11)
+#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11)

 /** flow has alerts */
-#define FLOW_HAS_ALERTS                 BIT_U32(12)
+#define FLOW_HAS_ALERTS BIT_U32(12)

 /** Pattern matcher alproto detection done */
-#define FLOW_TS_PM_ALPROTO_DETECT_DONE  BIT_U32(13)
+#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13)
 /** Probing parser alproto detection done */
-#define FLOW_TS_PP_ALPROTO_DETECT_DONE  BIT_U32(14)
+#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14)
 /** Expectation alproto detection done */
-#define FLOW_TS_PE_ALPROTO_DETECT_DONE  BIT_U32(15)
+#define FLOW_TS_PE_ALPROTO_DETECT_DONE BIT_U32(15)
 /** Pattern matcher alproto detection done */
-#define FLOW_TC_PM_ALPROTO_DETECT_DONE  BIT_U32(16)
+#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(16)
 /** Probing parser alproto detection done */
-#define FLOW_TC_PP_ALPROTO_DETECT_DONE  BIT_U32(17)
+#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(17)
 /** Expectation alproto detection done */
-#define FLOW_TC_PE_ALPROTO_DETECT_DONE  BIT_U32(18)
-#define FLOW_TIMEOUT_REASSEMBLY_DONE    BIT_U32(19)
+#define FLOW_TC_PE_ALPROTO_DETECT_DONE BIT_U32(18)
+#define FLOW_TIMEOUT_REASSEMBLY_DONE   BIT_U32(19)

 /** flow is ipv4 */
-#define FLOW_IPV4                       BIT_U32(20)
+#define FLOW_IPV4 BIT_U32(20)
 /** flow is ipv6 */
-#define FLOW_IPV6                       BIT_U32(21)
+#define FLOW_IPV6 BIT_U32(21)

-#define FLOW_PROTO_DETECT_TS_DONE       BIT_U32(22)
-#define FLOW_PROTO_DETECT_TC_DONE       BIT_U32(23)
+#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(22)
+#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(23)

 /** Indicate that alproto detection for flow should be done again */
-#define FLOW_CHANGE_PROTO               BIT_U32(24)
+#define FLOW_CHANGE_PROTO BIT_U32(24)

-#define FLOW_WRONG_THREAD               BIT_U32(25)
+#define FLOW_WRONG_THREAD BIT_U32(25)
 /** Protocol detection told us flow is picked up in wrong direction (midstream) */
-#define FLOW_DIR_REVERSED               BIT_U32(26)
+#define FLOW_DIR_REVERSED BIT_U32(26)
 /** Indicate that the flow did trigger an expectation creation */
-#define FLOW_HAS_EXPECTATION            BIT_U32(27)
+#define FLOW_HAS_EXPECTATION BIT_U32(27)

 /** All packets in this flow should be passed */
 #define FLOW_ACTION_PASS BIT_U32(28)
@@ -117,70 +117,62 @@ typedef struct AppLayerParserState_ AppLayerParserState;

 /* File flags */

-#define FLOWFILE_INIT                   0
+#define FLOWFILE_INIT 0

 /** no magic on files in this flow */
-#define FLOWFILE_NO_MAGIC_TS            BIT_U16(0)
-#define FLOWFILE_NO_MAGIC_TC            BIT_U16(1)
+#define FLOWFILE_NO_MAGIC_TS BIT_U16(0)
+#define FLOWFILE_NO_MAGIC_TC BIT_U16(1)

 /** even if the flow has files, don't store 'm */
-#define FLOWFILE_NO_STORE_TS            BIT_U16(2)
-#define FLOWFILE_NO_STORE_TC            BIT_U16(3)
+#define FLOWFILE_NO_STORE_TS BIT_U16(2)
+#define FLOWFILE_NO_STORE_TC BIT_U16(3)
 /** no md5 on files in this flow */
-#define FLOWFILE_NO_MD5_TS              BIT_U16(4)
-#define FLOWFILE_NO_MD5_TC              BIT_U16(5)
+#define FLOWFILE_NO_MD5_TS BIT_U16(4)
+#define FLOWFILE_NO_MD5_TC BIT_U16(5)

 /** no sha1 on files in this flow */
-#define FLOWFILE_NO_SHA1_TS             BIT_U16(6)
-#define FLOWFILE_NO_SHA1_TC             BIT_U16(7)
+#define FLOWFILE_NO_SHA1_TS BIT_U16(6)
+#define FLOWFILE_NO_SHA1_TC BIT_U16(7)

 /** no sha256 on files in this flow */
-#define FLOWFILE_NO_SHA256_TS           BIT_U16(8)
-#define FLOWFILE_NO_SHA256_TC           BIT_U16(9)
+#define FLOWFILE_NO_SHA256_TS BIT_U16(8)
+#define FLOWFILE_NO_SHA256_TC BIT_U16(9)

 /** no size tracking of files in this flow */
-#define FLOWFILE_NO_SIZE_TS             BIT_U16(10)
-#define FLOWFILE_NO_SIZE_TC             BIT_U16(11)
+#define FLOWFILE_NO_SIZE_TS BIT_U16(10)
+#define FLOWFILE_NO_SIZE_TC BIT_U16(11)

 /** store files in the flow */
 #define FLOWFILE_STORE_TS BIT_U16(12)
 #define FLOWFILE_STORE_TC BIT_U16(13)

-#define FLOWFILE_NONE_TS (FLOWFILE_NO_MAGIC_TS | \
-                          FLOWFILE_NO_STORE_TS | \
-                          FLOWFILE_NO_MD5_TS   | \
-                          FLOWFILE_NO_SHA1_TS  | \
-                          FLOWFILE_NO_SHA256_TS| \
-                          FLOWFILE_NO_SIZE_TS)
-#define FLOWFILE_NONE_TC (FLOWFILE_NO_MAGIC_TC | \
-                          FLOWFILE_NO_STORE_TC | \
-                          FLOWFILE_NO_MD5_TC   | \
-                          FLOWFILE_NO_SHA1_TC  | \
-                          FLOWFILE_NO_SHA256_TC| \
-                          FLOWFILE_NO_SIZE_TC)
-#define FLOWFILE_NONE    (FLOWFILE_NONE_TS|FLOWFILE_NONE_TC)
-
-#define FLOW_IS_IPV4(f) \
-    (((f)->flags & FLOW_IPV4) == FLOW_IPV4)
-#define FLOW_IS_IPV6(f) \
-    (((f)->flags & FLOW_IPV6) == FLOW_IPV6)
-
-#define FLOW_GET_SP(f)  \
-    ((f)->flags & FLOW_DIR_REVERSED) ? (f)->dp : (f)->sp;
-#define FLOW_GET_DP(f)  \
-    ((f)->flags & FLOW_DIR_REVERSED) ? (f)->sp : (f)->dp;
-
-#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) do {      \
-        (pa)->family = AF_INET;                         \
-        (pa)->addr_data32[0] = (fa)->addr_data32[0];    \
+#define FLOWFILE_NONE_TS                                                                           \
+    (FLOWFILE_NO_MAGIC_TS | FLOWFILE_NO_STORE_TS | FLOWFILE_NO_MD5_TS | FLOWFILE_NO_SHA1_TS |      \
+            FLOWFILE_NO_SHA256_TS | FLOWFILE_NO_SIZE_TS)
+#define FLOWFILE_NONE_TC                                                                           \
+    (FLOWFILE_NO_MAGIC_TC | FLOWFILE_NO_STORE_TC | FLOWFILE_NO_MD5_TC | FLOWFILE_NO_SHA1_TC |      \
+            FLOWFILE_NO_SHA256_TC | FLOWFILE_NO_SIZE_TC)
+#define FLOWFILE_NONE (FLOWFILE_NONE_TS | FLOWFILE_NONE_TC)
+
+#define FLOW_IS_IPV4(f) (((f)->flags & FLOW_IPV4) == FLOW_IPV4)
+#define FLOW_IS_IPV6(f) (((f)->flags & FLOW_IPV6) == FLOW_IPV6)
+
+#define FLOW_GET_SP(f) ((f)->flags & FLOW_DIR_REVERSED) ? (f)->dp : (f)->sp;
+#define FLOW_GET_DP(f) ((f)->flags & FLOW_DIR_REVERSED) ? (f)->sp : (f)->dp;
+
+#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa)                                                      \
+    do {                                                                                           \
+        (pa)->family = AF_INET;                                                                    \
+        (pa)->addr_data32[0] = (fa)->addr_data32[0];                                               \
     } while (0)

-#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) do {      \
-        (pa)->family = AF_INET6;                        \
-        (pa)->addr_data32[0] = (fa)->addr_data32[0];    \
-        (pa)->addr_data32[1] = (fa)->addr_data32[1];    \
-        (pa)->addr_data32[2] = (fa)->addr_data32[2];    \
-        (pa)->addr_data32[3] = (fa)->addr_data32[3];    \
+#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa)                                                      \
+    do {                                                                                           \
+        (pa)->family = AF_INET6;                                                                   \
+        (pa)->addr_data32[0] = (fa)->addr_data32[0];                                               \
+        (pa)->addr_data32[1] = (fa)->addr_data32[1];                                               \
+        (pa)->addr_data32[2] = (fa)->addr_data32[2];                                               \
+        (pa)->addr_data32[3] = (fa)->addr_data32[3];                                               \
     } while (0)

 /* Set the IPv4 addressesinto the Addrs of the Packet.
@@ -188,47 +180,51 @@ typedef struct AppLayerParserState_ AppLayerParserState;
  *
  * We set the rest of the struct to 0 so we can
  * prevent using memset. */
-#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) do {             \
-        (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \
-        (a)->addr_data32[1] = 0;                                  \
-        (a)->addr_data32[2] = 0;                                  \
-        (a)->addr_data32[3] = 0;                                  \
+#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a)                                                   \
+    do {                                                                                           \
+        (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr;                                \
+        (a)->addr_data32[1] = 0;                                                                   \
+        (a)->addr_data32[2] = 0;                                                                   \
+        (a)->addr_data32[3] = 0;                                                                   \
     } while (0)

-#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) do {             \
-        (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \
-        (a)->addr_data32[1] = 0;                                  \
-        (a)->addr_data32[2] = 0;                                  \
-        (a)->addr_data32[3] = 0;                                  \
+#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a)                                                   \
+    do {                                                                                           \
+        (a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr;                                \
+        (a)->addr_data32[1] = 0;                                                                   \
+        (a)->addr_data32[2] = 0;                                                                   \
+        (a)->addr_data32[3] = 0;                                                                   \
     } while (0)

 /* Set the IPv6 addressesinto the Addrs of the Packet.
  * Make sure p->ip6h is initialized and validated. */
-#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) do {   \
-        (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0];  \
-        (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1];  \
-        (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2];  \
-        (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3];  \
+#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a)                                                   \
+    do {                                                                                           \
+        (a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0];                                             \
+        (a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1];                                             \
+        (a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2];                                             \
+        (a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3];                                             \
     } while (0)

-#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) do {   \
-        (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0];  \
-        (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1];  \
-        (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2];  \
-        (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3];  \
+#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a)                                                   \
+    do {                                                                                           \
+        (a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0];                                             \
+        (a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1];                                             \
+        (a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2];                                             \
+        (a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3];                                             \
     } while (0)

 /* pkt flow flags */
-#define FLOW_PKT_TOSERVER               0x01
-#define FLOW_PKT_TOCLIENT               0x02
-#define FLOW_PKT_ESTABLISHED            0x04
-#define FLOW_PKT_TOSERVER_IPONLY_SET    0x08
-#define FLOW_PKT_TOCLIENT_IPONLY_SET    0x10
-#define FLOW_PKT_TOSERVER_FIRST         0x20
-#define FLOW_PKT_TOCLIENT_FIRST         0x40
+#define FLOW_PKT_TOSERVER            0x01
+#define FLOW_PKT_TOCLIENT            0x02
+#define FLOW_PKT_ESTABLISHED         0x04
+#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08
+#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10
+#define FLOW_PKT_TOSERVER_FIRST      0x20
+#define FLOW_PKT_TOCLIENT_FIRST      0x40
 /** last pseudo packet in the flow. Can be used to trigger final clean,
  *  logging, etc. */
-#define FLOW_PKT_LAST_PSEUDO            0x80
+#define FLOW_PKT_LAST_PSEUDO 0x80

 #define FLOW_END_FLAG_STATE_NEW         0x01
 #define FLOW_END_FLAG_STATE_ESTABLISHED 0x02
@@ -240,50 +236,67 @@ typedef struct AppLayerParserState_ AppLayerParserState;
 #define FLOW_END_FLAG_STATE_BYPASSED    0x80

 /** Mutex or RWLocks for the flow. */
-//#define FLOWLOCK_RWLOCK
+// #define FLOWLOCK_RWLOCK
 #define FLOWLOCK_MUTEX

 #ifdef FLOWLOCK_RWLOCK
-    #ifdef FLOWLOCK_MUTEX
-        #error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX
-    #endif
+#ifdef FLOWLOCK_MUTEX
+#error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX
+#endif
 #endif

 #ifdef FLOWLOCK_RWLOCK
-    #define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL)
-    #define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r)
-    #define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r)
-    #define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r)
-    #define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r)
-    #define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r)
-    #define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r)
+#define FLOWLOCK_INIT(fb)      SCRWLockInit(&(fb)->r, NULL)
+#define FLOWLOCK_DESTROY(fb)   SCRWLockDestroy(&(fb)->r)
+#define FLOWLOCK_RDLOCK(fb)    SCRWLockRDLock(&(fb)->r)
+#define FLOWLOCK_WRLOCK(fb)    SCRWLockWRLock(&(fb)->r)
+#define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r)
+#define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r)
+#define FLOWLOCK_UNLOCK(fb)    SCRWLockUnlock(&(fb)->r)
 #elif defined FLOWLOCK_MUTEX
-    #define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL)
-    #define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m)
-    #define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m)
-    #define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m)
-    #define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m)
-    #define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m)
-    #define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m)
+#define FLOWLOCK_INIT(fb)      SCMutexInit(&(fb)->m, NULL)
+#define FLOWLOCK_DESTROY(fb)   SCMutexDestroy(&(fb)->m)
+#define FLOWLOCK_RDLOCK(fb)    SCMutexLock(&(fb)->m)
+#define FLOWLOCK_WRLOCK(fb)    SCMutexLock(&(fb)->m)
+#define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m)
+#define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m)
+#define FLOWLOCK_UNLOCK(fb)    SCMutexUnlock(&(fb)->m)
 #else
-    #error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
+#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
 #endif

-#define FLOW_IS_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE))
-#define FLOW_IS_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE))
-#define FLOW_IS_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PE_ALPROTO_DETECT_DONE))
-
-#define FLOW_SET_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE))
-#define FLOW_SET_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE))
-#define FLOW_SET_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PE_ALPROTO_DETECT_DONE))
-
-#define FLOW_RESET_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PM_ALPROTO_DETECT_DONE))
-#define FLOW_RESET_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PP_ALPROTO_DETECT_DONE))
-#define FLOW_RESET_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PE_ALPROTO_DETECT_DONE))
+#define FLOW_IS_PM_DONE(f, dir)                                                                    \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE)                     \
+                               : ((f)->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE))
+#define FLOW_IS_PP_DONE(f, dir)                                                                    \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE)                     \
+                               : ((f)->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE))
+#define FLOW_IS_PE_DONE(f, dir)                                                                    \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PE_ALPROTO_DETECT_DONE)                     \
+                               : ((f)->flags & FLOW_TC_PE_ALPROTO_DETECT_DONE))
+
+#define FLOW_SET_PM_DONE(f, dir)                                                                   \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE)                    \
+                               : ((f)->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE))
+#define FLOW_SET_PP_DONE(f, dir)                                                                   \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE)                    \
+                               : ((f)->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE))
+#define FLOW_SET_PE_DONE(f, dir)                                                                   \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PE_ALPROTO_DETECT_DONE)                    \
+                               : ((f)->flags |= FLOW_TC_PE_ALPROTO_DETECT_DONE))
+
+#define FLOW_RESET_PM_DONE(f, dir)                                                                 \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PM_ALPROTO_DETECT_DONE)                   \
+                               : ((f)->flags &= ~FLOW_TC_PM_ALPROTO_DETECT_DONE))
+#define FLOW_RESET_PP_DONE(f, dir)                                                                 \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PP_ALPROTO_DETECT_DONE)                   \
+                               : ((f)->flags &= ~FLOW_TC_PP_ALPROTO_DETECT_DONE))
+#define FLOW_RESET_PE_DONE(f, dir)                                                                 \
+    (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PE_ALPROTO_DETECT_DONE)                   \
+                               : ((f)->flags &= ~FLOW_TC_PE_ALPROTO_DETECT_DONE))

 /* global flow config */
-typedef struct FlowCnf_
-{
+typedef struct FlowCnf_ {
     uint32_t hash_rand;
     uint32_t hash_size;
     uint32_t prealloc;
@@ -299,8 +312,7 @@ typedef struct FlowCnf_
 } FlowConfig;

 /* Hash key for the flow hash */
-typedef struct FlowKey_
-{
+typedef struct FlowKey_ {
     Address src, dst;
     Port sp, dp;
     uint8_t proto;
@@ -311,9 +323,9 @@ typedef struct FlowKey_

 typedef struct FlowAddress_ {
     union {
-        uint32_t       address_un_data32[4]; /* type-specific field */
-        uint16_t       address_un_data16[8]; /* type-specific field */
-        uint8_t        address_un_data8[16]; /* type-specific field */
+        uint32_t address_un_data32[4]; /* type-specific field */
+        uint16_t address_un_data16[8]; /* type-specific field */
+        uint8_t address_un_data8[16];  /* type-specific field */
     } address;
 } FlowAddress;

@@ -344,16 +356,15 @@ typedef uint16_t FlowThreadId;
  *  of a flow. This is why we can access those without protection of the lock.
  */

-typedef struct Flow_
-{
+typedef struct Flow_ {
     /* flow "header", used for hashing and flow lookup. Static after init,
      * so safe to look at without lock */
     FlowAddress src, dst;
     union {
-        Port sp;        /**< tcp/udp source port */
+        Port sp; /**< tcp/udp source port */
         struct {
-            uint8_t type;   /**< icmp type */
-            uint8_t code;   /**< icmp code */
+            uint8_t type; /**< icmp type */
+            uint8_t code; /**< icmp code */
         } icmp_s;

         struct {
@@ -361,10 +372,10 @@ typedef struct Flow_
         } esp;
     };
     union {
-        Port dp;        /**< tcp/udp destination port */
+        Port dp; /**< tcp/udp destination port */
         struct {
-            uint8_t type;   /**< icmp type */
-            uint8_t code;   /**< icmp code */
+            uint8_t type; /**< icmp type */
+            uint8_t code; /**< icmp code */
         } icmp_d;
     };
     uint8_t proto;
@@ -376,8 +387,8 @@ typedef struct Flow_
     /* track toserver/toclient flow timeout needs */
     union {
         struct {
-            uint8_t ffr_ts:4;
-            uint8_t ffr_tc:4;
+            uint8_t ffr_ts : 4;
+            uint8_t ffr_tc : 4;
         };
         uint8_t ffr;
     };
@@ -415,9 +426,9 @@ typedef struct Flow_
     uint32_t probing_parser_toserver_alproto_masks;
     uint32_t probing_parser_toclient_alproto_masks;

-    uint32_t flags;         /**< generic flags */
+    uint32_t flags; /**< generic flags */

-    uint16_t file_flags;    /**< file tracking/extraction flags */
+    uint16_t file_flags; /**< file tracking/extraction flags */

     /** destination port to be used in protocol detection. This is meant
      *  for use with STARTTLS and HTTP CONNECT detection */
@@ -431,7 +442,7 @@ typedef struct Flow_
 #elif defined FLOWLOCK_MUTEX
     SCMutex m;
 #else
-    #error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
+#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
 #endif

     /** protocol specific data pointer, e.g. for TcpSession */
@@ -469,8 +480,8 @@ typedef struct Flow_
     /** application level storage ptrs.
      *
      */
-    AppLayerParserState *alparser;     /**< parser internal state */
-    void *alstate;      /**< application layer state */
+    AppLayerParserState *alparser; /**< parser internal state */
+    void *alstate;                 /**< application layer state */

     /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag
      *  has been set. */
@@ -490,6 +501,13 @@ typedef struct Flow_
     uint32_t tosrcpktcnt;
     uint64_t todstbytecnt;
     uint64_t tosrcbytecnt;
+    /** Remaining packets that should be logged by the pcap-log "context-packets-after"
+     *  feature once an alert has fired for this flow. This field is **only** used by
+     *  the pcap-log output module and is otherwise ignored by the rest of the engine.
+     *  It is initialised to 0 and set to `context_packets_after` when the first alert
+     *  for this flow is encountered. It is then decremented for each subsequent packet
+     *  the module logs until it reaches 0. */
+    uint32_t pcap_after_remaining;
 } Flow;

 enum FlowState {
@@ -519,8 +537,8 @@ typedef struct FlowProtoFreeFunc_ {
 } FlowProtoFreeFunc;

 typedef struct FlowBypassInfo_ {
-    bool (* BypassUpdate)(Flow *f, void *data, time_t tsec);
-    void (* BypassFree)(void *data);
+    bool (*BypassUpdate)(Flow *f, void *data, time_t tsec);
+    void (*BypassFree)(void *data);
     void *bypass_data;
     uint64_t tosrcpktcnt;
     uint64_t tosrcbytecnt;
@@ -544,7 +562,7 @@ typedef struct FlowLookupStruct_ // TODO name
  *  and calc the hash value to be used in the lookup and autofp flow
  *  balancing. */
 void FlowSetupPacket(Packet *p);
-void FlowHandlePacket (ThreadVars *, FlowLookupStruct *, Packet *);
+void FlowHandlePacket(ThreadVars *, FlowLookupStruct *, Packet *);
 void FlowInitConfig(bool);
 void FlowReset(void);
 void FlowShutdown(void);
@@ -597,7 +615,7 @@ static inline void *FlowGetAppState(const Flow *f)
  *
  * \param f Flow to set the flag in
  */
-static inline  void FlowSetNoPacketInspectionFlag(Flow *f)
+static inline void FlowSetNoPacketInspectionFlag(Flow *f)
 {
     SCEnter();

@@ -688,7 +706,7 @@ static inline bool FlowIsBypassed(const Flow *f)
     return false;
 }

-int FlowClearMemory(Flow *,uint8_t );
+int FlowClearMemory(Flow *, uint8_t);

 AppProto FlowGetAppProtocol(const Flow *f);
 void *FlowGetAppState(const Flow *f);
diff --git a/src/log-pcap.c b/src/log-pcap.c
index d997471e3..e95a3a65a 100644
--- a/src/log-pcap.c
+++ b/src/log-pcap.c
@@ -25,6 +25,10 @@
  */

 #include "suricata-common.h"
+#include <errno.h>
+#include <pcap.h>
+#include <string.h>
+#include <sys/stat.h>
 #ifdef HAVE_LIBLZ4
 #include <lz4frame.h>
 #include "util-fmemopen.h"
@@ -34,6 +38,7 @@
 #define INIT_RING_BUFFER
 #include <dirent.h>
 #include <fnmatch.h>
+#include <pcre2.h>
 #endif

 #include "log-pcap.h"
@@ -56,15 +61,19 @@
 #include "util-profiling.h"
 #include "util-time.h"

-#define DEFAULT_LOG_FILENAME            "pcaplog"
-#define MODULE_NAME                     "PcapLog"
-#define MIN_LIMIT                       4 * 1024 * 1024
-#define DEFAULT_LIMIT                   100 * 1024 * 1024
-#define DEFAULT_FILE_LIMIT              0
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "conf-yaml-loader.h"

-#define LOGMODE_NORMAL                  0
-#define LOGMODE_SGUIL                   1
-#define LOGMODE_MULTI                   2
+#define DEFAULT_LOG_FILENAME "pcaplog"
+#define MODULE_NAME          "PcapLog"
+#define MIN_LIMIT            4 * 1024 * 1024
+#define DEFAULT_LIMIT        100 * 1024 * 1024
+#define DEFAULT_FILE_LIMIT   0
+
+#define LOGMODE_NORMAL 0
+#define LOGMODE_SGUIL  1
+#define LOGMODE_MULTI  2

 typedef enum LogModeConditionalType_ {
     LOGMODE_COND_ALL,
@@ -72,21 +81,21 @@ typedef enum LogModeConditionalType_ {
     LOGMODE_COND_TAG
 } LogModeConditionalType;

-#define RING_BUFFER_MODE_DISABLED       0
-#define RING_BUFFER_MODE_ENABLED        1
+#define RING_BUFFER_MODE_DISABLED 0
+#define RING_BUFFER_MODE_ENABLED  1

-#define TS_FORMAT_SEC                   0
-#define TS_FORMAT_USEC                  1
+#define TS_FORMAT_SEC  0
+#define TS_FORMAT_USEC 1

-#define USE_STREAM_DEPTH_DISABLED       0
-#define USE_STREAM_DEPTH_ENABLED        1
+#define USE_STREAM_DEPTH_DISABLED 0
+#define USE_STREAM_DEPTH_ENABLED  1

-#define HONOR_PASS_RULES_DISABLED       0
-#define HONOR_PASS_RULES_ENABLED        1
+#define HONOR_PASS_RULES_DISABLED 0
+#define HONOR_PASS_RULES_ENABLED  1

-#define PCAP_SNAPLEN                    262144
-#define PCAP_BUFFER_TIMEOUT             1000000 // microseconds
-#define PCAP_PKTHDR_SIZE                16
+#define PCAP_SNAPLEN        262144
+#define PCAP_BUFFER_TIMEOUT 1000000 // microseconds
+#define PCAP_PKTHDR_SIZE    16

 SC_ATOMIC_DECLARE(uint32_t, thread_cnt);

@@ -111,7 +120,7 @@ typedef struct PcapLogProfileData_ {
     uint64_t cnt;
 } PcapLogProfileData;

-#define MAX_TOKS 9
+#define MAX_TOKS        9
 #define MAX_FILENAMELEN 513

 enum PcapLogCompressionFormat {
@@ -140,11 +149,11 @@ typedef struct PcapLogCompressionData_ {
  * Used for storing file options.
  */
 typedef struct PcapLogData_ {
-    int use_stream_depth;       /**< use stream depth i.e. ignore packets that reach limit */
-    int honor_pass_rules;       /**< don't log if pass rules have matched */
-    int is_private;             /**< TRUE if ctx is thread local */
+    int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */
+    int honor_pass_rules; /**< don't log if pass rules have matched */
+    int is_private;       /**< TRUE if ctx is thread local */
     SCMutex plog_lock;
-    uint64_t pkt_cnt;		    /**< total number of packets */
+    uint64_t pkt_cnt;           /**< total number of packets */
     struct pcap_pkthdr *h;      /**< pcap header struct */
     char *filename;             /**< current filename */
     int mode;                   /**< normal or sguil */
@@ -169,20 +178,28 @@ typedef struct PcapLogData_ {

     TAILQ_HEAD(, PcapFileName_) pcap_file_list;

-    uint32_t thread_number;     /**< thread number, first thread is 1, second 2, etc */
-    int use_ringbuffer;         /**< ring buffer mode enabled or disabled */
-    int timestamp_format;       /**< timestamp format sec or usec */
-    char *prefix;               /**< filename prefix */
-    const char *suffix;         /**< filename suffix */
-    char dir[PATH_MAX];         /**< pcap log directory */
+    uint32_t thread_number; /**< thread number, first thread is 1, second 2, etc */
+    int use_ringbuffer;     /**< ring buffer mode enabled or disabled */
+    int timestamp_format;   /**< timestamp format sec or usec */
+    char *prefix;           /**< filename prefix */
+    const char *suffix;     /**< filename suffix */
+    char dir[PATH_MAX];     /**< pcap log directory */
     int reported;
-    int threads;                /**< number of threads (only set in the global) */
+    int threads; /**< number of threads (only set in the global) */
     char *filename_parts[MAX_TOKS];
     int filename_part_cnt;
     struct timeval last_pcap_dump;
     int fopen_err;      /**< set to the last fopen error */
     bool pcap_open_err; /**< true if the last pcap open errored */

+    uint32_t context_packets_before;     /**< packets to capture before alert */
+    uint32_t context_packets_after;      /**< packets to capture after alert */
+    uint8_t **context_buffer;            /**< circular buffer for context packets */
+    struct pcap_pkthdr *context_headers; /**< headers for context packets */
+    uint32_t context_buffer_size;        /**< size of context buffer */
+    uint32_t context_buffer_pos;         /**< current position in buffer */
+    uint32_t context_buffer_count;       /**< packets stored in buffer */
+
     PcapLogCompressionData compression;
 } PcapLogData;

@@ -209,29 +226,48 @@ static OutputInitResult PcapLogInitCtx(ConfNode *);
 static void PcapLogProfilingDump(PcapLogData *);
 static int PcapLogCondition(ThreadVars *, void *, const Packet *);

+#ifdef UNITTESTS
+static void PcapLogRegisterTests(void);
+#endif
+
 void PcapLogRegister(void)
 {
-    OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log",
-        PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit,
-        PcapLogDataDeinit, NULL);
+    OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", PcapLogInitCtx, PcapLog,
+            PcapLogCondition, PcapLogDataInit, PcapLogDataDeinit, NULL);
+
     PcapLogProfileSetup();
     SC_ATOMIC_INIT(thread_cnt);
     SC_ATOMIC_SET(thread_cnt, 1); /* first id is 1 */
+#ifdef UNITTESTS
+    PcapLogRegisterTests();
+#endif
     return;
 }

-#define PCAPLOG_PROFILE_START \
-    uint64_t pcaplog_profile_ticks = UtilCpuGetTicks()
+#define PCAPLOG_PROFILE_START uint64_t pcaplog_profile_ticks = UtilCpuGetTicks()

-#define PCAPLOG_PROFILE_END(prof) \
-    (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \
+#define PCAPLOG_PROFILE_END(prof)                                                                  \
+    (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks);                                   \
     (prof).cnt++

 static int PcapLogCondition(ThreadVars *tv, void *thread_data, const Packet *p)
 {
     PcapLogThreadData *ptd = (PcapLogThreadData *)thread_data;

-    /* Log alerted flow or tagged flow */
+    /* If context packets are enabled, we need to process all packets to fill the context buffer */
+    if ((ptd->pcap_log->context_packets_before > 0 || ptd->pcap_log->context_packets_after > 0) &&
+            ptd->pcap_log->conditional == LOGMODE_COND_ALERTS) {
+        /* Always process packets when context is enabled, but let PcapLog decide what to write */
+        if (p->flags & PKT_PSEUDO_STREAM_END) {
+            return FALSE;
+        }
+        if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
+            return FALSE;
+        }
+        return TRUE;
+    }
+
+    /* Original conditional logic for when context is not enabled */
     switch (ptd->pcap_log->conditional) {
         case LOGMODE_COND_ALL:
             break;
@@ -280,8 +316,7 @@ static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl)
                 /* pcap_dump_close() has closed its output ``file'',
                  * so we need to call fmemopen again. */

-                comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf,
-                        comp->pcap_buf_size, "w");
+                comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, comp->pcap_buf_size, "w");
                 if (comp->pcap_buf_wrapper == NULL) {
                     SCLogError("SCFmemopen failed: %s", strerror(errno));
                     return TM_ECODE_FAILED;
@@ -302,8 +337,8 @@ static int PcapLogCloseFile(ThreadVars *t, PcapLogData *pl)
             /* pcap_dump_close did not write any data because we call
              * pcap_dump_flush() after every write when writing
              * compressed output. */
-            uint64_t bytes_written = LZ4F_compressEnd(comp->lz4f_context,
-                    comp->buffer, comp->buffer_size, NULL);
+            uint64_t bytes_written =
+                    LZ4F_compressEnd(comp->lz4f_context, comp->buffer, comp->buffer_size, NULL);
             if (LZ4F_isError(bytes_written)) {
                 SCLogError("LZ4F_compressEnd: %s", LZ4F_getErrorName(bytes_written));
                 return TM_ECODE_FAILED;
@@ -354,7 +389,12 @@ static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl)

     PCAPLOG_PROFILE_START;

-    if (PcapLogCloseFile(t,pl) < 0) {
+    /* Ensure all data is flushed before rotation */
+    if (pl->pcap_dumper != NULL) {
+        pcap_dump_flush(pl->pcap_dumper);
+    }
+
+    if (PcapLogCloseFile(t, pl) < 0) {
         SCLogDebug("PcapLogCloseFile failed");
         return -1;
     }
@@ -371,15 +411,15 @@ static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl)

         /* Remove directory if Sguil mode and no files left in sguil dir */
         if (pl->mode == LOGMODE_SGUIL) {
-            pfnext = TAILQ_NEXT(pf,next);
+            pfnext = TAILQ_NEXT(pf, next);

             if (strcmp(pf->dirname, pfnext->dirname) == 0) {
                 SCLogDebug("Current entry dir %s and next entry %s "
-                        "are equal: not removing dir",
+                           "are equal: not removing dir",
                         pf->dirname, pfnext->dirname);
             } else {
                 SCLogDebug("current entry %s and %s are "
-                        "not equal: removing dir",
+                           "not equal: removing dir",
                         pf->dirname, pfnext->dirname);

                 if (remove(pf->dirname) != 0) {
@@ -423,8 +463,7 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p)

     if (pl->pcap_dumper == NULL) {
         if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
-            if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle,
-                    pl->filename)) == NULL) {
+            if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, pl->filename)) == NULL) {
                 if (!pl->pcap_open_err) {
                     SCLogError("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle));
                     pl->pcap_open_err = true;
@@ -462,8 +501,8 @@ static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p)
                 pl->pcap_open_err = false;
             }

-            uint64_t bytes_written = LZ4F_compressBegin(comp->lz4f_context,
-                    comp->buffer, comp->buffer_size, NULL);
+            uint64_t bytes_written =
+                    LZ4F_compressBegin(comp->lz4f_context, comp->buffer, comp->buffer_size, NULL);
             if (LZ4F_isError(bytes_written)) {
                 SCLogError("LZ4F_compressBegin: %s", LZ4F_getErrorName(bytes_written));
                 return TM_ECODE_FAILED;
@@ -506,8 +545,31 @@ static void PcapLogUnlock(PcapLogData *pl)
     }
 }

+/**
+ * \brief Force a flush of the pcap log file
+ *
+ * \param pl PcapLog thread variable.
+ *
+ * \retval TM_ECODE_OK on success
+ * \retval TM_ECODE_FAILED on failure
+ */
+static int PcapLogFlush(PcapLogData *pl)
+{
+    if (pl == NULL || pl->pcap_dumper == NULL)
+        return TM_ECODE_OK;
+
+    SCLogDebug("Flushing pcap file %s", pl->filename ? pl->filename : "(unknown)");
+    pcap_dump_flush(pl->pcap_dumper);
+    return TM_ECODE_OK;
+}
+
+/** \internal
+ *  \brief Write a packet to pcap file
+ *  \param pl PcapLog thread variable
+ *  \param p Packet
+ */
 static inline int PcapWrite(
-        PcapLogData *pl, PcapLogCompressionData *comp, uint8_t *data, size_t len)
+        PcapLogData *pl, PcapLogCompressionData *comp, uint8_t *data, size_t len, bool force_flush)
 {
     struct timeval current_dump;
     gettimeofday(&current_dump, NULL);
@@ -545,8 +607,14 @@ static inline int PcapWrite(
         }
     }
 #endif /* HAVE_LIBLZ4 */
-    if (TimeDifferenceMicros(pl->last_pcap_dump, current_dump) >= PCAP_BUFFER_TIMEOUT) {
+    // Flush in strategic cases:
+    // 1. When explicitly forced (flow end, last after-packet, etc.)
+    // 2. When the time interval has passed
+    // 3. For alert packets and context packets (after packets)
+    if (force_flush ||
+            TimeDifferenceMicros(pl->last_pcap_dump, current_dump) >= PCAP_BUFFER_TIMEOUT) {
         pcap_dump_flush(pl->pcap_dumper);
+        SCLogDebug("PCAP-FLUSH: %s", force_flush ? "forced" : "time-based");
     }
     pl->last_pcap_dump = current_dump;
     return TM_ECODE_OK;
@@ -572,7 +640,8 @@ static int PcapLogSegmentCallback(
         MemBufferWriteRaw(pctx->buf, seg->pcap_hdr_storage->pkt_hdr, seg->pcap_hdr_storage->pktlen);
         MemBufferWriteRaw(pctx->buf, buf, buflen);

-        PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len);
+        // Only flush at true flow endpoints
+        PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len, false);
     }
     return 1;
 }
@@ -598,11 +667,12 @@ static void PcapLogDumpSegments(
  * \retval TM_ECODE_OK on succes
  * \retval TM_ECODE_FAILED on serious error
  */
-static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
+static int PcapLog(ThreadVars *t, void *thread_data, const Packet *p)
 {
     size_t len;
     int rotate = 0;
     int ret = 0;
+    bool do_write = false; /* set to true when this packet must be written */
     Packet *rp = NULL;

     PcapLogThreadData *td = (PcapLogThreadData *)thread_data;
@@ -650,7 +720,7 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
     PcapLogCompressionData *comp = &pl->compression;
     if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
         if ((pl->size_current + len) > pl->size_limit || rotate) {
-            if (PcapLogRotateFile(t,pl) < 0) {
+            if (PcapLogRotateFile(t, pl) < 0) {
                 PcapLogUnlock(pl);
                 SCLogDebug("rotation of pcap failed");
                 return TM_ECODE_FAILED;
@@ -665,9 +735,8 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
          * bytes that have been fed into lz4 since the last write, and
          * act as if they would be written uncompressed. */

-        if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit ||
-                rotate) {
-            if (PcapLogRotateFile(t,pl) < 0) {
+        if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit || rotate) {
+            if (PcapLogRotateFile(t, pl) < 0) {
                 PcapLogUnlock(pl);
                 SCLogDebug("rotation of pcap failed");
                 return TM_ECODE_FAILED;
@@ -687,6 +756,17 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)

     PCAPLOG_PROFILE_START;

+    // NEW: determine if this packet itself should always be written in
+    // conditional modes (alerts or tag based packets).
+    // This has to be done before we possibly early-return based on
+    // the `do_write` flag later on.
+    if (pl->conditional == LOGMODE_COND_ALERTS) {
+        /* Alert packets */
+        if (p->alerts.cnt > 0) {
+            do_write = true;
+        }
+    }
+
     /* if we are using alerted logging and if packet is first one with alert in flow
      * then we need to dump in the pcap the stream acked by the packet */
     if ((p->flags & PKT_FIRST_ALERTS) && (td->pcap_log->conditional != LOGMODE_COND_ALL)) {
@@ -718,18 +798,114 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
         }
     }

+    /* First, handle context packets before writing alert packets */
+    if (p->alerts.cnt > 0 && pl->context_packets_before > 0 && pl->context_buffer != NULL) {
+        /* Calculate how many "before" packets to dump */
+        uint32_t packets_to_dump = (pl->context_buffer_count < pl->context_packets_before)
+                                           ? pl->context_buffer_count
+                                           : pl->context_packets_before;
+
+        /* Calculate start position in circular buffer for oldest packets */
+        uint32_t start_pos;
+        if (pl->context_buffer_count < pl->context_buffer_size) {
+            /* Buffer not full yet, start from beginning */
+            start_pos = 0;
+        } else {
+            /* Buffer is full, start from oldest packet */
+            start_pos = pl->context_buffer_pos;
+        }
+
+        /* Write context packets */
+        for (uint32_t i = 0; i < packets_to_dump; i++) {
+            uint32_t pos = (start_pos + i) % pl->context_buffer_size;
+            struct pcap_pkthdr *ctx_hdr = &pl->context_headers[pos];
+            uint8_t *ctx_data = pl->context_buffer[pos];
+
+            /* Write context packet directly using pcap_dump */
+            if (pl->pcap_dumper != NULL) {
+                pcap_dump((u_char *)pl->pcap_dumper, ctx_hdr, ctx_data);
+                pl->size_current += PCAP_PKTHDR_SIZE + ctx_hdr->caplen;
+            }
+        }
+    }
+
+    /* Store packet in context buffer for future "before" packets (except alert packets in
+     * conditional mode) */
+    /* Store ALL packets in context buffer for future "before" packets, but do this AFTER dumping
+     * "before" packets for alerts */
+    if ((pl->context_packets_before > 0 || pl->context_packets_after > 0) &&
+            pl->context_buffer != NULL) {
+
+        /* Store packets in the context buffer when context is enabled */
+        uint32_t pkt_len =
+                IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p) ? GET_PKT_LEN(p->root) : GET_PKT_LEN(p);
+        if (pkt_len > PCAP_SNAPLEN)
+            pkt_len = PCAP_SNAPLEN;
+
+        /* Store pcap header */
+        pl->context_headers[pl->context_buffer_pos].ts.tv_sec = SCTIME_SECS(p->ts);
+        pl->context_headers[pl->context_buffer_pos].ts.tv_usec = SCTIME_USECS(p->ts);
+        pl->context_headers[pl->context_buffer_pos].caplen = pkt_len;
+        pl->context_headers[pl->context_buffer_pos].len = pkt_len;
+
+        /* Store packet data */
+        const uint8_t *pkt_data = IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p) ? GET_PKT_DATA(p->root)
+                                                                             : GET_PKT_DATA(p);
+        memcpy(pl->context_buffer[pl->context_buffer_pos], pkt_data, pkt_len);
+
+        /* Update circular buffer position */
+        pl->context_buffer_pos = (pl->context_buffer_pos + 1) % pl->context_buffer_size;
+        if (pl->context_buffer_count < pl->context_buffer_size) {
+            pl->context_buffer_count++;
+        }
+    }
+
+    /* Handle "after" packets by checking flow state */
+    if (pl->context_packets_after > 0 && p->flow != NULL) {
+        /* Use the dedicated pcap_after_remaining field */
+        if (p->alerts.cnt > 0) {
+            /* Set "after" packet counter in flow */
+            p->flow->pcap_after_remaining = pl->context_packets_after;
+            SCLogNotice("PCAP-AFTER: alert resets counter to %u (flow %p)",
+                    pl->context_packets_after, (void *)p->flow);
+        } else if (p->flow->pcap_after_remaining > 0) {
+            /* This is an "after" packet - decrement counter */
+            p->flow->pcap_after_remaining--;
+            do_write = true; /* after-packet */
+            SCLogNotice("PCAP-AFTER: wrote after-pkt, remaining=%u (flow %p)",
+                    p->flow->pcap_after_remaining, (void *)p->flow);
+        }
+    }
+
+    /* For conditional modes ensure we only write if required */
+    if (!do_write && pl->conditional != LOGMODE_COND_ALL) {
+        SCLogNotice("PCAP-AFTER: skipped ordinary pkt, remaining=%u (flow %p)",
+                p->flow ? p->flow->pcap_after_remaining : 0, (void *)p->flow);
+
+        PCAPLOG_PROFILE_END(pl->profile_write);
+        PcapLogUnlock(pl);
+        return TM_ECODE_OK;
+    }
+
+    // Strategic flush points:
+    // 1. On flow end (natural termination)
+    // 2. On ALL "after" packets (to ensure context is captured)
+    // 3. On alert packets (since they trigger context tracking)
+    bool should_flush = (p->flags & PKT_PSEUDO_STREAM_END) || (p->alerts.cnt > 0) ||
+                        (p->flow && pl->context_packets_after > 0 &&
+                                p->flow->pcap_after_remaining >= 0 && do_write);
     if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
         rp = p->root;
 #ifdef HAVE_LIBLZ4
-        ret = PcapWrite(pl, comp, GET_PKT_DATA(rp), len);
+        ret = PcapWrite(pl, comp, GET_PKT_DATA(rp), len, should_flush);
 #else
-        ret = PcapWrite(pl, NULL, GET_PKT_DATA(rp), len);
+        ret = PcapWrite(pl, NULL, GET_PKT_DATA(rp), len, should_flush);
 #endif
     } else {
 #ifdef HAVE_LIBLZ4
-        ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len);
+        ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len, should_flush);
 #else
-        ret = PcapWrite(pl, NULL, GET_PKT_DATA(p), len);
+        ret = PcapWrite(pl, NULL, GET_PKT_DATA(p), len, should_flush);
 #endif
     }
     if (ret != TM_ECODE_OK) {
@@ -741,8 +917,8 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
     PCAPLOG_PROFILE_END(pl->profile_write);
     pl->profile_data_size += len;

-    SCLogDebug("pl->size_current %"PRIu64",  pl->size_limit %"PRIu64,
-               pl->size_current, pl->size_limit);
+    SCLogDebug("pl->size_current %" PRIu64 ",  pl->size_limit %" PRIu64, pl->size_current,
+            pl->size_limit);

     PcapLogUnlock(pl);
     return TM_ECODE_OK;
@@ -781,6 +957,39 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl)
     copy->size_limit = pl->size_limit;
     copy->conditional = pl->conditional;

+    /* Copy context settings */
+    copy->context_packets_before = pl->context_packets_before;
+    copy->context_packets_after = pl->context_packets_after;
+    copy->context_buffer_size = pl->context_buffer_size;
+    copy->context_buffer_pos = 0;
+    copy->context_buffer_count = 0;
+
+    /* Allocate context buffers if needed */
+    if (pl->context_buffer_size > 0) {
+        copy->context_buffer = SCCalloc(copy->context_buffer_size, sizeof(uint8_t *));
+        if (copy->context_buffer == NULL) {
+            SCLogError("Failed to allocate context buffer array");
+            goto fail_copy;
+        }
+
+        for (uint32_t i = 0; i < copy->context_buffer_size; i++) {
+            copy->context_buffer[i] = SCMalloc(PCAP_SNAPLEN);
+            if (copy->context_buffer[i] == NULL) {
+                SCLogError("Failed to allocate context buffer slot %u", i);
+                goto fail_copy;
+            }
+        }
+
+        copy->context_headers = SCCalloc(copy->context_buffer_size, sizeof(struct pcap_pkthdr));
+        if (copy->context_headers == NULL) {
+            SCLogError("Failed to allocate context headers");
+            goto fail_copy;
+        }
+    } else {
+        copy->context_buffer = NULL;
+        copy->context_headers = NULL;
+    }
+
     const PcapLogCompressionData *comp = &pl->compression;
     PcapLogCompressionData *copy_comp = &copy->compression;
     copy_comp->format = comp->format;
@@ -798,41 +1007,26 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl)
         copy_comp->buffer = SCMalloc(copy_comp->buffer_size);
         if (copy_comp->buffer == NULL) {
             SCLogError("SCMalloc failed: %s", strerror(errno));
-            SCFree(copy->h);
-            SCFree(copy);
-            return NULL;
+            goto fail_copy;
         }
         copy_comp->pcap_buf = SCMalloc(copy_comp->pcap_buf_size);
         if (copy_comp->pcap_buf == NULL) {
             SCLogError("SCMalloc failed: %s", strerror(errno));
-            SCFree(copy_comp->buffer);
-            SCFree(copy->h);
-            SCFree(copy);
-            return NULL;
+            goto fail_copy;
         }
-        copy_comp->pcap_buf_wrapper = SCFmemopen(copy_comp->pcap_buf,
-                copy_comp->pcap_buf_size, "w");
+        copy_comp->pcap_buf_wrapper =
+                SCFmemopen(copy_comp->pcap_buf, copy_comp->pcap_buf_size, "w");
         if (copy_comp->pcap_buf_wrapper == NULL) {
             SCLogError("SCFmemopen failed: %s", strerror(errno));
-            SCFree(copy_comp->buffer);
-            SCFree(copy_comp->pcap_buf);
-            SCFree(copy->h);
-            SCFree(copy);
-            return NULL;
+            goto fail_copy;
         }

         /* Initialize a new compression context. */

-        LZ4F_errorCode_t errcode =
-               LZ4F_createCompressionContext(&copy_comp->lz4f_context, 1);
+        LZ4F_errorCode_t errcode = LZ4F_createCompressionContext(&copy_comp->lz4f_context, 1);
         if (LZ4F_isError(errcode)) {
             SCLogError("LZ4F_createCompressionContext failed: %s", LZ4F_getErrorName(errcode));
-            fclose(copy_comp->pcap_buf_wrapper);
-            SCFree(copy_comp->buffer);
-            SCFree(copy_comp->pcap_buf);
-            SCFree(copy->h);
-            SCFree(copy);
-            return NULL;
+            goto fail_copy;
         }

         /* Initialize the rest. */
@@ -857,11 +1051,37 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl)

     SCLogDebug("copied, returning %p", copy);
     return copy;
+
+fail_copy:
+    if (copy) {
+        if (copy->context_buffer) {
+            for (uint32_t i = 0; i < copy->context_buffer_size; i++) {
+                SCFree(copy->context_buffer[i]);
+            }
+            SCFree(copy->context_buffer);
+        }
+        SCFree(copy->context_headers);
+#ifdef HAVE_LIBLZ4
+        if (copy->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
+            if (copy->compression.pcap_buf_wrapper) {
+                fclose(copy->compression.pcap_buf_wrapper);
+            }
+            SCFree(copy->compression.buffer);
+            SCFree(copy->compression.pcap_buf);
+            if (copy->compression.lz4f_context) {
+                LZ4F_freeCompressionContext(copy->compression.lz4f_context);
+            }
+        }
+#endif
+        SCFree(copy->prefix);
+        SCFree(copy->h);
+        SCFree(copy);
+    }
+    return NULL;
 }

 #ifdef INIT_RING_BUFFER
-static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs,
-    uint32_t *usecs)
+static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs, uint32_t *usecs)
 {
     char buf[PATH_MAX];
     size_t copylen;
@@ -903,8 +1123,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl)
 {
     char pattern[PATH_MAX];

-    SCLogInfo("Initializing PCAP ring buffer for %s/%s.",
-        pl->dir, pl->prefix);
+    SCLogInfo("Initializing PCAP ring buffer for %s/%s.", pl->dir, pl->prefix);

     strlcpy(pattern, pl->dir, PATH_MAX);
     if (pattern[strlen(pattern) - 1] != '/') {
@@ -926,7 +1145,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl)
                     return TM_ECODE_FAILED;
                 case 'n': {
                     char tmp[PATH_MAX];
-                    snprintf(tmp, PATH_MAX, "%"PRIu32, pl->thread_number);
+                    snprintf(tmp, PATH_MAX, "%" PRIu32, pl->thread_number);
                     strlcat(pattern, tmp, PATH_MAX);
                     break;
                 }
@@ -994,7 +1213,7 @@ static TmEcode PcapLogInitRingBuffer(PcapLogData *pl)
         } else {
             /* Ordered insert. */
             PcapFileName *it = NULL;
-            TAILQ_FOREACH(it, &pl->pcap_file_list, next) {
+            TAILQ_FOREACH (it, &pl->pcap_file_list, next) {
                 if (pf->secs < it->secs) {
                     break;
                 } else if (pf->secs == it->secs && pf->usecs < it->usecs) {
@@ -1197,13 +1416,21 @@ static void PcapLogDataFree(PcapLogData *pl)
         SCFree(pl->compression.buffer);
         fclose(pl->compression.pcap_buf_wrapper);
         SCFree(pl->compression.pcap_buf);
-        LZ4F_errorCode_t errcode =
-                LZ4F_freeCompressionContext(pl->compression.lz4f_context);
+        LZ4F_errorCode_t errcode = LZ4F_freeCompressionContext(pl->compression.lz4f_context);
         if (LZ4F_isError(errcode)) {
             SCLogWarning("Error freeing lz4 context.");
         }
     }
 #endif /* HAVE_LIBLZ4 */
+
+    if (pl->context_buffer) {
+        for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+            SCFree(pl->context_buffer[i]);
+        }
+        SCFree(pl->context_buffer);
+    }
+    SCFree(pl->context_headers);
+
     SCFree(pl);
 }

@@ -1221,7 +1448,10 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data)
     PcapLogData *pl = td->pcap_log;

     if (pl->pcap_dumper != NULL) {
-        if (PcapLogCloseFile(t,pl) < 0) {
+        PcapLogFlush(pl);
+        SCLogNotice("PCAP: flushing at thread cleanup for end of processing");
+
+        if (PcapLogCloseFile(t, pl) < 0) {
             SCLogDebug("PcapLogCloseFile failed");
         }
     }
@@ -1251,7 +1481,6 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data)
     return TM_ECODE_OK;
 }

-
 static int ParseFilename(PcapLogData *pl, const char *filename)
 {
     char *toks[MAX_TOKS] = { NULL };
@@ -1264,7 +1493,7 @@ static int ParseFilename(PcapLogData *pl, const char *filename)

     if (filename) {
         filename_len = strlen(filename);
-        if (filename_len > (MAX_FILENAMELEN-1)) {
+        if (filename_len > (MAX_FILENAMELEN - 1)) {
             SCLogError("invalid filename option. Max filename-length: %d", MAX_FILENAMELEN - 1);
             goto error;
         }
@@ -1278,7 +1507,7 @@ static int ParseFilename(PcapLogData *pl, const char *filename)
             str[s++] = filename[i];

             if (filename[i] == '%') {
-                str[s-1] = '\0';
+                str[s - 1] = '\0';
                 SCLogDebug("filename with %%-sign: %s", str);

                 p = SCStrdup(str);
@@ -1288,19 +1517,20 @@ static int ParseFilename(PcapLogData *pl, const char *filename)

                 s = 0;

-                if (i+1 < (int)strlen(filename)) {
+                if (i + 1 < (int)strlen(filename)) {
                     if (tok >= MAX_TOKS) {
                         SCLogError("invalid filename option. Max 2 %%-sign options");
                         goto error;
                     }

-                    if (filename[i+1] != 'n' && filename[i+1] != 't' && filename[i+1] != 'i') {
+                    if (filename[i + 1] != 'n' && filename[i + 1] != 't' &&
+                            filename[i + 1] != 'i') {
                         SCLogError(
                                 "invalid filename option. Valid %%-sign options: %%n, %%i and %%t");
                         goto error;
                     }
                     str[0] = '%';
-                    str[1] = filename[i+1];
+                    str[1] = filename[i + 1];
                     str[2] = '\0';
                     p = SCStrdup(str);
                     if (p == NULL)
@@ -1320,7 +1550,6 @@ static int ParseFilename(PcapLogData *pl, const char *filename)
             if (tok >= MAX_TOKS) {
                 SCLogError("invalid filename option. Max 3 %%-sign options");
                 goto error;
-
             }
             str[s++] = '\0';
             p = SCStrdup(str);
@@ -1420,8 +1649,9 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
                 exit(EXIT_FAILURE);
             }
             if (pl->size_limit < 4096) {
-                SCLogInfo("pcap-log \"limit\" value of %"PRIu64" assumed to be pre-1.2 "
-                        "style: setting limit to %"PRIu64"mb", pl->size_limit, pl->size_limit);
+                SCLogInfo("pcap-log \"limit\" value of %" PRIu64 " assumed to be pre-1.2 "
+                          "style: setting limit to %" PRIu64 "mb",
+                        pl->size_limit, pl->size_limit);
                 uint64_t size = pl->size_limit * 1024 * 1024;
                 pl->size_limit = size;
             } else if (pl->size_limit < MIN_LIMIT) {
@@ -1463,20 +1693,17 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
                 const char *log_dir = NULL;
                 log_dir = ConfigGetLogDirectory();

-                strlcpy(pl->dir,
-                    log_dir, sizeof(pl->dir));
-                    SCLogInfo("Using log dir %s", pl->dir);
+                strlcpy(pl->dir, log_dir, sizeof(pl->dir));
+                SCLogInfo("Using log dir %s", pl->dir);
             }
         } else {
             if (PathIsAbsolute(s_dir)) {
-                strlcpy(pl->dir,
-                        s_dir, sizeof(pl->dir));
+                strlcpy(pl->dir, s_dir, sizeof(pl->dir));
             } else {
                 const char *log_dir = NULL;
                 log_dir = ConfigGetLogDirectory();

-                snprintf(pl->dir, sizeof(pl->dir), "%s/%s",
-                    log_dir, s_dir);
+                snprintf(pl->dir, sizeof(pl->dir), "%s/%s", log_dir, s_dir);
             }

             struct stat stat_buf;
@@ -1489,8 +1716,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
             SCLogInfo("Using log dir %s", pl->dir);
         }

-        const char *compression_str = ConfNodeLookupChildValue(conf,
-                "compression");
+        const char *compression_str = ConfNodeLookupChildValue(conf, "compression");

         PcapLogCompressionData *comp = &pl->compression;
         if (compression_str == NULL || strcmp(compression_str, "none") == 0) {
@@ -1514,15 +1740,14 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)

             /* Use SCFmemopen so we can make pcap_dump write to a buffer. */

-            comp->pcap_buf_size = sizeof(struct pcap_file_header) +
-                    sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN;
+            comp->pcap_buf_size =
+                    sizeof(struct pcap_file_header) + sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN;
             comp->pcap_buf = SCMalloc(comp->pcap_buf_size);
             if (comp->pcap_buf == NULL) {
                 SCLogError("SCMalloc failed: %s", strerror(errno));
                 exit(EXIT_FAILURE);
             }
-            comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf,
-                    comp->pcap_buf_size, "w");
+            comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, comp->pcap_buf_size, "w");
             if (comp->pcap_buf_wrapper == NULL) {
                 SCLogError("SCFmemopen failed: %s", strerror(errno));
                 exit(EXIT_FAILURE);
@@ -1535,8 +1760,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
             comp->lz4f_prefs.frameInfo.blockMode = LZ4F_blockLinked;
             if (ConfNodeChildValueIsTrue(conf, "lz4-checksum")) {
                 comp->lz4f_prefs.frameInfo.contentChecksumFlag = 1;
-            }
-            else {
+            } else {
                 comp->lz4f_prefs.frameInfo.contentChecksumFlag = 0;
             }
             intmax_t lvl = 0;
@@ -1554,7 +1778,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
             /* Allocate resources for lz4. */

             LZ4F_errorCode_t errcode =
-                LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1);
+                    LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1);

             if (LZ4F_isError(errcode)) {
                 SCLogError("LZ4F_createCompressionContext failed: %s", LZ4F_getErrorName(errcode));
@@ -1563,8 +1787,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)

             /* Calculate the size of the lz4 output buffer. */

-            comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size,
-                    &comp->lz4f_prefs);
+            comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size, &comp->lz4f_prefs);

             comp->buffer = SCMalloc(comp->buffer_size);
             if (unlikely(comp->buffer == NULL)) {
@@ -1584,8 +1807,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
             PcapLogDataFree(pl);
             return result;
 #endif /* HAVE_LIBLZ4 */
-        }
-        else {
+        } else {
             SCLogError("Unsupported pcap-log "
                        "compression format: %s",
                     compression_str);
@@ -1615,19 +1837,51 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf)
                 "Selected pcap-log conditional logging: %s", s_conditional ? s_conditional : "all");
     }

+    const char *context_before = ConfNodeLookupChildValue(conf, "context-packets-before");
+    if (context_before != NULL) {
+        if (StringParseUint32(&pl->context_packets_before, 10, 0, context_before) < 0) {
+            SCLogError("Invalid context-packets-before value: %s", context_before);
+            exit(EXIT_FAILURE);
+        }
+        if (pl->context_packets_before > 0) {
+            pl->context_buffer_size = pl->context_packets_before;
+            pl->context_buffer = SCCalloc(pl->context_buffer_size, sizeof(uint8_t *));
+            pl->context_headers = SCCalloc(pl->context_buffer_size, sizeof(struct pcap_pkthdr));
+            if (!pl->context_buffer || !pl->context_headers) {
+                SCLogError("Failed to allocate context buffer");
+                exit(EXIT_FAILURE);
+            }
+            for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+                pl->context_buffer[i] = SCMalloc(PCAP_SNAPLEN);
+                if (!pl->context_buffer[i]) {
+                    SCLogError("Failed to allocate context packet buffer");
+                    exit(EXIT_FAILURE);
+                }
+            }
+        }
+    }
+
+    const char *context_after = ConfNodeLookupChildValue(conf, "context-packets-after");
+    if (context_after != NULL) {
+        if (StringParseUint32(&pl->context_packets_after, 10, 0, context_after) < 0) {
+            SCLogError("Invalid context-packets-after value: %s", context_after);
+            exit(EXIT_FAILURE);
+        }
+    }
+
     if (ParseFilename(pl, filename) != 0)
         exit(EXIT_FAILURE);

-    SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL ?
-              "Sguil compatible" : (pl->mode == LOGMODE_MULTI ? "multi" : "normal"));
+    SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL
+                                          ? "Sguil compatible"
+                                          : (pl->mode == LOGMODE_MULTI ? "multi" : "normal"));

     uint32_t max_file_limit = DEFAULT_FILE_LIMIT;
     if (conf != NULL) {
         const char *max_number_of_files_s = NULL;
         max_number_of_files_s = ConfNodeLookupChildValue(conf, "max-files");
         if (max_number_of_files_s != NULL) {
-            if (StringParseUint32(&max_file_limit, 10, 0,
-                                        max_number_of_files_s) == -1) {
+            if (StringParseUint32(&max_file_limit, 10, 0, max_number_of_files_s) == -1) {
                 SCLogError("Failed to initialize "
                            "pcap-log output, invalid number of files limit: %s",
                         max_number_of_files_s);
@@ -1708,7 +1962,7 @@ static void PcapLogFileDeInitCtx(OutputCtx *output_ctx)
     PcapLogData *pl = output_ctx->data;

     PcapFileName *pf = NULL;
-    TAILQ_FOREACH(pf, &pl->pcap_file_list, next) {
+    TAILQ_FOREACH (pf, &pl->pcap_file_list, next) {
         SCLogDebug("PCAP files left at exit: %s\n", pf->filename);
     }
     PcapLogDataFree(pl);
@@ -1760,8 +2014,8 @@ static int PcapLogOpenFileCtx(PcapLogData *pl)

         char dirname[32], dirfull[PATH_MAX] = "";

-        snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d",
-                tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday);
+        snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d", tms->tm_year + 1900, tms->tm_mon + 1,
+                tms->tm_mday);

         /* create the filename to use */
         int ret = snprintf(dirfull, sizeof(dirfull), "%s/%s", pl->dir, dirname);
@@ -1814,7 +2068,7 @@ static int PcapLogOpenFileCtx(PcapLogData *pl)

             int i;
             for (i = 0; i < pl->filename_part_cnt; i++) {
-                if (pl->filename_parts[i] == NULL ||strlen(pl->filename_parts[i]) == 0)
+                if (pl->filename_parts[i] == NULL || strlen(pl->filename_parts[i]) == 0)
                     continue;

                 /* handle variables */
@@ -1823,28 +2077,27 @@ static int PcapLogOpenFileCtx(PcapLogData *pl)
                     if (strlen(pl->filename_parts[i]) < 2)
                         continue;

-                    switch(pl->filename_parts[i][1]) {
+                    switch (pl->filename_parts[i][1]) {
                         case 'n':
                             snprintf(str, sizeof(str), "%u", pl->thread_number);
                             break;
-                        case 'i':
-                        {
+                        case 'i': {
                             long thread_id = SCGetThreadIdLong();
-                            snprintf(str, sizeof(str), "%"PRIu64, (uint64_t)thread_id);
+                            snprintf(str, sizeof(str), "%" PRIu64, (uint64_t)thread_id);
                             break;
                         }
                         case 't':
-                        /* create the filename to use */
-                        if (pl->timestamp_format == TS_FORMAT_SEC) {
-                            snprintf(str, sizeof(str), "%" PRIu32, (uint32_t)SCTIME_SECS(ts));
-                        } else {
-                            snprintf(str, sizeof(str), "%" PRIu32 ".%" PRIu32,
-                                    (uint32_t)SCTIME_SECS(ts), (uint32_t)SCTIME_USECS(ts));
-                        }
+                            /* create the filename to use */
+                            if (pl->timestamp_format == TS_FORMAT_SEC) {
+                                snprintf(str, sizeof(str), "%" PRIu32, (uint32_t)SCTIME_SECS(ts));
+                            } else {
+                                snprintf(str, sizeof(str), "%" PRIu32 ".%" PRIu32,
+                                        (uint32_t)SCTIME_SECS(ts), (uint32_t)SCTIME_USECS(ts));
+                            }
                     }
                     strlcat(filename, str, PATH_MAX);

-                /* copy the rest over */
+                    /* copy the rest over */
                 } else {
                     strlcat(filename, pl->filename_parts[i], PATH_MAX);
                 }
@@ -1898,19 +2151,19 @@ char *PcapLogGetFilename(void)

 static int profiling_pcaplog_enabled = 0;
 static int profiling_pcaplog_output_to_file = 0;
-static char *profiling_pcaplog_file_name = NULL;
+static char profiling_pcaplog_file_name[PATH_MAX] = "pcap.log";
 static const char *profiling_pcaplog_file_mode = "a";

 static void FormatNumber(uint64_t num, char *str, size_t size)
 {
     if (num < 1000UL)
-        snprintf(str, size, "%"PRIu64, num);
+        snprintf(str, size, "%" PRIu64, num);
     else if (num < 1000000UL)
-        snprintf(str, size, "%3.1fk", (float)num/1000UL);
+        snprintf(str, size, "%3.1fk", (float)num / 1000UL);
     else if (num < 1000000000UL)
-        snprintf(str, size, "%3.1fm", (float)num/1000000UL);
+        snprintf(str, size, "%3.1fm", (float)num / 1000000UL);
     else
-        snprintf(str, size, "%3.1fb", (float)num/1000000000UL);
+        snprintf(str, size, "%3.1fb", (float)num / 1000000000UL);
 }

 static void ProfileReportPair(FILE *fp, const char *name, PcapLogProfileData *p)
@@ -1922,7 +2175,7 @@ static void ProfileReportPair(FILE *fp, const char *name, PcapLogProfileData *p)
     FormatNumber((uint64_t)p->cnt, cnt_str, sizeof(cnt_str));
     FormatNumber((uint64_t)p->total, ticks_str, sizeof(ticks_str));
     if (p->cnt && p->total)
-        FormatNumber((uint64_t)(p->total/p->cnt), avg_str, sizeof(avg_str));
+        FormatNumber((uint64_t)(p->total / p->cnt), avg_str, sizeof(avg_str));

     fprintf(fp, "%-28s %-10s %-10s %-10s\n", name, cnt_str, avg_str, ticks_str);
 }
@@ -1941,13 +2194,13 @@ static void ProfileReport(FILE *fp, PcapLogData *pl)
 static void FormatBytes(uint64_t num, char *str, size_t size)
 {
     if (num < 1000UL)
-        snprintf(str, size, "%"PRIu64, num);
+        snprintf(str, size, "%" PRIu64, num);
     else if (num < 1048576UL)
-        snprintf(str, size, "%3.1fKiB", (float)num/1000UL);
+        snprintf(str, size, "%3.1fKiB", (float)num / 1000UL);
     else if (num < 1073741824UL)
-        snprintf(str, size, "%3.1fMiB", (float)num/1000000UL);
+        snprintf(str, size, "%3.1fMiB", (float)num / 1000000UL);
     else
-        snprintf(str, size, "%3.1fGiB", (float)num/1000000000UL);
+        snprintf(str, size, "%3.1fGiB", (float)num / 1000000000UL);
 }

 static void PcapLogProfilingDump(PcapLogData *pl)
@@ -1964,25 +2217,24 @@ static void PcapLogProfilingDump(PcapLogData *pl)
             return;
         }
     } else {
-       fp = stdout;
+        fp = stdout;
     }

     /* counters */
     fprintf(fp, "\n\nOperation                    Cnt        Avg ticks  Total ticks\n");
-    fprintf(fp,     "---------------------------- ---------- ---------- -----------\n");
+    fprintf(fp, "---------------------------- ---------- ---------- -----------\n");

     ProfileReport(fp, pl);
     uint64_t total = pl->profile_write.total + pl->profile_rotate.total +
-                     pl->profile_handles.total + pl->profile_open.total +
-                     pl->profile_close.total + pl->profile_lock.total +
-                     pl->profile_unlock.total;
+                     pl->profile_handles.total + pl->profile_open.total + pl->profile_close.total +
+                     pl->profile_lock.total + pl->profile_unlock.total;

     /* overall stats */
-    fprintf(fp, "\nOverall: %"PRIu64" bytes written, average %d bytes per write.\n",
-        pl->profile_data_size, pl->profile_write.cnt ?
-            (int)(pl->profile_data_size / pl->profile_write.cnt) : 0);
-    fprintf(fp, "         PCAP data structure overhead: %"PRIuMAX" per write.\n",
-        (uintmax_t)sizeof(struct pcap_pkthdr));
+    fprintf(fp, "\nOverall: %" PRIu64 " bytes written, average %d bytes per write.\n",
+            pl->profile_data_size,
+            pl->profile_write.cnt ? (int)(pl->profile_data_size / pl->profile_write.cnt) : 0);
+    fprintf(fp, "         PCAP data structure overhead: %" PRIuMAX " per write.\n",
+            (uintmax_t)sizeof(struct pcap_pkthdr));

     /* print total bytes written */
     char bytes_str[32];
@@ -1991,17 +2243,17 @@ static void PcapLogProfilingDump(PcapLogData *pl)

     /* ticks per MiB and GiB */
     uint64_t ticks_per_mib = 0, ticks_per_gib = 0;
-    uint64_t mib = pl->profile_data_size/(1024*1024);
+    uint64_t mib = pl->profile_data_size / (1024 * 1024);
     if (mib)
-        ticks_per_mib = total/mib;
+        ticks_per_mib = total / mib;
     char ticks_per_mib_str[32] = "n/a";
     if (ticks_per_mib > 0)
         FormatNumber(ticks_per_mib, ticks_per_mib_str, sizeof(ticks_per_mib_str));
     fprintf(fp, "         Ticks per MiB: %s\n", ticks_per_mib_str);

-    uint64_t gib = pl->profile_data_size/(1024*1024*1024);
+    uint64_t gib = pl->profile_data_size / (1024 * 1024 * 1024);
     if (gib)
-        ticks_per_gib = total/gib;
+        ticks_per_gib = total / gib;
     char ticks_per_gib_str[32] = "n/a";
     if (ticks_per_gib > 0)
         FormatNumber(ticks_per_gib, ticks_per_gib_str, sizeof(ticks_per_gib_str));
@@ -2013,33 +2265,508 @@ static void PcapLogProfilingDump(PcapLogData *pl)

 void PcapLogProfileSetup(void)
 {
-    ConfNode *conf = ConfGetNode("profiling.pcap-log");
-    if (conf != NULL && ConfNodeChildValueIsTrue(conf, "enabled")) {
-        profiling_pcaplog_enabled = 1;
-        SCLogInfo("pcap-log profiling enabled");
-
-        const char *filename = ConfNodeLookupChildValue(conf, "filename");
-        if (filename != NULL) {
-            const char *log_dir;
-            log_dir = ConfigGetLogDirectory();
-
-            profiling_pcaplog_file_name = SCMalloc(PATH_MAX);
-            if (unlikely(profiling_pcaplog_file_name == NULL)) {
-                FatalError("can't duplicate file name");
+    if (g_pcap_data != NULL) {
+        ConfNode *pcap_conf = ConfGetNode("pcap-log");
+        const char *prof = NULL;
+        if (pcap_conf != NULL) {
+            prof = ConfNodeLookupChildValue(pcap_conf, "profiling");
+        }
+        if (prof != NULL && ConfValIsTrue(prof)) {
+            profiling_pcaplog_enabled = 1;
+            SCLogInfo("pcap-log profiling is enabled");
+
+            const char *file = ConfNodeLookupChildValue(pcap_conf, "profiling-file");
+            if (file != NULL) {
+                if (strcmp(file, "stdout") == 0) {
+                    profiling_pcaplog_output_to_file = 0;
+                } else {
+                    profiling_pcaplog_output_to_file = 1;
+                    strlcpy(profiling_pcaplog_file_name, file, sizeof(profiling_pcaplog_file_name));
+
+                    const char *v = ConfNodeLookupChildValue(pcap_conf, "profiling-append");
+                    if (v != NULL && ConfValIsTrue(v)) {
+                        profiling_pcaplog_file_mode = "a";
+                    } else {
+                        profiling_pcaplog_file_mode = "w";
+                    }
+                }
             }

-            snprintf(profiling_pcaplog_file_name, PATH_MAX, "%s/%s", log_dir, filename);
+            profiling_pcaplog_output_to_file = 1;
+            SCLogInfo("pcap-log profiling output goes to %s (mode %s)", profiling_pcaplog_file_name,
+                    profiling_pcaplog_file_mode);
+        }
+    }
+}
+#ifdef UNITTESTS

-            const char *v = ConfNodeLookupChildValue(conf, "append");
-            if (v == NULL || ConfValIsTrue(v)) {
-                profiling_pcaplog_file_mode = "a";
-            } else {
-                profiling_pcaplog_file_mode = "w";
+/**
+ * \test PcapLogContextConfigParsingTest01 tests context packet configuration parsing
+ */
+static int PcapLogContextConfigParsingTest01(void)
+{
+    ConfCreateContextBackup();
+    ConfInit();
+
+    // Create ConfNode manually instead of parsing YAML
+    ConfNode *pcap_node = ConfNodeNew();
+    FAIL_IF(pcap_node == NULL);
+
+    pcap_node->name = SCStrdup("pcap-log");
+    FAIL_IF(pcap_node->name == NULL);
+
+    ConfNode *enabled = ConfNodeNew();
+    enabled->name = SCStrdup("enabled");
+    enabled->val = SCStrdup("yes");
+    TAILQ_INSERT_TAIL(&pcap_node->head, enabled, next);
+
+    ConfNode *filename = ConfNodeNew();
+    filename->name = SCStrdup("filename");
+    filename->val = SCStrdup("test.pcap");
+    TAILQ_INSERT_TAIL(&pcap_node->head, filename, next);
+
+    ConfNode *context_before = ConfNodeNew();
+    context_before->name = SCStrdup("context-packets-before");
+    context_before->val = SCStrdup("5");
+    TAILQ_INSERT_TAIL(&pcap_node->head, context_before, next);
+
+    ConfNode *context_after = ConfNodeNew();
+    context_after->name = SCStrdup("context-packets-after");
+    context_after->val = SCStrdup("3");
+    TAILQ_INSERT_TAIL(&pcap_node->head, context_after, next);
+
+    // Test configuration parsing
+    OutputInitResult result = PcapLogInitCtx(pcap_node);
+    FAIL_IF(result.ctx == NULL);
+
+    PcapLogData *pl = (PcapLogData *)result.ctx->data;
+    FAIL_IF(pl->context_packets_before != 5);
+    FAIL_IF(pl->context_packets_after != 3);
+    FAIL_IF(pl->context_buffer_size != 5);
+    FAIL_IF(pl->context_buffer == NULL);
+    FAIL_IF(pl->context_headers == NULL);
+
+    // Cleanup
+    PcapLogFileDeInitCtx(result.ctx);
+    ConfRestoreContextBackup();
+
+    PASS;
+}
+
+/**
+ * \test PcapLogContextCircularBufferTest01 tests circular buffer logic for context packets
+ */
+static int PcapLogContextCircularBufferTest01(void)
+{
+    PcapLogData *pl = SCCalloc(1, sizeof(PcapLogData));
+    FAIL_IF(pl == NULL);
+
+    pl->context_packets_before = 3;
+    pl->context_buffer_size = 3;
+    pl->context_buffer_pos = 0;
+    pl->context_buffer_count = 0;
+    pl->conditional = LOGMODE_COND_ALERTS;
+
+    pl->context_buffer = SCCalloc(3, sizeof(uint8_t *));
+    FAIL_IF(pl->context_buffer == NULL);
+
+    for (uint32_t i = 0; i < 3; i++) {
+        pl->context_buffer[i] = SCMalloc(100);
+        FAIL_IF(pl->context_buffer[i] == NULL);
+    }
+
+    pl->context_headers = SCCalloc(3, sizeof(struct pcap_pkthdr));
+    FAIL_IF(pl->context_headers == NULL);
+
+    pl->h = SCMalloc(sizeof(struct pcap_pkthdr));
+    FAIL_IF(pl->h == NULL);
+
+    // Test circular buffer behavior with packet storage
+    // Store 5 packets in a buffer of size 3 (buffer should wrap around)
+    for (uint32_t i = 0; i < 5; i++) {
+        // Simulate storing a packet
+        pl->context_headers[pl->context_buffer_pos].ts.tv_sec = i + 1000;
+        pl->context_headers[pl->context_buffer_pos].ts.tv_usec = i;
+        pl->context_headers[pl->context_buffer_pos].caplen = 64;
+        pl->context_headers[pl->context_buffer_pos].len = 64;
+
+        // Fill buffer with test pattern
+        memset(pl->context_buffer[pl->context_buffer_pos], i + 1, 64);
+
+        pl->context_buffer_pos = (pl->context_buffer_pos + 1) % pl->context_buffer_size;
+        if (pl->context_buffer_count < pl->context_buffer_size) {
+            pl->context_buffer_count++;
+        }
+    }
+
+    // After storing 5 packets in buffer of size 3:
+    // - buffer_pos should be 2 (5 % 3)
+    // - buffer_count should be 3 (full)
+    // - packets at positions 2,0,1 should contain data for packets 3,4,5
+    FAIL_IF(pl->context_buffer_pos != 2);
+    FAIL_IF(pl->context_buffer_count != 3);
+
+    // Check that the oldest packets are at the correct positions
+    FAIL_IF(pl->context_headers[2].ts.tv_sec != 1002); // packet 3
+    FAIL_IF(pl->context_headers[0].ts.tv_sec != 1003); // packet 4
+    FAIL_IF(pl->context_headers[1].ts.tv_sec != 1004); // packet 5
+
+    // Test buffer start position calculation for dumping "before" packets
+    uint32_t packets_to_dump = 3;
+    uint32_t start_pos;
+
+    // Buffer is full, so start from oldest packet
+    if (pl->context_buffer_count < pl->context_buffer_size) {
+        start_pos = 0;
+    } else {
+        start_pos = pl->context_buffer_pos;
+    }
+
+    // start_pos should be 2 (position of oldest packet)
+    FAIL_IF(start_pos != 2);
+
+    // Verify the order of packets when dumping
+    for (uint32_t i = 0; i < packets_to_dump; i++) {
+        uint32_t pos = (start_pos + i) % pl->context_buffer_size;
+        uint32_t expected_timestamp = 1002 + i; // packets 3, 4, 5
+        FAIL_IF(pl->context_headers[pos].ts.tv_sec != expected_timestamp);
+    }
+
+    // Cleanup
+    for (uint32_t i = 0; i < 3; i++) {
+        SCFree(pl->context_buffer[i]);
+    }
+    SCFree(pl->context_buffer);
+    SCFree(pl->context_headers);
+    SCFree(pl->h);
+    SCFree(pl);
+
+    PASS;
+}
+
+/**
+ * \test PcapLogContextConditionalModeTest01 tests that context only works in conditional mode
+ */
+static int PcapLogContextConditionalModeTest01(void)
+{
+    PcapLogData *pl = SCCalloc(1, sizeof(PcapLogData));
+    FAIL_IF(pl == NULL);
+
+    pl->context_packets_before = 5;
+    pl->context_packets_after = 3;
+
+    // Test 1: LOGMODE_COND_ALL should not enable context
+    pl->conditional = LOGMODE_COND_ALL;
+
+    // Simulate the logic from PcapLog function
+    bool should_use_context = (pl->context_packets_before > 0 || pl->context_packets_after > 0) &&
+                              pl->conditional != LOGMODE_COND_ALL;
+
+    FAIL_IF(should_use_context == true); // Should be false
+
+    // Test 2: LOGMODE_COND_ALERTS should enable context
+    pl->conditional = LOGMODE_COND_ALERTS;
+
+    should_use_context = (pl->context_packets_before > 0 || pl->context_packets_after > 0) &&
+                         pl->conditional == LOGMODE_COND_ALERTS;
+
+    FAIL_IF(should_use_context == false); // Should be true
+
+    // Test 3: LOGMODE_COND_TAG should not enable context now
+    pl->conditional = LOGMODE_COND_TAG;
+
+    should_use_context = (pl->context_packets_before > 0 || pl->context_packets_after > 0) &&
+                         pl->conditional == LOGMODE_COND_ALERTS;
+
+    FAIL_IF(should_use_context == true); // Should be false
+
+    SCFree(pl);
+    PASS;
+}
+
+/**
+ * \test PcapLogContextAfterPacketsTest01 tests "after" packet functionality using flow tracking
+ */
+static int PcapLogContextAfterPacketsTest01(void)
+{
+    // Create a mock flow structure for testing
+    Flow flow;
+    memset(&flow, 0, sizeof(Flow));
+
+    PcapLogData *pl = SCCalloc(1, sizeof(PcapLogData));
+    FAIL_IF(pl == NULL);
+
+    pl->context_packets_after = 3;
+    pl->conditional = LOGMODE_COND_ALERTS;
+
+    // Test scenario: Packet with alert sets "after" counter in flow
+    flow.pcap_after_remaining = 0; // Initially no after packets
+
+    // Simulate alert packet - should set after counter
+    uint32_t alert_count = 1;
+    if (alert_count > 0) {
+        flow.pcap_after_remaining = pl->context_packets_after;
+    }
+
+    FAIL_IF(flow.pcap_after_remaining != 3); // Should be set to 3
+
+    // Test scenario: Subsequent packets should decrement counter
+    for (int i = 0; i < 3; i++) {
+        bool should_log = false;
+
+        // Simulate non-alert packet in same flow
+        if (flow.pcap_after_remaining > 0) {
+            flow.pcap_after_remaining--;
+            should_log = true; // Should be logged as "after" packet
+        }
+
+        FAIL_IF(should_log == false);                            // Should be true for after packets
+        FAIL_IF(flow.pcap_after_remaining != (uint32_t)(2 - i)); // Should decrement each time
+    }
+
+    // After 3 packets, counter should be 0 and no more packets should be logged
+    bool should_log = false;
+    if (flow.pcap_after_remaining > 0) {
+        should_log = true;
+    }
+
+    FAIL_IF(should_log == true); // Should be false now
+
+    SCFree(pl);
+    PASS;
+}
+/**
+ * \test PcapLogContextBufferAllocationTest01 tests proper memory allocation for context buffers
+ */
+static int PcapLogContextBufferAllocationTest01(void)
+{
+    PcapLogData *pl = SCCalloc(1, sizeof(PcapLogData));
+    FAIL_IF(pl == NULL);
+
+    pl->context_packets_before = 10;
+    pl->context_buffer_size = 10;
+
+    // Test buffer allocation
+    pl->context_buffer = SCCalloc(pl->context_buffer_size, sizeof(uint8_t *));
+    FAIL_IF(pl->context_buffer == NULL);
+
+    for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+        pl->context_buffer[i] = SCMalloc(PCAP_SNAPLEN);
+        FAIL_IF(pl->context_buffer[i] == NULL);
+
+        // Test write access to allocated memory
+        memset(pl->context_buffer[i], i % 256, PCAP_SNAPLEN);
+    }
+
+    pl->context_headers = SCCalloc(pl->context_buffer_size, sizeof(struct pcap_pkthdr));
+    FAIL_IF(pl->context_headers == NULL);
+
+    // Test header array access
+    for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+        pl->context_headers[i].ts.tv_sec = i + 1000;
+        pl->context_headers[i].caplen = 64;
+        pl->context_headers[i].len = 64;
+    }
+
+    // Verify data integrity
+    for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+        FAIL_IF(pl->context_headers[i].ts.tv_sec != (i + 1000));
+        FAIL_IF(pl->context_headers[i].caplen != 64);
+        FAIL_IF(pl->context_buffer[i][0] != (i % 256));
+        FAIL_IF(pl->context_buffer[i][PCAP_SNAPLEN - 1] != (i % 256));
+    }
+
+    // Test cleanup
+    for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+        SCFree(pl->context_buffer[i]);
+    }
+    SCFree(pl->context_buffer);
+    SCFree(pl->context_headers);
+    SCFree(pl);
+
+    PASS;
+}
+
+/**
+ * \test PcapLogContextConfigDisabledTest01 tests that context is not enabled by default
+ */
+static int PcapLogContextConfigDisabledTest01(void)
+{
+    ConfCreateContextBackup();
+    ConfInit();
+
+    // Create ConfNode manually instead of parsing YAML
+    ConfNode *pcap_node = ConfNodeNew();
+    FAIL_IF(pcap_node == NULL);
+
+    pcap_node->name = SCStrdup("pcap-log");
+    FAIL_IF(pcap_node->name == NULL);
+
+    ConfNode *enabled = ConfNodeNew();
+    enabled->name = SCStrdup("enabled");
+    enabled->val = SCStrdup("yes");
+    TAILQ_INSERT_TAIL(&pcap_node->head, enabled, next);
+
+    ConfNode *filename = ConfNodeNew();
+    filename->name = SCStrdup("filename");
+    filename->val = SCStrdup("test.pcap");
+    TAILQ_INSERT_TAIL(&pcap_node->head, filename, next);
+
+    // Test configuration parsing without context settings
+    OutputInitResult result = PcapLogInitCtx(pcap_node);
+    FAIL_IF(result.ctx == NULL);
+
+    PcapLogData *pl = (PcapLogData *)result.ctx->data;
+    FAIL_IF(pl->context_packets_before != 0);
+    FAIL_IF(pl->context_packets_after != 0);
+    FAIL_IF(pl->context_buffer_size != 0);
+    FAIL_IF(pl->context_buffer != NULL);
+    FAIL_IF(pl->context_headers != NULL);
+
+    // Cleanup
+    PcapLogFileDeInitCtx(result.ctx);
+    ConfRestoreContextBackup();
+
+    PASS;
+}
+
+static int PcapLogContextAfterWriteTest01(void)
+{
+    /* Prepare minimal PcapLogData with after-packet support */
+    PcapLogData pl; // stack allocation is fine for test
+    memset(&pl, 0, sizeof(pl));
+    pl.context_packets_after = 3;
+    pl.conditional = LOGMODE_COND_ALERTS;
+
+    /* Dummy pcap header pointer required by some helper macros */
+    pl.h = SCMalloc(sizeof(*pl.h));
+    FAIL_IF(pl.h == NULL);
+
+    /* Create single Flow shared by our packets */
+    Flow f;
+    memset(&f, 0, sizeof(f));
+
+    /* Build 4 packet stubs: 1 alert + 3 regular */
+    Packet pkts[4];
+    memset(pkts, 0, sizeof(pkts));
+    for (int i = 0; i < 4; i++) {
+        Packet *p = &pkts[i];
+        p->flow = &f;
+        p->datalink = DLT_RAW; /* non-zero */
+        p->payload_len = 0;
+        p->pktlen = 0;
+        p->ts.secs = 0;
+        p->ts.usecs = i;
+    }
+    pkts[0].alerts.cnt = 1; /* first pkt has alert */
+
+    uint32_t write_cnt = 0;
+
+    for (int i = 0; i < 4; i++) {
+        Packet *p = &pkts[i];
+        bool do_write = false;
+
+        /* Replicate the after-packet branch from PcapLog() */
+        if (pl.context_packets_after > 0 && p->flow != NULL) {
+            if (p->alerts.cnt > 0) {
+                p->flow->pcap_after_remaining = pl.context_packets_after;
+                do_write = true; /* alert packet */
+            } else if (p->flow->pcap_after_remaining > 0) {
+                p->flow->pcap_after_remaining--;
+                do_write = true; /* after packet */
             }
+        }
+        if (do_write)
+            write_cnt++;
+    }

-            profiling_pcaplog_output_to_file = 1;
-            SCLogInfo("pcap-log profiling output goes to %s (mode %s)",
-                    profiling_pcaplog_file_name, profiling_pcaplog_file_mode);
+    /* We expect 4 writes: 1 alert + 3 after packets */
+    FAIL_IF(write_cnt != 4);
+    FAIL_IF(f.pcap_after_remaining != 0);
+
+    SCFree(pl.h);
+    PASS;
+}
+
+/**
+ * \test PcapLogContextBeforeBufferNotFullTest01 tests "before" packet dumping when buffer is not
+ * full
+ */
+static int PcapLogContextBeforeBufferNotFullTest01(void)
+{
+    PcapLogData *pl = SCCalloc(1, sizeof(PcapLogData));
+    FAIL_IF(pl == NULL);
+
+    pl->context_packets_before = 5;
+    pl->context_buffer_size = 5;
+    pl->context_buffer_pos = 0;
+    pl->context_buffer_count = 0;
+    pl->conditional = LOGMODE_COND_ALERTS;
+
+    pl->context_buffer = SCCalloc(pl->context_buffer_size, sizeof(uint8_t *));
+    FAIL_IF(pl->context_buffer == NULL);
+    for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+        pl->context_buffer[i] = SCMalloc(100);
+        FAIL_IF(pl->context_buffer[i] == NULL);
+    }
+    pl->context_headers = SCCalloc(pl->context_buffer_size, sizeof(struct pcap_pkthdr));
+    FAIL_IF(pl->context_headers == NULL);
+
+    // Simulate storing 3 packets in a buffer of size 5
+    for (uint32_t i = 0; i < 3; i++) {
+        pl->context_headers[pl->context_buffer_pos].ts.tv_sec = i + 2000;
+        pl->context_buffer_pos = (pl->context_buffer_pos + 1) % pl->context_buffer_size;
+        if (pl->context_buffer_count < pl->context_buffer_size) {
+            pl->context_buffer_count++;
         }
     }
+
+    FAIL_IF(pl->context_buffer_pos != 3);
+    FAIL_IF(pl->context_buffer_count != 3);
+
+    // Simulate an alert and check the logic for dumping "before" packets
+    uint32_t packets_to_dump = (pl->context_buffer_count < pl->context_packets_before)
+                                       ? pl->context_buffer_count
+                                       : pl->context_packets_before;
+    FAIL_IF(packets_to_dump != 3);
+
+    uint32_t start_pos;
+    if (pl->context_buffer_count < pl->context_buffer_size) {
+        start_pos = 0;
+    } else {
+        start_pos = pl->context_buffer_pos;
+    }
+    FAIL_IF(start_pos != 0);
+
+    // Verify correct packets would be dumped
+    for (uint32_t i = 0; i < packets_to_dump; i++) {
+        uint32_t pos = (start_pos + i) % pl->context_buffer_size;
+        uint32_t expected_timestamp = 2000 + i;
+        FAIL_IF(pl->context_headers[pos].ts.tv_sec != expected_timestamp);
+    }
+
+    // Cleanup
+    for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
+        SCFree(pl->context_buffer[i]);
+    }
+    SCFree(pl->context_buffer);
+    SCFree(pl->context_headers);
+    SCFree(pl);
+
+    PASS;
 }
+
+void PcapLogRegisterTests(void)
+{
+    UtRegisterTest("PcapLogContextConfigParsingTest01", PcapLogContextConfigParsingTest01);
+    UtRegisterTest("PcapLogContextCircularBufferTest01", PcapLogContextCircularBufferTest01);
+    UtRegisterTest("PcapLogContextConditionalModeTest01", PcapLogContextConditionalModeTest01);
+    UtRegisterTest("PcapLogContextAfterPacketsTest01", PcapLogContextAfterPacketsTest01);
+    UtRegisterTest("PcapLogContextBufferAllocationTest01", PcapLogContextBufferAllocationTest01);
+    UtRegisterTest("PcapLogContextConfigDisabledTest01", PcapLogContextConfigDisabledTest01);
+    UtRegisterTest("PcapLogContextAfterWriteTest01", PcapLogContextAfterWriteTest01);
+    UtRegisterTest(
+            "PcapLogContextBeforeBufferNotFullTest01", PcapLogContextBeforeBufferNotFullTest01);
+}
+
+#endif /* UNITTESTS */
