suricata
util-mpm-ac-bs.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2014 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22  *
23  * First iteration of aho-corasick MPM from -
24  *
25  * Efficient String Matching: An Aid to Bibliographic Search
26  * Alfred V. Aho and Margaret J. Corasick
27  *
28  * - Uses the delta table for calculating transitions, instead of having
29  * separate goto and failure transitions.
30  * - If we cross 2 ** 16 states, we use 4 bytes in the transition table
31  * to hold each state, otherwise we use 2 bytes.
32  * - This version of the MPM is heavy on memory, but it performs well.
33  * If you can fit the ruleset with this mpm on your box without hitting
34  * swap, this is the MPM to go for.
35  *
36  * \todo - Do a proper analysis of our existing MPMs and suggest a good one based
37  * on the pattern distribution and the expected traffic(say http).
38  * - Tried out loop unrolling without any perf increase. Need to dig deeper.
39  * - Irrespective of whether we cross 2 ** 16 states or not,shift to using
40  * uint32_t for state type, so that we can integrate it's status as a
41  * final state or not in the topmost byte. We are already doing it if
42  * state_count is > 2 ** 16.
43  * - Test case-sensitive patterns if they have any ascii chars. If they
44  * don't treat them as nocase.
45  * - Carry out other optimizations we are working on. hashes, compression.
46  */
47 
48 #include "suricata-common.h"
49 #include "suricata.h"
50 
51 #include "detect.h"
52 #include "detect-parse.h"
53 #include "detect-engine.h"
54 #include "detect-engine-build.h"
55 #include "util-mpm-ac-bs.h"
56 
57 #include "conf.h"
58 #include "util-debug.h"
59 #include "util-unittest.h"
60 #include "util-unittest-helper.h"
61 #include "util-memcmp.h"
62 #include "util-memcpy.h"
63 #include "util-validate.h"
64 
65 void SCACBSInitCtx(MpmCtx *);
67 void SCACBSDestroyCtx(MpmCtx *);
69 int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
70  uint32_t, SigIntId, uint8_t);
71 int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
72  uint32_t, SigIntId, uint8_t);
73 int SCACBSPreparePatterns(MpmCtx *mpm_ctx);
74 uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
75  PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen);
76 void SCACBSPrintInfo(MpmCtx *mpm_ctx);
77 void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx);
78 void SCACBSRegisterTests(void);
79 
80 /* a placeholder to denote a failure transition in the goto table */
81 #define SC_AC_BS_FAIL (-1)
82 
83 #define STATE_QUEUE_CONTAINER_SIZE 65536
84 
85 /**
86  * \brief Helper structure used by AC during state table creation
87  */
88 typedef struct StateQueue_ {
90  int top;
91  int bot;
93 
94 /**
95  * \brief Register the aho-corasick mpm.
96  */
97 void MpmACBSRegister(void)
98 {
99  mpm_table[MPM_AC_BS].name = "ac-bs";
111 
112  return;
113 }
114 
115 /**
116  * \internal
117  * \brief Initialize the AC context with user specified conf parameters. We
118  * aren't retrieving anything for AC conf now, but we will certainly
119  * need it, when we customize AC.
120  */
121 static void SCACBSGetConfig(void)
122 {
123  //ConfNode *ac_conf;
124  //const char *hash_val = NULL;
125 
126  //ConfNode *pm = ConfGetNode("pattern-matcher");
127 
128  return;
129 }
130 
131 /**
132  * \internal
133  * \brief Initialize a new state in the goto and output tables.
134  *
135  * \param mpm_ctx Pointer to the mpm context.
136  *
137  * \retval The state id, of the newly created state.
138  */
139 static inline int SCACBSInitNewState(MpmCtx *mpm_ctx)
140 {
141  void *ptmp;
142  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
143  int ascii_code = 0;
144  int size = 0;
145 
146  /* reallocate space in the goto table to include a new state */
147  size = (ctx->state_count + 1) * ctx->single_state_size;
148  ptmp = SCRealloc(ctx->goto_table, size);
149  if (ptmp == NULL) {
150  SCFree(ctx->goto_table);
151  ctx->goto_table = NULL;
152  FatalError("Error allocating memory");
153  }
154  ctx->goto_table = ptmp;
155 
156  /* set all transitions for the newly assigned state as FAIL transitions */
157  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
158  ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_BS_FAIL;
159  }
160 
161  /* reallocate space in the output table for the new state */
162  size = (ctx->state_count + 1) * sizeof(SCACBSOutputTable);
163  ptmp = SCRealloc(ctx->output_table, size);
164  if (ptmp == NULL) {
165  SCFree(ctx->output_table);
166  ctx->output_table = NULL;
167  FatalError("Error allocating memory");
168  }
169  ctx->output_table = ptmp;
170 
171  memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACBSOutputTable));
172 
173  /* \todo using it temporarily now during dev, since I have restricted
174  * state var in SCACBSCtx->state_table to uint16_t. */
175  //if (ctx->state_count > 65536) {
176  // printf("state count exceeded\n");
177  // exit(EXIT_FAILURE);
178  //}
179 
180  return ctx->state_count++;
181 }
182 
183 /**
184  * \internal
185  * \brief Adds a pid to the output table for a state.
186  *
187  * \param state The state to whose output table we should add the pid.
188  * \param pid The pattern id to add.
189  * \param mpm_ctx Pointer to the mpm context.
190  */
191 static void SCACBSSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx)
192 {
193  void *ptmp;
194  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
195  SCACBSOutputTable *output_state = &ctx->output_table[state];
196  uint32_t i = 0;
197 
198  for (i = 0; i < output_state->no_of_entries; i++) {
199  if (output_state->pids[i] == pid)
200  return;
201  }
202 
203  output_state->no_of_entries++;
204  ptmp = SCRealloc(output_state->pids,
205  output_state->no_of_entries * sizeof(uint32_t));
206  if (ptmp == NULL) {
207  SCFree(output_state->pids);
208  output_state->pids = NULL;
209  FatalError("Error allocating memory");
210  }
211  output_state->pids = ptmp;
212 
213  output_state->pids[output_state->no_of_entries - 1] = pid;
214 
215  return;
216 }
217 
218 /**
219  * \brief Helper function used by SCACBSCreateGotoTable. Adds a pattern to the
220  * goto table.
221  *
222  * \param pattern Pointer to the pattern.
223  * \param pattern_len Pattern length.
224  * \param pid The pattern id, that corresponds to this pattern. We
225  * need it to updated the output table for this pattern.
226  * \param mpm_ctx Pointer to the mpm context.
227  */
228 static inline void SCACBSEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid,
229  MpmCtx *mpm_ctx)
230 {
231  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
232  int32_t state = 0;
233  int32_t newstate = 0;
234  int i = 0;
235  int p = 0;
236 
237  /* walk down the trie till we have a match for the pattern prefix */
238  state = 0;
239  for (i = 0; i < pattern_len; i++) {
240  if (ctx->goto_table[state][pattern[i]] != SC_AC_BS_FAIL) {
241  state = ctx->goto_table[state][pattern[i]];
242  } else {
243  break;
244  }
245  }
246 
247  /* add the non-matching pattern suffix to the trie, from the last state
248  * we left off */
249  for (p = i; p < pattern_len; p++) {
250  newstate = SCACBSInitNewState(mpm_ctx);
251  ctx->goto_table[state][pattern[p]] = newstate;
252  state = newstate;
253  }
254 
255  /* add this pattern id, to the output table of the last state, where the
256  * pattern ends in the trie */
257  SCACBSSetOutputState(state, pid, mpm_ctx);
258 
259  return;
260 }
261 
262 /**
263  * \internal
264  * \brief Create the goto table.
265  *
266  * \param mpm_ctx Pointer to the mpm context.
267  */
268 static inline void SCACBSCreateGotoTable(MpmCtx *mpm_ctx)
269 {
270  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
271  uint32_t i = 0;
272 
273  /* add each pattern to create the goto table */
274  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
275  SCACBSEnter(ctx->parray[i]->ci, ctx->parray[i]->len,
276  ctx->parray[i]->id, mpm_ctx);
277  }
278 
279  int ascii_code = 0;
280  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
281  if (ctx->goto_table[0][ascii_code] == SC_AC_BS_FAIL) {
282  ctx->goto_table[0][ascii_code] = 0;
283  }
284  }
285 
286  return;
287 }
288 
289 static inline int SCACBSStateQueueIsEmpty(StateQueue *q)
290 {
291  if (q->top == q->bot)
292  return 1;
293  else
294  return 0;
295 }
296 
297 static inline void SCACBSEnqueue(StateQueue *q, int32_t state)
298 {
299  int i = 0;
300 
301  /*if we already have this */
302  for (i = q->bot; i < q->top; i++) {
303  if (q->store[i] == state)
304  return;
305  }
306 
307  q->store[q->top++] = state;
308 
310  q->top = 0;
311 
312  if (q->top == q->bot) {
313  FatalError("Just ran out of space in the queue. "
314  "Fatal Error. Exiting. Please file a bug report on this");
315  }
316 
317  return;
318 }
319 
320 static inline int32_t SCACBSDequeue(StateQueue *q)
321 {
323  q->bot = 0;
324 
325  if (q->bot == q->top) {
326  FatalError("StateQueue behaving weirdly. "
327  "Fatal Error. Exiting. Please file a bug report on this");
328  }
329 
330  return q->store[q->bot++];
331 }
332 
333 /*
334 #define SCACBSStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0)
335 
336 #define SCACBSEnqueue(q, state) do { \
337  int i = 0; \
338  \
339  for (i = (q)->bot; i < (q)->top; i++) { \
340  if ((q)->store[i] == state) \
341  return; \
342  } \
343  \
344  (q)->store[(q)->top++] = state; \
345  \
346  if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \
347  (q)->top = 0; \
348  \
349  if ((q)->top == (q)->bot) { \
350  FatalError("Just ran out of space in the queue. " \
351  "Fatal Error. Exiting. Please file a bug report on
352 this"); \
353  } \
354  } while (0)
355 
356 #define SCACBSDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \
357  (((q)->bot == (q)->top) ? \
358  (printf("StateQueue behaving " \
359  "weirdly. Fatal Error. Exiting. Please " \
360  "file a bug report on this"), \
361  exit(EXIT_FAILURE)) : 0), \
362  (q)->store[(q)->bot++]) \
363 */
364 
365 /**
366  * \internal
367  * \brief Club the output data from 2 states and store it in the 1st state.
368  * dst_state_data = {dst_state_data} UNION {src_state_data}
369  *
370  * \param dst_state First state(also the destination) for the union operation.
371  * \param src_state Second state for the union operation.
372  * \param mpm_ctx Pointer to the mpm context.
373  */
374 static inline void SCACBSClubOutputStates(int32_t dst_state, int32_t src_state,
375  MpmCtx *mpm_ctx)
376 {
377  void *ptmp;
378  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
379  uint32_t i = 0;
380  uint32_t j = 0;
381 
382  SCACBSOutputTable *output_dst_state = &ctx->output_table[dst_state];
383  SCACBSOutputTable *output_src_state = &ctx->output_table[src_state];
384 
385  for (i = 0; i < output_src_state->no_of_entries; i++) {
386  for (j = 0; j < output_dst_state->no_of_entries; j++) {
387  if (output_src_state->pids[i] == output_dst_state->pids[j]) {
388  break;
389  }
390  }
391  if (j == output_dst_state->no_of_entries) {
392  output_dst_state->no_of_entries++;
393 
394  ptmp = SCRealloc(output_dst_state->pids,
395  (output_dst_state->no_of_entries * sizeof(uint32_t)));
396  if (ptmp == NULL) {
397  SCFree(output_dst_state->pids);
398  output_dst_state->pids = NULL;
399  FatalError("Error allocating memory");
400  }
401  else {
402  output_dst_state->pids = ptmp;
403  }
404 
405  output_dst_state->pids[output_dst_state->no_of_entries - 1] =
406  output_src_state->pids[i];
407  }
408  }
409 
410  return;
411 }
412 
413 /**
414  * \internal
415  * \brief Create the failure table.
416  *
417  * \param mpm_ctx Pointer to the mpm context.
418  */
419 static inline void SCACBSCreateFailureTable(MpmCtx *mpm_ctx)
420 {
421  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
422  int ascii_code = 0;
423  int32_t state = 0;
424  int32_t r_state = 0;
425 
426  StateQueue q;
427  memset(&q, 0, sizeof(StateQueue));
428 
429  /* allot space for the failure table. A failure entry in the table for
430  * every state(SCACBSCtx->state_count) */
431  ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t));
432  if (ctx->failure_table == NULL) {
433  FatalError("Error allocating memory");
434  }
435  memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t));
436 
437  /* add the failure transitions for the 0th state, and add every non-fail
438  * transition from the 0th state to the queue for further processing
439  * of failure states */
440  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
441  int32_t temp_state = ctx->goto_table[0][ascii_code];
442  if (temp_state != 0) {
443  SCACBSEnqueue(&q, temp_state);
444  ctx->failure_table[temp_state] = 0;
445  }
446  }
447 
448  while (!SCACBSStateQueueIsEmpty(&q)) {
449  /* pick up every state from the queue and add failure transitions */
450  r_state = SCACBSDequeue(&q);
451  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
452  int32_t temp_state = ctx->goto_table[r_state][ascii_code];
453  if (temp_state == SC_AC_BS_FAIL)
454  continue;
455  SCACBSEnqueue(&q, temp_state);
456  state = ctx->failure_table[r_state];
457 
458  while(ctx->goto_table[state][ascii_code] == SC_AC_BS_FAIL)
459  state = ctx->failure_table[state];
460  ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code];
461  SCACBSClubOutputStates(temp_state, ctx->failure_table[temp_state],
462  mpm_ctx);
463  }
464  }
465 
466  return;
467 }
468 
469 /**
470  * \internal
471  * \brief Create the delta table.
472  *
473  * \param mpm_ctx Pointer to the mpm context.
474  */
475 static inline void SCACBSCreateDeltaTable(MpmCtx *mpm_ctx)
476 {
477  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
478  int ascii_code = 0;
479  int32_t r_state = 0;
480 
481  if (ctx->state_count < 32767) {
482  ctx->state_table_u16 = SCCalloc(ctx->state_count, sizeof(*ctx->state_table_u16));
483  if (ctx->state_table_u16 == NULL) {
484  FatalError("Error allocating memory");
485  }
486  mpm_ctx->memory_cnt++;
487  mpm_ctx->memory_size += (ctx->state_count * sizeof(*ctx->state_table_u16));
488 
489  StateQueue q;
490  memset(&q, 0, sizeof(StateQueue));
491 
492  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
493  DEBUG_VALIDATE_BUG_ON(ctx->goto_table[0][ascii_code] > UINT16_MAX);
494  SC_AC_BS_STATE_TYPE_U16 temp_state = (uint16_t)ctx->goto_table[0][ascii_code];
495  ctx->state_table_u16[0][ascii_code] = temp_state;
496  if (temp_state != 0)
497  SCACBSEnqueue(&q, temp_state);
498  }
499 
500  while (!SCACBSStateQueueIsEmpty(&q)) {
501  r_state = SCACBSDequeue(&q);
502 
503  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
504  int32_t temp_state = ctx->goto_table[r_state][ascii_code];
505  if (temp_state != SC_AC_BS_FAIL) {
506  SCACBSEnqueue(&q, temp_state);
507  DEBUG_VALIDATE_BUG_ON(temp_state > UINT16_MAX);
508  ctx->state_table_u16[r_state][ascii_code] = (uint16_t)temp_state;
509  } else {
510  ctx->state_table_u16[r_state][ascii_code] =
511  ctx->state_table_u16[ctx->failure_table[r_state]][ascii_code];
512  }
513  }
514  }
515  } else {
516  /* create space for the state table. We could have used the existing goto
517  * table, but since we have it set to hold 32 bit state values, we will create
518  * a new state table here of type SC_AC_BS_STATE_TYPE(current set to uint16_t) */
519  ctx->state_table_u32 = SCCalloc(ctx->state_count, sizeof(*ctx->state_table_u32));
520  if (ctx->state_table_u32 == NULL) {
521  FatalError("Error allocating memory");
522  }
523  mpm_ctx->memory_cnt++;
524  mpm_ctx->memory_size += (ctx->state_count * sizeof(*ctx->state_table_u32));
525 
526  StateQueue q;
527  memset(&q, 0, sizeof(StateQueue));
528 
529  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
530  SC_AC_BS_STATE_TYPE_U32 temp_state = ctx->goto_table[0][ascii_code];
531  ctx->state_table_u32[0][ascii_code] = temp_state;
532  if (temp_state != 0)
533  SCACBSEnqueue(&q, temp_state);
534  }
535 
536  while (!SCACBSStateQueueIsEmpty(&q)) {
537  r_state = SCACBSDequeue(&q);
538 
539  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
540  int32_t temp_state = ctx->goto_table[r_state][ascii_code];
541  if (temp_state != SC_AC_BS_FAIL) {
542  SCACBSEnqueue(&q, temp_state);
543  ctx->state_table_u32[r_state][ascii_code] = temp_state;
544  } else {
545  ctx->state_table_u32[r_state][ascii_code] =
546  ctx->state_table_u32[ctx->failure_table[r_state]][ascii_code];
547  }
548  }
549  }
550  }
551 
552  return;
553 }
554 
555 static inline void SCACBSClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx)
556 {
557  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
558  int ascii_code = 0;
559  uint32_t state = 0;
560  uint32_t temp_state = 0;
561 
562  if (ctx->state_count < 32767) {
563  for (state = 0; state < ctx->state_count; state++) {
564  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
565  temp_state = ctx->state_table_u16[state & 0x7FFF][ascii_code];
566  if (ctx->output_table[temp_state & 0x7FFF].no_of_entries != 0)
567  ctx->state_table_u16[state & 0x7FFF][ascii_code] |= (1 << 15);
568  }
569  }
570  } else {
571  for (state = 0; state < ctx->state_count; state++) {
572  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
573  temp_state = ctx->state_table_u32[state & 0x00FFFFFF][ascii_code];
574  if (ctx->output_table[temp_state & 0x00FFFFFF].no_of_entries != 0)
575  ctx->state_table_u32[state & 0x00FFFFFF][ascii_code] |= (1 << 24);
576  }
577  }
578  }
579 
580  return;
581 }
582 
583 static inline void SCACBSInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx)
584 {
585  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
586  uint32_t state = 0;
587  uint32_t k = 0;
588 
589  for (state = 0; state < ctx->state_count; state++) {
590  if (ctx->output_table[state].no_of_entries == 0)
591  continue;
592 
593  for (k = 0; k < ctx->output_table[state].no_of_entries; k++) {
594  if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) {
595  ctx->output_table[state].pids[k] &= 0x0000FFFF;
596  ctx->output_table[state].pids[k] |= 1 << 16;
597  }
598  }
599  }
600 
601  return;
602 }
603 
604 #if 0
605 static void SCACBSPrintDeltaTable(MpmCtx *mpm_ctx)
606 {
607  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
608  int i = 0, j = 0;
609 
610  printf("##############Delta Table##############\n");
611  for (i = 0; i < ctx->state_count; i++) {
612  printf("%d: \n", i);
613  for (j = 0; j < 256; j++) {
614  if (SCACBSGetDelta(i, j, mpm_ctx) != 0) {
615  printf(" %c -> %d\n", j, SCACBSGetDelta(i, j, mpm_ctx));
616  }
617  }
618  }
619 
620  return;
621 }
622 #endif
623 
624 static inline int SCACBSZeroTransitionPresent(SCACBSCtx *ctx, uint32_t state)
625 {
626  if (state == 0)
627  return 1;
628 
629  if (ctx->state_count < 32767) {
630  int ascii;
631  for (ascii = 0; ascii < 256; ascii++) {
632  if ((ctx->state_table_u16[0][ascii] & 0x7fff) == (state & 0x7fff)) {
633  return 1;
634  }
635  }
636 
637  return 0;
638  } else {
639  int ascii;
640  for (ascii = 0; ascii < 256; ascii++) {
641  if ((ctx->state_table_u32[0][ascii] & 0x00FFFFFF) ==
642  (state & 0x00FFFFFF)) {
643  return 1;
644  }
645  }
646 
647  return 0;
648  }
649 }
650 
651 /**
652  * \internal
653  * \brief Creates a new goto table structure(throw out all the failure
654  * transitions), to hold the existing goto table.
655  *
656  * \param mpm_ctx Pointer to the mpm context.
657  */
658 static inline void SCACBSCreateModDeltaTable(MpmCtx *mpm_ctx)
659 {
660  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
661 
662  if (ctx->state_count < 32767) {
663  int size = 0;
664  uint32_t state;
665 
666  for (state = 1; state < ctx->state_count; state++) {
667  int ascii_code;
668  int k = 0;
669  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
670  uint32_t temp_state = ctx->state_table_u16[state][ascii_code];
671  if (SCACBSZeroTransitionPresent(ctx, temp_state))
672  continue;
673  k++;
674  }
675  size += sizeof(uint16_t) * k * 2;
676  }
677 
678  /* Let us use uint16_t for all. That way we don//'t have to worry about
679  * alignment. Technically 8 bits is all we need to store ascii codes,
680  * but by avoiding it, we save a lot of time on handling alignment */
681  size += (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U16) +
682  256 * sizeof(SC_AC_BS_STATE_TYPE_U16) * 1);
683  ctx->state_table_mod = SCMalloc(size);
684  if (ctx->state_table_mod == NULL) {
685  FatalError("Error allocating memory");
686  }
687  memset(ctx->state_table_mod, 0, size);
688 
689  mpm_ctx->memory_cnt++;
690  mpm_ctx->memory_size += size;
691 
692  /* buffer to hold pointers in the buffer, so that a state can use it
693  * directly to access its state data */
694  ctx->state_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *));
695  if (ctx->state_table_mod_pointers == NULL) {
696  FatalError("Error allocating memory");
697  }
698  memset(ctx->state_table_mod_pointers, 0,
699  ctx->state_count * sizeof(uint8_t *));
700 
701  SC_AC_BS_STATE_TYPE_U16 temp_states[256];
702  uint16_t *curr_loc = (uint16_t *)ctx->state_table_mod;
703  uint16_t *no_of_entries = NULL;
704  uint16_t *ascii_codes = NULL;
705  uint16_t ascii_code = 0;
706  uint16_t k = 0;
707  for (state = 0; state < ctx->state_count; state++) {
708  /* store the starting location in the buffer for this state */
709  ctx->state_table_mod_pointers[state] = (uint8_t *)curr_loc;
710  no_of_entries = curr_loc++;
711  ascii_codes = curr_loc;
712  k = 0;
713  /* store all states that have non 0 transitions in the temp buffer */
714  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
715  uint32_t temp_state = ctx->state_table_u16[state][ascii_code];
716  if (state != 0 && SCACBSZeroTransitionPresent(ctx, temp_state))
717  continue;
718 
719  ascii_codes[k] = ascii_code;
720  temp_states[k] = ctx->state_table_u16[state][ascii_code];
721  k++;
722  }
723  /* if we have any non 0 transitions from our previous for search,
724  * store the ascii codes as well the corresponding states */
725  if (k > 0) {
726  no_of_entries[0] = k;
727  if (state != 0)
728  curr_loc += k;
729  memcpy(curr_loc, temp_states, k * sizeof(SC_AC_BS_STATE_TYPE_U16));
730  curr_loc += k;
731  }
732  }
733 
734  /* > 33766 */
735  } else {
736  int size = 0;
737  uint32_t state;
738  for (state = 1; state < ctx->state_count; state++) {
739  int ascii_code;
740  int k = 0;
741  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
742  uint32_t temp_state = ctx->state_table_u32[state][ascii_code];
743  if (SCACBSZeroTransitionPresent(ctx, temp_state))
744  continue;
745  k++;
746  }
747  size += sizeof(uint32_t) * k * 2;
748  }
749 
750  /* Let us use uint32_t for all. That way we don//'t have to worry about
751  * alignment. Technically 8 bits is all we need to store ascii codes,
752  * but by avoiding it, we save a lot of time on handling alignment */
753  size += (ctx->state_count * sizeof(SC_AC_BS_STATE_TYPE_U32) +
754  256 * sizeof(SC_AC_BS_STATE_TYPE_U32) * 1);
755  ctx->state_table_mod = SCMalloc(size);
756  if (ctx->state_table_mod == NULL) {
757  FatalError("Error allocating memory");
758  }
759  memset(ctx->state_table_mod, 0, size);
760 
761  mpm_ctx->memory_cnt++;
762  mpm_ctx->memory_size += size;
763 
764  /* buffer to hold pointers in the buffer, so that a state can use it
765  * directly to access its state data */
766  ctx->state_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *));
767  if (ctx->state_table_mod_pointers == NULL) {
768  FatalError("Error allocating memory");
769  }
770  memset(ctx->state_table_mod_pointers, 0,
771  ctx->state_count * sizeof(uint8_t *));
772 
773  SC_AC_BS_STATE_TYPE_U32 temp_states[256];
774  uint32_t *curr_loc = (uint32_t *)ctx->state_table_mod;
775  uint32_t *no_of_entries = NULL;
776  uint32_t *ascii_codes = NULL;
777  uint32_t ascii_code = 0;
778  uint32_t k = 0;
779  for (state = 0; state < ctx->state_count; state++) {
780  /* store the starting location in the buffer for this state */
781  ctx->state_table_mod_pointers[state] = (uint8_t *)curr_loc;
782  no_of_entries = curr_loc++;
783  ascii_codes = curr_loc;
784  k = 0;
785  /* store all states that have non 0 transitions in the temp buffer */
786  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
787  uint32_t temp_state = ctx->state_table_u32[state][ascii_code];
788  if (state != 0 && SCACBSZeroTransitionPresent(ctx, temp_state))
789  continue;
790 
791  ascii_codes[k] = ascii_code;
792  temp_states[k] = ctx->state_table_u32[state][ascii_code];
793  k++;
794  }
795  /* if we have any non 0 transitions from our previous for search,
796  * store the ascii codes as well the corresponding states */
797  if (k > 0) {
798  no_of_entries[0] = k;
799  if (state != 0)
800  curr_loc += k;
801  memcpy(curr_loc, temp_states, k * sizeof(SC_AC_BS_STATE_TYPE_U32));
802  curr_loc += k;
803  }
804  }
805 
806  }
807 
808  return;
809 }
810 
811 /**
812  * \brief Process the patterns and prepare the state table.
813  *
814  * \param mpm_ctx Pointer to the mpm context.
815  */
816 static inline void SCACBSPrepareStateTable(MpmCtx *mpm_ctx)
817 {
818  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
819 
820  /* create the 0th state in the goto table and output_table */
821  SCACBSInitNewState(mpm_ctx);
822 
823  /* create the goto table */
824  SCACBSCreateGotoTable(mpm_ctx);
825  /* create the failure table */
826  SCACBSCreateFailureTable(mpm_ctx);
827  /* create the final state(delta) table */
828  SCACBSCreateDeltaTable(mpm_ctx);
829  /* club the output state presence with delta transition entries */
830  SCACBSClubOutputStatePresenceWithDeltaTable(mpm_ctx);
831  /* create the modified table */
832  SCACBSCreateModDeltaTable(mpm_ctx);
833 
834  /* club nocase entries */
835  SCACBSInsertCaseSensitiveEntriesForPatterns(mpm_ctx);
836 
837 // int state = 0;
838 // for (state = 0; state < ctx->state_count; state++) {
839 // int i = 0;
840 // for (i = 0; i < 256; i++) {
841 // if (ctx->state_table_u16[state][i] != 0) {
842 // printf("%d-%d-%d\n", state, i, ctx->state_table_u16[state][i] & 0x7fff) ;
843 // }
844 // }
845 // }
846 
847 #if 0
848  SCACBSPrintDeltaTable(mpm_ctx);
849 #endif
850 
851  /* we don't need these anymore */
852  SCFree(ctx->goto_table);
853  ctx->goto_table = NULL;
854  SCFree(ctx->failure_table);
855  ctx->failure_table = NULL;
856  SCFree(ctx->state_table_u16);
857  ctx->state_table_u16 = NULL;
858  SCFree(ctx->state_table_u32);
859  ctx->state_table_u32 = NULL;
860 
861  return;
862 }
863 
864 /**
865  * \brief Process the patterns added to the mpm, and create the internal tables.
866  *
867  * \param mpm_ctx Pointer to the mpm context.
868  */
870 {
871  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
872 
873  if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) {
874  SCLogDebug("no patterns supplied to this mpm_ctx");
875  return 0;
876  }
877 
878  /* alloc the pattern array */
879  ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt *
880  sizeof(MpmPattern *));
881  if (ctx->parray == NULL)
882  goto error;
883  memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
884  mpm_ctx->memory_cnt++;
885  mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
886 
887  /* populate it with the patterns in the hash */
888  uint32_t i = 0, p = 0;
889  for (i = 0; i < MPM_INIT_HASH_SIZE; i++) {
890  MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL;
891  while(node != NULL) {
892  nnode = node->next;
893  node->next = NULL;
894  ctx->parray[p++] = node;
895  node = nnode;
896  }
897  }
898 
899  /* we no longer need the hash, so free it's memory */
900  SCFree(mpm_ctx->init_hash);
901  mpm_ctx->init_hash = NULL;
902 
903  /* the memory consumed by a single state in our goto table */
904  ctx->single_state_size = sizeof(int32_t) * 256;
905 
906  /* handle no case patterns */
907  ctx->pid_pat_list = SCMalloc((mpm_ctx->max_pat_id + 1)* sizeof(SCACBSPatternList));
908  if (ctx->pid_pat_list == NULL) {
909  FatalError("Error allocating memory");
910  }
911  memset(ctx->pid_pat_list, 0, (mpm_ctx->max_pat_id + 1) * sizeof(SCACBSPatternList));
912 
913  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
914  if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) {
915  ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len);
916  if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) {
917  FatalError("Error allocating memory");
918  }
919  memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs,
920  ctx->parray[i]->original_pat, ctx->parray[i]->len);
921  ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len;
922  }
923 
924  /* ACPatternList now owns this memory */
925  ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size;
926  ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids;
927  }
928 
929  /* prepare the state table required by AC */
930  SCACBSPrepareStateTable(mpm_ctx);
931 
932  /* free all the stored patterns. Should save us a good 100-200 mbs */
933  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
934  if (ctx->parray[i] != NULL) {
935  MpmFreePattern(mpm_ctx, ctx->parray[i]);
936  }
937  }
938  SCFree(ctx->parray);
939  ctx->parray = NULL;
940  mpm_ctx->memory_cnt--;
941  mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
942 
943  ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1;
944 
945  return 0;
946 
947 error:
948  return -1;
949 }
950 
951 /**
952  * \brief Init the mpm thread context.
953  *
954  * \param mpm_ctx Pointer to the mpm context.
955  * \param mpm_thread_ctx Pointer to the mpm thread context.
956  * \param matchsize We don't need this.
957  */
958 void SCACBSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
959 {
960  memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
961 
962  mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACBSThreadCtx));
963  if (mpm_thread_ctx->ctx == NULL) {
964  exit(EXIT_FAILURE);
965  }
966  memset(mpm_thread_ctx->ctx, 0, sizeof(SCACBSThreadCtx));
967  mpm_thread_ctx->memory_cnt++;
968  mpm_thread_ctx->memory_size += sizeof(SCACBSThreadCtx);
969 
970  return;
971 }
972 
973 /**
974  * \brief Initialize the AC context.
975  *
976  * \param mpm_ctx Mpm context.
977  */
978 void SCACBSInitCtx(MpmCtx *mpm_ctx)
979 {
980  if (mpm_ctx->ctx != NULL)
981  return;
982 
983  mpm_ctx->ctx = SCMalloc(sizeof(SCACBSCtx));
984  if (mpm_ctx->ctx == NULL) {
985  exit(EXIT_FAILURE);
986  }
987  memset(mpm_ctx->ctx, 0, sizeof(SCACBSCtx));
988 
989  mpm_ctx->memory_cnt++;
990  mpm_ctx->memory_size += sizeof(SCACBSCtx);
991 
992  /* initialize the hash we use to speed up pattern insertions */
993  mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE);
994  if (mpm_ctx->init_hash == NULL) {
995  exit(EXIT_FAILURE);
996  }
997  memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE);
998 
999  /* get conf values for AC from our yaml file. We have no conf values for
1000  * now. We will certainly need this, as we develop the algo */
1001  SCACBSGetConfig();
1002 
1003  SCReturn;
1004 }
1005 
1006 /**
1007  * \brief Destroy the mpm thread context.
1008  *
1009  * \param mpm_ctx Pointer to the mpm context.
1010  * \param mpm_thread_ctx Pointer to the mpm thread context.
1011  */
1012 void SCACBSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
1013 {
1014  SCACBSPrintSearchStats(mpm_thread_ctx);
1015 
1016  if (mpm_thread_ctx->ctx != NULL) {
1017  SCFree(mpm_thread_ctx->ctx);
1018  mpm_thread_ctx->ctx = NULL;
1019  mpm_thread_ctx->memory_cnt--;
1020  mpm_thread_ctx->memory_size -= sizeof(SCACBSThreadCtx);
1021  }
1022 
1023  return;
1024 }
1025 
1026 /**
1027  * \brief Destroy the mpm context.
1028  *
1029  * \param mpm_ctx Pointer to the mpm context.
1030  */
1031 void SCACBSDestroyCtx(MpmCtx *mpm_ctx)
1032 {
1033  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
1034  if (ctx == NULL)
1035  return;
1036 
1037  if (mpm_ctx->init_hash != NULL) {
1038  SCFree(mpm_ctx->init_hash);
1039  mpm_ctx->init_hash = NULL;
1040  mpm_ctx->memory_cnt--;
1041  mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *));
1042  }
1043 
1044  if (ctx->parray != NULL) {
1045  uint32_t i;
1046  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
1047  if (ctx->parray[i] != NULL) {
1048  MpmFreePattern(mpm_ctx, ctx->parray[i]);
1049  }
1050  }
1051 
1052  SCFree(ctx->parray);
1053  ctx->parray = NULL;
1054  mpm_ctx->memory_cnt--;
1055  mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
1056  }
1057 
1058  if (ctx->state_table_u16 != NULL) {
1059  SCFree(ctx->state_table_u16);
1060  ctx->state_table_u16 = NULL;
1061 
1062  mpm_ctx->memory_cnt++;
1063  mpm_ctx->memory_size -= (ctx->state_count *
1064  sizeof(SC_AC_BS_STATE_TYPE_U16) * 256);
1065  } else if (ctx->state_table_u32 != NULL) {
1066  SCFree(ctx->state_table_u32);
1067  ctx->state_table_u32 = NULL;
1068 
1069  mpm_ctx->memory_cnt++;
1070  mpm_ctx->memory_size -= (ctx->state_count *
1071  sizeof(SC_AC_BS_STATE_TYPE_U32) * 256);
1072  }
1073 
1074  if (ctx->output_table != NULL) {
1075  uint32_t state_count;
1076  for (state_count = 0; state_count < ctx->state_count; state_count++) {
1077  if (ctx->output_table[state_count].pids != NULL) {
1078  SCFree(ctx->output_table[state_count].pids);
1079  }
1080  }
1081  SCFree(ctx->output_table);
1082  }
1083 
1084  if (ctx->pid_pat_list != NULL) {
1085  uint32_t i;
1086  for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) {
1087  if (ctx->pid_pat_list[i].cs != NULL)
1088  SCFree(ctx->pid_pat_list[i].cs);
1089  if (ctx->pid_pat_list[i].sids != NULL)
1090  SCFree(ctx->pid_pat_list[i].sids);
1091  }
1092  SCFree(ctx->pid_pat_list);
1093  }
1094 
1095  if (ctx->state_table_mod != NULL) {
1096  SCFree(ctx->state_table_mod);
1097  ctx->state_table_mod = NULL;
1098  }
1099 
1100  if (ctx->state_table_mod_pointers != NULL) {
1102  ctx->state_table_mod_pointers = NULL;
1103  }
1104 
1105  SCFree(mpm_ctx->ctx);
1106  mpm_ctx->memory_cnt--;
1107  mpm_ctx->memory_size -= sizeof(SCACBSCtx);
1108 
1109  return;
1110 }
1111 
1112 /**
1113  * \brief The aho corasick search function.
1114  *
1115  * \param mpm_ctx Pointer to the mpm context.
1116  * \param mpm_thread_ctx Pointer to the mpm thread context.
1117  * \param pmq Pointer to the Pattern Matcher Queue to hold
1118  * search matches.
1119  * \param buf Buffer to be searched.
1120  * \param buflen Buffer length.
1121  *
1122  * \retval matches Match count.
1123  */
1124 uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
1125  PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen)
1126 {
1127  const SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
1128  uint32_t i = 0;
1129  int matches = 0;
1130  uint8_t buf_local;
1131 
1132  /* \todo tried loop unrolling with register var, with no perf increase. Need
1133  * to dig deeper */
1134  /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */
1135  SCACBSPatternList *pid_pat_list = ctx->pid_pat_list;
1136 
1137  uint8_t bitarray[ctx->pattern_id_bitarray_size];
1138  memset(bitarray, 0, ctx->pattern_id_bitarray_size);
1139 
1140  if (ctx->state_count < 32767) {
1141  register SC_AC_BS_STATE_TYPE_U16 state = 0;
1142  uint16_t no_of_entries;
1143  uint16_t *ascii_codes;
1144  uint16_t **state_table_mod_pointers = (uint16_t **)ctx->state_table_mod_pointers;
1145  uint16_t *zero_state = state_table_mod_pointers[0] + 1;
1146 
1147  for (i = 0; i < buflen; i++) {
1148  if (state == 0) {
1149  state = zero_state[u8_tolower(buf[i])];
1150  } else {
1151  no_of_entries = *(state_table_mod_pointers[state & 0x7FFF]);
1152  if (no_of_entries == 1) {
1153  ascii_codes = state_table_mod_pointers[state & 0x7FFF] + 1;
1154  buf_local = u8_tolower(buf[i]);
1155  if (buf_local == ascii_codes[0]) {
1156  state = *(ascii_codes + no_of_entries);
1157  } else {
1158  state = zero_state[buf_local];
1159  }
1160  } else {
1161  if (no_of_entries == 0) {
1162  state = zero_state[u8_tolower(buf[i])];
1163  goto match_u16;
1164  }
1165  buf_local = u8_tolower(buf[i]);
1166  ascii_codes = state_table_mod_pointers[state & 0x7FFF] + 1;
1167  int low = 0;
1168  int high = no_of_entries;
1169  int mid;
1170  while (low <= high) {
1171  mid = (low + high) / 2;
1172  if (ascii_codes[mid] == buf_local) {
1173  state = ((ascii_codes + no_of_entries))[mid];
1174  goto match_u16;
1175  } else if (ascii_codes[mid] < buf_local) {
1176  low = mid + 1;
1177  } else {
1178  high = mid - 1;
1179  }
1180  } /* while */
1181  state = zero_state[buf_local];
1182  } /* else - if (no_of_entires == 1) */
1183  }
1184 
1185  match_u16:
1186  if (state & 0x8000) {
1187  uint32_t nentries = ctx->output_table[state & 0x7FFF].no_of_entries;
1188  uint32_t *pids = ctx->output_table[state & 0x7FFF].pids;
1189  uint32_t k;
1190  for (k = 0; k < nentries; k++) {
1191  if (pids[k] & 0xFFFF0000) {
1192  uint32_t lower_pid = pids[k] & 0x0000FFFF;
1193  if (SCMemcmp(pid_pat_list[lower_pid].cs,
1194  buf + i - pid_pat_list[lower_pid].patlen + 1,
1195  pid_pat_list[lower_pid].patlen) != 0) {
1196  /* inside loop */
1197  continue;
1198  }
1199  if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) {
1200  ;
1201  } else {
1202  bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8));
1203  PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids,
1204  pid_pat_list[lower_pid].sids_size);
1205  }
1206  matches++;
1207  } else {
1208  if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) {
1209  ;
1210  } else {
1211  bitarray[pids[k] / 8] |= (1 << (pids[k] % 8));
1212  PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids,
1213  pid_pat_list[pids[k]].sids_size);
1214  }
1215  matches++;
1216  }
1217  //loop1:
1218  //;
1219  }
1220  }
1221  } /* for (i = 0; i < buflen; i++) */
1222 
1223  } else {
1224  register SC_AC_BS_STATE_TYPE_U32 state = 0;
1225  uint32_t no_of_entries;
1226  uint32_t *ascii_codes;
1227  uint32_t **state_table_mod_pointers = (uint32_t **)ctx->state_table_mod_pointers;
1228  uint32_t *zero_state = state_table_mod_pointers[0] + 1;
1229 
1230  for (i = 0; i < buflen; i++) {
1231  if (state == 0) {
1232  state = zero_state[u8_tolower(buf[i])];
1233  } else {
1234  no_of_entries = *(state_table_mod_pointers[state & 0x00FFFFFF]);
1235  if (no_of_entries == 1) {
1236  ascii_codes = state_table_mod_pointers[state & 0x00FFFFFF] + 1;
1237  buf_local = u8_tolower(buf[i]);
1238  if (buf_local == ascii_codes[0]) {
1239  state = *(ascii_codes + no_of_entries);
1240  } else {
1241  state = zero_state[buf_local];
1242  }
1243  } else {
1244  if (no_of_entries == 0) {
1245  state = zero_state[u8_tolower(buf[i])];
1246  goto match_u32;
1247  }
1248  buf_local = u8_tolower(buf[i]);
1249  ascii_codes = state_table_mod_pointers[state & 0x00FFFFFF] + 1;
1250  int low = 0;
1251  int high = no_of_entries;
1252  int mid;
1253  while (low <= high) {
1254  mid = (low + high) / 2;
1255  if (ascii_codes[mid] == buf_local) {
1256  state = ((ascii_codes + no_of_entries))[mid];
1257  goto match_u32;
1258  } else if (ascii_codes[mid] < buf_local) {
1259  low = mid + 1;
1260  } else {
1261  high = mid - 1;
1262  }
1263  } /* while */
1264  state = zero_state[buf_local];
1265  } /* else - if (no_of_entires == 1) */
1266  }
1267 
1268  match_u32:
1269  if (state & 0xFF000000) {
1270  uint32_t nentries = ctx->output_table[state & 0x00FFFFFF].no_of_entries;
1271  uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids;
1272  uint32_t k;
1273  for (k = 0; k < nentries; k++) {
1274  if (pids[k] & 0xFFFF0000) {
1275  uint32_t lower_pid = pids[k] & 0x0000FFFF;
1276  if (SCMemcmp(pid_pat_list[lower_pid].cs,
1277  buf + i - pid_pat_list[lower_pid].patlen + 1,
1278  pid_pat_list[lower_pid].patlen) != 0) {
1279  /* inside loop */
1280  continue;
1281  }
1282  if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) {
1283  ;
1284  } else {
1285  bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8));
1286  PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids,
1287  pid_pat_list[lower_pid].sids_size);
1288  }
1289  matches++;
1290  } else {
1291  if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) {
1292  ;
1293  } else {
1294  bitarray[pids[k] / 8] |= (1 << (pids[k] % 8));
1295  PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids,
1296  pid_pat_list[pids[k]].sids_size);
1297  }
1298  matches++;
1299  }
1300  //loop1:
1301  //;
1302  }
1303  }
1304  } /* for (i = 0; i < buflen; i++) */
1305  }
1306 
1307  return matches;
1308 }
1309 
1310 /**
1311  * \brief Add a case insensitive pattern. Although we have different calls for
1312  * adding case sensitive and insensitive patterns, we make a single call
1313  * for either case. No special treatment for either case.
1314  *
1315  * \param mpm_ctx Pointer to the mpm context.
1316  * \param pat The pattern to add.
1317  * \param patnen The pattern length.
1318  * \param offset Ignored.
1319  * \param depth Ignored.
1320  * \param pid The pattern id.
1321  * \param sid Ignored.
1322  * \param flags Flags associated with this pattern.
1323  *
1324  * \retval 0 On success.
1325  * \retval -1 On failure.
1326  */
1327 int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
1328  uint16_t offset, uint16_t depth, uint32_t pid,
1329  SigIntId sid, uint8_t flags)
1330 {
1332  return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
1333 }
1334 
1335 /**
1336  * \brief Add a case sensitive pattern. Although we have different calls for
1337  * adding case sensitive and insensitive patterns, we make a single call
1338  * for either case. No special treatment for either case.
1339  *
1340  * \param mpm_ctx Pointer to the mpm context.
1341  * \param pat The pattern to add.
1342  * \param patnen The pattern length.
1343  * \param offset Ignored.
1344  * \param depth Ignored.
1345  * \param pid The pattern id.
1346  * \param sid Ignored.
1347  * \param flags Flags associated with this pattern.
1348  *
1349  * \retval 0 On success.
1350  * \retval -1 On failure.
1351  */
1352 int SCACBSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
1353  uint16_t offset, uint16_t depth, uint32_t pid,
1354  SigIntId sid, uint8_t flags)
1355 {
1356  return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
1357 }
1358 
1360 {
1361 
1362 #ifdef SC_AC_BS_COUNTERS
1363  SCACBSThreadCtx *ctx = (SCACBSThreadCtx *)mpm_thread_ctx->ctx;
1364  printf("AC Thread Search stats (ctx %p)\n", ctx);
1365  printf("Total calls: %" PRIu32 "\n", ctx->total_calls);
1366  printf("Total matches: %" PRIu64 "\n", ctx->total_matches);
1367 #endif /* SC_AC_BS_COUNTERS */
1368 
1369  return;
1370 }
1371 
1372 void SCACBSPrintInfo(MpmCtx *mpm_ctx)
1373 {
1374  SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx;
1375 
1376  printf("MPM AC Information:\n");
1377  printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt);
1378  printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size);
1379  printf(" Sizeof:\n");
1380  printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx));
1381  printf(" SCACBSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSCtx));
1382  printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern));
1383  printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern));
1384  printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt);
1385  printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen);
1386  printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen);
1387  printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count);
1388  printf("\n");
1389 
1390  return;
1391 }
1392 
1393 /*************************************Unittests********************************/
1394 
1395 #ifdef UNITTESTS
1396 #include "detect-engine-alert.h"
1397 
1398 static int SCACBSTest01(void)
1399 {
1400  int result = 0;
1401  MpmCtx mpm_ctx;
1402  MpmThreadCtx mpm_thread_ctx;
1403  PrefilterRuleStore pmq;
1404 
1405  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1406  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1407  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1408  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1409 
1410  /* 1 match */
1411  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1412  PmqSetup(&pmq);
1413 
1414  SCACBSPreparePatterns(&mpm_ctx);
1415 
1416  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1417 
1418  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1419  (uint8_t *)buf, strlen(buf));
1420 
1421  if (cnt == 1)
1422  result = 1;
1423  else
1424  printf("1 != %" PRIu32 " ",cnt);
1425 
1426  SCACBSDestroyCtx(&mpm_ctx);
1427  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1428  PmqFree(&pmq);
1429  return result;
1430 }
1431 
1432 static int SCACBSTest02(void)
1433 {
1434  int result = 0;
1435  MpmCtx mpm_ctx;
1436  MpmThreadCtx mpm_thread_ctx;
1437  PrefilterRuleStore pmq;
1438 
1439  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1440  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1441  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1442  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1443 
1444  /* 1 match */
1445  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0);
1446  PmqSetup(&pmq);
1447 
1448  SCACBSPreparePatterns(&mpm_ctx);
1449 
1450  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1451  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1452  (uint8_t *)buf, strlen(buf));
1453 
1454  if (cnt == 0)
1455  result = 1;
1456  else
1457  printf("0 != %" PRIu32 " ",cnt);
1458 
1459  SCACBSDestroyCtx(&mpm_ctx);
1460  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1461  PmqFree(&pmq);
1462  return result;
1463 }
1464 
1465 static int SCACBSTest03(void)
1466 {
1467  int result = 0;
1468  MpmCtx mpm_ctx;
1469  MpmThreadCtx mpm_thread_ctx;
1470  PrefilterRuleStore pmq;
1471 
1472  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1473  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1474  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1475  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1476 
1477  /* 1 match */
1478  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1479  /* 1 match */
1480  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0);
1481  /* 1 match */
1482  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0);
1483  PmqSetup(&pmq);
1484 
1485  SCACBSPreparePatterns(&mpm_ctx);
1486 
1487  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1488  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1489  (uint8_t *)buf, strlen(buf));
1490 
1491  if (cnt == 3)
1492  result = 1;
1493  else
1494  printf("3 != %" PRIu32 " ",cnt);
1495 
1496  SCACBSDestroyCtx(&mpm_ctx);
1497  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1498  PmqFree(&pmq);
1499  return result;
1500 }
1501 
1502 static int SCACBSTest04(void)
1503 {
1504  int result = 0;
1505  MpmCtx mpm_ctx;
1506  MpmThreadCtx mpm_thread_ctx;
1507  PrefilterRuleStore pmq;
1508 
1509  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1510  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1511  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1512  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1513 
1514  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1515  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0);
1516  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0);
1517  PmqSetup(&pmq);
1518 
1519  SCACBSPreparePatterns(&mpm_ctx);
1520 
1521  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1522  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1523  (uint8_t *)buf, strlen(buf));
1524 
1525  if (cnt == 1)
1526  result = 1;
1527  else
1528  printf("1 != %" PRIu32 " ",cnt);
1529 
1530  SCACBSDestroyCtx(&mpm_ctx);
1531  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1532  PmqFree(&pmq);
1533  return result;
1534 }
1535 
1536 static int SCACBSTest05(void)
1537 {
1538  int result = 0;
1539  MpmCtx mpm_ctx;
1540  MpmThreadCtx mpm_thread_ctx;
1541  PrefilterRuleStore pmq;
1542 
1543  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1544  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1545  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1546  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1547 
1548  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
1549  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
1550  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0);
1551  PmqSetup(&pmq);
1552 
1553  SCACBSPreparePatterns(&mpm_ctx);
1554 
1555  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1556  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1557  (uint8_t *)buf, strlen(buf));
1558 
1559  if (cnt == 3)
1560  result = 1;
1561  else
1562  printf("3 != %" PRIu32 " ",cnt);
1563 
1564  SCACBSDestroyCtx(&mpm_ctx);
1565  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1566  PmqFree(&pmq);
1567  return result;
1568 }
1569 
1570 static int SCACBSTest06(void)
1571 {
1572  int result = 0;
1573  MpmCtx mpm_ctx;
1574  MpmThreadCtx mpm_thread_ctx;
1575  PrefilterRuleStore pmq;
1576 
1577  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1578  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1579  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1580  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1581 
1582  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1583  PmqSetup(&pmq);
1584 
1585  SCACBSPreparePatterns(&mpm_ctx);
1586 
1587  const char *buf = "abcd";
1588  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1589  (uint8_t *)buf, strlen(buf));
1590 
1591  if (cnt == 1)
1592  result = 1;
1593  else
1594  printf("1 != %" PRIu32 " ",cnt);
1595 
1596  SCACBSDestroyCtx(&mpm_ctx);
1597  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1598  PmqFree(&pmq);
1599  return result;
1600 }
1601 
1602 static int SCACBSTest07(void)
1603 {
1604  int result = 0;
1605  MpmCtx mpm_ctx;
1606  MpmThreadCtx mpm_thread_ctx;
1607  PrefilterRuleStore pmq;
1608 
1609  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1610  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1611  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1612  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1613 
1614  /* should match 30 times */
1615  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0);
1616  /* should match 29 times */
1617  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0);
1618  /* should match 28 times */
1619  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0);
1620  /* 26 */
1621  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0);
1622  /* 21 */
1623  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0);
1624  /* 1 */
1625  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1626  30, 0, 0, 5, 0, 0);
1627  PmqSetup(&pmq);
1628  /* total matches: 135 */
1629 
1630  SCACBSPreparePatterns(&mpm_ctx);
1631 
1632  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1633  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1634  (uint8_t *)buf, strlen(buf));
1635 
1636  if (cnt == 135)
1637  result = 1;
1638  else
1639  printf("135 != %" PRIu32 " ",cnt);
1640 
1641  SCACBSDestroyCtx(&mpm_ctx);
1642  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1643  PmqFree(&pmq);
1644  return result;
1645 }
1646 
1647 static int SCACBSTest08(void)
1648 {
1649  int result = 0;
1650  MpmCtx mpm_ctx;
1651  MpmThreadCtx mpm_thread_ctx;
1652  PrefilterRuleStore pmq;
1653 
1654  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1655  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1656  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1657  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1658 
1659  /* 1 match */
1660  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1661  PmqSetup(&pmq);
1662 
1663  SCACBSPreparePatterns(&mpm_ctx);
1664 
1665  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1666  (uint8_t *)"a", 1);
1667 
1668  if (cnt == 0)
1669  result = 1;
1670  else
1671  printf("0 != %" PRIu32 " ",cnt);
1672 
1673  SCACBSDestroyCtx(&mpm_ctx);
1674  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1675  PmqFree(&pmq);
1676  return result;
1677 }
1678 
1679 static int SCACBSTest09(void)
1680 {
1681  int result = 0;
1682  MpmCtx mpm_ctx;
1683  MpmThreadCtx mpm_thread_ctx;
1684  PrefilterRuleStore pmq;
1685 
1686  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1687  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1688  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1689  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1690 
1691  /* 1 match */
1692  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0);
1693  PmqSetup(&pmq);
1694 
1695  SCACBSPreparePatterns(&mpm_ctx);
1696 
1697  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1698  (uint8_t *)"ab", 2);
1699 
1700  if (cnt == 1)
1701  result = 1;
1702  else
1703  printf("1 != %" PRIu32 " ",cnt);
1704 
1705  SCACBSDestroyCtx(&mpm_ctx);
1706  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1707  PmqFree(&pmq);
1708  return result;
1709 }
1710 
1711 static int SCACBSTest10(void)
1712 {
1713  int result = 0;
1714  MpmCtx mpm_ctx;
1715  MpmThreadCtx mpm_thread_ctx;
1716  PrefilterRuleStore pmq;
1717 
1718  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1719  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1720  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1721  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1722 
1723  /* 1 match */
1724  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0);
1725  PmqSetup(&pmq);
1726 
1727  SCACBSPreparePatterns(&mpm_ctx);
1728 
1729  const char *buf = "01234567890123456789012345678901234567890123456789"
1730  "01234567890123456789012345678901234567890123456789"
1731  "abcdefgh"
1732  "01234567890123456789012345678901234567890123456789"
1733  "01234567890123456789012345678901234567890123456789";
1734  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1735  (uint8_t *)buf, strlen(buf));
1736 
1737  if (cnt == 1)
1738  result = 1;
1739  else
1740  printf("1 != %" PRIu32 " ",cnt);
1741 
1742  SCACBSDestroyCtx(&mpm_ctx);
1743  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1744  PmqFree(&pmq);
1745  return result;
1746 }
1747 
1748 static int SCACBSTest11(void)
1749 {
1750  int result = 0;
1751  MpmCtx mpm_ctx;
1752  MpmThreadCtx mpm_thread_ctx;
1753  PrefilterRuleStore pmq;
1754 
1755  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1756  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1757  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1758  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1759 
1760  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1)
1761  goto end;
1762  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1)
1763  goto end;
1764  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1)
1765  goto end;
1766  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1)
1767  goto end;
1768  PmqSetup(&pmq);
1769 
1770  if (SCACBSPreparePatterns(&mpm_ctx) == -1)
1771  goto end;
1772 
1773  result = 1;
1774 
1775  const char *buf = "he";
1776  result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1777  strlen(buf)) == 1);
1778  buf = "she";
1779  result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1780  strlen(buf)) == 2);
1781  buf = "his";
1782  result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1783  strlen(buf)) == 1);
1784  buf = "hers";
1785  result &= (SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1786  strlen(buf)) == 2);
1787 
1788  end:
1789  SCACBSDestroyCtx(&mpm_ctx);
1790  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1791  PmqFree(&pmq);
1792  return result;
1793 }
1794 
1795 static int SCACBSTest12(void)
1796 {
1797  int result = 0;
1798  MpmCtx mpm_ctx;
1799  MpmThreadCtx mpm_thread_ctx;
1800  PrefilterRuleStore pmq;
1801 
1802  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1803  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1804  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1805  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1806 
1807  /* 1 match */
1808  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0);
1809  /* 1 match */
1810  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0);
1811  PmqSetup(&pmq);
1812 
1813  SCACBSPreparePatterns(&mpm_ctx);
1814 
1815  const char *buf = "abcdefghijklmnopqrstuvwxyz";
1816  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1817  (uint8_t *)buf, strlen(buf));
1818 
1819  if (cnt == 2)
1820  result = 1;
1821  else
1822  printf("2 != %" PRIu32 " ",cnt);
1823 
1824  SCACBSDestroyCtx(&mpm_ctx);
1825  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1826  PmqFree(&pmq);
1827  return result;
1828 }
1829 
1830 static int SCACBSTest13(void)
1831 {
1832  int result = 0;
1833  MpmCtx mpm_ctx;
1834  MpmThreadCtx mpm_thread_ctx;
1835  PrefilterRuleStore pmq;
1836 
1837  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1838  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1839  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1840  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1841 
1842  /* 1 match */
1843  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD";
1844  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1845  PmqSetup(&pmq);
1846 
1847  SCACBSPreparePatterns(&mpm_ctx);
1848 
1849  const char *buf = "abcdefghijklmnopqrstuvwxyzABCD";
1850  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1851  (uint8_t *)buf, strlen(buf));
1852 
1853  if (cnt == 1)
1854  result = 1;
1855  else
1856  printf("1 != %" PRIu32 " ",cnt);
1857 
1858  SCACBSDestroyCtx(&mpm_ctx);
1859  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1860  PmqFree(&pmq);
1861  return result;
1862 }
1863 
1864 static int SCACBSTest14(void)
1865 {
1866  int result = 0;
1867  MpmCtx mpm_ctx;
1868  MpmThreadCtx mpm_thread_ctx;
1869  PrefilterRuleStore pmq;
1870 
1871  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1872  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1873  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1874  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1875 
1876  /* 1 match */
1877  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE";
1878  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1879  PmqSetup(&pmq);
1880 
1881  SCACBSPreparePatterns(&mpm_ctx);
1882 
1883  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE";
1884  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1885  (uint8_t *)buf, strlen(buf));
1886 
1887  if (cnt == 1)
1888  result = 1;
1889  else
1890  printf("1 != %" PRIu32 " ",cnt);
1891 
1892  SCACBSDestroyCtx(&mpm_ctx);
1893  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1894  PmqFree(&pmq);
1895  return result;
1896 }
1897 
1898 static int SCACBSTest15(void)
1899 {
1900  int result = 0;
1901  MpmCtx mpm_ctx;
1902  MpmThreadCtx mpm_thread_ctx;
1903  PrefilterRuleStore pmq;
1904 
1905  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1906  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1907  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1908  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1909 
1910  /* 1 match */
1911  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF";
1912  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1913  PmqSetup(&pmq);
1914 
1915  SCACBSPreparePatterns(&mpm_ctx);
1916 
1917  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF";
1918  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1919  (uint8_t *)buf, strlen(buf));
1920 
1921  if (cnt == 1)
1922  result = 1;
1923  else
1924  printf("1 != %" PRIu32 " ",cnt);
1925 
1926  SCACBSDestroyCtx(&mpm_ctx);
1927  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1928  PmqFree(&pmq);
1929  return result;
1930 }
1931 
1932 static int SCACBSTest16(void)
1933 {
1934  int result = 0;
1935  MpmCtx mpm_ctx;
1936  MpmThreadCtx mpm_thread_ctx;
1937  PrefilterRuleStore pmq;
1938 
1939  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1940  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1941  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1942  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1943 
1944  /* 1 match */
1945  const char pat[] = "abcdefghijklmnopqrstuvwxyzABC";
1946  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1947  PmqSetup(&pmq);
1948 
1949  SCACBSPreparePatterns(&mpm_ctx);
1950 
1951  const char *buf = "abcdefghijklmnopqrstuvwxyzABC";
1952  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1953  (uint8_t *)buf, strlen(buf));
1954 
1955  if (cnt == 1)
1956  result = 1;
1957  else
1958  printf("1 != %" PRIu32 " ",cnt);
1959 
1960  SCACBSDestroyCtx(&mpm_ctx);
1961  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1962  PmqFree(&pmq);
1963  return result;
1964 }
1965 
1966 static int SCACBSTest17(void)
1967 {
1968  int result = 0;
1969  MpmCtx mpm_ctx;
1970  MpmThreadCtx mpm_thread_ctx;
1971  PrefilterRuleStore pmq;
1972 
1973  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1974  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1975  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
1976  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1977 
1978  /* 1 match */
1979  const char pat[] = "abcdefghijklmnopqrstuvwxyzAB";
1980  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1981  PmqSetup(&pmq);
1982 
1983  SCACBSPreparePatterns(&mpm_ctx);
1984 
1985  const char *buf = "abcdefghijklmnopqrstuvwxyzAB";
1986  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1987  (uint8_t *)buf, strlen(buf));
1988 
1989  if (cnt == 1)
1990  result = 1;
1991  else
1992  printf("1 != %" PRIu32 " ",cnt);
1993 
1994  SCACBSDestroyCtx(&mpm_ctx);
1995  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1996  PmqFree(&pmq);
1997  return result;
1998 }
1999 
2000 static int SCACBSTest18(void)
2001 {
2002  int result = 0;
2003  MpmCtx mpm_ctx;
2004  MpmThreadCtx mpm_thread_ctx;
2005  PrefilterRuleStore pmq;
2006 
2007  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2008  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2009  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2010  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2011 
2012  /* 1 match */
2013  const char pat[] = "abcde"
2014  "fghij"
2015  "klmno"
2016  "pqrst"
2017  "uvwxy"
2018  "z";
2019  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
2020  PmqSetup(&pmq);
2021 
2022  SCACBSPreparePatterns(&mpm_ctx);
2023 
2024  const char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z";
2025  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2026  (uint8_t *)buf, strlen(buf));
2027 
2028  if (cnt == 1)
2029  result = 1;
2030  else
2031  printf("1 != %" PRIu32 " ",cnt);
2032 
2033  SCACBSDestroyCtx(&mpm_ctx);
2034  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2035  PmqFree(&pmq);
2036  return result;
2037 }
2038 
2039 static int SCACBSTest19(void)
2040 {
2041  int result = 0;
2042  MpmCtx mpm_ctx;
2043  MpmThreadCtx mpm_thread_ctx;
2044  PrefilterRuleStore pmq;
2045 
2046  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2047  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2048  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2049  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2050 
2051  /* 1 */
2052  const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
2053  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
2054  PmqSetup(&pmq);
2055 
2056  SCACBSPreparePatterns(&mpm_ctx);
2057 
2058  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
2059  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2060  (uint8_t *)buf, strlen(buf));
2061 
2062  if (cnt == 1)
2063  result = 1;
2064  else
2065  printf("1 != %" PRIu32 " ",cnt);
2066 
2067  SCACBSDestroyCtx(&mpm_ctx);
2068  PmqFree(&pmq);
2069  return result;
2070 }
2071 
2072 static int SCACBSTest20(void)
2073 {
2074  int result = 0;
2075  MpmCtx mpm_ctx;
2076  MpmThreadCtx mpm_thread_ctx;
2077  PrefilterRuleStore pmq;
2078 
2079  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2080  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2081  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2082  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2083 
2084  /* 1 */
2085  const char pat[] = "AAAAA"
2086  "AAAAA"
2087  "AAAAA"
2088  "AAAAA"
2089  "AAAAA"
2090  "AAAAA"
2091  "AA";
2092  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
2093  PmqSetup(&pmq);
2094 
2095  SCACBSPreparePatterns(&mpm_ctx);
2096 
2097  const char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA";
2098  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2099  (uint8_t *)buf, strlen(buf));
2100 
2101  if (cnt == 1)
2102  result = 1;
2103  else
2104  printf("1 != %" PRIu32 " ",cnt);
2105 
2106  SCACBSDestroyCtx(&mpm_ctx);
2107  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2108  PmqFree(&pmq);
2109  return result;
2110 }
2111 
2112 static int SCACBSTest21(void)
2113 {
2114  int result = 0;
2115  MpmCtx mpm_ctx;
2116  MpmThreadCtx mpm_thread_ctx;
2117  PrefilterRuleStore pmq;
2118 
2119  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2120  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2121  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2122  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2123 
2124  /* 1 */
2125  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2126  PmqSetup(&pmq);
2127 
2128  SCACBSPreparePatterns(&mpm_ctx);
2129 
2130  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2131  (uint8_t *)"AA", 2);
2132 
2133  if (cnt == 1)
2134  result = 1;
2135  else
2136  printf("1 != %" PRIu32 " ",cnt);
2137 
2138  SCACBSDestroyCtx(&mpm_ctx);
2139  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2140  PmqFree(&pmq);
2141  return result;
2142 }
2143 
2144 static int SCACBSTest22(void)
2145 {
2146  int result = 0;
2147  MpmCtx mpm_ctx;
2148  MpmThreadCtx mpm_thread_ctx;
2149  PrefilterRuleStore pmq;
2150 
2151  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2152  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2153  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2154  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2155 
2156  /* 1 match */
2157  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
2158  /* 1 match */
2159  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0);
2160  PmqSetup(&pmq);
2161 
2162  SCACBSPreparePatterns(&mpm_ctx);
2163 
2164  const char *buf = "abcdefghijklmnopqrstuvwxyz";
2165  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2166  (uint8_t *)buf, strlen(buf));
2167 
2168  if (cnt == 2)
2169  result = 1;
2170  else
2171  printf("2 != %" PRIu32 " ",cnt);
2172 
2173  SCACBSDestroyCtx(&mpm_ctx);
2174  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2175  PmqFree(&pmq);
2176  return result;
2177 }
2178 
2179 static int SCACBSTest23(void)
2180 {
2181  int result = 0;
2182  MpmCtx mpm_ctx;
2183  MpmThreadCtx mpm_thread_ctx;
2184  PrefilterRuleStore pmq;
2185 
2186  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2187  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2188  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2189  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2190 
2191  /* 1 */
2192  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2193  PmqSetup(&pmq);
2194 
2195  SCACBSPreparePatterns(&mpm_ctx);
2196 
2197  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2198  (uint8_t *)"aa", 2);
2199 
2200  if (cnt == 0)
2201  result = 1;
2202  else
2203  printf("1 != %" PRIu32 " ",cnt);
2204 
2205  SCACBSDestroyCtx(&mpm_ctx);
2206  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2207  PmqFree(&pmq);
2208  return result;
2209 }
2210 
2211 static int SCACBSTest24(void)
2212 {
2213  int result = 0;
2214  MpmCtx mpm_ctx;
2215  MpmThreadCtx mpm_thread_ctx;
2216  PrefilterRuleStore pmq;
2217 
2218  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2219  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2220  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2221  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2222 
2223  /* 1 */
2224  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2225  PmqSetup(&pmq);
2226 
2227  SCACBSPreparePatterns(&mpm_ctx);
2228 
2229  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2230  (uint8_t *)"aa", 2);
2231 
2232  if (cnt == 1)
2233  result = 1;
2234  else
2235  printf("1 != %" PRIu32 " ",cnt);
2236 
2237  SCACBSDestroyCtx(&mpm_ctx);
2238  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2239  PmqFree(&pmq);
2240  return result;
2241 }
2242 
2243 static int SCACBSTest25(void)
2244 {
2245  int result = 0;
2246  MpmCtx mpm_ctx;
2247  MpmThreadCtx mpm_thread_ctx;
2248  PrefilterRuleStore pmq;
2249 
2250  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2251  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2252  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2253  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2254 
2255  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
2256  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
2257  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0);
2258  PmqSetup(&pmq);
2259 
2260  SCACBSPreparePatterns(&mpm_ctx);
2261 
2262  const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2263  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2264  (uint8_t *)buf, strlen(buf));
2265 
2266  if (cnt == 3)
2267  result = 1;
2268  else
2269  printf("3 != %" PRIu32 " ",cnt);
2270 
2271  SCACBSDestroyCtx(&mpm_ctx);
2272  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2273  PmqFree(&pmq);
2274  return result;
2275 }
2276 
2277 static int SCACBSTest26(void)
2278 {
2279  int result = 0;
2280  MpmCtx mpm_ctx;
2281  MpmThreadCtx mpm_thread_ctx;
2282  PrefilterRuleStore pmq;
2283 
2284  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2285  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2286  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2287  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2288 
2289  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0);
2290  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0);
2291  PmqSetup(&pmq);
2292 
2293  SCACBSPreparePatterns(&mpm_ctx);
2294 
2295  const char *buf = "works";
2296  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2297  (uint8_t *)buf, strlen(buf));
2298 
2299  if (cnt == 1)
2300  result = 1;
2301  else
2302  printf("3 != %" PRIu32 " ",cnt);
2303 
2304  SCACBSDestroyCtx(&mpm_ctx);
2305  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2306  PmqFree(&pmq);
2307  return result;
2308 }
2309 
2310 static int SCACBSTest27(void)
2311 {
2312  int result = 0;
2313  MpmCtx mpm_ctx;
2314  MpmThreadCtx mpm_thread_ctx;
2315  PrefilterRuleStore pmq;
2316 
2317  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2318  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2319  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2320  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2321 
2322  /* 0 match */
2323  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0);
2324  PmqSetup(&pmq);
2325 
2326  SCACBSPreparePatterns(&mpm_ctx);
2327 
2328  const char *buf = "tone";
2329  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2330  (uint8_t *)buf, strlen(buf));
2331 
2332  if (cnt == 0)
2333  result = 1;
2334  else
2335  printf("0 != %" PRIu32 " ",cnt);
2336 
2337  SCACBSDestroyCtx(&mpm_ctx);
2338  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2339  PmqFree(&pmq);
2340  return result;
2341 }
2342 
2343 static int SCACBSTest28(void)
2344 {
2345  int result = 0;
2346  MpmCtx mpm_ctx;
2347  MpmThreadCtx mpm_thread_ctx;
2348  PrefilterRuleStore pmq;
2349 
2350  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2351  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2352  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2353  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2354 
2355  /* 0 match */
2356  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0);
2357  PmqSetup(&pmq);
2358 
2359  SCACBSPreparePatterns(&mpm_ctx);
2360 
2361  const char *buf = "tONE";
2362  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2363  (uint8_t *)buf, strlen(buf));
2364 
2365  if (cnt == 0)
2366  result = 1;
2367  else
2368  printf("0 != %" PRIu32 " ",cnt);
2369 
2370  SCACBSDestroyCtx(&mpm_ctx);
2371  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2372  PmqFree(&pmq);
2373  return result;
2374 }
2375 
2376 static int SCACBSTest29(void)
2377 {
2378  int result = 0;
2379  MpmCtx mpm_ctx;
2380  MpmThreadCtx mpm_thread_ctx;
2381  PrefilterRuleStore pmq;
2382 
2383  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2384  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2385  MpmInitCtx(&mpm_ctx, MPM_AC_BS);
2386  SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2387 
2388  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0);
2389  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdef", 5, 0, 0, 1, 0, 0);
2390  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdefg", 5, 0, 0, 3, 0, 0);
2391  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"defgh", 5, 0, 0, 4, 0, 0);
2392  PmqSetup(&pmq);
2393 
2394  SCACBSPreparePatterns(&mpm_ctx);
2395 
2396  const char *buf = "abcdefgh";
2397  uint32_t cnt = SCACBSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2398  (uint8_t *)buf, strlen(buf));
2399 
2400  if (cnt == 4)
2401  result = 1;
2402  else
2403  printf("3 != %" PRIu32 " ",cnt);
2404 
2405  SCACBSDestroyCtx(&mpm_ctx);
2406  SCACBSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2407  PmqFree(&pmq);
2408  return result;
2409 }
2410 
2411 static int SCACBSTest30(void)
2412 {
2413  uint8_t buf[] = "onetwothreefourfivesixseveneightnine";
2414  uint16_t buflen = sizeof(buf) - 1;
2415  Packet *p = NULL;
2416  ThreadVars th_v;
2417  DetectEngineThreadCtx *det_ctx = NULL;
2418  int result = 0;
2419 
2420  memset(&th_v, 0, sizeof(th_v));
2421  p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2422 
2424  if (de_ctx == NULL)
2425  goto end;
2427 
2428  de_ctx->flags |= DE_QUIET;
2429 
2430  de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
2431  "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)");
2432  if (de_ctx->sig_list == NULL)
2433  goto end;
2434  de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any "
2435  "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)");
2436  if (de_ctx->sig_list->next == NULL)
2437  goto end;
2438 
2440  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2441 
2442  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2443  if (PacketAlertCheck(p, 1) != 1) {
2444  printf("if (PacketAlertCheck(p, 1) != 1) failure\n");
2445  goto end;
2446  }
2447  if (PacketAlertCheck(p, 2) != 1) {
2448  printf("if (PacketAlertCheck(p, 1) != 2) failure\n");
2449  goto end;
2450  }
2451 
2452  result = 1;
2453 end:
2454  if (de_ctx != NULL) {
2457 
2458  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2460  }
2461 
2462  UTHFreePackets(&p, 1);
2463  return result;
2464 }
2465 
2466 #endif /* UNITTESTS */
2467 
2469 {
2470 
2471 #ifdef UNITTESTS
2472  UtRegisterTest("SCACBSTest01", SCACBSTest01);
2473  UtRegisterTest("SCACBSTest02", SCACBSTest02);
2474  UtRegisterTest("SCACBSTest03", SCACBSTest03);
2475  UtRegisterTest("SCACBSTest04", SCACBSTest04);
2476  UtRegisterTest("SCACBSTest05", SCACBSTest05);
2477  UtRegisterTest("SCACBSTest06", SCACBSTest06);
2478  UtRegisterTest("SCACBSTest07", SCACBSTest07);
2479  UtRegisterTest("SCACBSTest08", SCACBSTest08);
2480  UtRegisterTest("SCACBSTest09", SCACBSTest09);
2481  UtRegisterTest("SCACBSTest10", SCACBSTest10);
2482  UtRegisterTest("SCACBSTest11", SCACBSTest11);
2483  UtRegisterTest("SCACBSTest12", SCACBSTest12);
2484  UtRegisterTest("SCACBSTest13", SCACBSTest13);
2485  UtRegisterTest("SCACBSTest14", SCACBSTest14);
2486  UtRegisterTest("SCACBSTest15", SCACBSTest15);
2487  UtRegisterTest("SCACBSTest16", SCACBSTest16);
2488  UtRegisterTest("SCACBSTest17", SCACBSTest17);
2489  UtRegisterTest("SCACBSTest18", SCACBSTest18);
2490  UtRegisterTest("SCACBSTest19", SCACBSTest19);
2491  UtRegisterTest("SCACBSTest20", SCACBSTest20);
2492  UtRegisterTest("SCACBSTest21", SCACBSTest21);
2493  UtRegisterTest("SCACBSTest22", SCACBSTest22);
2494  UtRegisterTest("SCACBSTest23", SCACBSTest23);
2495  UtRegisterTest("SCACBSTest24", SCACBSTest24);
2496  UtRegisterTest("SCACBSTest25", SCACBSTest25);
2497  UtRegisterTest("SCACBSTest26", SCACBSTest26);
2498  UtRegisterTest("SCACBSTest27", SCACBSTest27);
2499  UtRegisterTest("SCACBSTest28", SCACBSTest28);
2500  UtRegisterTest("SCACBSTest29", SCACBSTest29);
2501  UtRegisterTest("SCACBSTest30", SCACBSTest30);
2502 #endif
2503 
2504  return;
2505 }
MpmTableElmt_::PrintThreadCtx
void(* PrintThreadCtx)(struct MpmThreadCtx_ *)
Definition: util-mpm.h:165
SCACBSThreadCtx
struct SCACBSThreadCtx_ SCACBSThreadCtx
detect-engine.h
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
MpmTableElmt_::InitThreadCtx
void(* InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:145
SCACBSPrintSearchStats
void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx)
Definition: util-mpm-ac-bs.c:1359
SCACBSCtx_::state_table_u16
SC_AC_BS_STATE_TYPE_U16(* state_table_u16)[256]
Definition: util-mpm-ac-bs.h:56
MpmThreadCtx_
Definition: util-mpm.h:47
MpmFreePattern
void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p)
Definition: util-mpm.c:352
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
MpmTableElmt_::name
const char * name
Definition: util-mpm.h:143
PrefilterRuleStore_
structure for storing potential rule matches
Definition: util-prefilter.h:34
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
SCACBSOutputTable_
Definition: util-mpm-ac-bs.h:39
SCACBSDestroyCtx
void SCACBSDestroyCtx(MpmCtx *)
Destroy the mpm context.
Definition: util-mpm-ac-bs.c:1031
SCACBSAddPatternCI
int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Add a case insensitive pattern. Although we have different calls for adding case sensitive and insens...
Definition: util-mpm-ac-bs.c:1327
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:141
MpmThreadCtx_::memory_cnt
uint32_t memory_cnt
Definition: util-mpm.h:50
SCACBSPatternList_
Definition: util-mpm-ac-bs.h:30
SCACBSCtx_::output_table
SCACBSOutputTable * output_table
Definition: util-mpm-ac-bs.h:67
StateQueue_
Helper structure used by AC during state table creation.
Definition: util-mpm-ac-bs.c:88
SCACBSPreparePatterns
int SCACBSPreparePatterns(MpmCtx *mpm_ctx)
Process the patterns added to the mpm, and create the internal tables.
Definition: util-mpm-ac-bs.c:869
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:826
util-memcpy.h
MpmCtx_::memory_size
uint32_t memory_size
Definition: util-mpm.h:104
SCACBSPrintInfo
void SCACBSPrintInfo(MpmCtx *mpm_ctx)
Definition: util-mpm-ac-bs.c:1372
SCACBSInitThreadCtx
void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *)
Init the mpm thread context.
Definition: util-mpm-ac-bs.c:958
SCACBSCtx_::parray
MpmPattern ** parray
Definition: util-mpm-ac-bs.h:48
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2592
MpmTableElmt_::AddPatternNocase
int(* AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:161
SCACBSAddPatternCS
int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Add a case sensitive pattern. Although we have different calls for adding case sensitive and insensit...
Definition: util-mpm-ac-bs.c:1352
u8_tolower
#define u8_tolower(c)
Definition: suricata-common.h:431
DE_QUIET
#define DE_QUIET
Definition: detect.h:314
MpmCtx_::maxlen
uint16_t maxlen
Definition: util-mpm.h:101
MpmTableElmt_::AddPattern
int(* AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:160
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:337
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1824
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:46
MpmPattern_::original_pat
uint8_t * original_pat
Definition: util-mpm.h:68
SCACBSThreadCtx_::total_calls
uint32_t total_calls
Definition: util-mpm-ac-bs.h:76
SCACBSCtx_::state_table_mod_pointers
uint8_t ** state_table_mod_pointers
Definition: util-mpm-ac-bs.h:61
MpmTableElmt_::InitCtx
void(* InitCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:144
util-unittest.h
SC_AC_BS_STATE_TYPE_U16
#define SC_AC_BS_STATE_TYPE_U16
Definition: util-mpm-ac-bs.h:27
util-unittest-helper.h
MpmPattern_::flags
uint8_t flags
Definition: util-mpm.h:59
util-memcmp.h
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition: util-mpm.c:203
Signature_::next
struct Signature_ * next
Definition: detect.h:656
MpmTableElmt_::PrintCtx
void(* PrintCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:164
MpmCtx_::max_pat_id
uint32_t max_pat_id
Definition: util-mpm.h:106
SCACBSThreadCtx_
Definition: util-mpm-ac-bs.h:74
SCACBSCtx_::goto_table
int32_t(* goto_table)[256]
Definition: util-mpm-ac-bs.h:65
util-debug.h
SC_AC_BS_STATE_TYPE_U32
#define SC_AC_BS_STATE_TYPE_U32
Definition: util-mpm-ac-bs.h:28
MpmPattern_::next
struct MpmPattern_ * next
Definition: util-mpm.h:80
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
SCACBSCtx_::pattern_id_bitarray_size
uint32_t pattern_id_bitarray_size
Definition: util-mpm-ac-bs.h:53
DetectEngineThreadCtx_
Definition: detect.h:1074
MpmPattern_::id
uint32_t id
Definition: util-mpm.h:74
MpmThreadCtx_::memory_size
uint32_t memory_size
Definition: util-mpm.h:51
SCACBSCtx_::state_table_u32
SC_AC_BS_STATE_TYPE_U32(* state_table_u32)[256]
Definition: util-mpm-ac-bs.h:58
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
SCACBSThreadCtx_::total_matches
uint64_t total_matches
Definition: util-mpm-ac-bs.h:78
DetectEngineCtx_::mpm_matcher
uint8_t mpm_matcher
Definition: detect.h:829
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2264
MpmCtx_::minlen
uint16_t minlen
Definition: util-mpm.h:100
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2042
MpmPattern_::sids_size
uint32_t sids_size
Definition: util-mpm.h:77
SCReturn
#define SCReturn
Definition: util-debug.h:273
SCACBSCtx_::state_count
uint32_t state_count
Definition: util-mpm-ac-bs.h:51
Packet_
Definition: decode.h:430
detect-engine-build.h
detect-engine-alert.h
conf.h
MPM_INIT_HASH_SIZE
#define MPM_INIT_HASH_SIZE
Definition: util-mpm.h:30
MpmTableElmt_::Prepare
int(* Prepare)(struct MpmCtx_ *)
Definition: util-mpm.h:162
StateQueue_::bot
int bot
Definition: util-mpm-ac-bs.c:91
MpmPattern_
Definition: util-mpm.h:55
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:163
MpmAddPatternCS
int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:244
SCACBSPatternList_::sids_size
uint32_t sids_size
Definition: util-mpm-ac-bs.h:35
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:1973
MpmPattern_::ci
uint8_t * ci
Definition: util-mpm.h:72
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
MPM_PATTERN_FLAG_NOCASE
#define MPM_PATTERN_FLAG_NOCASE
Definition: util-mpm.h:133
MpmACBSRegister
void MpmACBSRegister(void)
Register the aho-corasick mpm.
Definition: util-mpm-ac-bs.c:97
SCACBSPatternList_::patlen
uint16_t patlen
Definition: util-mpm-ac-bs.h:32
SCACBSCtx_::pid_pat_list
SCACBSPatternList * pid_pat_list
Definition: util-mpm-ac-bs.h:68
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
Definition: detect-engine.c:3308
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
Definition: detect-engine.c:3522
MpmCtx_::pattern_cnt
uint32_t pattern_cnt
Definition: util-mpm.h:98
STATE_QUEUE_CONTAINER_SIZE
#define STATE_QUEUE_CONTAINER_SIZE
Definition: util-mpm-ac-bs.c:83
SC_AC_BS_FAIL
#define SC_AC_BS_FAIL
Definition: util-mpm-ac-bs.c:81
SCACBSCtx_::state_table_mod
uint8_t * state_table_mod
Definition: util-mpm-ac-bs.h:60
util-mpm-ac-bs.h
StateQueue
struct StateQueue_ StateQueue
Helper structure used by AC during state table creation.
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:834
util-validate.h
SCACBSDestroyThreadCtx
void SCACBSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *)
Destroy the mpm thread context.
Definition: util-mpm-ac-bs.c:1012
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCACBSOutputTable_::pids
uint32_t * pids
Definition: util-mpm-ac-bs.h:41
SCACBSCtx_
Definition: util-mpm-ac-bs.h:46
MpmPattern_::sids
SigIntId * sids
Definition: util-mpm.h:78
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:146
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
SCACBSOutputTable_::no_of_entries
uint32_t no_of_entries
Definition: util-mpm-ac-bs.h:43
MpmCtx_::memory_cnt
uint32_t memory_cnt
Definition: util-mpm.h:103
MpmCtx_::init_hash
MpmPattern ** init_hash
Definition: util-mpm.h:109
MpmPattern_::len
uint16_t len
Definition: util-mpm.h:57
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2553
SCACBSCtx_::single_state_size
uint16_t single_state_size
Definition: util-mpm-ac-bs.h:71
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:48
suricata.h
PmqFree
void PmqFree(PrefilterRuleStore *pmq)
Cleanup and free a Pmq.
Definition: util-prefilter.c:126
SCACBSPatternList_::sids
SigIntId * sids
Definition: util-mpm-ac-bs.h:36
SCACBSPatternList_::cs
uint8_t * cs
Definition: util-mpm-ac-bs.h:31
MpmAddPattern
int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:430
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:828
MpmTableElmt_::DestroyThreadCtx
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:147
MpmCtx_
Definition: util-mpm.h:89
SCACBSInitCtx
void SCACBSInitCtx(MpmCtx *)
Initialize the AC context.
Definition: util-mpm-ac-bs.c:978
SigIntId
#define SigIntId
Definition: suricata-common.h:310
SCACBSCtx_::failure_table
int32_t * failure_table
Definition: util-mpm-ac-bs.h:66
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
MpmCtx_::ctx
void * ctx
Definition: util-mpm.h:90
MpmAddPatternCI
int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:253
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:290
SCACBSCtx
struct SCACBSCtx_ SCACBSCtx
SCACBSRegisterTests
void SCACBSRegisterTests(void)
Definition: util-mpm-ac-bs.c:2468
MpmThreadCtx_::ctx
void * ctx
Definition: util-mpm.h:48
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:104
MpmTableElmt_::RegisterUnittests
void(* RegisterUnittests)(void)
Definition: util-mpm.h:166
PmqSetup
int PmqSetup(PrefilterRuleStore *pmq)
Setup a pmq.
Definition: util-prefilter.c:37
SCACBSSearch
uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen)
The aho corasick search function.
Definition: util-mpm-ac-bs.c:1124
StateQueue_::top
int top
Definition: util-mpm-ac-bs.c:90
MPM_AC_BS
@ MPM_AC_BS
Definition: util-mpm.h:37
StateQueue_::store
int32_t store[STATE_QUEUE_CONTAINER_SIZE]
Definition: util-mpm-ac-bs.c:89
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:468