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 <openthread/logging.h>
43
44 #include "utils/code_utils.h"
45
46 #if RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM || RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
47 static uint16_t sPanId = 0;
48
utilsSoftSrcMatchSetPanId(uint16_t aPanId)49 void utilsSoftSrcMatchSetPanId(uint16_t aPanId)
50 {
51 sPanId = aPanId;
52 }
53 #endif // RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM || RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
54
55 #if RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM
56 typedef struct srcMatchShortEntry
57 {
58 uint16_t checksum;
59 bool allocated;
60 } sSrcMatchShortEntry;
61
62 static sSrcMatchShortEntry srcMatchShortEntry[RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM];
63
utilsSoftSrcMatchShortFindEntry(uint16_t aShortAddress)64 int16_t utilsSoftSrcMatchShortFindEntry(uint16_t aShortAddress)
65 {
66 int16_t entry = -1;
67 uint16_t checksum = aShortAddress + sPanId;
68
69 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++)
70 {
71 if (checksum == srcMatchShortEntry[i].checksum && srcMatchShortEntry[i].allocated)
72 {
73 entry = i;
74 break;
75 }
76 }
77
78 return entry;
79 }
80
findSrcMatchShortAvailEntry(void)81 static int16_t findSrcMatchShortAvailEntry(void)
82 {
83 int16_t entry = -1;
84
85 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++)
86 {
87 if (!srcMatchShortEntry[i].allocated)
88 {
89 entry = i;
90 break;
91 }
92 }
93
94 return entry;
95 }
96
addToSrcMatchShortIndirect(uint16_t entry,uint16_t aShortAddress)97 static inline void addToSrcMatchShortIndirect(uint16_t entry, uint16_t aShortAddress)
98 {
99 uint16_t checksum = aShortAddress + sPanId;
100
101 srcMatchShortEntry[entry].checksum = checksum;
102 srcMatchShortEntry[entry].allocated = true;
103 }
104
removeFromSrcMatchShortIndirect(uint16_t entry)105 static inline void removeFromSrcMatchShortIndirect(uint16_t entry)
106 {
107 srcMatchShortEntry[entry].allocated = false;
108 srcMatchShortEntry[entry].checksum = 0;
109 }
110
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)111 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
112 {
113 OT_UNUSED_VARIABLE(aInstance);
114
115 otError error = OT_ERROR_NONE;
116 int16_t entry = -1;
117
118 entry = findSrcMatchShortAvailEntry();
119 otLogDebgPlat("Add ShortAddr entry: %d", entry);
120
121 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM, error = OT_ERROR_NO_BUFS);
122
123 addToSrcMatchShortIndirect((uint16_t)entry, aShortAddress);
124
125 exit:
126 return error;
127 }
128
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)129 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
130 {
131 OT_UNUSED_VARIABLE(aInstance);
132
133 otError error = OT_ERROR_NONE;
134 int16_t entry = -1;
135
136 entry = utilsSoftSrcMatchShortFindEntry(aShortAddress);
137 otLogDebgPlat("Clear ShortAddr entry: %d", entry);
138
139 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM, error = OT_ERROR_NO_ADDRESS);
140
141 removeFromSrcMatchShortIndirect((uint16_t)entry);
142
143 exit:
144 return error;
145 }
146
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)147 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
148 {
149 OT_UNUSED_VARIABLE(aInstance);
150
151 otLogDebgPlat("Clear ShortAddr entries", NULL);
152
153 memset(srcMatchShortEntry, 0, sizeof(srcMatchShortEntry));
154 }
155 #endif // RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM
156
157 #if RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
158 typedef struct srcMatchExtEntry
159 {
160 uint16_t checksum;
161 bool allocated;
162 } sSrcMatchExtEntry;
163
164 static sSrcMatchExtEntry srcMatchExtEntry[RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM];
165
utilsSoftSrcMatchExtFindEntry(const otExtAddress * aExtAddress)166 int16_t utilsSoftSrcMatchExtFindEntry(const otExtAddress *aExtAddress)
167 {
168 int16_t entry = -1;
169 uint16_t checksum = sPanId;
170
171 checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8);
172 checksum += (uint16_t)aExtAddress->m8[2] | (uint16_t)(aExtAddress->m8[3] << 8);
173 checksum += (uint16_t)aExtAddress->m8[4] | (uint16_t)(aExtAddress->m8[5] << 8);
174 checksum += (uint16_t)aExtAddress->m8[6] | (uint16_t)(aExtAddress->m8[7] << 8);
175
176 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++)
177 {
178 if (checksum == srcMatchExtEntry[i].checksum && srcMatchExtEntry[i].allocated)
179 {
180 entry = i;
181 break;
182 }
183 }
184
185 return entry;
186 }
187
findSrcMatchExtAvailEntry(void)188 static int16_t findSrcMatchExtAvailEntry(void)
189 {
190 int16_t entry = -1;
191
192 for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++)
193 {
194 if (!srcMatchExtEntry[i].allocated)
195 {
196 entry = i;
197 break;
198 }
199 }
200
201 return entry;
202 }
203
addToSrcMatchExtIndirect(uint16_t entry,const otExtAddress * aExtAddress)204 static inline void addToSrcMatchExtIndirect(uint16_t entry, const otExtAddress *aExtAddress)
205 {
206 uint16_t checksum = sPanId;
207
208 checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8);
209 checksum += (uint16_t)aExtAddress->m8[2] | (uint16_t)(aExtAddress->m8[3] << 8);
210 checksum += (uint16_t)aExtAddress->m8[4] | (uint16_t)(aExtAddress->m8[5] << 8);
211 checksum += (uint16_t)aExtAddress->m8[6] | (uint16_t)(aExtAddress->m8[7] << 8);
212
213 srcMatchExtEntry[entry].checksum = checksum;
214 srcMatchExtEntry[entry].allocated = true;
215 }
216
removeFromSrcMatchExtIndirect(uint16_t entry)217 static inline void removeFromSrcMatchExtIndirect(uint16_t entry)
218 {
219 srcMatchExtEntry[entry].allocated = false;
220 srcMatchExtEntry[entry].checksum = 0;
221 }
222
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)223 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
224 {
225 OT_UNUSED_VARIABLE(aInstance);
226
227 otError error = OT_ERROR_NONE;
228 int16_t entry = -1;
229
230 entry = findSrcMatchExtAvailEntry();
231 otLogDebgPlat("Add ExtAddr entry: %d", entry);
232
233 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM, error = OT_ERROR_NO_BUFS);
234
235 addToSrcMatchExtIndirect((uint16_t)entry, aExtAddress);
236
237 exit:
238 return error;
239 }
240
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)241 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
242 {
243 OT_UNUSED_VARIABLE(aInstance);
244
245 otError error = OT_ERROR_NONE;
246 int16_t entry = -1;
247
248 entry = utilsSoftSrcMatchExtFindEntry(aExtAddress);
249 otLogDebgPlat("Clear ExtAddr entry: %d", entry);
250
251 otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM, error = OT_ERROR_NO_ADDRESS);
252
253 removeFromSrcMatchExtIndirect((uint16_t)entry);
254
255 exit:
256 return error;
257 }
258
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)259 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
260 {
261 OT_UNUSED_VARIABLE(aInstance);
262
263 otLogDebgPlat("Clear ExtAddr entries", NULL);
264
265 memset(srcMatchExtEntry, 0, sizeof(srcMatchExtEntry));
266 }
267 #endif // RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM
268