Line data Source code
1 : /**
2 : *
3 : * Copyright (c) 2020-2023 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 : #include <app/util/attribute-storage.h>
19 :
20 : #include <app/util/attribute-storage-detail.h>
21 :
22 : #include <app/AttributeAccessInterfaceRegistry.h>
23 : #include <app/CommandHandlerInterfaceRegistry.h>
24 : #include <app/InteractionModelEngine.h>
25 : #include <app/reporting/reporting.h>
26 : #include <app/util/config.h>
27 : #include <app/util/ember-io-storage.h>
28 : #include <app/util/ember-strings.h>
29 : #include <app/util/endpoint-config-api.h>
30 : #include <app/util/generic-callbacks.h>
31 : #include <app/util/persistence/AttributePersistenceProvider.h>
32 : #include <lib/core/CHIPConfig.h>
33 : #include <lib/support/CodeUtils.h>
34 : #include <lib/support/logging/CHIPLogging.h>
35 : #include <platform/LockTracker.h>
36 : #include <protocols/interaction_model/StatusCode.h>
37 :
38 : using chip::Protocols::InteractionModel::Status;
39 :
40 : // Attribute storage depends on knowing the current layout/setup of attributes
41 : // and corresponding callbacks. Specifically:
42 : // - zap-generated/callback.h is needed because endpoint_config will call the
43 : // corresponding callbacks (via GENERATED_FUNCTION_ARRAYS) and the include
44 : // for it is:
45 : // util/config.h -> zap-generated/endpoint_config.h
46 : #include <app-common/zap-generated/callback.h>
47 :
48 : using namespace chip;
49 : using namespace chip::app;
50 :
51 : //------------------------------------------------------------------------------
52 : // Globals
53 : // This is not declared CONST in order to handle dynamic endpoint information
54 : // retrieved from tokens.
55 : EmberAfDefinedEndpoint emAfEndpoints[MAX_ENDPOINT_COUNT];
56 :
57 : #if (ATTRIBUTE_MAX_SIZE == 0)
58 : #define ACTUAL_ATTRIBUTE_SIZE 1
59 : #else
60 : #define ACTUAL_ATTRIBUTE_SIZE ATTRIBUTE_MAX_SIZE
61 : #endif
62 :
63 : uint8_t attributeData[ACTUAL_ATTRIBUTE_SIZE];
64 :
65 : // ----- internal-only methods, not part of the external API -----
66 :
67 : // Loads the attributes from built-in default and storage.
68 : static void emAfLoadAttributeDefaults(EndpointId endpoint, Optional<ClusterId> = NullOptional);
69 :
70 : static bool emAfMatchCluster(const EmberAfCluster * cluster, const EmberAfAttributeSearchRecord * attRecord);
71 : static bool emAfMatchAttribute(const EmberAfCluster * cluster, const EmberAfAttributeMetadata * am,
72 : const EmberAfAttributeSearchRecord * attRecord);
73 :
74 : // If server == true, returns the number of server clusters,
75 : // otherwise number of client clusters on the endpoint at the given index.
76 : static uint8_t emberAfClusterCountByIndex(uint16_t endpointIndex, bool server);
77 :
78 : // Check whether there is an endpoint defined with the given endpoint id that is
79 : // enabled.
80 : static bool emberAfEndpointIsEnabled(EndpointId endpoint);
81 :
82 : namespace {
83 :
84 : #if (!defined(ATTRIBUTE_SINGLETONS_SIZE)) || (ATTRIBUTE_SINGLETONS_SIZE == 0)
85 : #define ACTUAL_SINGLETONS_SIZE 1
86 : #else
87 : #define ACTUAL_SINGLETONS_SIZE ATTRIBUTE_SINGLETONS_SIZE
88 : #endif
89 : uint8_t singletonAttributeData[ACTUAL_SINGLETONS_SIZE];
90 :
91 : uint16_t emberEndpointCount = 0;
92 :
93 : /// Determines a incremental unique index for ember
94 : /// metadata that is increased whenever a structural change is made to the
95 : /// ember metadata (e.g. changing dynamic endpoints or enabling/disabling endpoints)
96 : unsigned emberMetadataStructureGeneration = 0;
97 :
98 : // If we have attributes that are more than 4 bytes, then
99 : // we need this data block for the defaults
100 : #if (defined(GENERATED_DEFAULTS) && GENERATED_DEFAULTS_COUNT)
101 : constexpr const uint8_t generatedDefaults[] = GENERATED_DEFAULTS;
102 : #define ZAP_LONG_DEFAULTS_INDEX(index) \
103 : { \
104 : &generatedDefaults[index] \
105 : }
106 : #endif // GENERATED_DEFAULTS
107 :
108 : #if (defined(GENERATED_MIN_MAX_DEFAULTS) && GENERATED_MIN_MAX_DEFAULT_COUNT)
109 : constexpr const EmberAfAttributeMinMaxValue minMaxDefaults[] = GENERATED_MIN_MAX_DEFAULTS;
110 : #define ZAP_MIN_MAX_DEFAULTS_INDEX(index) \
111 : { \
112 : &minMaxDefaults[index] \
113 : }
114 : #endif // GENERATED_MIN_MAX_DEFAULTS
115 :
116 : #ifdef GENERATED_FUNCTION_ARRAYS
117 : GENERATED_FUNCTION_ARRAYS
118 : #endif
119 :
120 : #ifdef GENERATED_COMMANDS
121 : constexpr const CommandId generatedCommands[] = GENERATED_COMMANDS;
122 : #define ZAP_GENERATED_COMMANDS_INDEX(index) (&generatedCommands[index])
123 : #endif // GENERATED_COMMANDS
124 :
125 : #if (defined(GENERATED_EVENTS) && (GENERATED_EVENT_COUNT > 0))
126 : constexpr const EventId generatedEvents[] = GENERATED_EVENTS;
127 : #define ZAP_GENERATED_EVENTS_INDEX(index) (&generatedEvents[index])
128 : #endif // GENERATED_EVENTS
129 :
130 : constexpr const EmberAfAttributeMetadata generatedAttributes[] = GENERATED_ATTRIBUTES;
131 : #define ZAP_ATTRIBUTE_INDEX(index) (&generatedAttributes[index])
132 :
133 : #ifdef GENERATED_CLUSTERS
134 : constexpr const EmberAfCluster generatedClusters[] = GENERATED_CLUSTERS;
135 : #define ZAP_CLUSTER_INDEX(index) (&generatedClusters[index])
136 : #endif
137 :
138 : #if FIXED_ENDPOINT_COUNT > 0
139 : constexpr const EmberAfEndpointType generatedEmberAfEndpointTypes[] = GENERATED_ENDPOINT_TYPES;
140 : constexpr const EmberAfDeviceType fixedDeviceTypeList[] = FIXED_DEVICE_TYPES;
141 :
142 : // Not const, because these need to mutate.
143 : DataVersion fixedEndpointDataVersions[ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT];
144 : #endif // FIXED_ENDPOINT_COUNT > 0
145 :
146 0 : bool emberAfIsThisDataTypeAListType(EmberAfAttributeType dataType)
147 : {
148 0 : return dataType == ZCL_ARRAY_ATTRIBUTE_TYPE;
149 : }
150 :
151 11177 : uint16_t findIndexFromEndpoint(EndpointId endpoint, bool ignoreDisabledEndpoints)
152 : {
153 11177 : if (endpoint == kInvalidEndpointId)
154 : {
155 0 : return kEmberInvalidEndpointIndex;
156 : }
157 :
158 : uint16_t epi;
159 22700 : for (epi = 0; epi < emberAfEndpointCount(); epi++)
160 : {
161 33773 : if (emAfEndpoints[epi].endpoint == endpoint &&
162 11126 : (!ignoreDisabledEndpoints || emAfEndpoints[epi].bitmask.Has(EmberAfEndpointOptions::isEnabled)))
163 : {
164 11124 : return epi;
165 : }
166 : }
167 53 : return kEmberInvalidEndpointIndex;
168 : }
169 :
170 : // Returns the index of a given endpoint. Considers disabled endpoints.
171 0 : uint16_t emberAfIndexFromEndpointIncludingDisabledEndpoints(EndpointId endpoint)
172 : {
173 0 : return findIndexFromEndpoint(endpoint, false /* ignoreDisabledEndpoints */);
174 : }
175 :
176 : } // anonymous namespace
177 :
178 : // Initial configuration
179 20 : void emberAfEndpointConfigure()
180 : {
181 : uint16_t ep;
182 :
183 : static_assert(FIXED_ENDPOINT_COUNT <= std::numeric_limits<decltype(ep)>::max(),
184 : "FIXED_ENDPOINT_COUNT must not exceed the size of the endpoint data type");
185 :
186 20 : emberEndpointCount = FIXED_ENDPOINT_COUNT;
187 :
188 : #if FIXED_ENDPOINT_COUNT > 0
189 :
190 20 : constexpr uint16_t fixedEndpoints[] = FIXED_ENDPOINT_ARRAY;
191 20 : constexpr uint16_t fixedDeviceTypeListLengths[] = FIXED_DEVICE_TYPE_LENGTHS;
192 20 : constexpr uint16_t fixedDeviceTypeListOffsets[] = FIXED_DEVICE_TYPE_OFFSETS;
193 20 : constexpr uint8_t fixedEmberAfEndpointTypes[] = FIXED_ENDPOINT_TYPES;
194 20 : constexpr EndpointId fixedParentEndpoints[] = FIXED_PARENT_ENDPOINTS;
195 :
196 : #if ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT > 0
197 : // Initialize our data version storage. If
198 : // ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT == 0, gcc complains about a memset
199 : // with size equal to number of elements without multiplication by element
200 : // size, because the sizeof() is also 0 in that case...
201 : if (Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(fixedEndpointDataVersions), sizeof(fixedEndpointDataVersions)) !=
202 : CHIP_NO_ERROR)
203 : {
204 : // Now what? At least 0-init it.
205 : memset(fixedEndpointDataVersions, 0, sizeof(fixedEndpointDataVersions));
206 : }
207 : #endif // ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT > 0
208 :
209 20 : DataVersion * currentDataVersions = fixedEndpointDataVersions;
210 40 : for (ep = 0; ep < FIXED_ENDPOINT_COUNT; ep++)
211 : {
212 20 : emAfEndpoints[ep].endpoint = fixedEndpoints[ep];
213 20 : emAfEndpoints[ep].deviceTypeList =
214 20 : Span<const EmberAfDeviceType>(&fixedDeviceTypeList[fixedDeviceTypeListOffsets[ep]], fixedDeviceTypeListLengths[ep]);
215 20 : emAfEndpoints[ep].endpointType = &generatedEmberAfEndpointTypes[fixedEmberAfEndpointTypes[ep]];
216 20 : emAfEndpoints[ep].dataVersions = currentDataVersions;
217 20 : emAfEndpoints[ep].parentEndpointId = fixedParentEndpoints[ep];
218 :
219 20 : emAfEndpoints[ep].bitmask.Set(EmberAfEndpointOptions::isEnabled);
220 20 : emAfEndpoints[ep].bitmask.Set(EmberAfEndpointOptions::isFlatComposition);
221 :
222 : // Increment currentDataVersions by 1 (slot) for every server cluster
223 : // this endpoint has.
224 20 : currentDataVersions += emberAfClusterCountByIndex(ep, /* server = */ true);
225 : }
226 :
227 : #endif // FIXED_ENDPOINT_COUNT > 0
228 :
229 : #if CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT
230 : if (MAX_ENDPOINT_COUNT > FIXED_ENDPOINT_COUNT)
231 : {
232 : //
233 : // Reset instances tracking dynamic endpoints to safe defaults.
234 : //
235 100 : for (ep = FIXED_ENDPOINT_COUNT; ep < MAX_ENDPOINT_COUNT; ep++)
236 : {
237 80 : emAfEndpoints[ep] = EmberAfDefinedEndpoint();
238 : }
239 : }
240 : #endif
241 20 : }
242 :
243 23 : void emberAfSetDynamicEndpointCount(uint16_t dynamicEndpointCount)
244 : {
245 23 : emberEndpointCount = static_cast<uint16_t>(FIXED_ENDPOINT_COUNT + dynamicEndpointCount);
246 23 : }
247 :
248 0 : uint16_t emberAfGetDynamicIndexFromEndpoint(EndpointId id)
249 : {
250 0 : if (id == kInvalidEndpointId)
251 : {
252 0 : return kEmberInvalidEndpointIndex;
253 : }
254 :
255 : uint16_t index;
256 0 : for (index = FIXED_ENDPOINT_COUNT; index < MAX_ENDPOINT_COUNT; index++)
257 : {
258 0 : if (emAfEndpoints[index].endpoint == id)
259 : {
260 0 : return static_cast<uint16_t>(index - FIXED_ENDPOINT_COUNT);
261 : }
262 : }
263 0 : return kEmberInvalidEndpointIndex;
264 : }
265 :
266 23 : CHIP_ERROR emberAfSetDynamicEndpoint(uint16_t index, EndpointId id, const EmberAfEndpointType * ep,
267 : const Span<DataVersion> & dataVersionStorage, Span<const EmberAfDeviceType> deviceTypeList,
268 : EndpointId parentEndpointId)
269 : {
270 23 : auto realIndex = index + FIXED_ENDPOINT_COUNT;
271 :
272 23 : if (realIndex >= MAX_ENDPOINT_COUNT)
273 : {
274 0 : return CHIP_ERROR_NO_MEMORY;
275 : }
276 23 : if (id == kInvalidEndpointId)
277 : {
278 0 : return CHIP_ERROR_INVALID_ARGUMENT;
279 : }
280 :
281 23 : auto serverClusterCount = emberAfClusterCountForEndpointType(ep, /* server = */ true);
282 23 : if (dataVersionStorage.size() < serverClusterCount)
283 : {
284 0 : return CHIP_ERROR_NO_MEMORY;
285 : }
286 :
287 23 : index = static_cast<uint16_t>(realIndex);
288 115 : for (uint16_t i = FIXED_ENDPOINT_COUNT; i < MAX_ENDPOINT_COUNT; i++)
289 : {
290 92 : if (emAfEndpoints[i].endpoint == id)
291 : {
292 0 : return CHIP_ERROR_ENDPOINT_EXISTS;
293 : }
294 : }
295 :
296 23 : const size_t bufferSize = Compatibility::Internal::gEmberAttributeIOBufferSpan.size();
297 52 : for (uint8_t i = 0; i < ep->clusterCount; i++)
298 : {
299 29 : const EmberAfCluster * cluster = &(ep->cluster[i]);
300 29 : if (!cluster->attributes)
301 : {
302 0 : continue;
303 : }
304 :
305 126 : for (uint16_t j = 0; j < cluster->attributeCount; j++)
306 : {
307 97 : const EmberAfAttributeMetadata * attr = &(cluster->attributes[j]);
308 97 : uint16_t attrSize = emberAfAttributeSize(attr);
309 97 : if (attrSize > bufferSize)
310 : {
311 0 : ChipLogError(DataManagement,
312 : "Attribute size %u exceeds max size %lu, (attrId=" ChipLogFormatMEI ", clusterId=" ChipLogFormatMEI
313 : ")",
314 : attrSize, static_cast<unsigned long>(bufferSize), ChipLogValueMEI(attr->attributeId),
315 : ChipLogValueMEI(cluster->clusterId));
316 0 : return CHIP_ERROR_NO_MEMORY;
317 : }
318 : }
319 : }
320 23 : emAfEndpoints[index].endpoint = id;
321 23 : emAfEndpoints[index].deviceTypeList = deviceTypeList;
322 23 : emAfEndpoints[index].endpointType = ep;
323 23 : emAfEndpoints[index].dataVersions = dataVersionStorage.data();
324 : // Start the endpoint off as disabled.
325 23 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isEnabled);
326 23 : emAfEndpoints[index].parentEndpointId = parentEndpointId;
327 :
328 23 : emberAfSetDynamicEndpointCount(MAX_ENDPOINT_COUNT - FIXED_ENDPOINT_COUNT);
329 :
330 : // Initialize the data versions.
331 23 : size_t dataSize = sizeof(DataVersion) * serverClusterCount;
332 23 : if (dataSize != 0)
333 : {
334 23 : if (Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(dataVersionStorage.data()), dataSize) != CHIP_NO_ERROR)
335 : {
336 : // Now what? At least 0-init it.
337 0 : memset(dataVersionStorage.data(), 0, dataSize);
338 : }
339 : }
340 :
341 : // Now enable the endpoint.
342 23 : emberAfEndpointEnableDisable(id, true);
343 :
344 23 : emberMetadataStructureGeneration++;
345 23 : return CHIP_NO_ERROR;
346 : }
347 :
348 22 : EndpointId emberAfClearDynamicEndpoint(uint16_t index)
349 : {
350 22 : EndpointId ep = 0;
351 :
352 22 : index = static_cast<uint16_t>(index + FIXED_ENDPOINT_COUNT);
353 :
354 44 : if ((index < MAX_ENDPOINT_COUNT) && (emAfEndpoints[index].endpoint != kInvalidEndpointId) &&
355 22 : (emberAfEndpointIndexIsEnabled(index)))
356 : {
357 22 : ep = emAfEndpoints[index].endpoint;
358 22 : emberAfEndpointEnableDisable(ep, false);
359 22 : emAfEndpoints[index].endpoint = kInvalidEndpointId;
360 : }
361 :
362 22 : emberMetadataStructureGeneration++;
363 22 : return ep;
364 : }
365 :
366 8405 : uint16_t emberAfFixedEndpointCount()
367 : {
368 8405 : return FIXED_ENDPOINT_COUNT;
369 : }
370 :
371 46175 : uint16_t emberAfEndpointCount()
372 : {
373 46175 : return emberEndpointCount;
374 : }
375 :
376 11482 : bool emberAfEndpointIndexIsEnabled(uint16_t index)
377 : {
378 11482 : return (emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isEnabled));
379 : }
380 :
381 : // This function is used to call the per-cluster attribute changed callback
382 0 : void emAfClusterAttributeChangedCallback(const ConcreteAttributePath & attributePath)
383 : {
384 0 : const EmberAfCluster * cluster = emberAfFindServerCluster(attributePath.mEndpointId, attributePath.mClusterId);
385 0 : if (cluster != nullptr)
386 : {
387 0 : EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_ATTRIBUTE_CHANGED_FUNCTION);
388 0 : if (f != nullptr)
389 : {
390 0 : ((EmberAfClusterAttributeChangedCallback) f)(attributePath);
391 : }
392 : }
393 0 : }
394 :
395 : // This function is used to call the per-cluster pre-attribute changed callback
396 0 : Status emAfClusterPreAttributeChangedCallback(const ConcreteAttributePath & attributePath, EmberAfAttributeType attributeType,
397 : uint16_t size, uint8_t * value)
398 : {
399 0 : const EmberAfCluster * cluster = emberAfFindServerCluster(attributePath.mEndpointId, attributePath.mClusterId);
400 0 : if (cluster == nullptr)
401 : {
402 0 : if (!emberAfEndpointIsEnabled(attributePath.mEndpointId))
403 : {
404 0 : return Status::UnsupportedEndpoint;
405 : }
406 0 : return Status::UnsupportedCluster;
407 : }
408 :
409 0 : Status status = Status::Success;
410 : // Casting and calling a function pointer on the same line results in ignoring the return
411 : // of the call on gcc-arm-none-eabi-9-2019-q4-major
412 0 : EmberAfClusterPreAttributeChangedCallback f = (EmberAfClusterPreAttributeChangedCallback) (emberAfFindClusterFunction(
413 : cluster, MATTER_CLUSTER_FLAG_PRE_ATTRIBUTE_CHANGED_FUNCTION));
414 0 : if (f != nullptr)
415 : {
416 0 : status = f(attributePath, attributeType, size, value);
417 : }
418 0 : return status;
419 : }
420 :
421 44 : static void initializeEndpoint(EmberAfDefinedEndpoint * definedEndpoint)
422 : {
423 : uint8_t clusterIndex;
424 44 : const EmberAfEndpointType * epType = definedEndpoint->endpointType;
425 2214 : for (clusterIndex = 0; clusterIndex < epType->clusterCount; clusterIndex++)
426 : {
427 2170 : const EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
428 : EmberAfGenericClusterFunction f;
429 2170 : emberAfClusterInitCallback(definedEndpoint->endpoint, cluster->clusterId);
430 2170 : f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_INIT_FUNCTION);
431 2170 : if (f != nullptr)
432 : {
433 0 : ((EmberAfInitFunction) f)(definedEndpoint->endpoint);
434 : }
435 : }
436 44 : }
437 :
438 23 : static void shutdownEndpoint(EmberAfDefinedEndpoint * definedEndpoint)
439 : {
440 : // Call shutdown callbacks from clusters, mainly for canceling pending timers
441 : uint8_t clusterIndex;
442 23 : const EmberAfEndpointType * epType = definedEndpoint->endpointType;
443 52 : for (clusterIndex = 0; clusterIndex < epType->clusterCount; clusterIndex++)
444 : {
445 29 : const EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
446 29 : EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_SHUTDOWN_FUNCTION);
447 29 : if (f != nullptr)
448 : {
449 0 : ((EmberAfShutdownFunction) f)(definedEndpoint->endpoint);
450 : }
451 : }
452 :
453 23 : CommandHandlerInterfaceRegistry::Instance().UnregisterAllCommandHandlersForEndpoint(definedEndpoint->endpoint);
454 23 : AttributeAccessInterfaceRegistry::Instance().UnregisterAllForEndpoint(definedEndpoint->endpoint);
455 23 : }
456 :
457 : // Calls the init functions.
458 20 : void emAfCallInits()
459 : {
460 : uint16_t index;
461 40 : for (index = 0; index < emberAfEndpointCount(); index++)
462 : {
463 20 : if (emberAfEndpointIndexIsEnabled(index))
464 : {
465 20 : initializeEndpoint(&(emAfEndpoints[index]));
466 : }
467 : }
468 20 : }
469 :
470 : // Returns the pointer to metadata, or null if it is not found
471 4190 : const EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId)
472 : {
473 4190 : const EmberAfAttributeMetadata * metadata = nullptr;
474 : EmberAfAttributeSearchRecord record;
475 4190 : record.endpoint = endpoint;
476 4190 : record.clusterId = clusterId;
477 4190 : record.attributeId = attributeId;
478 4190 : emAfReadOrWriteAttribute(&record, &metadata,
479 : nullptr, // buffer
480 : 0, // buffer size
481 : false); // write?
482 4190 : return metadata;
483 : }
484 :
485 0 : static uint8_t * singletonAttributeLocation(const EmberAfAttributeMetadata * am)
486 : {
487 0 : const EmberAfAttributeMetadata * m = &(generatedAttributes[0]);
488 0 : uint16_t index = 0;
489 0 : while (m < am)
490 : {
491 0 : if (m->IsSingleton() && !m->IsExternal())
492 : {
493 0 : index = static_cast<uint16_t>(index + m->size);
494 : }
495 0 : m++;
496 : }
497 0 : return (uint8_t *) (singletonAttributeData + index);
498 : }
499 :
500 : // This function does mem copy, but smartly, which means that if the type is a
501 : // string, it will copy as much as it can.
502 : // If src == NULL, then this method will set memory to zeroes
503 : // See documentation for emAfReadOrWriteAttribute for the semantics of
504 : // readLength when reading and writing.
505 0 : static Status typeSensitiveMemCopy(ClusterId clusterId, uint8_t * dest, uint8_t * src, const EmberAfAttributeMetadata * am,
506 : bool write, uint16_t readLength)
507 : {
508 0 : EmberAfAttributeType attributeType = am->attributeType;
509 : // readLength == 0 for a read indicates that we should just trust that the
510 : // caller has enough space for an attribute...
511 0 : bool ignoreReadLength = write || (readLength == 0);
512 0 : uint16_t bufferSize = ignoreReadLength ? am->size : readLength;
513 :
514 0 : if (emberAfIsStringAttributeType(attributeType))
515 : {
516 0 : if (bufferSize < 1)
517 : {
518 0 : return Status::ResourceExhausted;
519 : }
520 0 : emberAfCopyString(dest, src, bufferSize - 1);
521 : }
522 0 : else if (emberAfIsLongStringAttributeType(attributeType))
523 : {
524 0 : if (bufferSize < 2)
525 : {
526 0 : return Status::ResourceExhausted;
527 : }
528 0 : emberAfCopyLongString(dest, src, bufferSize - 2);
529 : }
530 0 : else if (emberAfIsThisDataTypeAListType(attributeType))
531 : {
532 0 : if (bufferSize < 2)
533 : {
534 0 : return Status::ResourceExhausted;
535 : }
536 :
537 : // Just copy the length.
538 0 : memmove(dest, src, 2);
539 : }
540 : else
541 : {
542 0 : if (!ignoreReadLength && readLength < am->size)
543 : {
544 0 : return Status::ResourceExhausted;
545 : }
546 0 : if (src == nullptr)
547 : {
548 0 : memset(dest, 0, am->size);
549 : }
550 : else
551 : {
552 0 : memmove(dest, src, am->size);
553 : }
554 : }
555 0 : return Status::Success;
556 : }
557 :
558 : /**
559 : * @brief Matches a cluster based on cluster id and direction.
560 : *
561 : * This function assumes that the passed cluster's endpoint already
562 : * matches the endpoint of the EmberAfAttributeSearchRecord.
563 : *
564 : * Clusters match if:
565 : * 1. Cluster ids match AND
566 : * 2. Cluster is a server cluster (because there are no client attributes).
567 : */
568 4190 : bool emAfMatchCluster(const EmberAfCluster * cluster, const EmberAfAttributeSearchRecord * attRecord)
569 : {
570 4190 : return (cluster->clusterId == attRecord->clusterId && (cluster->mask & MATTER_CLUSTER_FLAG_SERVER));
571 : }
572 :
573 : /**
574 : * @brief Matches an attribute based on attribute id.
575 : * This function assumes that the passed cluster already matches the
576 : * clusterId and direction of the passed EmberAfAttributeSearchRecord.
577 : *
578 : * Attributes match if attr ids match.
579 : */
580 7263 : bool emAfMatchAttribute(const EmberAfCluster * cluster, const EmberAfAttributeMetadata * am,
581 : const EmberAfAttributeSearchRecord * attRecord)
582 : {
583 7263 : return (am->attributeId == attRecord->attributeId);
584 : }
585 :
586 : // When reading non-string attributes, this function returns an error when destination
587 : // buffer isn't large enough to accommodate the attribute type. For strings, the
588 : // function will copy at most readLength bytes. This means the resulting string
589 : // may be truncated. The length byte(s) in the resulting string will reflect
590 : // any truncation. If readLength is zero, we are working with backwards-
591 : // compatibility wrapper functions and we just cross our fingers and hope for
592 : // the best.
593 : //
594 : // When writing attributes, readLength is ignored. For non-string attributes,
595 : // this function assumes the source buffer is the same size as the attribute
596 : // type. For strings, the function will copy as many bytes as will fit in the
597 : // attribute. This means the resulting string may be truncated. The length
598 : // byte(s) in the resulting string will reflect any truncated.
599 4190 : Status emAfReadOrWriteAttribute(const EmberAfAttributeSearchRecord * attRecord, const EmberAfAttributeMetadata ** metadata,
600 : uint8_t * buffer, uint16_t readLength, bool write)
601 : {
602 4190 : assertChipStackLockedByCurrentThread();
603 :
604 4190 : uint16_t attributeOffsetIndex = 0;
605 :
606 8405 : for (uint16_t ep = 0; ep < emberAfEndpointCount(); ep++)
607 : {
608 : // Is this a dynamic endpoint?
609 8405 : bool isDynamicEndpoint = (ep >= emberAfFixedEndpointCount());
610 :
611 8405 : if (emAfEndpoints[ep].endpoint == attRecord->endpoint)
612 : {
613 4190 : const EmberAfEndpointType * endpointType = emAfEndpoints[ep].endpointType;
614 : uint8_t clusterIndex;
615 4190 : if (!emberAfEndpointIndexIsEnabled(ep))
616 : {
617 0 : continue;
618 : }
619 4190 : for (clusterIndex = 0; clusterIndex < endpointType->clusterCount; clusterIndex++)
620 : {
621 4190 : const EmberAfCluster * cluster = &(endpointType->cluster[clusterIndex]);
622 4190 : if (emAfMatchCluster(cluster, attRecord))
623 : { // Got the cluster
624 : uint16_t attrIndex;
625 7263 : for (attrIndex = 0; attrIndex < cluster->attributeCount; attrIndex++)
626 : {
627 7263 : const EmberAfAttributeMetadata * am = &(cluster->attributes[attrIndex]);
628 7263 : if (emAfMatchAttribute(cluster, am, attRecord))
629 : { // Got the attribute
630 : // If passed metadata location is not null, populate
631 4190 : if (metadata != nullptr)
632 : {
633 4190 : *metadata = am;
634 : }
635 :
636 : {
637 : uint8_t * attributeLocation =
638 4190 : (am->mask & MATTER_ATTRIBUTE_FLAG_SINGLETON ? singletonAttributeLocation(am)
639 4190 : : attributeData + attributeOffsetIndex);
640 : uint8_t *src, *dst;
641 4190 : if (write)
642 : {
643 0 : src = buffer;
644 0 : dst = attributeLocation;
645 0 : if (!emberAfAttributeWriteAccessCallback(attRecord->endpoint, attRecord->clusterId,
646 0 : am->attributeId))
647 : {
648 0 : return Status::UnsupportedAccess;
649 : }
650 : }
651 : else
652 : {
653 4190 : if (buffer == nullptr)
654 : {
655 4190 : return Status::Success;
656 : }
657 :
658 0 : src = attributeLocation;
659 0 : dst = buffer;
660 0 : if (!emberAfAttributeReadAccessCallback(attRecord->endpoint, attRecord->clusterId,
661 0 : am->attributeId))
662 : {
663 0 : return Status::UnsupportedAccess;
664 : }
665 : }
666 :
667 : // Is the attribute externally stored?
668 0 : if (am->mask & MATTER_ATTRIBUTE_FLAG_EXTERNAL_STORAGE)
669 : {
670 0 : if (write)
671 : {
672 0 : return emberAfExternalAttributeWriteCallback(attRecord->endpoint, attRecord->clusterId, am,
673 0 : buffer);
674 : }
675 :
676 0 : if (readLength < emberAfAttributeSize(am))
677 : {
678 : // Prevent a potential buffer overflow
679 0 : return Status::ResourceExhausted;
680 : }
681 :
682 0 : return emberAfExternalAttributeReadCallback(attRecord->endpoint, attRecord->clusterId, am,
683 0 : buffer, emberAfAttributeSize(am));
684 : }
685 :
686 : // Internal storage is only supported for fixed endpoints
687 0 : if (!isDynamicEndpoint)
688 : {
689 0 : return typeSensitiveMemCopy(attRecord->clusterId, dst, src, am, write, readLength);
690 : }
691 :
692 0 : return Status::Failure;
693 : }
694 : }
695 : else
696 : { // Not the attribute we are looking for
697 : // Increase the index if attribute is not externally stored
698 3073 : if (!(am->mask & MATTER_ATTRIBUTE_FLAG_EXTERNAL_STORAGE) &&
699 0 : !(am->mask & MATTER_ATTRIBUTE_FLAG_SINGLETON))
700 : {
701 0 : attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + emberAfAttributeSize(am));
702 : }
703 : }
704 : }
705 :
706 : // Attribute is not in the cluster.
707 0 : return Status::UnsupportedAttribute;
708 : }
709 :
710 : // Not the cluster we are looking for
711 0 : attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + cluster->clusterSize);
712 : }
713 :
714 : // Cluster is not in the endpoint.
715 0 : return Status::UnsupportedCluster;
716 : }
717 :
718 : // Not the endpoint we are looking for
719 : // Dynamic endpoints are external and don't factor into storage size
720 4215 : if (!isDynamicEndpoint)
721 : {
722 4190 : attributeOffsetIndex = static_cast<uint16_t>(attributeOffsetIndex + emAfEndpoints[ep].endpointType->endpointSize);
723 : }
724 : }
725 0 : return Status::UnsupportedEndpoint; // Sorry, endpoint was not found.
726 : }
727 :
728 4310 : const EmberAfEndpointType * emberAfFindEndpointType(EndpointId endpointId)
729 : {
730 4310 : uint16_t ep = emberAfIndexFromEndpoint(endpointId);
731 4310 : if (ep == kEmberInvalidEndpointIndex)
732 : {
733 5 : return nullptr;
734 : }
735 4305 : return emAfEndpoints[ep].endpointType;
736 : }
737 :
738 6772 : const EmberAfCluster * emberAfFindClusterInType(const EmberAfEndpointType * endpointType, ClusterId clusterId,
739 : EmberAfClusterMask mask, uint8_t * index)
740 : {
741 : uint8_t i;
742 6772 : uint8_t scopedIndex = 0;
743 :
744 6793 : for (i = 0; i < endpointType->clusterCount; i++)
745 : {
746 6793 : const EmberAfCluster * cluster = &(endpointType->cluster[i]);
747 :
748 6793 : if (mask == 0 || ((cluster->mask & mask) != 0))
749 : {
750 6793 : if (cluster->clusterId == clusterId)
751 : {
752 6772 : if (index)
753 : {
754 6742 : *index = scopedIndex;
755 : }
756 :
757 6772 : return cluster;
758 : }
759 :
760 21 : scopedIndex++;
761 : }
762 : }
763 :
764 0 : return nullptr;
765 : }
766 :
767 6742 : uint8_t emberAfClusterIndex(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask)
768 : {
769 13559 : for (uint16_t ep = 0; ep < emberAfEndpointCount(); ep++)
770 : {
771 : // Check the endpoint id first, because that way we avoid examining the
772 : // endpoint type for endpoints that are not actually defined.
773 13559 : if (emAfEndpoints[ep].endpoint == endpoint)
774 : {
775 6742 : const EmberAfEndpointType * endpointType = emAfEndpoints[ep].endpointType;
776 6742 : uint8_t index = 0xFF;
777 6742 : if (emberAfFindClusterInType(endpointType, clusterId, mask, &index) != nullptr)
778 : {
779 6742 : return index;
780 : }
781 : }
782 : }
783 0 : return 0xFF;
784 : }
785 :
786 : // Returns whether the given endpoint has the server of the given cluster on it.
787 0 : bool emberAfContainsServer(EndpointId endpoint, ClusterId clusterId)
788 : {
789 0 : return (emberAfFindServerCluster(endpoint, clusterId) != nullptr);
790 : }
791 :
792 : // Returns whether the given endpoint has the client of the given cluster on it.
793 0 : bool emberAfContainsClient(EndpointId endpoint, ClusterId clusterId)
794 : {
795 0 : uint16_t ep = emberAfIndexFromEndpoint(endpoint);
796 0 : if (ep == kEmberInvalidEndpointIndex)
797 : {
798 0 : return false;
799 : }
800 :
801 0 : return (emberAfFindClusterInType(emAfEndpoints[ep].endpointType, clusterId, MATTER_CLUSTER_FLAG_CLIENT) != nullptr);
802 : }
803 :
804 : // This will find the first server that has the clusterId given from the index of endpoint.
805 0 : bool emberAfContainsServerFromIndex(uint16_t index, ClusterId clusterId)
806 : {
807 0 : if (index == kEmberInvalidEndpointIndex)
808 : {
809 0 : return false;
810 : }
811 :
812 0 : return emberAfFindClusterInType(emAfEndpoints[index].endpointType, clusterId, MATTER_CLUSTER_FLAG_SERVER);
813 : }
814 :
815 : namespace chip {
816 : namespace app {
817 :
818 0 : EnabledEndpointsWithServerCluster::EnabledEndpointsWithServerCluster(ClusterId clusterId) :
819 0 : mEndpointCount(emberAfEndpointCount()), mClusterId(clusterId)
820 : {
821 0 : EnsureMatchingEndpoint();
822 0 : }
823 :
824 0 : EndpointId EnabledEndpointsWithServerCluster::operator*() const
825 : {
826 0 : return emberAfEndpointFromIndex(mEndpointIndex);
827 : }
828 :
829 0 : EnabledEndpointsWithServerCluster & EnabledEndpointsWithServerCluster::operator++()
830 : {
831 0 : ++mEndpointIndex;
832 0 : EnsureMatchingEndpoint();
833 0 : return *this;
834 : }
835 :
836 0 : void EnabledEndpointsWithServerCluster::EnsureMatchingEndpoint()
837 : {
838 0 : for (; mEndpointIndex < mEndpointCount; ++mEndpointIndex)
839 : {
840 0 : if (!emberAfEndpointIndexIsEnabled(mEndpointIndex))
841 : {
842 0 : continue;
843 : }
844 :
845 0 : if (emberAfContainsServerFromIndex(mEndpointIndex, mClusterId))
846 : {
847 0 : break;
848 : }
849 : }
850 0 : }
851 :
852 : } // namespace app
853 : } // namespace chip
854 :
855 : // Finds the cluster that matches endpoint, clusterId, direction.
856 31 : const EmberAfCluster * emberAfFindServerCluster(EndpointId endpoint, ClusterId clusterId)
857 : {
858 31 : uint16_t ep = emberAfIndexFromEndpoint(endpoint);
859 31 : if (ep == kEmberInvalidEndpointIndex)
860 : {
861 1 : return nullptr;
862 : }
863 :
864 30 : return emberAfFindClusterInType(emAfEndpoints[ep].endpointType, clusterId, MATTER_CLUSTER_FLAG_SERVER);
865 : }
866 :
867 : // Returns cluster within the endpoint; Does not ignore disabled endpoints
868 0 : const EmberAfCluster * emberAfFindClusterIncludingDisabledEndpoints(EndpointId endpoint, ClusterId clusterId,
869 : EmberAfClusterMask mask)
870 : {
871 0 : uint16_t ep = emberAfIndexFromEndpointIncludingDisabledEndpoints(endpoint);
872 0 : if (ep < MAX_ENDPOINT_COUNT)
873 : {
874 0 : return emberAfFindClusterInType(emAfEndpoints[ep].endpointType, clusterId, mask);
875 : }
876 0 : return nullptr;
877 : }
878 :
879 0 : uint16_t emberAfGetClusterServerEndpointIndex(EndpointId endpoint, ClusterId cluster, uint16_t fixedClusterServerEndpointCount)
880 : {
881 0 : VerifyOrDie(fixedClusterServerEndpointCount <= FIXED_ENDPOINT_COUNT);
882 0 : uint16_t epIndex = findIndexFromEndpoint(endpoint, true /*ignoreDisabledEndpoints*/);
883 :
884 : // Endpoint must be configured and enabled
885 0 : if (epIndex == kEmberInvalidEndpointIndex)
886 : {
887 0 : return kEmberInvalidEndpointIndex;
888 : }
889 :
890 0 : if (emberAfFindClusterInType(emAfEndpoints[epIndex].endpointType, cluster, MATTER_CLUSTER_FLAG_SERVER) == nullptr)
891 : {
892 : // The provided endpoint does not contain the given cluster server.
893 0 : return kEmberInvalidEndpointIndex;
894 : }
895 :
896 0 : if (epIndex < FIXED_ENDPOINT_COUNT)
897 : {
898 : // This endpoint is a fixed one.
899 : // Return the index of this endpoint in the list of fixed endpoints that support the given cluster.
900 0 : uint16_t adjustedEndpointIndex = 0;
901 0 : for (uint16_t i = 0; i < epIndex; i++)
902 : {
903 : // Increase adjustedEndpointIndex for every endpoint containing the cluster server
904 : // before our endpoint of interest
905 0 : if (emAfEndpoints[i].endpoint != kInvalidEndpointId &&
906 0 : (emberAfFindClusterInType(emAfEndpoints[i].endpointType, cluster, MATTER_CLUSTER_FLAG_SERVER) != nullptr))
907 : {
908 0 : adjustedEndpointIndex++;
909 : }
910 : }
911 :
912 : // If this asserts, the provided fixedClusterServerEndpointCount doesn't match the app data model.
913 0 : VerifyOrDie(adjustedEndpointIndex < fixedClusterServerEndpointCount);
914 0 : epIndex = adjustedEndpointIndex;
915 : }
916 : else
917 : {
918 : // This is a dynamic endpoint.
919 : // Its index is just its index in the dynamic endpoint list, offset by fixedClusterServerEndpointCount.
920 0 : epIndex = static_cast<uint16_t>(fixedClusterServerEndpointCount + (epIndex - FIXED_ENDPOINT_COUNT));
921 : }
922 :
923 0 : return epIndex;
924 : }
925 :
926 0 : bool emberAfEndpointIsEnabled(EndpointId endpoint)
927 : {
928 0 : uint16_t index = findIndexFromEndpoint(endpoint, false /* ignoreDisabledEndpoints */);
929 :
930 0 : if (kEmberInvalidEndpointIndex == index)
931 : {
932 0 : return false;
933 : }
934 :
935 0 : return emberAfEndpointIndexIsEnabled(index);
936 : }
937 :
938 47 : bool emberAfEndpointEnableDisable(EndpointId endpoint, bool enable)
939 : {
940 47 : uint16_t index = findIndexFromEndpoint(endpoint, false /* ignoreDisabledEndpoints */);
941 : bool currentlyEnabled;
942 :
943 47 : if (kEmberInvalidEndpointIndex == index)
944 : {
945 0 : return false;
946 : }
947 :
948 47 : currentlyEnabled = emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isEnabled);
949 :
950 47 : if (enable)
951 : {
952 24 : emAfEndpoints[index].bitmask.Set(EmberAfEndpointOptions::isEnabled);
953 : }
954 :
955 47 : if (currentlyEnabled != enable)
956 : {
957 47 : if (enable)
958 : {
959 24 : initializeEndpoint(&(emAfEndpoints[index]));
960 24 : emberAfEndpointChanged(endpoint, emberAfGlobalInteractionModelAttributesChangedListener());
961 : }
962 : else
963 : {
964 23 : shutdownEndpoint(&(emAfEndpoints[index]));
965 23 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isEnabled);
966 : }
967 :
968 47 : EndpointId parentEndpointId = emberAfParentEndpointFromIndex(index);
969 47 : while (parentEndpointId != kInvalidEndpointId)
970 : {
971 0 : emberAfAttributeChanged(parentEndpointId, Clusters::Descriptor::Id, Clusters::Descriptor::Attributes::PartsList::Id,
972 : emberAfGlobalInteractionModelAttributesChangedListener());
973 0 : uint16_t parentIndex = emberAfIndexFromEndpoint(parentEndpointId);
974 0 : if (parentIndex == kEmberInvalidEndpointIndex)
975 : {
976 : // Something has gone wrong.
977 0 : break;
978 : }
979 0 : parentEndpointId = emberAfParentEndpointFromIndex(parentIndex);
980 : }
981 :
982 47 : emberAfAttributeChanged(/* endpoint = */ 0, Clusters::Descriptor::Id, Clusters::Descriptor::Attributes::PartsList::Id,
983 : emberAfGlobalInteractionModelAttributesChangedListener());
984 : }
985 :
986 47 : emberMetadataStructureGeneration++;
987 47 : return true;
988 : }
989 :
990 8228 : unsigned emberAfMetadataStructureGeneration()
991 : {
992 8228 : return emberMetadataStructureGeneration;
993 : }
994 :
995 : // Returns the index of a given endpoint. Does not consider disabled endpoints.
996 11130 : uint16_t emberAfIndexFromEndpoint(EndpointId endpoint)
997 : {
998 11130 : return findIndexFromEndpoint(endpoint, true /* ignoreDisabledEndpoints */);
999 : }
1000 :
1001 2917 : EndpointId emberAfEndpointFromIndex(uint16_t index)
1002 : {
1003 2917 : return emAfEndpoints[index].endpoint;
1004 : }
1005 :
1006 2964 : EndpointId emberAfParentEndpointFromIndex(uint16_t index)
1007 : {
1008 2964 : return emAfEndpoints[index].parentEndpointId;
1009 : }
1010 :
1011 : // If server == true, returns the number of server clusters,
1012 : // otherwise number of client clusters on this endpoint
1013 0 : uint8_t emberAfClusterCount(EndpointId endpoint, bool server)
1014 : {
1015 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1016 0 : if (index == kEmberInvalidEndpointIndex)
1017 : {
1018 0 : return 0;
1019 : }
1020 :
1021 0 : return emberAfClusterCountByIndex(index, server);
1022 : }
1023 :
1024 20 : uint8_t emberAfClusterCountByIndex(uint16_t endpointIndex, bool server)
1025 : {
1026 20 : const EmberAfDefinedEndpoint * de = &(emAfEndpoints[endpointIndex]);
1027 20 : if (de->endpointType == nullptr)
1028 : {
1029 0 : return 0;
1030 : }
1031 :
1032 20 : return emberAfClusterCountForEndpointType(de->endpointType, server);
1033 : }
1034 :
1035 4348 : uint8_t emberAfClusterCountForEndpointType(const EmberAfEndpointType * type, bool server)
1036 : {
1037 4348 : const EmberAfClusterMask cluster_mask = server ? MATTER_CLUSTER_FLAG_SERVER : MATTER_CLUSTER_FLAG_CLIENT;
1038 :
1039 4348 : return static_cast<uint8_t>(std::count_if(type->cluster, type->cluster + type->clusterCount,
1040 12221 : [=](const EmberAfCluster & cluster) { return (cluster.mask & cluster_mask) != 0; }));
1041 : }
1042 :
1043 0 : uint8_t emberAfGetClusterCountForEndpoint(EndpointId endpoint)
1044 : {
1045 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1046 0 : if (index == kEmberInvalidEndpointIndex)
1047 : {
1048 0 : return 0;
1049 : }
1050 0 : return emAfEndpoints[index].endpointType->clusterCount;
1051 : }
1052 :
1053 0 : Span<const EmberAfDeviceType> emberAfDeviceTypeListFromEndpoint(EndpointId endpoint, CHIP_ERROR & err)
1054 : {
1055 0 : return emberAfDeviceTypeListFromEndpointIndex(emberAfIndexFromEndpoint(endpoint), err);
1056 : }
1057 :
1058 0 : chip::Span<const EmberAfDeviceType> emberAfDeviceTypeListFromEndpointIndex(unsigned endpointIndex, CHIP_ERROR & err)
1059 : {
1060 0 : if (endpointIndex == 0xFFFF)
1061 : {
1062 0 : err = CHIP_ERROR_INVALID_ARGUMENT;
1063 0 : return Span<const EmberAfDeviceType>();
1064 : }
1065 :
1066 0 : err = CHIP_NO_ERROR;
1067 0 : return emAfEndpoints[endpointIndex].deviceTypeList;
1068 : }
1069 :
1070 0 : CHIP_ERROR GetSemanticTagForEndpointAtIndex(EndpointId endpoint, size_t index,
1071 : Clusters::Descriptor::Structs::SemanticTagStruct::Type & tag)
1072 : {
1073 0 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1074 :
1075 0 : if (endpointIndex == 0xFFFF || index >= emAfEndpoints[endpointIndex].tagList.size())
1076 : {
1077 0 : return CHIP_ERROR_NOT_FOUND;
1078 : }
1079 0 : tag = emAfEndpoints[endpointIndex].tagList[index];
1080 0 : return CHIP_NO_ERROR;
1081 : }
1082 :
1083 0 : CHIP_ERROR emberAfSetDeviceTypeList(EndpointId endpoint, Span<const EmberAfDeviceType> deviceTypeList)
1084 : {
1085 0 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1086 0 : if (endpointIndex == 0xFFFF)
1087 : {
1088 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1089 : }
1090 :
1091 0 : emAfEndpoints[endpointIndex].deviceTypeList = deviceTypeList;
1092 0 : return CHIP_NO_ERROR;
1093 : }
1094 :
1095 0 : CHIP_ERROR SetTagList(EndpointId endpoint, Span<const Clusters::Descriptor::Structs::SemanticTagStruct::Type> tagList)
1096 : {
1097 0 : uint16_t endpointIndex = emberAfIndexFromEndpoint(endpoint);
1098 0 : if (endpointIndex == 0xFFFF)
1099 : {
1100 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1101 : }
1102 :
1103 0 : emAfEndpoints[endpointIndex].tagList = tagList;
1104 0 : return CHIP_NO_ERROR;
1105 : }
1106 :
1107 : // Returns the cluster of Nth server or client cluster,
1108 : // depending on server toggle.
1109 0 : const EmberAfCluster * emberAfGetNthCluster(EndpointId endpoint, uint8_t n, bool server)
1110 : {
1111 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1112 0 : if (index == kEmberInvalidEndpointIndex)
1113 : {
1114 0 : return nullptr;
1115 : }
1116 :
1117 0 : const EmberAfEndpointType * endpointType = emAfEndpoints[index].endpointType;
1118 0 : const EmberAfClusterMask cluster_mask = server ? MATTER_CLUSTER_FLAG_SERVER : MATTER_CLUSTER_FLAG_CLIENT;
1119 0 : const uint8_t clusterCount = endpointType->clusterCount;
1120 :
1121 0 : uint8_t c = 0;
1122 0 : for (uint8_t i = 0; i < clusterCount; i++)
1123 : {
1124 0 : const EmberAfCluster * cluster = &(endpointType->cluster[i]);
1125 :
1126 0 : if ((cluster->mask & cluster_mask) == 0)
1127 : {
1128 0 : continue;
1129 : }
1130 :
1131 0 : if (c == n)
1132 : {
1133 0 : return cluster;
1134 : }
1135 :
1136 0 : c++;
1137 : }
1138 0 : return nullptr;
1139 : }
1140 :
1141 : // Returns the cluster id of Nth server or client cluster,
1142 : // depending on server toggle.
1143 : // Returns Optional<ClusterId>::Missing() if cluster does not exist.
1144 0 : Optional<ClusterId> emberAfGetNthClusterId(EndpointId endpoint, uint8_t n, bool server)
1145 : {
1146 0 : const EmberAfCluster * cluster = emberAfGetNthCluster(endpoint, n, server);
1147 0 : if (cluster == nullptr)
1148 : {
1149 0 : return Optional<ClusterId>::Missing();
1150 : }
1151 0 : return Optional<ClusterId>(cluster->clusterId);
1152 : }
1153 :
1154 : // Returns number of clusters put into the passed cluster list
1155 : // for the given endpoint and client/server polarity
1156 0 : uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen, bool server)
1157 : {
1158 0 : uint8_t clusterCount = emberAfClusterCount(endpoint, server);
1159 : uint8_t i;
1160 : const EmberAfCluster * cluster;
1161 0 : if (clusterCount > listLen)
1162 : {
1163 0 : clusterCount = listLen;
1164 : }
1165 0 : for (i = 0; i < clusterCount; i++)
1166 : {
1167 0 : cluster = emberAfGetNthCluster(endpoint, i, server);
1168 0 : clusterList[i] = (cluster == nullptr ? kEmberInvalidEndpointIndex : cluster->clusterId);
1169 : }
1170 0 : return clusterCount;
1171 : }
1172 :
1173 20 : void emberAfInitializeAttributes(EndpointId endpoint)
1174 : {
1175 20 : emAfLoadAttributeDefaults(endpoint);
1176 20 : }
1177 :
1178 20 : void emAfLoadAttributeDefaults(EndpointId endpoint, Optional<ClusterId> clusterId)
1179 : {
1180 : uint16_t ep;
1181 : uint8_t clusterI;
1182 : uint16_t attr;
1183 : uint8_t * ptr;
1184 20 : uint16_t epCount = emberAfEndpointCount();
1185 : uint8_t attrData[ATTRIBUTE_LARGEST];
1186 20 : auto * attrStorage = GetAttributePersistenceProvider();
1187 : // Don't check whether we actually have an attrStorage here, because it's OK
1188 : // to have one if none of our attributes have NVM storage.
1189 :
1190 40 : for (ep = 0; ep < epCount; ep++)
1191 : {
1192 : EmberAfDefinedEndpoint * de;
1193 20 : if (endpoint != kInvalidEndpointId)
1194 : {
1195 0 : ep = emberAfIndexFromEndpoint(endpoint);
1196 0 : if (ep == kEmberInvalidEndpointIndex)
1197 : {
1198 0 : return;
1199 : }
1200 : }
1201 20 : de = &(emAfEndpoints[ep]);
1202 :
1203 2160 : for (clusterI = 0; clusterI < de->endpointType->clusterCount; clusterI++)
1204 : {
1205 2140 : const EmberAfCluster * cluster = &(de->endpointType->cluster[clusterI]);
1206 2140 : if (clusterId.HasValue())
1207 : {
1208 0 : if (clusterId.Value() != cluster->clusterId)
1209 : {
1210 0 : continue;
1211 : }
1212 : }
1213 :
1214 : // when the attributeCount is high, the loop takes too long to run and a
1215 : // watchdog kicks in causing a reset. As a workaround, we'll
1216 : // conditionally manually reset the watchdog. 300 sounds like a good
1217 : // magic number for now.
1218 2140 : if (cluster->attributeCount > 300)
1219 : {
1220 : // halResetWatchdog();
1221 : }
1222 2140 : for (attr = 0; attr < cluster->attributeCount; attr++)
1223 : {
1224 0 : const EmberAfAttributeMetadata * am = &(cluster->attributes[attr]);
1225 0 : ptr = nullptr; // Will get set to the value to write, as needed.
1226 :
1227 : // First check for a persisted value.
1228 0 : if (am->IsAutomaticallyPersisted())
1229 : {
1230 0 : VerifyOrDieWithMsg(attrStorage != nullptr, Zcl, "Attribute persistence needs a persistence provider");
1231 0 : MutableByteSpan bytes(attrData);
1232 : CHIP_ERROR err =
1233 0 : attrStorage->ReadValue(ConcreteAttributePath(de->endpoint, cluster->clusterId, am->attributeId), am, bytes);
1234 0 : if (err == CHIP_NO_ERROR)
1235 : {
1236 0 : ptr = attrData;
1237 : }
1238 : else
1239 : {
1240 0 : ChipLogDetail(
1241 : DataManagement,
1242 : "Failed to read stored attribute (%u, " ChipLogFormatMEI ", " ChipLogFormatMEI ": %" CHIP_ERROR_FORMAT,
1243 : de->endpoint, ChipLogValueMEI(cluster->clusterId), ChipLogValueMEI(am->attributeId), err.Format());
1244 : // Just fall back to default value.
1245 : }
1246 : }
1247 :
1248 0 : if (!am->IsExternal())
1249 : {
1250 : EmberAfAttributeSearchRecord record;
1251 0 : record.endpoint = de->endpoint;
1252 0 : record.clusterId = cluster->clusterId;
1253 0 : record.attributeId = am->attributeId;
1254 :
1255 0 : if (ptr == nullptr)
1256 : {
1257 0 : size_t defaultValueSizeForBigEndianNudger = 0;
1258 : // Bypasses compiler warning about unused variable for little endian platforms.
1259 : (void) defaultValueSizeForBigEndianNudger;
1260 0 : if ((am->mask & MATTER_ATTRIBUTE_FLAG_MIN_MAX) != 0U)
1261 : {
1262 : // This is intentionally 2 and not 4 bytes since defaultValue in min/max
1263 : // attributes is still uint16_t.
1264 0 : if (emberAfAttributeSize(am) <= 2)
1265 : {
1266 : static_assert(sizeof(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue) == 2,
1267 : "if statement relies on size of max/min defaultValue being 2");
1268 0 : ptr = (uint8_t *) &(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue);
1269 0 : defaultValueSizeForBigEndianNudger =
1270 : sizeof(am->defaultValue.ptrToMinMaxValue->defaultValue.defaultValue);
1271 : }
1272 : else
1273 : {
1274 0 : ptr = (uint8_t *) am->defaultValue.ptrToMinMaxValue->defaultValue.ptrToDefaultValue;
1275 : }
1276 : }
1277 : else
1278 : {
1279 0 : if ((emberAfAttributeSize(am) <= 4) && !emberAfIsStringAttributeType(am->attributeType))
1280 : {
1281 0 : ptr = (uint8_t *) &(am->defaultValue.defaultValue);
1282 0 : defaultValueSizeForBigEndianNudger = sizeof(am->defaultValue.defaultValue);
1283 : }
1284 : else
1285 : {
1286 0 : ptr = (uint8_t *) am->defaultValue.ptrToDefaultValue;
1287 : }
1288 : }
1289 : // At this point, ptr either points to a default value, or is NULL, in which case
1290 : // it should be treated as if it is pointing to an array of all zeroes.
1291 :
1292 : #if (CHIP_CONFIG_BIG_ENDIAN_TARGET)
1293 : // The default values for attributes that are less than or equal to
1294 : // defaultValueSizeForBigEndianNudger in bytes are stored in an
1295 : // uint32_t. On big-endian platforms, a pointer to the default value
1296 : // of size less than defaultValueSizeForBigEndianNudger will point to the wrong
1297 : // byte. So, for those cases, nudge the pointer forward so it points
1298 : // to the correct byte.
1299 : if (emberAfAttributeSize(am) < defaultValueSizeForBigEndianNudger && ptr != NULL)
1300 : {
1301 : ptr += (defaultValueSizeForBigEndianNudger - emberAfAttributeSize(am));
1302 : }
1303 : #endif // BIGENDIAN
1304 : }
1305 :
1306 0 : emAfReadOrWriteAttribute(&record,
1307 : nullptr, // metadata - unused
1308 : ptr,
1309 : 0, // buffer size - unused
1310 : true); // write?
1311 : }
1312 : }
1313 : }
1314 20 : if (endpoint != kInvalidEndpointId)
1315 : {
1316 0 : break;
1317 : }
1318 : }
1319 : }
1320 :
1321 : // 'data' argument may be null, since we changed the ptrToDefaultValue
1322 : // to be null instead of pointing to all zeroes.
1323 : // This function has to be able to deal with that.
1324 0 : void emAfSaveAttributeToStorageIfNeeded(uint8_t * data, EndpointId endpoint, ClusterId clusterId,
1325 : const EmberAfAttributeMetadata * metadata)
1326 : {
1327 : // Get out of here if this attribute isn't marked non-volatile.
1328 0 : if (!metadata->IsAutomaticallyPersisted())
1329 : {
1330 0 : return;
1331 : }
1332 :
1333 : // TODO: Maybe we should have a separate constant for the size of the
1334 : // largest non-volatile attribute?
1335 0 : uint8_t allZeroData[ATTRIBUTE_LARGEST] = { 0 };
1336 0 : if (data == nullptr)
1337 : {
1338 0 : data = allZeroData;
1339 : }
1340 :
1341 : size_t dataSize;
1342 0 : EmberAfAttributeType type = metadata->attributeType;
1343 0 : if (emberAfIsStringAttributeType(type))
1344 : {
1345 0 : dataSize = emberAfStringLength(data) + 1;
1346 : }
1347 0 : else if (emberAfIsLongStringAttributeType(type))
1348 : {
1349 0 : dataSize = emberAfLongStringLength(data) + 2;
1350 : }
1351 : else
1352 : {
1353 0 : dataSize = metadata->size;
1354 : }
1355 :
1356 0 : auto * attrStorage = GetAttributePersistenceProvider();
1357 0 : if (attrStorage)
1358 : {
1359 0 : attrStorage->WriteValue(ConcreteAttributePath(endpoint, clusterId, metadata->attributeId), ByteSpan(data, dataSize));
1360 : }
1361 : else
1362 : {
1363 0 : ChipLogProgress(DataManagement, "Can't store attribute value: no persistence provider");
1364 : }
1365 : }
1366 :
1367 : // This function returns the actual function point from the array,
1368 : // iterating over the function bits.
1369 2199 : EmberAfGenericClusterFunction emberAfFindClusterFunction(const EmberAfCluster * cluster, EmberAfClusterMask functionMask)
1370 : {
1371 2199 : EmberAfClusterMask mask = 0x01;
1372 2199 : uint8_t functionIndex = 0;
1373 :
1374 2199 : if ((cluster->mask & functionMask) == 0)
1375 : {
1376 2199 : return nullptr;
1377 : }
1378 :
1379 0 : while (mask < functionMask)
1380 : {
1381 0 : if ((cluster->mask & mask) != 0)
1382 : {
1383 0 : functionIndex++;
1384 : }
1385 0 : mask = static_cast<EmberAfClusterMask>(mask << 1);
1386 : }
1387 0 : return cluster->functions[functionIndex];
1388 : }
1389 :
1390 : namespace chip {
1391 : namespace app {
1392 :
1393 0 : CHIP_ERROR SetParentEndpointForEndpoint(EndpointId childEndpoint, EndpointId parentEndpoint)
1394 : {
1395 0 : uint16_t childIndex = emberAfIndexFromEndpoint(childEndpoint);
1396 0 : uint16_t parentIndex = emberAfIndexFromEndpoint(parentEndpoint);
1397 :
1398 0 : if (childIndex == kEmberInvalidEndpointIndex || parentIndex == kEmberInvalidEndpointIndex)
1399 : {
1400 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1401 : }
1402 0 : emAfEndpoints[childIndex].parentEndpointId = parentEndpoint;
1403 0 : return CHIP_NO_ERROR;
1404 : }
1405 :
1406 0 : CHIP_ERROR SetFlatCompositionForEndpoint(EndpointId endpoint)
1407 : {
1408 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1409 0 : if (index == kEmberInvalidEndpointIndex)
1410 : {
1411 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1412 : }
1413 0 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isTreeComposition);
1414 0 : emAfEndpoints[index].bitmask.Set(EmberAfEndpointOptions::isFlatComposition);
1415 0 : return CHIP_NO_ERROR;
1416 : }
1417 :
1418 0 : CHIP_ERROR SetTreeCompositionForEndpoint(EndpointId endpoint)
1419 : {
1420 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1421 0 : if (index == kEmberInvalidEndpointIndex)
1422 : {
1423 0 : return CHIP_ERROR_INVALID_ARGUMENT;
1424 : }
1425 0 : emAfEndpoints[index].bitmask.Clear(EmberAfEndpointOptions::isFlatComposition);
1426 0 : emAfEndpoints[index].bitmask.Set(EmberAfEndpointOptions::isTreeComposition);
1427 0 : return CHIP_NO_ERROR;
1428 : }
1429 :
1430 0 : bool IsFlatCompositionForEndpoint(EndpointId endpoint)
1431 : {
1432 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1433 0 : if (index == kEmberInvalidEndpointIndex)
1434 : {
1435 0 : return false;
1436 : }
1437 0 : return emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isFlatComposition);
1438 : }
1439 :
1440 0 : bool IsTreeCompositionForEndpoint(EndpointId endpoint)
1441 : {
1442 0 : uint16_t index = emberAfIndexFromEndpoint(endpoint);
1443 0 : if (index == kEmberInvalidEndpointIndex)
1444 : {
1445 0 : return false;
1446 : }
1447 0 : return emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isTreeComposition);
1448 : }
1449 :
1450 2917 : EndpointComposition GetCompositionForEndpointIndex(uint16_t endpointIndex)
1451 : {
1452 2917 : VerifyOrReturnValue(endpointIndex < MATTER_ARRAY_SIZE(emAfEndpoints), EndpointComposition::kInvalid);
1453 2917 : if (emAfEndpoints[endpointIndex].bitmask.Has(EmberAfEndpointOptions::isFlatComposition))
1454 : {
1455 1438 : return EndpointComposition::kFullFamily;
1456 : }
1457 1479 : if (emAfEndpoints[endpointIndex].bitmask.Has(EmberAfEndpointOptions::isTreeComposition))
1458 : {
1459 1479 : return EndpointComposition::kTree;
1460 : }
1461 0 : return EndpointComposition::kInvalid;
1462 : }
1463 :
1464 : } // namespace app
1465 : } // namespace chip
1466 :
1467 0 : uint16_t emberAfGetServerAttributeCount(EndpointId endpoint, ClusterId cluster)
1468 : {
1469 0 : const EmberAfCluster * clusterObj = emberAfFindServerCluster(endpoint, cluster);
1470 0 : VerifyOrReturnError(clusterObj != nullptr, 0);
1471 0 : return clusterObj->attributeCount;
1472 : }
1473 :
1474 0 : uint16_t emberAfGetServerAttributeIndexByAttributeId(EndpointId endpoint, ClusterId cluster, AttributeId attributeId)
1475 : {
1476 0 : const EmberAfCluster * clusterObj = emberAfFindServerCluster(endpoint, cluster);
1477 0 : VerifyOrReturnError(clusterObj != nullptr, UINT16_MAX);
1478 :
1479 0 : for (uint16_t i = 0; i < clusterObj->attributeCount; i++)
1480 : {
1481 0 : if (clusterObj->attributes[i].attributeId == attributeId)
1482 : {
1483 0 : return i;
1484 : }
1485 : }
1486 0 : return UINT16_MAX;
1487 : }
1488 :
1489 0 : Optional<AttributeId> emberAfGetServerAttributeIdByIndex(EndpointId endpoint, ClusterId cluster, uint16_t attributeIndex)
1490 : {
1491 0 : const EmberAfCluster * clusterObj = emberAfFindServerCluster(endpoint, cluster);
1492 0 : if (clusterObj == nullptr || clusterObj->attributeCount <= attributeIndex)
1493 : {
1494 0 : return Optional<AttributeId>::Missing();
1495 : }
1496 0 : return Optional<AttributeId>(clusterObj->attributes[attributeIndex].attributeId);
1497 : }
1498 :
1499 6789 : DataVersion * emberAfDataVersionStorage(const ConcreteClusterPath & aConcreteClusterPath)
1500 : {
1501 6789 : uint16_t index = emberAfIndexFromEndpoint(aConcreteClusterPath.mEndpointId);
1502 6789 : if (index == kEmberInvalidEndpointIndex)
1503 : {
1504 : // Unknown endpoint.
1505 47 : return nullptr;
1506 : }
1507 6742 : const EmberAfDefinedEndpoint & ep = emAfEndpoints[index];
1508 6742 : if (!ep.dataVersions)
1509 : {
1510 : // No storage provided.
1511 0 : return nullptr;
1512 : }
1513 :
1514 : // This does a second walk over endpoints to find the right one, but
1515 : // probably worth it to avoid duplicating code.
1516 : auto clusterIndex =
1517 6742 : emberAfClusterIndex(aConcreteClusterPath.mEndpointId, aConcreteClusterPath.mClusterId, MATTER_CLUSTER_FLAG_SERVER);
1518 6742 : if (clusterIndex == 0xFF)
1519 : {
1520 : // No such cluster on this endpoint.
1521 0 : return nullptr;
1522 : }
1523 :
1524 6742 : return ep.dataVersions + clusterIndex;
1525 : }
1526 :
1527 : namespace {
1528 : class GlobalInteractionModelEngineChangedpathListener : public AttributesChangedListener
1529 : {
1530 : public:
1531 6 : ~GlobalInteractionModelEngineChangedpathListener() = default;
1532 :
1533 71 : void MarkDirty(const AttributePathParams & path) override
1534 : {
1535 71 : InteractionModelEngine::GetInstance()->GetReportingEngine().SetDirty(path);
1536 71 : }
1537 : };
1538 :
1539 : } // namespace
1540 :
1541 71 : AttributesChangedListener * emberAfGlobalInteractionModelAttributesChangedListener()
1542 : {
1543 71 : static GlobalInteractionModelEngineChangedpathListener listener;
1544 71 : return &listener;
1545 : }
1546 :
1547 2476 : void emberAfAttributeChanged(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId,
1548 : AttributesChangedListener * listener)
1549 : {
1550 : // Increase cluster data path
1551 2476 : DataVersion * version = emberAfDataVersionStorage(ConcreteClusterPath(endpoint, clusterId));
1552 2476 : if (version == nullptr)
1553 : {
1554 47 : ChipLogError(DataManagement, "Endpoint %x, Cluster " ChipLogFormatMEI " not found in IncreaseClusterDataVersion!", endpoint,
1555 : ChipLogValueMEI(clusterId));
1556 : }
1557 : else
1558 : {
1559 2429 : (*(version))++;
1560 2429 : ChipLogDetail(DataManagement, "Endpoint %x, Cluster " ChipLogFormatMEI " update version to %" PRIx32, endpoint,
1561 : ChipLogValueMEI(clusterId), *(version));
1562 : }
1563 :
1564 2476 : listener->MarkDirty(AttributePathParams(endpoint, clusterId, attributeId));
1565 2476 : }
1566 :
1567 24 : void emberAfEndpointChanged(EndpointId endpoint, AttributesChangedListener * listener)
1568 : {
1569 24 : listener->MarkDirty(AttributePathParams(endpoint));
1570 24 : }
|