1 /*--------------------------------------------------------------------------
2 // Copyright (C) 2015-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 */
19 /* daq_hext.c author Russ Combs <rucombs@cisco.com> */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "daq_user.h"
26 
27 #include <arpa/inet.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <inttypes.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 #include <daq_module_api.h>
41 
42 #define DAQ_MOD_VERSION 1
43 #define DAQ_NAME "hext"
44 #define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE|DAQ_TYPE_INTF_CAPABLE|DAQ_TYPE_MULTI_INSTANCE)
45 
46 #define HEXT_DEFAULT_POOL_SIZE 16
47 #define DEF_BUF_SZ 16384
48 #define MAX_LINE_SZ  128
49 
50 #define SET_ERROR(modinst, ...)    daq_base_api.set_errbuf(modinst, __VA_ARGS__)
51 
52 typedef struct _hext_msg_desc
53 {
54     DAQ_Msg_t msg;
55     DAQ_PktHdr_t pkthdr;
56     DAQ_FlowStats_t flowstats;
57     DAQ_UsrHdr_t pci;
58     uint8_t* data;
59     struct _hext_msg_desc* next;
60 } HextMsgDesc;
61 
62 typedef struct
63 {
64     HextMsgDesc* pool;
65     HextMsgDesc* freelist;
66     DAQ_MsgPoolInfo_t info;
67 } HextMsgPool;
68 
69 typedef struct
70 {
71     /* Configuration */
72     char* filename;
73     unsigned snaplen;
74     int dlt;
75 
76     /* State */
77     DAQ_ModuleInstance_h modinst;
78     HextMsgPool pool;
79     FILE* fp;
80     volatile bool interrupted;
81 
82     bool sof;
83     bool eof;
84 
85     DAQ_UsrHdr_t pci;
86     DAQ_UsrHdr_t cfg;
87 
88     DAQ_Stats_t stats;
89 } HextContext;
90 
91 static DAQ_VariableDesc_t hext_variable_descriptions[] = {
92     { "dlt", "Data link type to report to the application instead of DLT_USER (integer)", DAQ_VAR_DESC_REQUIRES_ARGUMENT },
93 };
94 
95 static DAQ_BaseAPI_t daq_base_api;
96 
97 //-------------------------------------------------------------------------
98 // utility functions
99 //-------------------------------------------------------------------------
100 
destroy_message_pool(HextContext * hc)101 static void destroy_message_pool(HextContext* hc)
102 {
103     HextMsgPool* pool = &hc->pool;
104     if (pool->pool)
105     {
106         while (pool->info.size > 0)
107             free(pool->pool[--pool->info.size].data);
108         free(pool->pool);
109         pool->pool = NULL;
110     }
111     pool->freelist = NULL;
112     pool->info.available = 0;
113     pool->info.mem_size = 0;
114 }
115 
create_message_pool(HextContext * hc,unsigned size)116 static int create_message_pool(HextContext* hc, unsigned size)
117 {
118     HextMsgPool* pool = &hc->pool;
119     pool->pool = calloc(sizeof(HextMsgDesc), size);
120     if (!pool->pool)
121     {
122         SET_ERROR(hc->modinst, "%s: Could not allocate %zu bytes for a packet descriptor pool!",
123                 __func__, sizeof(HextMsgDesc) * size);
124         return DAQ_ERROR_NOMEM;
125     }
126     pool->info.mem_size = sizeof(HextMsgDesc) * size;
127     while (pool->info.size < size)
128     {
129         /* Allocate packet data and set up descriptor */
130         HextMsgDesc *desc = &pool->pool[pool->info.size];
131         desc->data = malloc(hc->snaplen);
132         if (!desc->data)
133         {
134             SET_ERROR(hc->modinst, "%s: Could not allocate %d bytes for a packet descriptor message buffer!",
135                     __func__, hc->snaplen);
136             return DAQ_ERROR_NOMEM;
137         }
138         pool->info.mem_size += hc->snaplen;
139 
140         /* Initialize non-zero invariant packet header fields. */
141         DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
142         pkthdr->address_space_id = 0;
143         pkthdr->ingress_index = DAQ_PKTHDR_UNKNOWN;
144         pkthdr->ingress_group = DAQ_PKTHDR_UNKNOWN;
145         pkthdr->egress_index = DAQ_PKTHDR_UNKNOWN;
146         pkthdr->egress_group = DAQ_PKTHDR_UNKNOWN;
147         pkthdr->flags = 0;
148 
149         /* Initialize non-zero invariant message header fields. */
150         DAQ_Msg_t *msg = &desc->msg;
151         msg->owner = hc->modinst;
152         msg->priv = desc;
153 
154         /* Place it on the free list */
155         desc->next = pool->freelist;
156         pool->freelist = desc;
157 
158         pool->info.size++;
159     }
160     pool->info.available = pool->info.size;
161     return DAQ_SUCCESS;
162 }
163 
set_c2s(HextContext * hc,int c2s)164 static void set_c2s(HextContext* hc, int c2s)
165 {
166     if (c2s)
167     {
168         hc->pci = hc->cfg;
169     }
170     else
171     {
172         hc->pci.src_addr = hc->cfg.dst_addr;
173         hc->pci.dst_addr = hc->cfg.src_addr;
174         hc->pci.src_port = hc->cfg.dst_port;
175         hc->pci.dst_port = hc->cfg.src_port;
176         hc->pci.flags &= ~DAQ_USR_FLAG_TO_SERVER;
177     }
178 }
179 
parse_host(const char * s,uint32_t * addr,uint16_t * port)180 static void parse_host(const char* s, uint32_t* addr, uint16_t* port)
181 {
182     char buf[32];  // oversize so pton() errors out if too long
183     unsigned c = 0;
184 
185     while (isspace(*s))
186         s++;
187 
188     while (*s && !isspace(*s) && c < sizeof(buf))
189         buf[c++] = *s++;
190 
191     if (c == sizeof(buf))
192         --c;
193 
194     buf[c] = '\0';
195 
196     inet_pton(AF_INET, buf, addr);
197     *port = atoi(s);
198 }
199 
parse_pci(HextContext * hc,const char * s)200 static void parse_pci(HextContext* hc, const char* s)
201 {
202     parse_host(s, &hc->pci.src_addr, &hc->pci.src_port);
203 
204     s = strstr(s, "->");
205 
206     if (!s)
207         return;
208 
209     parse_host(s+2, &hc->pci.dst_addr, &hc->pci.dst_port);
210 
211     // hack until client / server is resolved:
212     if (hc->pci.src_port >= hc->pci.dst_port)
213         hc->pci.flags |= DAQ_USR_FLAG_TO_SERVER;
214     else
215         hc->pci.flags &= ~DAQ_USR_FLAG_TO_SERVER;
216 }
217 
is_ipv4(char const * src)218 static bool is_ipv4(char const* src)
219 {
220     struct in6_addr temp;
221     if (inet_pton(AF_INET, src, &temp) == 1)
222         return true;
223     else if (inet_pton(AF_INET6, src, &temp) == 1)
224         return false;
225 
226     return false;
227 }
228 
IpAddr(uint32_t * addr,char const * ip)229 static void IpAddr(uint32_t* addr, char const* ip)
230 {
231     if (is_ipv4(ip))
232     {
233         addr[0] = 0;
234         addr[1] = 0;
235         addr[2] = htonl(0xffff);
236         inet_pton(AF_INET, ip, &addr[3]);
237     }
238     else
239         inet_pton(AF_INET6, ip, addr);
240 }
241 
parse_flowstats(DAQ_MsgType type,const char * line,HextMsgDesc * desc)242 static bool parse_flowstats(DAQ_MsgType type, const char* line, HextMsgDesc *desc)
243 {
244 #define FLOWSTATS_FORMAT \
245     "%" SCNi16 " "  /* ingress_group */  \
246     "%" SCNi16 " "  /* egress_group */   \
247     "%" SCNi32 " "  /* ingress_intf */   \
248     "%" SCNi32 " "  /* egress_intf */    \
249     "%s "           /* srcAddr */       \
250     "%" SCNu16 " "  /* initiator_port */ \
251     "%s "           /* dstAddr */       \
252     "%" SCNu16 " "  /* responder_port */ \
253     "%" SCNu32 " "  /* opaque */        \
254     "%" SCNu64 " "  /* initiator_pkts */ \
255     "%" SCNu64 " "  /* responder_pkts */ \
256     "%" SCNu64 " "  /* initiator_pkts_dropped */  \
257     "%" SCNu64 " "  /* responder_pkts_dropped */  \
258     "%" SCNu64 " "  /* initiator_bytes_dropped */ \
259     "%" SCNu64 " "  /* responder_bytes_dropped */ \
260     "%" SCNu8  " "  /* is_qos_applied_on_src_intf */ \
261     "%" SCNu32 " "  /* sof_timestamp.tv_sec */  \
262     "%" SCNu32 " "  /* eof_timestamp.tv_sec */  \
263     "%" SCNu16 " "  /* vlan_tag */      \
264     "%" SCNu16 " "  /* address_space_id */  \
265     "%" SCNu8  " "  /* protocol */ \
266     "%" SCNu8       /* flags */
267 #define FLOWSTATS_ITEMS 22
268     DAQ_FlowStats_t* f = &desc->flowstats;
269     char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
270     uint32_t sof_sec, eof_sec;
271     int rval = sscanf(line, FLOWSTATS_FORMAT, &f->ingress_group, &f->egress_group, &f->ingress_intf,
272             &f->egress_intf, srcaddr, &f->initiator_port, dstaddr, &f->responder_port, &f->opaque,
273             &f->initiator_pkts, &f->responder_pkts, &f->initiator_pkts_dropped, &f->responder_pkts_dropped,
274             &f->initiator_bytes_dropped, &f->responder_bytes_dropped, &f->is_qos_applied_on_src_intf,
275             &sof_sec, &eof_sec, &f->vlan_tag, &f->address_space_id,
276             &f->protocol, &f->flags);
277     if (rval != FLOWSTATS_ITEMS)
278         return false;
279 
280     f->sof_timestamp.tv_sec = sof_sec;
281     f->eof_timestamp.tv_sec = eof_sec;
282 
283     desc->msg.type = type;
284     desc->msg.hdr_len = sizeof(desc->flowstats);
285     desc->msg.hdr = &desc->flowstats;
286     desc->msg.data_len = 0;
287     desc->msg.data = NULL;
288 
289     IpAddr((uint32_t*)&f->initiator_ip, srcaddr);
290     f->initiator_port = htons(f->initiator_port);
291     IpAddr((uint32_t*)&f->responder_ip, dstaddr);
292     f->responder_port = htons(f->responder_port);
293     f->sof_timestamp.tv_usec = 0;
294     f->eof_timestamp.tv_usec = 0;
295     if (f->vlan_tag == 0)
296         f->vlan_tag = 0xfff;
297 
298     return true;
299 }
300 
xlat(char c)301 static uint8_t xlat(char c)
302 {
303     switch (c)
304     {
305     case 'r': return '\r';
306     case 'n': return '\n';
307     case 't': return '\t';
308     case '\\': return '\\';
309     }
310     return c;
311 }
312 
unescape(char c,char * u)313 static int unescape(char c, char* u)
314 {
315     static int esc = 0;
316     if (!esc && c == '\\')
317     {
318         esc = 1;
319         return 0;
320     }
321     else if (esc)
322     {
323         esc = 0;
324         *u = xlat(c);
325     }
326     else
327         *u = c;
328 
329     return 1;
330 }
331 
332 //-------------------------------------------------------------------------
333 // parsing functions
334 //-------------------------------------------------------------------------
335 // all commands start with $
336 // $packet <addr> <port> -> <addr> <port>
337 // $packet -> client
338 // $packet -> server
339 // $client <addr> <port>
340 // $server <addr> <port>
parse_command(HextContext * hc,const char * s,HextMsgDesc * desc)341 static bool parse_command(HextContext* hc, const char* s, HextMsgDesc *desc)
342 {
343     bool msg = false;
344 
345     if (!strncmp(s, "packet -> client", 16))
346         set_c2s(hc, 0);
347 
348     else if (!strncmp(s, "packet -> server", 16))
349         set_c2s(hc, 1);
350 
351     else if (!strncmp(s, "packet ", 7))
352         parse_pci(hc, s+7);
353 
354     else if (!strncmp(s, "client ", 7))
355         parse_host(s+7, &hc->cfg.src_addr, &hc->cfg.src_port);
356 
357     else if (!strncmp(s, "server ", 7))
358         parse_host(s+7, &hc->cfg.dst_addr, &hc->cfg.dst_port);
359 
360     else if (!strncmp(s, "sof ", 4))
361         msg = parse_flowstats(DAQ_MSG_TYPE_SOF, s+4, desc);
362 
363     else if (!strncmp(s, "eof ", 4))
364         msg = parse_flowstats(DAQ_MSG_TYPE_EOF, s+4, desc);
365 
366     return msg;
367 }
368 
369 // load quoted string data into buffer up to snaplen
parse_string(HextContext * hc,char * s,HextMsgDesc * desc)370 static void parse_string(HextContext* hc, char* s, HextMsgDesc *desc)
371 {
372     char t;
373 
374     while (*s && *s != '"' && desc->msg.data_len < hc->snaplen)
375     {
376         if (unescape(*s++, &t))
377             desc->data[desc->msg.data_len++] = t;
378     }
379     desc->pkthdr.pktlen = desc->msg.data_len;
380 }
381 
382 // load hex data into buffer up to snaplen
parse_hex(HextContext * hc,char * s,HextMsgDesc * desc)383 static void parse_hex(HextContext* hc, char* s, HextMsgDesc *desc)
384 {
385     char* t = s;
386     long x = strtol(t, &s, 16);
387 
388     while (*s && s != t && desc->msg.data_len  < hc->snaplen)
389     {
390         desc->data[desc->msg.data_len++] = (uint8_t) x;
391         x = strtol(t=s, &s, 16);
392     }
393     desc->pkthdr.pktlen = desc->msg.data_len;
394 }
395 
init_packet_message(HextContext * hc,HextMsgDesc * desc)396 static void init_packet_message(HextContext* hc, HextMsgDesc* desc)
397 {
398     DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
399 
400     desc->msg.type = DAQ_MSG_TYPE_PACKET;
401     desc->msg.hdr_len = sizeof(*pkthdr);
402     desc->msg.hdr = pkthdr;
403     desc->msg.data_len = 0;
404     desc->msg.data = desc->data;
405 
406     struct timeval t;
407     gettimeofday(&t, NULL);
408 
409     pkthdr->ts.tv_sec = t.tv_sec;
410     pkthdr->ts.tv_usec = t.tv_usec;
411 
412     desc->pci = hc->pci;
413     if (hc->sof)
414     {
415         desc->pci.flags |= DAQ_USR_FLAG_START_FLOW;
416         hc->sof = false;
417     }
418 }
419 
parse(HextContext * hc,char * line,HextMsgDesc * desc)420 static bool parse(HextContext* hc, char* line, HextMsgDesc* desc)
421 {
422     char* s = line;
423     bool got_msg = false;
424 
425     while (isspace(*s))
426         s++;
427 
428     // Force a flush of the current packet message if we hit a blank line or command
429     switch (*s)
430     {
431     case '\0':
432         if (desc->msg.data)
433             got_msg = true;
434         break;
435 
436     case '#':
437         break;
438 
439     case '$':
440         // Do not reset the line buffer so that we can parse the command the next time through
441         if (desc->msg.data)
442             return true;
443 
444         got_msg = parse_command(hc, s+1, desc);
445         break;
446 
447     case '"':
448         if (!desc->msg.data)
449             init_packet_message(hc, desc);
450         parse_string(hc, s+1, desc);
451         break;
452 
453     case 'x':
454         if (!desc->msg.data)
455             init_packet_message(hc, desc);
456         parse_hex(hc, s+1, desc);
457         break;
458     }
459     line[0] = '\0';
460     return got_msg;
461 }
462 
hext_read_message(HextContext * hc,HextMsgDesc * desc)463 static DAQ_RecvStatus hext_read_message(HextContext* hc, HextMsgDesc* desc)
464 {
465     char line[MAX_LINE_SZ];
466     char* s = NULL;
467 
468     desc->msg.data = NULL;
469     line[0] = '\0';
470     while (line[0] != '\0' || (s = fgets(line, sizeof(line), hc->fp)) != NULL)
471     {
472         // FIXIT-L Currently no error checking, just ignores bad lines
473         if (parse(hc, line, desc))
474             break;
475     }
476 
477     if (!s)
478     {
479         if (feof(hc->fp))
480         {
481             // If there is still pending data in a packet message, mark it as End of Flow and flush it
482             // Otherwise, create an empty packet message to convey the End of Flow
483             // FIXIT-M - Make this actually the case, for now Snort can't handle data on packets marked EoF
484             /*
485             if (!hc->eof)
486             {
487                 if (!desc->msg.data)
488                     init_packet_message(hc, desc);
489                 desc->pci.flags |= DAQ_USR_FLAG_END_FLOW;
490                 hc->eof = true;
491                 return DAQ_RSTAT_OK;
492             }
493             */
494             if (desc->msg.data)
495                 return DAQ_RSTAT_OK;
496             if (!hc->eof)
497             {
498                 init_packet_message(hc, desc);
499                 desc->pci.flags |= DAQ_USR_FLAG_END_FLOW;
500                 hc->eof = true;
501                 return DAQ_RSTAT_OK;
502             }
503             return DAQ_RSTAT_EOF;
504         }
505 
506         if (ferror(hc->fp))
507         {
508             char error_msg[1024] = {0};
509             if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
510                 SET_ERROR(hc->modinst, "%s: can't read from file (%s)\n", DAQ_NAME, error_msg);
511             else
512                 SET_ERROR(hc->modinst, "%s: can't read from file: %d\n", DAQ_NAME, errno);
513             return DAQ_RSTAT_ERROR;
514         }
515     }
516 
517     return DAQ_RSTAT_OK;
518 }
519 
520 //-------------------------------------------------------------------------
521 // file functions
522 //-------------------------------------------------------------------------
523 
hext_setup(HextContext * hc)524 static int hext_setup(HextContext* hc)
525 {
526     if (!strcmp(hc->filename, "tty"))
527     {
528         hc->fp = stdin;
529     }
530     else if (!(hc->fp = fopen(hc->filename, "r")))
531     {
532         char error_msg[1024] = {0};
533         if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
534             SET_ERROR(hc->modinst, "%s: can't open file (%s)\n", DAQ_NAME, error_msg);
535         else
536             SET_ERROR(hc->modinst, "%s: can't open file: %d\n", DAQ_NAME, errno);
537         return -1;
538     }
539     parse_host("192.168.1.2 12345", &hc->cfg.src_addr, &hc->cfg.src_port);
540     parse_host("10.1.2.3 80", &hc->cfg.dst_addr, &hc->cfg.dst_port);
541 
542     hc->cfg.ip_proto = hc->pci.ip_proto = IPPROTO_TCP;
543     hc->cfg.flags = hc->pci.flags = DAQ_USR_FLAG_TO_SERVER;
544     hc->sof = true;
545     hc->eof = false;
546 
547     return 0;
548 }
549 
550 
551 //-------------------------------------------------------------------------
552 // daq
553 //-------------------------------------------------------------------------
554 
hext_daq_module_load(const DAQ_BaseAPI_t * base_api)555 static int hext_daq_module_load(const DAQ_BaseAPI_t* base_api)
556 {
557     if (base_api->api_version != DAQ_BASE_API_VERSION || base_api->api_size != sizeof(DAQ_BaseAPI_t))
558         return DAQ_ERROR;
559 
560     daq_base_api = *base_api;
561 
562     return DAQ_SUCCESS;
563 }
564 
hext_daq_get_variable_descs(const DAQ_VariableDesc_t ** var_desc_table)565 static int hext_daq_get_variable_descs(const DAQ_VariableDesc_t** var_desc_table)
566 {
567     *var_desc_table = hext_variable_descriptions;
568 
569     return sizeof(hext_variable_descriptions) / sizeof(DAQ_VariableDesc_t);
570 }
571 
hext_daq_instantiate(const DAQ_ModuleConfig_h modcfg,DAQ_ModuleInstance_h modinst,void ** ctxt_ptr)572 static int hext_daq_instantiate(const DAQ_ModuleConfig_h modcfg, DAQ_ModuleInstance_h modinst, void** ctxt_ptr)
573 {
574     HextContext* hc;
575     int rval = DAQ_ERROR;
576 
577     hc = calloc(1, sizeof(*hc));
578     if (!hc)
579     {
580         SET_ERROR(modinst, "%s: Couldn't allocate memory for the new Hext context!", DAQ_NAME);
581         rval = DAQ_ERROR_NOMEM;
582         goto err;
583     }
584     hc->modinst = modinst;
585 
586     hc->snaplen = daq_base_api.config_get_snaplen(modcfg) ? daq_base_api.config_get_snaplen(modcfg) : DEF_BUF_SZ;
587     hc->dlt = DLT_USER;
588 
589     const char* varKey, * varValue;
590     daq_base_api.config_first_variable(modcfg, &varKey, &varValue);
591     while (varKey)
592     {
593         /* Retrieve the requested buffer size (default = 0) */
594         if (!strcmp(varKey, "dlt"))
595             hc->dlt = strtol(varValue, NULL, 10);
596         else
597         {
598             SET_ERROR(modinst, "%s: Unknown variable name: '%s'", DAQ_NAME, varKey);
599             rval = DAQ_ERROR_INVAL;
600             goto err;
601         }
602 
603         daq_base_api.config_next_variable(modcfg, &varKey, &varValue);
604     }
605 
606     const char* filename = daq_base_api.config_get_input(modcfg);
607     if (filename)
608     {
609         if (!(hc->filename = strdup(filename)))
610         {
611             SET_ERROR(modinst, "%s: Couldn't allocate memory for the filename!", DAQ_NAME);
612             rval = DAQ_ERROR_NOMEM;
613             goto err;
614         }
615     }
616 
617     uint32_t pool_size = daq_base_api.config_get_msg_pool_size(modcfg);
618     rval = create_message_pool(hc, pool_size ? pool_size : HEXT_DEFAULT_POOL_SIZE);
619     if (rval != DAQ_SUCCESS)
620         goto err;
621 
622     *ctxt_ptr = hc;
623 
624     return DAQ_SUCCESS;
625 
626 err:
627     if (hc)
628     {
629         if (hc->filename)
630             free(hc->filename);
631         destroy_message_pool(hc);
632         free(hc);
633     }
634     return rval;
635 }
636 
hext_daq_destroy(void * handle)637 static void hext_daq_destroy(void* handle)
638 {
639     HextContext* hc = (HextContext*) handle;
640 
641     if (hc->filename)
642         free(hc->filename);
643     destroy_message_pool(hc);
644     free(hc);
645 }
646 
hext_daq_start(void * handle)647 static int hext_daq_start(void* handle)
648 {
649     HextContext* hc = (HextContext*) handle;
650 
651     if (hext_setup(hc))
652         return DAQ_ERROR;
653 
654     return DAQ_SUCCESS;
655 }
656 
hext_daq_interrupt(void * handle)657 static int hext_daq_interrupt(void* handle)
658 {
659     HextContext* hc = (HextContext*) handle;
660     hc->interrupted = true;
661     return DAQ_SUCCESS;
662 }
663 
hext_daq_stop(void * handle)664 static int hext_daq_stop(void* handle)
665 {
666     HextContext* hc = (HextContext*) handle;
667 
668     if (hc->fp != stdin)
669         fclose(hc->fp);
670 
671     hc->fp = NULL;
672 
673     return DAQ_SUCCESS;
674 }
675 
hext_daq_ioctl(void * handle,DAQ_IoctlCmd cmd,void * arg,size_t arglen)676 static int hext_daq_ioctl(void* handle, DAQ_IoctlCmd cmd, void* arg, size_t arglen)
677 {
678     (void) handle;
679 
680     if (cmd == DIOCTL_QUERY_USR_PCI)
681     {
682         if (arglen != sizeof(DIOCTL_QueryUsrPCI))
683             return DAQ_ERROR_INVAL;
684         DIOCTL_QueryUsrPCI* qup = (DIOCTL_QueryUsrPCI*) arg;
685         if (!qup->msg)
686             return DAQ_ERROR_INVAL;
687         HextMsgDesc* desc = (HextMsgDesc*) qup->msg->priv;
688         qup->pci = &desc->pci;
689         return DAQ_SUCCESS;
690     }
691     return DAQ_ERROR_NOTSUP;
692 }
693 
hext_daq_get_stats(void * handle,DAQ_Stats_t * stats)694 static int hext_daq_get_stats(void* handle, DAQ_Stats_t* stats)
695 {
696     HextContext* hc = (HextContext*) handle;
697     memcpy(stats, &hc->stats, sizeof(DAQ_Stats_t));
698     return DAQ_SUCCESS;
699 }
700 
hext_daq_reset_stats(void * handle)701 static void hext_daq_reset_stats(void* handle)
702 {
703     HextContext* hc = (HextContext*) handle;
704     memset(&hc->stats, 0, sizeof(hc->stats));
705 }
706 
hext_daq_get_snaplen(void * handle)707 static int hext_daq_get_snaplen (void* handle)
708 {
709     HextContext* hc = (HextContext*) handle;
710     return hc->snaplen;
711 }
712 
hext_daq_get_capabilities(void * handle)713 static uint32_t hext_daq_get_capabilities(void* handle)
714 {
715     (void) handle;
716     return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
717         | DAQ_CAPA_INTERRUPT | DAQ_CAPA_UNPRIV_START;
718 }
719 
hext_daq_get_datalink_type(void * handle)720 static int hext_daq_get_datalink_type(void* handle)
721 {
722     HextContext* hc = (HextContext*) handle;
723     return hc->dlt;
724 }
725 
hext_daq_msg_receive(void * handle,const unsigned max_recv,const DAQ_Msg_t * msgs[],DAQ_RecvStatus * rstat)726 static unsigned hext_daq_msg_receive(void* handle, const unsigned max_recv, const DAQ_Msg_t* msgs[], DAQ_RecvStatus* rstat)
727 {
728     HextContext* hc = (HextContext*) handle;
729     DAQ_RecvStatus status = DAQ_RSTAT_OK;
730     unsigned idx = 0;
731 
732     while (idx < max_recv)
733     {
734         /* Check to see if the receive has been canceled.  If so, reset it and return appropriately. */
735         if (hc->interrupted)
736         {
737             hc->interrupted = false;
738             status = DAQ_RSTAT_INTERRUPTED;
739             break;
740         }
741 
742         /* Make sure that we have a message descriptor available to populate. */
743         HextMsgDesc* desc = hc->pool.freelist;
744         if (!desc)
745         {
746             status = DAQ_RSTAT_NOBUF;
747             break;
748         }
749 
750         /* Attempt to read a message into the descriptor. */
751         status = hext_read_message(hc, desc);
752         if (status != DAQ_RSTAT_OK)
753             break;
754 
755         /* Last, but not least, extract this descriptor from the free list and
756            place the message in the return vector. */
757         hc->pool.freelist = desc->next;
758         desc->next = NULL;
759         hc->pool.info.available--;
760         msgs[idx] = &desc->msg;
761 
762         idx++;
763     }
764 
765     *rstat = status;
766 
767     return idx;
768 }
769 
hext_daq_msg_finalize(void * handle,const DAQ_Msg_t * msg,DAQ_Verdict verdict)770 static int hext_daq_msg_finalize(void* handle, const DAQ_Msg_t* msg, DAQ_Verdict verdict)
771 {
772     HextContext* hc = (HextContext*) handle;
773     HextMsgDesc* desc = (HextMsgDesc *) msg->priv;
774 
775     if (verdict >= MAX_DAQ_VERDICT)
776         verdict = DAQ_VERDICT_PASS;
777     hc->stats.verdicts[verdict]++;
778 
779     /* Toss the descriptor back on the free list for reuse. */
780     desc->next = hc->pool.freelist;
781     hc->pool.freelist = desc;
782     hc->pool.info.available++;
783 
784     return DAQ_SUCCESS;
785 }
786 
hext_daq_get_msg_pool_info(void * handle,DAQ_MsgPoolInfo_t * info)787 static int hext_daq_get_msg_pool_info(void* handle, DAQ_MsgPoolInfo_t* info)
788 {
789     HextContext* hc = (HextContext*) handle;
790 
791     *info = hc->pool.info;
792 
793     return DAQ_SUCCESS;
794 }
795 
796 //-------------------------------------------------------------------------
797 
798 #ifdef BUILDING_SO
799 DAQ_SO_PUBLIC const DAQ_ModuleAPI_t DAQ_MODULE_DATA =
800 #else
801 const DAQ_ModuleAPI_t hext_daq_module_data =
802 #endif
803 {
804     /* .api_version = */ DAQ_MODULE_API_VERSION,
805     /* .api_size = */ sizeof(DAQ_ModuleAPI_t),
806     /* .module_version = */ DAQ_MOD_VERSION,
807     /* .name = */ DAQ_NAME,
808     /* .type = */ DAQ_TYPE,
809     /* .load = */ hext_daq_module_load,
810     /* .unload = */ NULL,
811     /* .get_variable_descs = */ hext_daq_get_variable_descs,
812     /* .instantiate = */ hext_daq_instantiate,
813     /* .destroy = */ hext_daq_destroy,
814     /* .set_filter = */ NULL,
815     /* .start = */ hext_daq_start,
816     /* .inject = */ NULL,
817     /* .inject_relative = */ NULL,
818     /* .interrupt = */ hext_daq_interrupt,
819     /* .stop = */ hext_daq_stop,
820     /* .ioctl = */ hext_daq_ioctl,
821     /* .get_stats = */ hext_daq_get_stats,
822     /* .reset_stats = */ hext_daq_reset_stats,
823     /* .get_snaplen = */ hext_daq_get_snaplen,
824     /* .get_capabilities = */ hext_daq_get_capabilities,
825     /* .get_datalink_type = */ hext_daq_get_datalink_type,
826     /* .config_load = */ NULL,
827     /* .config_swap = */ NULL,
828     /* .config_free = */ NULL,
829     /* .msg_receive = */ hext_daq_msg_receive,
830     /* .msg_finalize = */ hext_daq_msg_finalize,
831     /* .get_msg_pool_info = */ hext_daq_get_msg_pool_info,
832 };
833 
834