Line data Source code
1 : /*
2 : * Copyright (c) 2021 Project CHIP Authors
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 :
17 : /**
18 : * @file
19 : * This file defines the Matter Group message counters of remote nodes for groups.
20 : *
21 : */
22 :
23 : #include <lib/support/DefaultStorageKeyAllocator.h>
24 : #include <limits>
25 : #include <transport/GroupPeerMessageCounter.h>
26 :
27 : #include <crypto/RandUtils.h>
28 : #include <utility>
29 :
30 : namespace chip {
31 : namespace Transport {
32 :
33 : namespace {
34 :
35 : /// Shift elements right and insert newEntry at front (MRU position).
36 : ///
37 : /// All elements [0..oldIndex) are shifted one slot to the right; newEntry
38 : /// becomes list[0] as the most-recently-used entry.
39 170 : void ShiftAndInsert(GroupSender * list, uint32_t oldIndex, GroupSender && newEntry)
40 : {
41 1855 : for (uint32_t j = oldIndex; j > 0; j--)
42 : {
43 1685 : list[j] = std::move(list[j - 1]);
44 : }
45 170 : list[0] = std::move(newEntry);
46 170 : }
47 :
48 : /// Find peer by nodeId (move to MRU) or add it; return counter.
49 : ///
50 : /// `list` is a list of `maxLimit` items, out of which the first `peerCount` elements are valid.
51 : /// `nodeId` is searched for and added if not found:
52 : /// - if found, it gets moved to `list[0]` as the most recently used element
53 : /// - if not found, it will be inserted at index 0, shifting everything else to the right.
54 : /// peerCount may increase if space exists, otherwise the LRU entry (at maxLimit - 1) will be evicted
55 : /// `peerType` is a label used only in eviction log messages.
56 : ///
57 : /// `outCounter` is an OUTPUT value, pointing to the PeerMessageCounter of the GroupSender found or inserted.
58 170 : CHIP_ERROR FindOrAddPeerFabricFound(GroupSender * list, uint32_t maxLimit, uint8_t & peerCount, NodeId nodeId,
59 : chip::Transport::PeerMessageCounter *& outCounter, const char * peerType)
60 : {
61 : static uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
62 :
63 170 : GroupSender temp;
64 170 : temp.mNodeId = nodeId;
65 :
66 170 : uint32_t insertPos = kInvalidIndex;
67 :
68 : // Search for peer
69 1966 : for (uint32_t i = 0; i < peerCount; i++)
70 : {
71 1801 : if (list[i].mNodeId == nodeId)
72 : {
73 5 : insertPos = i;
74 5 : temp = std::move(list[i]);
75 5 : break;
76 : }
77 : }
78 :
79 170 : if (insertPos == kInvalidIndex)
80 : {
81 : // GroupSender was not found, must add a new one for this node id.
82 165 : if (peerCount < maxLimit)
83 : {
84 54 : peerCount++;
85 : }
86 : else
87 : {
88 : // Evict LRU
89 111 : ChipLogProgress(SecureChannel, "GroupPeerTable: Evicting %s peer " ChipLogFormatX64 " due to table being full",
90 : peerType, ChipLogValueX64(list[maxLimit - 1].mNodeId));
91 : }
92 165 : insertPos = peerCount - 1;
93 : }
94 :
95 170 : ShiftAndInsert(list, insertPos, std::move(temp));
96 170 : outCounter = &(list[0].msgCounter);
97 170 : return CHIP_NO_ERROR;
98 170 : }
99 :
100 : } // anonymous namespace
101 :
102 237 : CHIP_ERROR GroupPeerTable::FindOrAddPeer(FabricIndex fabricIndex, NodeId nodeId, bool isControl,
103 : chip::Transport::PeerMessageCounter *& counter)
104 : {
105 237 : if (fabricIndex == kUndefinedFabricIndex || nodeId == kUndefinedNodeId)
106 : {
107 0 : return CHIP_ERROR_INVALID_ARGUMENT;
108 : }
109 :
110 795 : for (auto & groupFabric : mGroupFabrics)
111 : {
112 793 : if (groupFabric.mFabricIndex == kUndefinedFabricIndex)
113 : {
114 : // Already iterated through all known fabricIndex
115 : // Add the new peer to save some processing time
116 65 : groupFabric.mFabricIndex = fabricIndex;
117 65 : if (isControl)
118 : {
119 27 : groupFabric.mControlGroupSenders[0].mNodeId = nodeId;
120 27 : counter = &(groupFabric.mControlGroupSenders[0].msgCounter);
121 27 : groupFabric.mControlPeerCount++;
122 : }
123 : else
124 : {
125 38 : groupFabric.mDataGroupSenders[0].mNodeId = nodeId;
126 38 : counter = &(groupFabric.mDataGroupSenders[0].msgCounter);
127 38 : groupFabric.mDataPeerCount++;
128 : }
129 65 : return CHIP_NO_ERROR;
130 : }
131 :
132 728 : if (fabricIndex == groupFabric.mFabricIndex)
133 : {
134 170 : if (isControl)
135 : {
136 29 : return FindOrAddPeerFabricFound(groupFabric.mControlGroupSenders, CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS,
137 29 : groupFabric.mControlPeerCount, nodeId, counter, "control");
138 : }
139 141 : return FindOrAddPeerFabricFound(groupFabric.mDataGroupSenders, CHIP_CONFIG_MAX_GROUP_DATA_PEERS,
140 141 : groupFabric.mDataPeerCount, nodeId, counter, "data");
141 : }
142 : }
143 :
144 : // Exceeded the Max number of Group fabrics
145 2 : return CHIP_ERROR_NO_MEMORY;
146 : }
147 :
148 : // Used in case of MCSP failure
149 38 : CHIP_ERROR GroupPeerTable::RemovePeer(FabricIndex fabricIndex, NodeId nodeId, bool isControl)
150 : {
151 38 : CHIP_ERROR err = CHIP_ERROR_NOT_FOUND;
152 38 : uint32_t fabricIt = CHIP_CONFIG_MAX_FABRICS;
153 :
154 38 : if (fabricIndex == kUndefinedFabricIndex || nodeId == kUndefinedNodeId)
155 : {
156 0 : return CHIP_ERROR_INVALID_ARGUMENT;
157 : }
158 :
159 156 : for (uint32_t it = 0; it < CHIP_CONFIG_MAX_FABRICS; it++)
160 : {
161 156 : if (fabricIndex == mGroupFabrics[it].mFabricIndex)
162 : {
163 38 : if (isControl)
164 : {
165 33 : if (RemoveSpecificPeer(mGroupFabrics[it].mControlGroupSenders, nodeId, CHIP_CONFIG_MAX_GROUP_CONTROL_PEERS))
166 : {
167 33 : fabricIt = it;
168 33 : mGroupFabrics[it].mControlPeerCount--;
169 33 : err = CHIP_NO_ERROR;
170 : }
171 : }
172 : else
173 : {
174 5 : if (RemoveSpecificPeer(mGroupFabrics[it].mDataGroupSenders, nodeId, CHIP_CONFIG_MAX_GROUP_DATA_PEERS))
175 : {
176 5 : fabricIt = it;
177 5 : mGroupFabrics[it].mDataPeerCount--;
178 5 : err = CHIP_NO_ERROR;
179 : }
180 : }
181 38 : break;
182 : }
183 : }
184 :
185 : // Remove Fabric entry from PeerTable if empty
186 38 : if (fabricIt < CHIP_CONFIG_MAX_FABRICS)
187 : {
188 38 : if (mGroupFabrics[fabricIt].mDataPeerCount == 0 && mGroupFabrics[fabricIt].mControlPeerCount == 0)
189 : {
190 18 : RemoveAndCompactFabric(fabricIt);
191 : }
192 : }
193 :
194 : // Cannot find Peer to remove
195 38 : return err;
196 : }
197 :
198 11 : CHIP_ERROR GroupPeerTable::FabricRemoved(FabricIndex fabricIndex)
199 : {
200 11 : CHIP_ERROR err = CHIP_ERROR_NOT_FOUND;
201 :
202 11 : if (fabricIndex == kUndefinedFabricIndex)
203 : {
204 0 : return CHIP_ERROR_INVALID_ARGUMENT;
205 : }
206 :
207 170 : for (uint32_t it = 0; it < CHIP_CONFIG_MAX_FABRICS; it++)
208 : {
209 161 : if (fabricIndex == mGroupFabrics[it].mFabricIndex)
210 : {
211 2 : RemoveAndCompactFabric(it);
212 2 : return CHIP_NO_ERROR;
213 : }
214 : }
215 :
216 : // Cannot find Fabric to remove
217 9 : return err;
218 : }
219 :
220 38 : bool GroupPeerTable::RemoveSpecificPeer(GroupSender * list, NodeId nodeId, uint32_t size)
221 : {
222 38 : bool removed = false;
223 64 : for (uint32_t nodeIt = 0; nodeIt < size; nodeIt++)
224 : {
225 64 : if (list[nodeIt].mNodeId == nodeId)
226 : {
227 38 : list[nodeIt].mNodeId = kUndefinedNodeId;
228 38 : list[nodeIt].msgCounter.Reset();
229 38 : removed = true;
230 38 : break;
231 : }
232 : }
233 :
234 38 : if (removed)
235 : {
236 38 : CompactPeers(list, size);
237 : }
238 :
239 38 : return removed;
240 : }
241 :
242 38 : void GroupPeerTable::CompactPeers(GroupSender * list, uint32_t size)
243 : {
244 38 : if (list == nullptr || size == 0)
245 : {
246 0 : return;
247 : }
248 :
249 38 : uint32_t writeIndex = 0;
250 179 : for (uint32_t readIndex = 0; readIndex < size; readIndex++)
251 : {
252 : // readIndex and writeIndex will iterate together, until a point
253 : // is found where the node id at the read index is kUndefinedNodeId. This
254 : // means the GroupSender entry at this index has been removed (likely by
255 : // RemoveSpecificPeer()). When this removed entry index is found, the read
256 : // index will be 1 ahead of the write index, and then all entries
257 : // that follow will be shifted down the list (moving 1 to the left).
258 141 : if (list[readIndex].mNodeId != kUndefinedNodeId)
259 : {
260 35 : if (readIndex != writeIndex)
261 : {
262 9 : list[writeIndex] = std::move(list[readIndex]);
263 : }
264 35 : writeIndex++;
265 : }
266 : }
267 :
268 : // Cleanup old entries at the end of the list. These were entries that were
269 : // moved further up in the list, and the entries from the writeIndex onwards
270 : // are in an unspecified state.
271 144 : for (uint32_t i = writeIndex; i < size; i++)
272 : {
273 106 : list[i] = GroupSender();
274 : }
275 : }
276 :
277 20 : void GroupPeerTable::RemoveAndCompactFabric(uint32_t tableIndex)
278 : {
279 20 : if (tableIndex >= CHIP_CONFIG_MAX_FABRICS)
280 : {
281 0 : return;
282 : }
283 20 : mGroupFabrics[tableIndex].mFabricIndex = kUndefinedFabricIndex;
284 20 : new (&mGroupFabrics[tableIndex]) GroupFabric();
285 :
286 : // To maintain logic integrity Fabric array cannot have empty slot in between data
287 : // Find the last non empty element
288 153 : for (uint32_t i = CHIP_CONFIG_MAX_FABRICS - 1; i > tableIndex; i--)
289 : {
290 144 : if (mGroupFabrics[i].mFabricIndex != kUndefinedFabricIndex)
291 : {
292 : // Logic works since all buffer are static
293 : // move it up front
294 11 : new (&mGroupFabrics[tableIndex]) GroupFabric(mGroupFabrics[i]);
295 11 : new (&mGroupFabrics[i]) GroupFabric();
296 11 : break;
297 : }
298 : }
299 : }
300 :
301 4 : GroupOutgoingCounters::GroupOutgoingCounters(chip::PersistentStorageDelegate * storage_delegate)
302 : {
303 4 : TEMPORARY_RETURN_IGNORED Init(storage_delegate);
304 4 : }
305 :
306 495 : CHIP_ERROR GroupOutgoingCounters::Init(chip::PersistentStorageDelegate * storage_delegate)
307 : {
308 :
309 495 : if (storage_delegate == nullptr)
310 : {
311 0 : return CHIP_ERROR_INVALID_ARGUMENT;
312 : }
313 :
314 : // Spec 4.5.1.3
315 495 : mStorage = storage_delegate;
316 495 : uint16_t size = static_cast<uint16_t>(sizeof(uint32_t));
317 : uint32_t temp;
318 : CHIP_ERROR err;
319 495 : err = mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::GroupControlCounter().KeyName(), &temp, size);
320 990 : if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
321 : {
322 : // First time retrieving the counter
323 491 : mGroupControlCounter = (chip::Crypto::GetRandU32() & kMessageCounterRandomInitMask) + 1;
324 : }
325 8 : else if (err != CHIP_NO_ERROR)
326 : {
327 0 : return err;
328 : }
329 : else
330 : {
331 4 : mGroupControlCounter = temp;
332 : }
333 :
334 495 : err = mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::GroupDataCounter().KeyName(), &temp, size);
335 990 : if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
336 : {
337 : // First time retrieving the counter
338 491 : mGroupDataCounter = (chip::Crypto::GetRandU32() & kMessageCounterRandomInitMask) + 1;
339 : }
340 8 : else if (err != CHIP_NO_ERROR)
341 : {
342 0 : return err;
343 : }
344 : else
345 : {
346 4 : mGroupDataCounter = temp;
347 : }
348 :
349 495 : temp = mGroupControlCounter + GROUP_MSG_COUNTER_MIN_INCREMENT;
350 495 : size = static_cast<uint16_t>(sizeof(temp));
351 495 : ReturnErrorOnFailure(mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::GroupControlCounter().KeyName(), &temp, size));
352 :
353 495 : temp = mGroupDataCounter + GROUP_MSG_COUNTER_MIN_INCREMENT;
354 :
355 495 : return mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::GroupDataCounter().KeyName(), &temp, size);
356 : }
357 :
358 17 : uint32_t GroupOutgoingCounters::GetCounter(bool isControl)
359 : {
360 17 : return (isControl) ? mGroupControlCounter : mGroupDataCounter;
361 : }
362 :
363 7 : CHIP_ERROR GroupOutgoingCounters::IncrementCounter(bool isControl)
364 : {
365 7 : uint32_t temp = 0;
366 7 : uint16_t size = static_cast<uint16_t>(sizeof(uint32_t));
367 7 : uint32_t value = 0;
368 :
369 7 : StorageKeyName key = StorageKeyName::Uninitialized();
370 :
371 7 : if (isControl)
372 : {
373 2 : mGroupControlCounter++;
374 2 : key = DefaultStorageKeyAllocator::GroupControlCounter();
375 2 : value = mGroupControlCounter;
376 : }
377 : else
378 : {
379 5 : mGroupDataCounter++;
380 5 : key = DefaultStorageKeyAllocator::GroupDataCounter();
381 5 : value = mGroupDataCounter;
382 : }
383 :
384 7 : if (mStorage == nullptr)
385 : {
386 0 : return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
387 : }
388 :
389 7 : ReturnErrorOnFailure(mStorage->SyncGetKeyValue(key.KeyName(), &temp, size));
390 7 : if (temp == value)
391 : {
392 0 : temp = value + GROUP_MSG_COUNTER_MIN_INCREMENT;
393 0 : return mStorage->SyncSetKeyValue(key.KeyName(), &temp, sizeof(uint32_t));
394 : }
395 7 : return CHIP_NO_ERROR;
396 7 : }
397 :
398 : } // namespace Transport
399 : } // namespace chip
|