Coverage Report

Created: 2026-08-14 07:34

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