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