1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2010-2013 Sourcefire, Inc.
4 ** Author: Michael R. Altizer <mialtize@cisco.com>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation.  You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <errno.h>
27 #include <pcap.h>
28 #include <pthread.h>
29 #include <stdbool.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "daq_module_api.h"
34 
35 #define DAQ_PCAP_VERSION 4
36 
37 #define PCAP_DEFAULT_POOL_SIZE 16
38 #define DAQ_PCAP_ROLLOVER_LIM 1000000000 //Check for rollover every billionth packet
39 
40 #define SET_ERROR(modinst, ...)    daq_base_api.set_errbuf(modinst, __VA_ARGS__)
41 
42 typedef struct _pcap_pkt_desc
43 {
44     DAQ_Msg_t msg;
45     DAQ_PktHdr_t pkthdr;
46     uint8_t *data;
47     struct _pcap_pkt_desc *next;
48 } PcapPktDesc;
49 
50 typedef struct _pcap_msg_pool
51 {
52     PcapPktDesc *pool;
53     PcapPktDesc *freelist;
54     DAQ_MsgPoolInfo_t info;
55 } PcapMsgPool;
56 
57 typedef struct _pcap_context
58 {
59     /* Configuration */
60     char *device;
61     char *filter_string;
62     unsigned snaplen;
63     bool promisc_mode;
64     bool immediate_mode;
65     int timeout;
66     struct timeval timeout_tv;
67     int buffer_size;
68     DAQ_Mode mode;
69     bool readback_timeout;
70     /* State */
71     DAQ_ModuleInstance_h modinst;
72     DAQ_Stats_t stats;
73     char pcap_errbuf[PCAP_ERRBUF_SIZE];
74     PcapMsgPool pool;
75     pcap_t *handle;
76     FILE *fp;
77     uint32_t netmask;
78     bool nonblocking;
79     volatile bool interrupted;
80     /* Readback timeout state */
81     struct timeval last_recv;
82     PcapPktDesc *pending_desc;
83     bool final_readback_timeout;
84     /* Stats tracking */
85     uint32_t base_recv;
86     uint32_t base_drop;
87     uint64_t rollover_recv;
88     uint64_t rollover_drop;
89     uint32_t wrap_recv;
90     uint32_t wrap_drop;
91     uint32_t hwupdate_count;
92 } Pcap_Context_t;
93 
94 static void pcap_daq_reset_stats(void *handle);
95 
96 static DAQ_VariableDesc_t pcap_variable_descriptions[] = {
97     { "buffer_size", "Packet buffer space to allocate in bytes", DAQ_VAR_DESC_REQUIRES_ARGUMENT },
98     { "no_promiscuous", "Disables opening the interface in promiscuous mode", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
99     { "no_immediate", "Disables immediate mode for traffic capture (may cause unbounded blocking)", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
100     { "readback_timeout", "Return timeout receive status in file readback mode", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
101 };
102 
103 static DAQ_BaseAPI_t daq_base_api;
104 static pthread_mutex_t bpf_mutex = PTHREAD_MUTEX_INITIALIZER;
105 
destroy_packet_pool(Pcap_Context_t * pc)106 static void destroy_packet_pool(Pcap_Context_t *pc)
107 {
108     PcapMsgPool *pool = &pc->pool;
109     if (pool->pool)
110     {
111         while (pool->info.size > 0)
112             free(pool->pool[--pool->info.size].data);
113         free(pool->pool);
114         pool->pool = NULL;
115     }
116     pool->freelist = NULL;
117     pool->info.available = 0;
118     pool->info.mem_size = 0;
119 }
120 
create_packet_pool(Pcap_Context_t * pc,unsigned size)121 static int create_packet_pool(Pcap_Context_t *pc, unsigned size)
122 {
123     PcapMsgPool *pool = &pc->pool;
124     pool->pool = calloc(sizeof(PcapPktDesc), size);
125     if (!pool->pool)
126     {
127         SET_ERROR(pc->modinst, "%s: Could not allocate %zu bytes for a packet descriptor pool!",
128                 __func__, sizeof(PcapPktDesc) * size);
129         return DAQ_ERROR_NOMEM;
130     }
131     pool->info.mem_size = sizeof(PcapPktDesc) * size;
132     while (pool->info.size < size)
133     {
134         /* Allocate packet data and set up descriptor */
135         PcapPktDesc *desc = &pool->pool[pool->info.size];
136         desc->data = malloc(pc->snaplen);
137         if (!desc->data)
138         {
139             SET_ERROR(pc->modinst, "%s: Could not allocate %d bytes for a packet descriptor message buffer!",
140                     __func__, pc->snaplen);
141             return DAQ_ERROR_NOMEM;
142         }
143         pool->info.mem_size += pc->snaplen;
144 
145         /* Initialize non-zero invariant packet header fields. */
146         DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
147         pkthdr->ingress_index = DAQ_PKTHDR_UNKNOWN;
148         pkthdr->egress_index = DAQ_PKTHDR_UNKNOWN;
149         pkthdr->ingress_group = DAQ_PKTHDR_UNKNOWN;
150         pkthdr->egress_group = DAQ_PKTHDR_UNKNOWN;
151 
152         /* Initialize non-zero invariant message header fields. */
153         DAQ_Msg_t *msg = &desc->msg;
154         msg->type = DAQ_MSG_TYPE_PACKET;
155         msg->hdr_len = sizeof(desc->pkthdr);
156         msg->hdr = &desc->pkthdr;
157         msg->data = desc->data;
158         msg->owner = pc->modinst;
159         msg->priv = desc;
160 
161         /* Place it on the free list */
162         desc->next = pool->freelist;
163         pool->freelist = desc;
164 
165         pool->info.size++;
166     }
167     pool->info.available = pool->info.size;
168     return DAQ_SUCCESS;
169 }
170 
update_hw_stats(Pcap_Context_t * pc)171 static int update_hw_stats(Pcap_Context_t *pc)
172 {
173     struct pcap_stat ps;
174 
175     if (pc->handle && pc->device)
176     {
177         memset(&ps, 0, sizeof(struct pcap_stat));
178         if (pcap_stats(pc->handle, &ps) == -1)
179         {
180             SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
181             return DAQ_ERROR;
182         }
183 
184         /* PCAP receive counter wrapped */
185         if (ps.ps_recv < pc->wrap_recv)
186             pc->rollover_recv += UINT32_MAX;
187 
188         /* PCAP drop counter wrapped */
189         if (ps.ps_drop < pc->wrap_drop)
190             pc->rollover_drop += UINT32_MAX;
191 
192         pc->wrap_recv = ps.ps_recv;
193         pc->wrap_drop = ps.ps_drop;
194 
195         pc->stats.hw_packets_received = pc->rollover_recv + pc->wrap_recv - pc->base_recv;
196         pc->stats.hw_packets_dropped = pc->rollover_drop + pc->wrap_drop - pc->base_drop;
197         pc->hwupdate_count = 0;
198     }
199 
200     return DAQ_SUCCESS;
201 }
202 
set_nonblocking(Pcap_Context_t * pc,bool nonblocking)203 static inline int set_nonblocking(Pcap_Context_t *pc, bool nonblocking)
204 {
205     if (nonblocking != pc->nonblocking)
206     {
207         int status;
208         if ((status = pcap_setnonblock(pc->handle, nonblocking ? 1 : 0, pc->pcap_errbuf)) < 0)
209         {
210             SET_ERROR(pc->modinst, "%s", pc->pcap_errbuf);
211             return status;
212         }
213         pc->nonblocking = nonblocking;
214     }
215     return 0;
216 }
217 
pcap_daq_module_load(const DAQ_BaseAPI_t * base_api)218 static int pcap_daq_module_load(const DAQ_BaseAPI_t *base_api)
219 {
220     if (base_api->api_version != DAQ_BASE_API_VERSION || base_api->api_size != sizeof(DAQ_BaseAPI_t))
221         return DAQ_ERROR;
222 
223     daq_base_api = *base_api;
224 
225     return DAQ_SUCCESS;
226 }
227 
pcap_daq_module_unload(void)228 static int pcap_daq_module_unload(void)
229 {
230     memset(&daq_base_api, 0, sizeof(daq_base_api));
231     return DAQ_SUCCESS;
232 }
233 
pcap_daq_get_variable_descs(const DAQ_VariableDesc_t ** var_desc_table)234 static int pcap_daq_get_variable_descs(const DAQ_VariableDesc_t **var_desc_table)
235 {
236     *var_desc_table = pcap_variable_descriptions;
237 
238     return sizeof(pcap_variable_descriptions) / sizeof(DAQ_VariableDesc_t);
239 }
240 
pcap_daq_instantiate(const DAQ_ModuleConfig_h modcfg,DAQ_ModuleInstance_h modinst,void ** ctxt_ptr)241 static int pcap_daq_instantiate(const DAQ_ModuleConfig_h modcfg, DAQ_ModuleInstance_h modinst, void **ctxt_ptr)
242 {
243     Pcap_Context_t *pc;
244 
245     pc = calloc(1, sizeof(Pcap_Context_t));
246     if (!pc)
247     {
248         SET_ERROR(modinst, "%s: Couldn't allocate memory for the new PCAP context!", __func__);
249         return DAQ_ERROR_NOMEM;
250     }
251     pc->modinst = modinst;
252 
253     pc->snaplen = daq_base_api.config_get_snaplen(modcfg);
254     pc->timeout = daq_base_api.config_get_timeout(modcfg);
255     pc->timeout_tv.tv_sec = pc->timeout / 1000;
256     pc->timeout_tv.tv_usec = (pc->timeout % 1000) * 1000;
257     pc->promisc_mode = true;
258     pc->immediate_mode = true;
259     pc->readback_timeout = false;
260 
261     const char *varKey, *varValue;
262     daq_base_api.config_first_variable(modcfg, &varKey, &varValue);
263     while (varKey)
264     {
265         /* Retrieve the requested buffer size (default = 0) */
266         if (!strcmp(varKey, "buffer_size"))
267             pc->buffer_size = strtol(varValue, NULL, 10);
268         else if (!strcmp(varKey, "no_promiscuous"))
269             pc->promisc_mode = false;
270         else if (!strcmp(varKey, "no_immediate"))
271             pc->immediate_mode = false;
272         else if (!strcmp(varKey, "readback_timeout"))
273             pc->readback_timeout = true;
274 
275         daq_base_api.config_next_variable(modcfg, &varKey, &varValue);
276     }
277 
278     uint32_t pool_size = daq_base_api.config_get_msg_pool_size(modcfg);
279     int rval = create_packet_pool(pc, pool_size ? pool_size : PCAP_DEFAULT_POOL_SIZE);
280     if (rval != DAQ_SUCCESS)
281     {
282         destroy_packet_pool(pc);
283         free(pc);
284         return rval;
285     }
286 
287     pc->mode = daq_base_api.config_get_mode(modcfg);
288     if (pc->mode == DAQ_MODE_READ_FILE)
289     {
290         const char *fname = daq_base_api.config_get_input(modcfg);
291         /* Special case: "-" is an alias for stdin */
292         if (fname[0] == '-' && fname[1] == '\0')
293             pc->fp = stdin;
294         else
295         {
296             pc->fp = fopen(daq_base_api.config_get_input(modcfg), "rb");
297             if (!pc->fp)
298             {
299                 SET_ERROR(modinst, "%s: Couldn't open file '%s' for reading: %s", __func__,
300                         daq_base_api.config_get_input(modcfg), strerror(errno));
301                 destroy_packet_pool(pc);
302                 free(pc);
303                 return DAQ_ERROR_NOMEM;
304             }
305         }
306     }
307     else
308     {
309         pc->device = strdup(daq_base_api.config_get_input(modcfg));
310         if (!pc->device)
311         {
312             SET_ERROR(modinst, "%s: Couldn't allocate memory for the device string!", __func__);
313             destroy_packet_pool(pc);
314             free(pc);
315             return DAQ_ERROR_NOMEM;
316         }
317     }
318 
319     pc->hwupdate_count = 0;
320 
321     *ctxt_ptr = pc;
322 
323     return DAQ_SUCCESS;
324 }
325 
pcap_daq_destroy(void * handle)326 static void pcap_daq_destroy(void *handle)
327 {
328     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
329 
330     if (pc->handle)
331         pcap_close(pc->handle);
332     if (pc->fp)
333         fclose(pc->fp);
334     if (pc->device)
335         free(pc->device);
336     if (pc->filter_string)
337         free(pc->filter_string);
338     destroy_packet_pool(pc);
339     free(pc);
340 }
341 
pcap_daq_install_filter(Pcap_Context_t * pc,const char * filter)342 static int pcap_daq_install_filter(Pcap_Context_t *pc, const char *filter)
343 {
344     struct bpf_program fcode;
345 
346     pthread_mutex_lock(&bpf_mutex);
347     if (pcap_compile(pc->handle, &fcode, filter, 1, pc->netmask) < 0)
348     {
349         pthread_mutex_unlock(&bpf_mutex);
350         SET_ERROR(pc->modinst, "%s: pcap_compile: %s", __func__, pcap_geterr(pc->handle));
351         return DAQ_ERROR;
352     }
353     pthread_mutex_unlock(&bpf_mutex);
354 
355     if (pcap_setfilter(pc->handle, &fcode) < 0)
356     {
357         pcap_freecode(&fcode);
358         SET_ERROR(pc->modinst, "%s: pcap_setfilter: %s", __func__, pcap_geterr(pc->handle));
359         return DAQ_ERROR;
360     }
361 
362     pcap_freecode(&fcode);
363 
364     return DAQ_SUCCESS;
365 }
366 
pcap_daq_set_filter(void * handle,const char * filter)367 static int pcap_daq_set_filter(void *handle, const char *filter)
368 {
369     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
370 
371     if (pc->handle)
372     {
373         int rval = pcap_daq_install_filter(handle, filter);
374         if (rval != DAQ_SUCCESS)
375             return rval;
376     }
377     else
378     {
379         /* Try to validate the BPF with a dead PCAP handle. */
380         pcap_t *dead_handle = pcap_open_dead(DLT_EN10MB, pc->snaplen);
381         if (!dead_handle)
382         {
383             SET_ERROR(pc->modinst, "%s: Could not allocate a dead PCAP handle!", __func__);
384             return DAQ_ERROR_NOMEM;
385         }
386         struct bpf_program fcode;
387         pthread_mutex_lock(&bpf_mutex);
388         if (pcap_compile(dead_handle, &fcode, filter, 1, pc->netmask) < 0)
389         {
390             pthread_mutex_unlock(&bpf_mutex);
391             SET_ERROR(pc->modinst, "%s: pcap_compile: %s", __func__, pcap_geterr(dead_handle));
392             return DAQ_ERROR;
393         }
394         pthread_mutex_unlock(&bpf_mutex);
395         pcap_freecode(&fcode);
396         pcap_close(dead_handle);
397 
398         /* Store the BPF string for later. */
399         if (pc->filter_string)
400             free(pc->filter_string);
401         pc->filter_string = strdup(filter);
402         if (!pc->filter_string)
403         {
404             SET_ERROR(pc->modinst, "%s: Could not allocate space to store a copy of the filter string!", __func__);
405             return DAQ_ERROR_NOMEM;
406         }
407     }
408 
409     return DAQ_SUCCESS;
410 }
411 
pcap_daq_start(void * handle)412 static int pcap_daq_start(void *handle)
413 {
414     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
415     uint32_t localnet, netmask;
416     uint32_t defaultnet = 0xFFFFFF00;
417     int status;
418 
419     if (pc->device)
420     {
421         pc->handle = pcap_create(pc->device, pc->pcap_errbuf);
422         if (!pc->handle)
423             goto fail;
424         if ((status = pcap_set_immediate_mode(pc->handle, pc->immediate_mode ? 1 : 0)) < 0)
425             goto fail;
426         if ((status = pcap_set_snaplen(pc->handle, pc->snaplen)) < 0)
427             goto fail;
428         if ((status = pcap_set_promisc(pc->handle, pc->promisc_mode ? 1 : 0)) < 0)
429             goto fail;
430         if ((status = pcap_set_timeout(pc->handle, pc->timeout)) < 0)
431             goto fail;
432         if ((status = pcap_set_buffer_size(pc->handle, pc->buffer_size)) < 0)
433             goto fail;
434         if ((status = pcap_activate(pc->handle)) < 0)
435             goto fail;
436         if ((status = set_nonblocking(pc, true)) < 0)
437             goto fail;
438         if (pcap_lookupnet(pc->device, &localnet, &netmask, pc->pcap_errbuf) < 0)
439             netmask = htonl(defaultnet);
440     }
441     else
442     {
443         pc->handle = pcap_fopen_offline(pc->fp, pc->pcap_errbuf);
444         if (!pc->handle)
445             goto fail;
446         pc->fp = NULL;
447 
448         netmask = htonl(defaultnet);
449     }
450     pc->netmask = netmask;
451 
452     if (pc->filter_string)
453     {
454         if ((status = pcap_daq_install_filter(pc, pc->filter_string)) != DAQ_SUCCESS)
455         {
456             pcap_close(pc->handle);
457             pc->handle = NULL;
458             return status;
459         }
460         free(pc->filter_string);
461         pc->filter_string = NULL;
462     }
463 
464     pcap_daq_reset_stats(handle);
465 
466     return DAQ_SUCCESS;
467 
468 fail:
469     if (pc->handle)
470     {
471         if (status == PCAP_ERROR || status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED)
472             SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
473         else
474             SET_ERROR(pc->modinst, "%s: %s", pc->device, pcap_statustostr(status));
475         pcap_close(pc->handle);
476         pc->handle = NULL;
477     }
478     else
479         SET_ERROR(pc->modinst, "%s", pc->pcap_errbuf);
480     return DAQ_ERROR;
481 }
482 
pcap_daq_inject(void * handle,DAQ_MsgType type,const void * hdr,const uint8_t * data,uint32_t data_len)483 static int pcap_daq_inject(void *handle, DAQ_MsgType type, const void *hdr, const uint8_t *data, uint32_t data_len)
484 {
485     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
486 
487     if (type != DAQ_MSG_TYPE_PACKET)
488         return DAQ_ERROR_NOTSUP;
489 
490     if (pcap_inject(pc->handle, data, data_len) < 0)
491     {
492         SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
493         return DAQ_ERROR;
494     }
495 
496     pc->stats.packets_injected++;
497     return DAQ_SUCCESS;
498 }
499 
pcap_daq_interrupt(void * handle)500 static int pcap_daq_interrupt(void *handle)
501 {
502     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
503 
504     pc->interrupted = true;
505 
506     return DAQ_SUCCESS;
507 }
508 
pcap_daq_stop(void * handle)509 static int pcap_daq_stop(void *handle)
510 {
511     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
512 
513     if (pc->handle)
514     {
515         /* Store the hardware stats for post-stop stat calls. */
516         update_hw_stats(pc);
517         pcap_close(pc->handle);
518         pc->handle = NULL;
519     }
520 
521     return DAQ_SUCCESS;
522 }
523 
pcap_daq_get_stats(void * handle,DAQ_Stats_t * stats)524 static int pcap_daq_get_stats(void *handle, DAQ_Stats_t *stats)
525 {
526     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
527 
528     if (update_hw_stats(pc) != DAQ_SUCCESS)
529         return DAQ_ERROR;
530 
531     memcpy(stats, &pc->stats, sizeof(DAQ_Stats_t));
532 
533     return DAQ_SUCCESS;
534 }
535 
pcap_daq_reset_stats(void * handle)536 static void pcap_daq_reset_stats(void *handle)
537 {
538     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
539     struct pcap_stat ps;
540 
541     memset(&pc->stats, 0, sizeof(DAQ_Stats_t));
542 
543     if (!pc->handle)
544         return;
545 
546     memset(&ps, 0, sizeof(struct pcap_stat));
547     if (pc->handle && pc->device && pcap_stats(pc->handle, &ps) == 0)
548     {
549         pc->base_recv = pc->wrap_recv = ps.ps_recv;
550         pc->base_drop = pc->wrap_drop = ps.ps_drop;
551     }
552 }
553 
pcap_daq_get_snaplen(void * handle)554 static int pcap_daq_get_snaplen(void *handle)
555 {
556     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
557 
558     return pc->snaplen;
559 }
560 
pcap_daq_get_capabilities(void * handle)561 static uint32_t pcap_daq_get_capabilities(void *handle)
562 {
563     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
564     uint32_t capabilities = DAQ_CAPA_BPF | DAQ_CAPA_INTERRUPT;
565 
566     if (pc->device)
567         capabilities |= DAQ_CAPA_INJECT;
568     else
569         capabilities |= DAQ_CAPA_UNPRIV_START;
570 
571     return capabilities;
572 }
573 
pcap_daq_get_datalink_type(void * handle)574 static int pcap_daq_get_datalink_type(void *handle)
575 {
576     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
577 
578     if (pc->handle)
579         return pcap_datalink(pc->handle);
580 
581     return DLT_NULL;
582 }
583 
pcap_daq_msg_receive(void * handle,const unsigned max_recv,const DAQ_Msg_t * msgs[],DAQ_RecvStatus * rstat)584 static unsigned pcap_daq_msg_receive(void *handle, const unsigned max_recv, const DAQ_Msg_t *msgs[], DAQ_RecvStatus *rstat)
585 {
586     struct pcap_pkthdr *pcaphdr;
587     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
588     const u_char *data;
589     unsigned idx;
590 
591     *rstat = DAQ_RSTAT_OK;
592     for (idx = 0; idx < max_recv; idx++)
593     {
594         /* Check to see if the receive has been canceled.  If so, reset it and return appropriately. */
595         if (pc->interrupted)
596         {
597             pc->interrupted = false;
598             *rstat = DAQ_RSTAT_INTERRUPTED;
599             break;
600         }
601 
602         /* If there is a pending descriptor from the readback timeout feature, check if it's ready
603             to be realized.  If it is, finish receiving it and carry on. */
604         if (pc->pending_desc)
605         {
606             struct timeval delta;
607             timersub(&pc->pending_desc->pkthdr.ts, &pc->last_recv, &delta);
608             if (timercmp(&delta, &pc->timeout_tv, >))
609             {
610                 timeradd(&pc->last_recv, &pc->timeout_tv, &pc->last_recv);
611                 *rstat = DAQ_RSTAT_TIMEOUT;
612                 break;
613             }
614             pc->last_recv = pc->pending_desc->pkthdr.ts;
615             pc->pool.info.available--;
616             msgs[idx] = &pc->pending_desc->msg;
617             pc->stats.packets_received++;
618             pc->pending_desc = NULL;
619             continue;
620         }
621 
622         /* Make sure that we have a packet descriptor available to populate *before*
623             calling into libpcap. */
624         PcapPktDesc *desc = pc->pool.freelist;
625         if (!desc)
626         {
627             *rstat = DAQ_RSTAT_NOBUF;
628             break;
629         }
630 
631         /* When dealing with a live interface, try to get the first packet in non-blocking mode.
632             If there's nothing to receive, switch to blocking mode. */
633         int pcap_rval;
634         if (pc->mode != DAQ_MODE_READ_FILE && idx == 0)
635         {
636             if (set_nonblocking(pc, true) != DAQ_SUCCESS)
637             {
638                 *rstat = DAQ_RSTAT_ERROR;
639                 break;
640             }
641             pcap_rval = pcap_next_ex(pc->handle, &pcaphdr, &data);
642             if (pcap_rval == 0)
643             {
644                 if (set_nonblocking(pc, false) != DAQ_SUCCESS)
645                 {
646                     *rstat = DAQ_RSTAT_ERROR;
647                     break;
648                 }
649                 pcap_rval = pcap_next_ex(pc->handle, &pcaphdr, &data);
650             }
651         }
652         else
653             pcap_rval = pcap_next_ex(pc->handle, &pcaphdr, &data);
654 
655         if (pcap_rval <= 0)
656         {
657             if (pcap_rval == 0)
658                 *rstat = (idx == 0) ? DAQ_RSTAT_TIMEOUT : DAQ_RSTAT_WOULD_BLOCK;
659             else if (pcap_rval == -1)
660             {
661                 SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
662                 *rstat = DAQ_RSTAT_ERROR;
663             }
664             else if (pcap_rval == -2)
665             {
666                 /* LibPCAP brilliantly decides to return -2 if it hit EOF in readback OR pcap_breakloop()
667                     was called.  Let's try to differentiate by checking to see if we asked for a break. */
668                 if (!pc->interrupted && pc->mode == DAQ_MODE_READ_FILE)
669                 {
670                     /* Insert a final timeout receive status when readback timeout mode is enabled. */
671                     if (pc->readback_timeout && !pc->final_readback_timeout)
672                     {
673                         pc->final_readback_timeout = true;
674                         *rstat = DAQ_RSTAT_TIMEOUT;
675                     }
676                     else
677                         *rstat = DAQ_RSTAT_EOF;
678                 }
679                 else
680                 {
681                     pc->interrupted = false;
682                     *rstat = DAQ_RSTAT_INTERRUPTED;
683                 }
684             }
685             break;
686         }
687 
688         /* Update hw packet counters to make sure we detect counter overflow */
689         if (++pc->hwupdate_count == DAQ_PCAP_ROLLOVER_LIM)
690             update_hw_stats(pc);
691 
692         /* Populate the packet descriptor */
693         int caplen = (pcaphdr->caplen > pc->snaplen) ? pc->snaplen : pcaphdr->caplen;
694         memcpy(desc->data, data, caplen);
695 
696         /* Next, set up the DAQ message.  Most fields are prepopulated and unchanging. */
697         DAQ_Msg_t *msg = &desc->msg;
698         msg->data_len = caplen;
699 
700         /* Then, set up the DAQ packet header. */
701         DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
702         pkthdr->pktlen = pcaphdr->len;
703         pkthdr->ts.tv_sec = pcaphdr->ts.tv_sec;
704         pkthdr->ts.tv_usec = pcaphdr->ts.tv_usec;
705 
706         /* Last, but not least, extract this descriptor from the free list and
707             place the message in the return vector. */
708         pc->pool.freelist = desc->next;
709         desc->next = NULL;
710         /* If the readback timeout feature is enabled, check to see if the configured timeout has
711             elapsed between the previous packet and this one.  If it has, store the descriptor for
712             later without modifying counters and return the timeout receive status. */
713         if (pc->mode == DAQ_MODE_READ_FILE && pc->readback_timeout && pc->timeout > 0)
714         {
715             if (timerisset(&pc->last_recv) && timercmp(&pkthdr->ts, &pc->last_recv, >))
716             {
717                 struct timeval delta;
718                 timersub(&pkthdr->ts, &pc->last_recv, &delta);
719                 if (timercmp(&delta, &pc->timeout_tv, >))
720                 {
721                     pc->pending_desc = desc;
722                     timeradd(&pc->last_recv, &pc->timeout_tv, &pc->last_recv);
723                     *rstat = DAQ_RSTAT_TIMEOUT;
724                     break;
725                 }
726             }
727             pc->last_recv = pkthdr->ts;
728         }
729         pc->pool.info.available--;
730         msgs[idx] = &desc->msg;
731 
732         /* Finally, increment the module instance's packet counter. */
733         pc->stats.packets_received++;
734     }
735 
736     return idx;
737 }
738 
pcap_daq_msg_finalize(void * handle,const DAQ_Msg_t * msg,DAQ_Verdict verdict)739 static int pcap_daq_msg_finalize(void *handle, const DAQ_Msg_t *msg, DAQ_Verdict verdict)
740 {
741     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
742     PcapPktDesc *desc = (PcapPktDesc *) msg->priv;
743 
744     /* Sanitize the verdict. */
745     if (verdict >= MAX_DAQ_VERDICT)
746         verdict = DAQ_VERDICT_PASS;
747     pc->stats.verdicts[verdict]++;
748 
749     /* Toss the descriptor back on the free list for reuse. */
750     desc->next = pc->pool.freelist;
751     pc->pool.freelist = desc;
752     pc->pool.info.available++;
753 
754     return DAQ_SUCCESS;
755 }
756 
pcap_daq_get_msg_pool_info(void * handle,DAQ_MsgPoolInfo_t * info)757 static int pcap_daq_get_msg_pool_info(void *handle, DAQ_MsgPoolInfo_t *info)
758 {
759     Pcap_Context_t *pc = (Pcap_Context_t *) handle;
760 
761     *info = pc->pool.info;
762 
763     return DAQ_SUCCESS;
764 }
765 
766 #ifdef BUILDING_SO
767 DAQ_SO_PUBLIC const DAQ_ModuleAPI_t DAQ_MODULE_DATA =
768 #else
769 const DAQ_ModuleAPI_t pcap_daq_module_data =
770 #endif
771 {
772     /* .api_version = */ DAQ_MODULE_API_VERSION,
773     /* .api_size = */ sizeof(DAQ_ModuleAPI_t),
774     /* .module_version = */ DAQ_PCAP_VERSION,
775     /* .name = */ "pcap",
776     /* .type = */ DAQ_TYPE_FILE_CAPABLE | DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,
777     /* .load = */ pcap_daq_module_load,
778     /* .unload = */ pcap_daq_module_unload,
779     /* .get_variable_descs = */ pcap_daq_get_variable_descs,
780     /* .instantiate = */ pcap_daq_instantiate,
781     /* .destroy = */ pcap_daq_destroy,
782     /* .set_filter = */ pcap_daq_set_filter,
783     /* .start = */ pcap_daq_start,
784     /* .inject = */ pcap_daq_inject,
785     /* .inject_relative = */ NULL,
786     /* .interrupt = */ pcap_daq_interrupt,
787     /* .stop = */ pcap_daq_stop,
788     /* .ioctl = */ NULL,
789     /* .get_stats = */ pcap_daq_get_stats,
790     /* .reset_stats = */ pcap_daq_reset_stats,
791     /* .get_snaplen = */ pcap_daq_get_snaplen,
792     /* .get_capabilities = */ pcap_daq_get_capabilities,
793     /* .get_datalink_type = */ pcap_daq_get_datalink_type,
794     /* .config_load = */ NULL,
795     /* .config_swap = */ NULL,
796     /* .config_free = */ NULL,
797     /* .msg_receive = */ pcap_daq_msg_receive,
798     /* .msg_finalize = */ pcap_daq_msg_finalize,
799     /* .get_msg_pool_info = */ pcap_daq_get_msg_pool_info,
800 };
801