Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / util / esi-management.cpp
1 /**
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17
18 /**
19  *
20  *    Copyright (c) 2020 Silicon Labs
21  *
22  *    Licensed under the Apache License, Version 2.0 (the "License");
23  *    you may not use this file except in compliance with the License.
24  *    You may obtain a copy of the License at
25  *
26  *        http://www.apache.org/licenses/LICENSE-2.0
27  *
28  *    Unless required by applicable law or agreed to in writing, software
29  *    distributed under the License is distributed on an "AS IS" BASIS,
30  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  *    See the License for the specific language governing permissions and
32  *    limitations under the License.
33  */
34 /***************************************************************************/
35 /**
36  * @file
37  * @brief It implements and manages the ESI table. The
38  *ESI table is shared among other plugins.
39  *******************************************************************************
40  ******************************************************************************/
41
42 #include "esi-management.h"
43 #include "af.h"
44 #include <assert.h>
45
46 using namespace chip;
47
48 static EmberAfPluginEsiManagementEsiEntry esiTable[EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE];
49 static EmberAfEsiManagementDeletionCallback deletionCallbackTable[EMBER_AF_PLUGIN_ESI_MANAGEMENT_PLUGIN_CALLBACK_TABLE_SIZE];
50 static uint8_t deletionCallbackTableSize = 0;
51
52 static void performDeletionAnnouncement(uint8_t index)
53 {
54     uint8_t i;
55
56     // Notify all the subscribed plugins about this deletion.
57     for (i = 0; i < deletionCallbackTableSize; i++)
58     {
59         (deletionCallbackTable[i])(index);
60     }
61 }
62
63 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementGetFreeEntry(void)
64 {
65     EmberAfPluginEsiManagementEsiEntry * entry = NULL;
66     uint8_t networkIndex                       = 0; /*emberGetCurrentNetwork(); #2552*/
67     uint8_t deletedEsiIndex                    = 0;
68     uint8_t i;
69
70     // Look for a free entry first.
71     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
72     {
73         if (esiTable[i].nodeId == EMBER_NULL_NODE_ID)
74         {
75             return &(esiTable[i]);
76         }
77     }
78
79     // No free entry found, we look for the oldest entry among those that
80     // can be erased.
81     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
82     {
83         if (esiTable[i].networkIndex == networkIndex && esiTable[i].age >= EMBER_AF_PLUGIN_ESI_MANAGEMENT_MIN_ERASING_AGE &&
84             (entry == NULL || esiTable[i].age > entry->age))
85         {
86             entry           = &(esiTable[i]);
87             deletedEsiIndex = i;
88         }
89     }
90
91     if (entry != NULL)
92     {
93         performDeletionAnnouncement(deletedEsiIndex);
94     }
95
96     return entry;
97 }
98
99 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByShortIdAndEndpoint(EmberNodeId shortId,
100                                                                                              EndpointId endpoint)
101 {
102     uint8_t index = emberAfPluginEsiManagementIndexLookUpByShortIdAndEndpoint(shortId, endpoint);
103     if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE)
104     {
105         return &(esiTable[index]);
106     }
107     else
108     {
109         return NULL;
110     }
111 }
112
113 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(EmberEUI64 longId, EndpointId endpoint)
114 {
115     uint8_t index = emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(longId, endpoint);
116     if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE)
117     {
118         return &(esiTable[index]);
119     }
120     else
121     {
122         return NULL;
123     }
124 }
125
126 uint8_t emberAfPluginEsiManagementIndexLookUpByShortIdAndEndpoint(EmberNodeId shortId, EndpointId endpoint)
127 {
128     uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
129     uint8_t i;
130     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
131     {
132         if (esiTable[i].networkIndex == networkIndex && esiTable[i].nodeId == shortId && esiTable[i].endpoint == endpoint)
133         {
134             return i;
135         }
136     }
137
138     return 0xFF;
139 }
140
141 uint8_t emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(EmberEUI64 longId, EndpointId endpoint)
142 {
143     uint8_t i;
144     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
145     {
146         if (memcmp(longId, esiTable[i].eui64, EUI64_SIZE) == 0 && esiTable[i].endpoint == endpoint)
147         {
148             return i;
149         }
150     }
151
152     return 0xFF;
153 }
154
155 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementEsiLookUpByIndex(uint8_t index)
156 {
157     if (index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE && esiTable[index].nodeId != EMBER_NULL_NODE_ID)
158     {
159         return &(esiTable[index]);
160     }
161     else
162     {
163         return NULL;
164     }
165 }
166
167 EmberAfPluginEsiManagementEsiEntry * emberAfPluginEsiManagementGetNextEntry(EmberAfPluginEsiManagementEsiEntry * entry, uint8_t age)
168 {
169     uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
170     uint8_t i;
171     bool entryFound = false;
172
173     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
174     {
175         // If the passed entry is NULL we return the first active entry (if any).
176         // If we already encountered the passed entry, we return the next active
177         // entry (if any).
178         if ((entry == NULL || entryFound) && esiTable[i].networkIndex == networkIndex && esiTable[i].nodeId != EMBER_NULL_NODE_ID &&
179             esiTable[i].age <= age)
180         {
181             return &(esiTable[i]);
182         }
183         // We found the passed entry in the table.
184         if (&(esiTable[i]) == entry)
185         {
186             entryFound = true;
187         }
188     }
189
190     return NULL;
191 }
192
193 void emberAfPluginEsiManagementDeleteEntry(uint8_t index)
194 {
195     assert(index < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE);
196
197     esiTable[index].nodeId = EMBER_NULL_NODE_ID;
198     performDeletionAnnouncement(index);
199 }
200
201 void emberAfPluginEsiManagementAgeAllEntries(void)
202 {
203     uint8_t networkIndex = 0; /*emberGetCurrentNetwork(); #2552*/
204     uint8_t i;
205     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
206     {
207         if (esiTable[i].networkIndex == networkIndex && esiTable[i].nodeId != EMBER_NULL_NODE_ID && esiTable[i].age < 0xFF)
208         {
209             esiTable[i].age++;
210         }
211     }
212 }
213
214 void emberAfPluginEsiManagementClearTable(void)
215 {
216     uint8_t i;
217     for (i = 0; i < EMBER_AF_PLUGIN_ESI_MANAGEMENT_ESI_TABLE_SIZE; i++)
218     {
219         emberAfPluginEsiManagementDeleteEntry(i);
220     }
221 }
222
223 bool emberAfPluginEsiManagementSubscribeToDeletionAnnouncements(EmberAfEsiManagementDeletionCallback callback)
224 {
225     if (deletionCallbackTableSize < EMBER_AF_PLUGIN_ESI_MANAGEMENT_PLUGIN_CALLBACK_TABLE_SIZE)
226     {
227         deletionCallbackTable[deletionCallbackTableSize++] = callback;
228         return true;
229     }
230     else
231     {
232         return false;
233     }
234 }
235
236 uint8_t emberAfPluginEsiManagementUpdateEsiAndGetIndex(const EmberAfClusterCommand * cmd)
237 {
238     EmberEUI64 esiEui64;
239     EmberAfPluginEsiManagementEsiEntry * esiEntry;
240     uint8_t index;
241
242     // Replace assert with equivalent conditional to quiet CSTAT complaint about
243     // possible dereference of null pointer.  The 'return 0' is never executed.
244     // This approach satisfies all code lines where 'cmd' is dereferenced.
245     // assert(cmd != NULL);
246     if (cmd == NULL)
247     {
248         assert(false);
249         return 0;
250     }
251
252     emberAfPushNetworkIndex(cmd->networkIndex);
253
254     /*emberLookupEui64ByNodeId(cmd->source, esiEui64); #2552*/
255     esiEntry = emberAfPluginEsiManagementEsiLookUpByLongIdAndEndpoint(esiEui64, cmd->apsFrame->sourceEndpoint);
256     // The source ESI is not in the ESI table.
257     if (esiEntry == NULL)
258     {
259         emberAfDebugPrintln("source ESI 0x%x not found in table", cmd->source);
260         // We add the ESI to the table.
261         esiEntry = emberAfPluginEsiManagementGetFreeEntry();
262         if (esiEntry != NULL)
263         {
264             esiEntry->nodeId       = cmd->source;
265             esiEntry->networkIndex = cmd->networkIndex;
266             esiEntry->endpoint     = cmd->apsFrame->sourceEndpoint;
267             esiEntry->age          = 0;
268             memmove(esiEntry->eui64, esiEui64, EUI64_SIZE);
269         }
270         else
271         {
272             emberAfDebugPrintln("No free entry available");
273         }
274     }
275     else
276     {
277         // Check that the short ID is still the one we stored in the ESI table.
278         // If not, update it.
279         if (esiEntry->nodeId != cmd->source)
280         {
281             emberAfDebugPrintln("ESI short ID changed, updating it");
282             esiEntry->nodeId = cmd->source;
283         }
284     }
285
286     index = emberAfPluginEsiManagementIndexLookUpByLongIdAndEndpoint(esiEui64, cmd->apsFrame->sourceEndpoint);
287     emberAfPopNetworkIndex();
288     return index;
289 }
290
291 void emberAfPluginEsiManagementInitCallback(void)
292 {
293     emberAfPluginEsiManagementClearTable();
294 }