Ejemplo n.º 1
0
/**
 *  \brief Main PCAP reading Loop function
 */
TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    int packet_q_len = 64;
    PcapThreadVars *ptv = (PcapThreadVars *)data;
    int r;
    TmSlot *s = (TmSlot *)slot;

    ptv->slot = s->slot_next;
    ptv->cb_result = TM_ECODE_OK;

    while (1) {
        if (suricata_ctl_flags & SURICATA_STOP) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        /* Right now we just support reading packets one at a time. */
        r = pcap_dispatch(ptv->pcap_handle, packet_q_len,
                          (pcap_handler)PcapCallbackLoop, (u_char *)ptv);
        if (unlikely(r < 0)) {
            int dbreak = 0;
            SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
                       r, pcap_geterr(ptv->pcap_handle));
#ifdef PCAP_ERROR_BREAK
            if (r == PCAP_ERROR_BREAK) {
                SCReturnInt(ptv->cb_result);
            }
#endif
            do {
                usleep(PCAP_RECONNECT_TIMEOUT);
                if (suricata_ctl_flags != 0) {
                    dbreak = 1;
                    break;
                }
                r = PcapTryReopen(ptv);
            } while (r < 0);
            if (dbreak) {
                break;
            }
        } else if (ptv->cb_result == TM_ECODE_FAILED) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapCallbackLoop failed");
            SCReturnInt(TM_ECODE_FAILED);
        } else if (unlikely(r == 0)) {
            TmThreadsCaptureInjectPacket(tv, ptv->slot, NULL);
        }

        StatsSyncCountersIfSignalled(tv);
    }

    PcapDumpCounters(ptv);
    StatsSyncCountersIfSignalled(tv);
    SCReturnInt(TM_ECODE_OK);
}
Ejemplo n.º 2
0
/**
 *  \brief Main PCAP file reading Loop function
 */
TmEcode PcapFileDispatch(PcapFileFileVars *ptv)
{
    SCEnter();

    int packet_q_len = 64;
    int r;
    TmEcode loop_result = TM_ECODE_OK;
    strlcpy(pcap_filename, ptv->filename, sizeof(pcap_filename));

    while (loop_result == TM_ECODE_OK) {
        if (suricata_ctl_flags & SURICATA_STOP) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        /* Right now we just support reading packets one at a time. */
        r = pcap_dispatch(ptv->pcap_handle, packet_q_len,
                          (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv);
        if (unlikely(r == -1)) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s for %s",
                       r, pcap_geterr(ptv->pcap_handle), ptv->filename);
            if (ptv->shared->cb_result == TM_ECODE_FAILED) {
                SCReturnInt(TM_ECODE_FAILED);
            }
            loop_result = TM_ECODE_DONE;
        } else if (unlikely(r == 0)) {
            SCLogInfo("pcap file %s end of file reached (pcap err code %" PRId32 ")",
                      ptv->filename, r);
            ptv->shared->files++;
            loop_result = TM_ECODE_DONE;
        } else if (ptv->shared->cb_result == TM_ECODE_FAILED) {
            SCLogError(SC_ERR_PCAP_DISPATCH,
                       "Pcap callback PcapFileCallbackLoop failed for %s", ptv->filename);
            loop_result = TM_ECODE_FAILED;
        }
        StatsSyncCountersIfSignalled(ptv->shared->tv);
    }

    SCReturnInt(loop_result);
}
Ejemplo n.º 3
0
/**
 *  \brief Main NFQ reading Loop function
 */
TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();
    NFQThreadVars *ntv = (NFQThreadVars *)data;
    NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index);

    ntv->slot = ((TmSlot *) slot)->slot_next;

    while(1) {
        if (suricata_ctl_flags != 0) {
            NFQDestroyQueue(nq);
            break;
        }
        NFQRecvPkt(nq, ntv);

        StatsSyncCountersIfSignalled(tv);
    }
    SCReturnInt(TM_ECODE_OK);
}
Ejemplo n.º 4
0
/* same as 'simple' */
Packet *TmqhInputFlow(ThreadVars *tv)
{
    PacketQueue *q = &trans_q[tv->inq->id];

    StatsSyncCountersIfSignalled(tv);

    SCMutexLock(&q->mutex_q);
    if (q->len == 0) {
        /* if we have no packets in queue, wait... */
        SCCondWait(&q->cond_q, &q->mutex_q);
    }

    if (q->len > 0) {
        Packet *p = PacketDequeue(q);
        SCMutexUnlock(&q->mutex_q);
        return p;
    } else {
        /* return NULL if we have no pkt. Should only happen on signals. */
        SCMutexUnlock(&q->mutex_q);
        return NULL;
    }
}
Ejemplo n.º 5
0
/**
 * \brief Recieves packets from an interface via libpfring.
 *
 *  This function recieves packets from an interface and passes
 *  the packet on to the pfring callback function.
 *
 * \param tv pointer to ThreadVars
 * \param data pointer that gets cast into PfringThreadVars for ptv
 * \param slot slot containing task information
 * \retval TM_ECODE_OK on success
 * \retval TM_ECODE_FAILED on failure
 */
TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    PfringThreadVars *ptv = (PfringThreadVars *)data;
    Packet *p = NULL;
    struct pfring_pkthdr hdr;
    TmSlot *s = (TmSlot *)slot;
    time_t last_dump = 0;
    u_int buffer_size;
    u_char *pkt_buffer;

    ptv->slot = s->slot_next;

    /* we have to enable the ring here as we need to do it after all
     * the threads have called pfring_set_cluster(). */
    int rc = pfring_enable_ring(ptv->pd);
    if (rc != 0) {
        SCLogError(SC_ERR_PF_RING_OPEN, "pfring_enable_ring failed returned %d ", rc);
        SCReturnInt(TM_ECODE_FAILED);
    }

    while(1) {
        if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        p = PacketGetFromQueueOrAlloc();
        if (p == NULL) {
            SCReturnInt(TM_ECODE_FAILED);
        }
        PKT_SET_SRC(p, PKT_SRC_WIRE);

        /* Some flavours of PF_RING may fail to set timestamp - see PF-RING-enabled libpcap code*/
        hdr.ts.tv_sec = hdr.ts.tv_usec = 0;

        /* Check for Zero-copy mode */
        if (ptv->flags & PFRING_FLAGS_ZERO_COPY) {
            buffer_size = 0;
            pkt_buffer = NULL;
        } else {
            buffer_size = GET_PKT_DIRECT_MAX_SIZE(p);
            pkt_buffer = GET_PKT_DIRECT_DATA(p);
        }

        int r = pfring_recv(ptv->pd, &pkt_buffer,
                buffer_size,
                &hdr,
                LIBPFRING_WAIT_FOR_INCOMING);
        if (likely(r == 1)) {
            /* profiling started before blocking pfring_recv call, so
             * reset it here */
            PACKET_PROFILING_RESTART(p);

            /* Check for Zero-copy mode */
            if (ptv->flags & PFRING_FLAGS_ZERO_COPY) {
                PacketSetData(p, pkt_buffer, hdr.caplen);
            }

            //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n",
            //        hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port);

            PfringProcessPacket(ptv, &hdr, p);

            if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
                TmqhOutputPacketpool(ptv->tv, p);
                SCReturnInt(TM_ECODE_FAILED);
            }

            /* Trigger one dump of stats every second */
            if (p->ts.tv_sec != last_dump) {
                PfringDumpCounters(ptv);
                last_dump = p->ts.tv_sec;
            }
        } else if (unlikely(r == 0)) {
            if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
                SCReturnInt(TM_ECODE_OK);
            }

            /* pfring didn't use the packet yet */
            TmThreadsCaptureInjectPacket(tv, ptv->slot, p);

        } else {
            SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error  %" PRId32 "", r);
            TmqhOutputPacketpool(ptv->tv, p);
            SCReturnInt(TM_ECODE_FAILED);
        }
        StatsSyncCountersIfSignalled(tv);
    }

    return TM_ECODE_OK;
}
Ejemplo n.º 6
0
/**
 *  \brief Main PCAP file reading Loop function
 */
TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    int packet_q_len = 64;
    PcapFileThreadVars *ptv = (PcapFileThreadVars *)data;
    int r;
    TmSlot *s = (TmSlot *)slot;

    ptv->slot = s->slot_next;
    ptv->cb_result = TM_ECODE_OK;

    while (1) {
        if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        /* Right now we just support reading packets one at a time. */
        r = pcap_dispatch(pcap_g.pcap_handle, packet_q_len,
                          (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv);
        if (unlikely(r == -1)) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
                       r, pcap_geterr(pcap_g.pcap_handle));
            if (! RunModeUnixSocketIsActive()) {
                /* in the error state we just kill the engine */
                EngineKill();
                SCReturnInt(TM_ECODE_FAILED);
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
        } else if (unlikely(r == 0)) {
            SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r);
            if (! RunModeUnixSocketIsActive()) {
                EngineStop();
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
            break;
        } else if (ptv->cb_result == TM_ECODE_FAILED) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed");
            if (! RunModeUnixSocketIsActive()) {
                EngineKill();
                SCReturnInt(TM_ECODE_FAILED);
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
        }
        StatsSyncCountersIfSignalled(tv);
    }

    SCReturnInt(TM_ECODE_OK);
}
Ejemplo n.º 7
0
/**
 * \brief Receives packets from a DAG interface.
 *
 * \param tv pointer to ThreadVars
 * \param data pointer to ErfDagThreadVars
 * \param slot slot containing task information
 *
 * \retval TM_ECODE_OK on success
 * \retval TM_ECODE_FAILED on failure
 */
TmEcode
ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    ErfDagThreadVars *dtv = (ErfDagThreadVars *)data;
    uint32_t diff = 0;
    int      err;
    uint8_t  *top = NULL;
    uint32_t pkts_read = 0;
    TmSlot *s = (TmSlot *)slot;

    dtv->slot = s->slot_next;

    while (1) {
        if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
            SCReturnInt(TM_ECODE_OK);
        }

        top = dag_advance_stream(dtv->dagfd, dtv->dagstream, &(dtv->btm));
        if (top == NULL) {
            if (errno == EAGAIN) {
                if (dtv->dagstream & 0x1) {
                    usleep(10 * 1000);
                    dtv->btm = dtv->top;
                }
                continue;
            } else {
                SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED,
                    "Failed to read from stream: %d, DAG: %s when "
                    "using dag_advance_stream",
                    dtv->dagstream, dtv->dagname);
                SCReturnInt(TM_ECODE_FAILED);
            }
        }

        diff = top - dtv->btm;
        if (diff == 0) {
            continue;
        }

        assert(diff >= dag_record_size);

        err = ProcessErfDagRecords(dtv, top, &pkts_read);

        if (err == TM_ECODE_FAILED) {
            SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED,
                "Failed to read from stream: %d, DAG: %s",
                dtv->dagstream, dtv->dagname);
            ReceiveErfDagCloseStream(dtv->dagfd, dtv->dagstream);
            SCReturnInt(TM_ECODE_FAILED);
        }

        StatsSyncCountersIfSignalled(tv);

        SCLogDebug("Read %d records from stream: %d, DAG: %s",
            pkts_read, dtv->dagstream, dtv->dagname);
    }

    SCReturnInt(TM_ECODE_OK);
}
Ejemplo n.º 8
0
/**
 * \brief Recieves packets from an interface via libpfring.
 *
 *  This function recieves packets from an interface and passes
 *  the packet on to the pfring callback function.
 *
 * \param tv pointer to ThreadVars
 * \param data pointer that gets cast into PfringThreadVars for ptv
 * \param slot slot containing task information
 * \retval TM_ECODE_OK on success
 * \retval TM_ECODE_FAILED on failure
 */
TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    PfringThreadVars *ptv = (PfringThreadVars *)data;
    Packet *p = NULL;
    struct pfring_pkthdr hdr;
    TmSlot *s = (TmSlot *)slot;
    time_t last_dump = 0;
    struct timeval current_time;

    ptv->slot = s->slot_next;

    /* we have to enable the ring here as we need to do it after all
     * the threads have called pfring_set_cluster(). */
    int rc = pfring_enable_ring(ptv->pd);
    if (rc != 0) {
        SCLogError(SC_ERR_PF_RING_OPEN, "pfring_enable_ring failed returned %d ", rc);
        SCReturnInt(TM_ECODE_FAILED);
    }

    while(1) {
        if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        p = PacketGetFromQueueOrAlloc();
        if (p == NULL) {
            SCReturnInt(TM_ECODE_FAILED);
        }
        PKT_SET_SRC(p, PKT_SRC_WIRE);

        /* Some flavours of PF_RING may fail to set timestamp - see PF-RING-enabled libpcap code*/
        hdr.ts.tv_sec = hdr.ts.tv_usec = 0;

        /* Depending on what compile time options are used for pfring we either return 0 or -1 on error and always 1 for success */
        u_char *pkt_buffer = GET_PKT_DIRECT_DATA(p);
        u_int buffer_size = GET_PKT_DIRECT_MAX_SIZE(p);
        int r = pfring_recv(ptv->pd, &pkt_buffer,
                buffer_size,
                &hdr,
                LIBPFRING_WAIT_FOR_INCOMING);

        /* Check for Zero-copy if buffer size is zero */
        if (buffer_size == 0) {
            PacketSetData(p, pkt_buffer, hdr.caplen);
        }

        if (r == 1) {
            //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n",
            //        hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port);

            PfringProcessPacket(ptv, &hdr, p);

            if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
                TmqhOutputPacketpool(ptv->tv, p);
                SCReturnInt(TM_ECODE_FAILED);
            }

            /* Trigger one dump of stats every second */
            TimeGet(&current_time);
            if (current_time.tv_sec != last_dump) {
                PfringDumpCounters(ptv);
                last_dump = current_time.tv_sec;
            }
        } else {
            SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error  %" PRId32 "", r);
            TmqhOutputPacketpool(ptv->tv, p);
            SCReturnInt(TM_ECODE_FAILED);
        }
        StatsSyncCountersIfSignalled(tv);
    }

    return TM_ECODE_OK;
}
Ejemplo n.º 9
0
/**
 *  \brief Main Napatech reading Loop function
 */
TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    int32_t status;
    char errbuf[100];
    uint64_t pkt_ts;
    NtNetBuf_t packet_buffer;
    NapatechThreadVars *ntv = (NapatechThreadVars *)data;
    NtNetRx_t stat_cmd;

    SCLogInfo("Opening NAPATECH Stream: %lu for processing", ntv->stream_id);

    if ((status = NT_NetRxOpen(&(ntv->rx_stream), "SuricataStream", NT_NET_INTERFACE_PACKET, ntv->stream_id, ntv->hba)) != NT_SUCCESS) {
        NT_ExplainError(status, errbuf, sizeof(errbuf));
        SCLogError(SC_ERR_NAPATECH_OPEN_FAILED, "Failed to open NAPATECH Stream: %lu - %s", ntv->stream_id, errbuf);
        SCFree(ntv);
        SCReturnInt(TM_ECODE_FAILED);
    }

    stat_cmd.cmd = NT_NETRX_READ_CMD_STREAM_DROP;

    SCLogInfo("Napatech Packet Stream Loop Started for Stream ID: %lu", ntv->stream_id);

    TmSlot *s = (TmSlot *)slot;
    ntv->slot = s->slot_next;

    while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) {
        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        /*
         * Napatech returns packets 1 at a time
         */
        status = NT_NetRxGet(ntv->rx_stream, &packet_buffer, 1000);
        if (unlikely(status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) {
            /*
             * no frames currently available
             */
            continue;
        } else if (unlikely(status != NT_SUCCESS)) {
            SCLogError(SC_ERR_NAPATECH_STREAM_NEXT_FAILED,
                       "Failed to read from Napatech Stream: %lu",
                       ntv->stream_id);
            SCReturnInt(TM_ECODE_FAILED);
        }

        Packet *p = PacketGetFromQueueOrAlloc();
        if (unlikely(p == NULL)) {
            NT_NetRxRelease(ntv->rx_stream, packet_buffer);
            SCReturnInt(TM_ECODE_FAILED);
        }

        pkt_ts = NT_NET_GET_PKT_TIMESTAMP(packet_buffer);

        /*
         * Handle the different timestamp forms that the napatech cards could use
         *   - NT_TIMESTAMP_TYPE_NATIVE is not supported due to having an base of 0 as opposed to NATIVE_UNIX which has a base of 1/1/1970
         */
        switch(NT_NET_GET_PKT_TIMESTAMP_TYPE(packet_buffer)) {
            case NT_TIMESTAMP_TYPE_NATIVE_UNIX:
                p->ts.tv_sec = pkt_ts / 100000000;
                p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0;
                break;
            case NT_TIMESTAMP_TYPE_PCAP:
                p->ts.tv_sec = pkt_ts >> 32;
                p->ts.tv_usec = pkt_ts & 0xFFFFFFFF;
                break;
            case NT_TIMESTAMP_TYPE_PCAP_NANOTIME:
                p->ts.tv_sec = pkt_ts >> 32;
                p->ts.tv_usec = ((pkt_ts & 0xFFFFFFFF) / 1000) + (pkt_ts % 1000) > 500 ? 1 : 0;
                break;
            case NT_TIMESTAMP_TYPE_NATIVE_NDIS:
                /* number of seconds between 1/1/1601 and 1/1/1970 */
                p->ts.tv_sec = (pkt_ts / 100000000) - 11644473600;
                p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0;
                break;
            default:
                SCLogError(SC_ERR_NAPATECH_TIMESTAMP_TYPE_NOT_SUPPORTED,
                           "Packet from Napatech Stream: %lu does not have a supported timestamp format",
                           ntv->stream_id);
                NT_NetRxRelease(ntv->rx_stream, packet_buffer);
                SCReturnInt(TM_ECODE_FAILED);
        }

        SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec);
        p->datalink = LINKTYPE_ETHERNET;

        ntv->pkts++;
        ntv->bytes += NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer);

        // Update drop counter
        if (unlikely((status = NT_NetRxRead(ntv->rx_stream, &stat_cmd)) != NT_SUCCESS))
        {
            NT_ExplainError(status, errbuf, sizeof(errbuf));
            SCLogWarning(SC_ERR_NAPATECH_STAT_DROPS_FAILED, "Couldn't retrieve drop statistics from the RX stream: %lu - %s", ntv->stream_id, errbuf);
        }
        else
        {
            ntv->drops += stat_cmd.u.streamDrop.pktsDropped;
        }

        if (unlikely(PacketCopyData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) {
            TmqhOutputPacketpool(ntv->tv, p);
            NT_NetRxRelease(ntv->rx_stream, packet_buffer);
            SCReturnInt(TM_ECODE_FAILED);
        }

        if (unlikely(TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK)) {
            TmqhOutputPacketpool(ntv->tv, p);
            NT_NetRxRelease(ntv->rx_stream, packet_buffer);
            SCReturnInt(TM_ECODE_FAILED);
        }

        NT_NetRxRelease(ntv->rx_stream, packet_buffer);
        StatsSyncCountersIfSignalled(tv);
    }

    SCReturnInt(TM_ECODE_OK);
}
Ejemplo n.º 10
0
TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    IPFWThreadVars *ptv = (IPFWThreadVars *)data;
    IPFWQueueVars *nq = NULL;
    uint8_t pkt[IP_MAXPACKET];
    int pktlen=0;
    struct pollfd IPFWpoll;
    struct timeval IPFWts;
    Packet *p = NULL;

    nq = IPFWGetQueue(ptv->ipfw_index);
    if (nq == NULL) {
        SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Can't get thread variable");
        SCReturnInt(TM_ECODE_FAILED);
    }

    SCLogInfo("Thread '%s' will run on port %d (item %d)",
              tv->name, nq->port_num, ptv->ipfw_index);
    while (1) {
        if (unlikely(suricata_ctl_flags != 0)) {
            SCReturnInt(TM_ECODE_OK);
        }

        IPFWpoll.fd = nq->fd;
        IPFWpoll.events = POLLRDNORM;
        /* Poll the socket for status */
        if ( (poll(&IPFWpoll, 1, IPFW_SOCKET_POLL_MSEC)) > 0) {
            if (!(IPFWpoll.revents & (POLLRDNORM | POLLERR)))
                continue;
        }

        if ((pktlen = recvfrom(nq->fd, pkt, sizeof(pkt), 0,
                               (struct sockaddr *)&nq->ipfw_sin,
                               &nq->ipfw_sinlen)) == -1) {
            /* We received an error on socket read */
            if (errno == EINTR || errno == EWOULDBLOCK) {
                /* Nothing for us to process */
                continue;
            } else {
                SCLogWarning(SC_WARN_IPFW_RECV,
                             "Read from IPFW divert socket failed: %s",
                             strerror(errno));
                SCReturnInt(TM_ECODE_FAILED);
            }
        }
        /* We have a packet to process */
        memset (&IPFWts, 0, sizeof(struct timeval));
        gettimeofday(&IPFWts, NULL);

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        p = PacketGetFromQueueOrAlloc();
        if (p == NULL) {
            SCReturnInt(TM_ECODE_FAILED);
        }
        PKT_SET_SRC(p, PKT_SRC_WIRE);

        SCLogDebug("Received Packet Len: %d", pktlen);

        p->ts.tv_sec = IPFWts.tv_sec;
        p->ts.tv_usec = IPFWts.tv_usec;

        ptv->pkts++;
        ptv->bytes += pktlen;

        p->datalink = ptv->datalink;

        p->ipfw_v.ipfw_index = ptv->ipfw_index;

        PacketCopyData(p, pkt, pktlen);
        SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)",
                   GET_PKT_LEN(p), *pkt, GET_PKT_DATA(p));

        if (TmThreadsSlotProcessPkt(tv, ((TmSlot *) slot)->slot_next, p)
                != TM_ECODE_OK) {
            TmqhOutputPacketpool(tv, p);
            SCReturnInt(TM_ECODE_FAILED);
        }

        StatsSyncCountersIfSignalled(tv);
    }

    SCReturnInt(TM_ECODE_OK);
}