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