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