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