]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
af-packet: avoid flag colision with kernel 6604/head
authorVictor Julien <victor@inliniac.net>
Sun, 31 Oct 2021 09:28:18 +0000 (10:28 +0100)
committerVictor Julien <vjulien@oisf.net>
Fri, 12 Nov 2021 10:51:10 +0000 (11:51 +0100)
Avoid colision of TP_STATUS_USER_BUSY with TP_STATUS_TS_RAW_HARDWARE,
both were using bit 31.

Bug: #4800.
(cherry picked from commit ad862fff371cddd19329d9ac0ddb106e1ad6b1b3)

src/source-af-packet.c

index ad84667b854c372a4e190b56bdb8550904f33d42..0cd3234fc8ef3098f3b48bb0bdb839682b80d5c5 100644 (file)
@@ -212,9 +212,23 @@ TmEcode NoAFPSupportExit(ThreadVars *tv, const void *initdata, void **data)
 #endif
 
 #ifndef TP_STATUS_USER_BUSY
-/* for new use latest bit available in tp_status */
-#define TP_STATUS_USER_BUSY     BIT_U32(31)
+/* HACK special setting in the tp_status field for frames we are
+ * still working on. This can happen in autofp mode where the
+ * capture thread goes around the ring and finds a frame that still
+ * hasn't been released by a worker thread.
+ *
+ * We use bits 29, 30, 31. 29 and 31 are software and hardware
+ * timestamps. 30 should not be set by the kernel at all. Combined
+ * they should never be set on the rx-ring together.
+ *
+ * The excessive casting is for handling the fact that the kernel
+ * defines almost all of these as int flags, not unsigned ints. */
+#define TP_STATUS_USER_BUSY                                                                        \
+    (uint32_t)((uint32_t)TP_STATUS_TS_SOFTWARE | (uint32_t)TP_STATUS_TS_SYS_HARDWARE |             \
+               (uint32_t)TP_STATUS_TS_RAW_HARDWARE)
 #endif
+#define FRAME_BUSY(tp_status)                                                                      \
+    (((uint32_t)(tp_status) & (uint32_t)TP_STATUS_USER_BUSY) == (uint32_t)TP_STATUS_USER_BUSY)
 
 enum {
     AFP_READ_OK,
@@ -374,7 +388,6 @@ void TmModuleReceiveAFPRegister (void)
 
 }
 
-
 /**
  *  \defgroup afppeers AFP peers list
  *
@@ -923,9 +936,9 @@ static bool AFPReadFromRingSetupPacket(
 {
     PKT_SET_SRC(p, PKT_SRC_WIRE);
 
-    /* Suricata will treat packet so telling it is busy, this
-     * status will be reset to 0 (ie TP_STATUS_KERNEL) in the release
-     * function. */
+    /* flag the packet as TP_STATUS_USER_BUSY, which is ignore by the kernel, but
+     * acts as an indicator that we've reached a frame that is not yet released by
+     * us in autofp mode. It will be cleared when the frame gets released to the kernel. */
     h.h2->tp_status |= TP_STATUS_USER_BUSY;
     p->livedev = ptv->livedev;
     p->datalink = ptv->datalink;
@@ -1054,7 +1067,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
             break;
         }
         /* if in autofp mode the frame is still busy, return to poll */
-        if (unlikely(tp_status & TP_STATUS_USER_BUSY)) {
+        if (unlikely(FRAME_BUSY(tp_status))) {
             break;
         }
         emergency_flush |= ((tp_status & TP_STATUS_LOSING) != 0);