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