1/*
2 * Copyright (c) 2015-2016, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** \file
30 * \brief NFA stream state handling.
31 */
32
33#include "util/join.h"
34#include "util/partial_store.h"
35#include "util/state_compress.h"
36#include <string.h>
37
38#if !defined(SIZE) || !defined(STATE_T) || !defined(LOAD_FROM_ENG)
39# error Must define SIZE, STATE_T, LOAD_FROM_ENG in includer.
40#endif
41
42#define IMPL_NFA_T JOIN(struct LimExNFA, SIZE)
43#define COMMON_T JOIN(NFACommon, SIZE)
44#define REACHMASK_FN JOIN(moNfaReachMask, SIZE)
45#define COMPRESS_FN JOIN(moNfaCompressState, SIZE)
46#define EXPAND_FN JOIN(moNfaExpandState, SIZE)
47#define COMPRESSED_STORE_FN JOIN(store_compressed_, STATE_T)
48#define COMPRESSED_LOAD_FN JOIN(load_compressed_, STATE_T)
49#define PARTIAL_STORE_FN JOIN(partial_store_, STATE_T)
50#define PARTIAL_LOAD_FN JOIN(partial_load_, STATE_T)
51#define OR_STATE JOIN(or_, STATE_T)
52#define AND_STATE JOIN(and_, STATE_T)
53#define ISZERO_STATE JOIN(isZero_, STATE_T)
54
55static really_inline
56const ENG_STATE_T *get_reach_table(const IMPL_NFA_T *limex) {
57 const ENG_STATE_T *reach
58 = (const ENG_STATE_T *)((const char *)limex + sizeof(*limex));
59 assert(ISALIGNED_N(reach, alignof(ENG_STATE_T)));
60 return reach;
61}
62
63static really_inline
64STATE_T REACHMASK_FN(const IMPL_NFA_T *limex, const u8 key) {
65 const ENG_STATE_T *reach = get_reach_table(limex);
66 return LOAD_FROM_ENG(&reach[limex->reachMap[key]]);
67}
68
69static really_inline
70void COMPRESS_FN(const IMPL_NFA_T *limex, u8 *dest, const STATE_T *src,
71 u8 key) {
72 assert(ISALIGNED_N(src, alignof(STATE_T)));
73 STATE_T a_src = *src;
74
75 DEBUG_PRINTF("compress state: %p -> %p\n", src, dest);
76
77 if (!(limex->flags & LIMEX_FLAG_COMPRESS_STATE)) {
78 // No key-based compression, just a partial store.
79 DEBUG_PRINTF("store state into %u bytes\n", limex->stateSize);
80 PARTIAL_STORE_FN(dest, a_src, limex->stateSize);
81 } else {
82 DEBUG_PRINTF("compress state, key=%hhx\n", key);
83
84 STATE_T reachmask = REACHMASK_FN(limex, key);
85
86 // Masked compression means that we mask off the initDs states and
87 // provide a shortcut for the all-zeroes case. Note that these must be
88 // switched on in the EXPAND call below.
89 if (limex->flags & LIMEX_FLAG_COMPRESS_MASKED) {
90 STATE_T s = AND_STATE(LOAD_FROM_ENG(&limex->compressMask), a_src);
91 if (ISZERO_STATE(s)) {
92 DEBUG_PRINTF("after compression mask, all states are zero\n");
93 memset(dest, 0, limex->stateSize);
94 return;
95 }
96
97 STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
98 reachmask);
99 COMPRESSED_STORE_FN(dest, &s, &mask, limex->stateSize);
100 } else {
101 COMPRESSED_STORE_FN(dest, src, &reachmask, limex->stateSize);
102 }
103 }
104}
105
106static really_inline
107void EXPAND_FN(const IMPL_NFA_T *limex, STATE_T *dest, const u8 *src, u8 key) {
108 assert(ISALIGNED_N(dest, alignof(STATE_T)));
109 DEBUG_PRINTF("expand state: %p -> %p\n", src, dest);
110
111 if (!(limex->flags & LIMEX_FLAG_COMPRESS_STATE)) {
112 // No key-based compression, just a partial load.
113 DEBUG_PRINTF("load state from %u bytes\n", limex->stateSize);
114 *dest = PARTIAL_LOAD_FN(src, limex->stateSize);
115 } else {
116 DEBUG_PRINTF("expand state, key=%hhx\n", key);
117 STATE_T reachmask = REACHMASK_FN(limex, key);
118
119 if (limex->flags & LIMEX_FLAG_COMPRESS_MASKED) {
120 STATE_T mask = AND_STATE(LOAD_FROM_ENG(&limex->compressMask),
121 reachmask);
122 COMPRESSED_LOAD_FN(dest, src, &mask, limex->stateSize);
123 *dest = OR_STATE(LOAD_FROM_ENG(&limex->initDS), *dest);
124 } else {
125 COMPRESSED_LOAD_FN(dest, src, &reachmask, limex->stateSize);
126 }
127 }
128}
129
130#undef IMPL_NFA_T
131#undef COMMON_T
132#undef REACHMASK_FN
133#undef COMPRESS_FN
134#undef EXPAND_FN
135#undef COMPRESSED_STORE_FN
136#undef COMPRESSED_LOAD_FN
137#undef PARTIAL_STORE_FN
138#undef PARTIAL_LOAD_FN
139#undef OR_STATE
140#undef AND_STATE
141#undef ISZERO_STATE
142