1 /*
2 * Copyright (c) 2019, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. 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 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software 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 HOLDER 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 /**
30 * @file
31 * This file implements a software Source Match table, for radios that don't have
32 * such hardware acceleration. It supports only the single-instance build of
33 * OpenThread.
34 *
35 */
36
37 #include "utils/soft_source_match_table.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "common/logging.hpp"
43 #include "utils/code_utils.h"
44
45 #if RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM || RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
46 static uint16_t sPanId = 0;
47
utilsSoftSrcMatchSetPanId(uint16_t aPanId)48 void utilsSoftSrcMatchSetPanId(uint16_t aPanId)
49 {
50 sPanId = aPanId;
51 }
52 #endif // RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM || RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
53
54 #if RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM
55 typedef struct srcMatchShortEntry
56 {
57 uint16_t checksum;
58 bool allocated;
59 } sSrcMatchShortEntry;
60
61 static sSrcMatchShortEntry srcMatchShortEntry[RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM];
62
utilsSoftSrcMatchShortFindEntry(uint16_t aShortAddress)63 int16_t utilsSoftSrcMatchShortFindEntry(uint16_t aShortAddress)
64 {
65 int16_t entry = -1;
66 uint16_t checksum = aShortAddress + sPanId;
67
68 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++)
69 {
70 if (checksum == srcMatchShortEntry[i].checksum && srcMatchShortEntry[i].allocated)
71 {
72 entry = i;
73 break;
74 }
75 }
76
77 return entry;
78 }
79
findSrcMatchShortAvailEntry(void)80 static int16_t findSrcMatchShortAvailEntry(void)
81 {
82 int16_t entry = -1;
83
84 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++)
85 {
86 if (!srcMatchShortEntry[i].allocated)
87 {
88 entry = i;
89 break;
90 }
91 }
92
93 return entry;
94 }
95
addToSrcMatchShortIndirect(uint16_t entry,uint16_t aShortAddress)96 static inline void addToSrcMatchShortIndirect(uint16_t entry, uint16_t aShortAddress)
97 {
98 uint16_t checksum = aShortAddress + sPanId;
99
100 srcMatchShortEntry[entry].checksum = checksum;
101 srcMatchShortEntry[entry].allocated = true;
102 }
103
removeFromSrcMatchShortIndirect(uint16_t entry)104 static inline void removeFromSrcMatchShortIndirect(uint16_t entry)
105 {
106 srcMatchShortEntry[entry].allocated = false;
107 srcMatchShortEntry[entry].checksum = 0;
108 }
109
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)110 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
111 {
112 OT_UNUSED_VARIABLE(aInstance);
113
114 otError error = OT_ERROR_NONE;
115 int16_t entry = -1;
116
117 entry = findSrcMatchShortAvailEntry();
118 otLogDebgPlat("Add ShortAddr entry: %d", entry);
119
120 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM, error = OT_ERROR_NO_BUFS);
121
122 addToSrcMatchShortIndirect((uint16_t)entry, aShortAddress);
123
124 exit:
125 return error;
126 }
127
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)128 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
129 {
130 OT_UNUSED_VARIABLE(aInstance);
131
132 otError error = OT_ERROR_NONE;
133 int16_t entry = -1;
134
135 entry = utilsSoftSrcMatchShortFindEntry(aShortAddress);
136 otLogDebgPlat("Clear ShortAddr entry: %d", entry);
137
138 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM, error = OT_ERROR_NO_ADDRESS);
139
140 removeFromSrcMatchShortIndirect((uint16_t)entry);
141
142 exit:
143 return error;
144 }
145
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)146 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
147 {
148 OT_UNUSED_VARIABLE(aInstance);
149
150 otLogDebgPlat("Clear ShortAddr entries", NULL);
151
152 memset(srcMatchShortEntry, 0, sizeof(srcMatchShortEntry));
153 }
154 #endif // RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM
155
156 #if RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
157 typedef struct srcMatchExtEntry
158 {
159 uint16_t checksum;
160 bool allocated;
161 } sSrcMatchExtEntry;
162
163 static sSrcMatchExtEntry srcMatchExtEntry[RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM];
164
utilsSoftSrcMatchExtFindEntry(const otExtAddress * aExtAddress)165 int16_t utilsSoftSrcMatchExtFindEntry(const otExtAddress *aExtAddress)
166 {
167 int16_t entry = -1;
168 uint16_t checksum = sPanId;
169
170 checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8);
171 checksum += (uint16_t)aExtAddress->m8[2] | (uint16_t)(aExtAddress->m8[3] << 8);
172 checksum += (uint16_t)aExtAddress->m8[4] | (uint16_t)(aExtAddress->m8[5] << 8);
173 checksum += (uint16_t)aExtAddress->m8[6] | (uint16_t)(aExtAddress->m8[7] << 8);
174
175 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++)
176 {
177 if (checksum == srcMatchExtEntry[i].checksum && srcMatchExtEntry[i].allocated)
178 {
179 entry = i;
180 break;
181 }
182 }
183
184 return entry;
185 }
186
findSrcMatchExtAvailEntry(void)187 static int16_t findSrcMatchExtAvailEntry(void)
188 {
189 int16_t entry = -1;
190
191 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++)
192 {
193 if (!srcMatchExtEntry[i].allocated)
194 {
195 entry = i;
196 break;
197 }
198 }
199
200 return entry;
201 }
202
addToSrcMatchExtIndirect(uint16_t entry,const otExtAddress * aExtAddress)203 static inline void addToSrcMatchExtIndirect(uint16_t entry, const otExtAddress *aExtAddress)
204 {
205 uint16_t checksum = sPanId;
206
207 checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8);
208 checksum += (uint16_t)aExtAddress->m8[2] | (uint16_t)(aExtAddress->m8[3] << 8);
209 checksum += (uint16_t)aExtAddress->m8[4] | (uint16_t)(aExtAddress->m8[5] << 8);
210 checksum += (uint16_t)aExtAddress->m8[6] | (uint16_t)(aExtAddress->m8[7] << 8);
211
212 srcMatchExtEntry[entry].checksum = checksum;
213 srcMatchExtEntry[entry].allocated = true;
214 }
215
removeFromSrcMatchExtIndirect(uint16_t entry)216 static inline void removeFromSrcMatchExtIndirect(uint16_t entry)
217 {
218 srcMatchExtEntry[entry].allocated = false;
219 srcMatchExtEntry[entry].checksum = 0;
220 }
221
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)222 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
223 {
224 OT_UNUSED_VARIABLE(aInstance);
225
226 otError error = OT_ERROR_NONE;
227 int16_t entry = -1;
228
229 entry = findSrcMatchExtAvailEntry();
230 otLogDebgPlat("Add ExtAddr entry: %d", entry);
231
232 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM, error = OT_ERROR_NO_BUFS);
233
234 addToSrcMatchExtIndirect((uint16_t)entry, aExtAddress);
235
236 exit:
237 return error;
238 }
239
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)240 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
241 {
242 OT_UNUSED_VARIABLE(aInstance);
243
244 otError error = OT_ERROR_NONE;
245 int16_t entry = -1;
246
247 entry = utilsSoftSrcMatchExtFindEntry(aExtAddress);
248 otLogDebgPlat("Clear ExtAddr entry: %d", entry);
249
250 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM, error = OT_ERROR_NO_ADDRESS);
251
252 removeFromSrcMatchExtIndirect((uint16_t)entry);
253
254 exit:
255 return error;
256 }
257
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)258 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
259 {
260 OT_UNUSED_VARIABLE(aInstance);
261
262 otLogDebgPlat("Clear ExtAddr entries", NULL);
263
264 memset(srcMatchExtEntry, 0, sizeof(srcMatchExtEntry));
265 }
266 #endif // RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
267