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