Line data Source code
1 : /**
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2018 Google LLC.
5 : * Copyright (c) 2016-2017 Nest Labs, Inc.
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include "AttributePathIB.h"
20 : #include "MessageDefHelper.h"
21 :
22 : #include <inttypes.h>
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 :
26 : #include <app/AppConfig.h>
27 : #include <app/data-model/Encode.h>
28 : #include <app/data-model/Nullable.h>
29 :
30 : namespace chip {
31 : namespace app {
32 : #if CHIP_CONFIG_IM_PRETTY_PRINT
33 10537 : CHIP_ERROR AttributePathIB::Parser::PrettyPrint() const
34 : {
35 10537 : CHIP_ERROR err = CHIP_NO_ERROR;
36 : TLV::TLVReader reader;
37 :
38 10537 : PRETTY_PRINT("AttributePathIB =");
39 10537 : PRETTY_PRINT("{");
40 :
41 : // make a copy of the Path reader
42 10537 : reader.Init(mReader);
43 :
44 45173 : while (CHIP_NO_ERROR == (err = reader.Next()))
45 : {
46 34636 : if (!TLV::IsContextTag(reader.GetTag()))
47 : {
48 0 : continue;
49 : }
50 34636 : uint32_t tagNum = TLV::TagNumFromTag(reader.GetTag());
51 34636 : switch (tagNum)
52 : {
53 14 : case to_underlying(Tag::kEnableTagCompression):
54 : #if CHIP_DETAIL_LOGGING
55 : {
56 : bool enableTagCompression;
57 14 : ReturnErrorOnFailure(reader.Get(enableTagCompression));
58 14 : PRETTY_PRINT("\tenableTagCompression = %s, ", enableTagCompression ? "true" : "false");
59 : }
60 : #endif // CHIP_DETAIL_LOGGING
61 14 : break;
62 27 : case to_underlying(Tag::kNode):
63 27 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
64 :
65 : #if CHIP_DETAIL_LOGGING
66 : {
67 : NodeId node;
68 27 : reader.Get(node);
69 27 : PRETTY_PRINT("\tNode = 0x" ChipLogFormatX64 ",", ChipLogValueX64(node));
70 : }
71 : #endif // CHIP_DETAIL_LOGGING
72 27 : break;
73 10120 : case to_underlying(Tag::kEndpoint):
74 10120 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
75 : #if CHIP_DETAIL_LOGGING
76 : {
77 : EndpointId endpoint;
78 10120 : reader.Get(endpoint);
79 10120 : PRETTY_PRINT("\tEndpoint = 0x%x,", endpoint);
80 : }
81 : #endif // CHIP_DETAIL_LOGGING
82 10120 : break;
83 10129 : case to_underlying(Tag::kCluster):
84 10129 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE);
85 :
86 : #if CHIP_DETAIL_LOGGING
87 : {
88 : ClusterId cluster;
89 10129 : ReturnErrorOnFailure(reader.Get(cluster));
90 10129 : PRETTY_PRINT("\tCluster = 0x%" PRIx32 ",", cluster);
91 : }
92 : #endif // CHIP_DETAIL_LOGGING
93 10129 : break;
94 9912 : case to_underlying(Tag::kAttribute):
95 9912 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
96 : #if CHIP_DETAIL_LOGGING
97 : {
98 : AttributeId attribute;
99 9912 : ReturnErrorOnFailure(reader.Get(attribute));
100 9912 : PRETTY_PRINT("\tAttribute = " ChipLogFormatMEI ",", ChipLogValueMEI(attribute));
101 : }
102 : #endif // CHIP_DETAIL_LOGGING
103 9912 : break;
104 4434 : case to_underlying(Tag::kListIndex):
105 4434 : VerifyOrReturnError(TLV::kTLVType_UnsignedInteger == reader.GetType() || TLV::kTLVType_Null == reader.GetType(),
106 : CHIP_ERROR_WRONG_TLV_TYPE);
107 : #if CHIP_DETAIL_LOGGING
108 : // We have checked the element is either uint or null
109 4434 : if (TLV::kTLVType_UnsignedInteger == reader.GetType())
110 : {
111 : uint16_t listIndex;
112 28 : ReturnErrorOnFailure(reader.Get(listIndex));
113 28 : PRETTY_PRINT("\tListIndex = 0x%x,", listIndex);
114 : }
115 : else
116 : {
117 4406 : PRETTY_PRINT("\tListIndex = Null,");
118 : }
119 : #endif // CHIP_DETAIL_LOGGING
120 4434 : break;
121 0 : default:
122 0 : PRETTY_PRINT("Unknown tag num %" PRIu32, tagNum);
123 0 : break;
124 : }
125 : }
126 :
127 10537 : PRETTY_PRINT("}");
128 10537 : PRETTY_PRINT("\t");
129 : // if we have exhausted this container
130 10537 : if (CHIP_END_OF_TLV == err)
131 : {
132 10537 : err = CHIP_NO_ERROR;
133 : }
134 10537 : ReturnErrorOnFailure(err);
135 10537 : return reader.ExitContainer(mOuterContainerType);
136 : }
137 : #endif // CHIP_CONFIG_IM_PRETTY_PRINT
138 :
139 1 : CHIP_ERROR AttributePathIB::Parser::GetEnableTagCompression(bool * const apEnableTagCompression) const
140 : {
141 1 : return GetSimpleValue(to_underlying(Tag::kEnableTagCompression), TLV::kTLVType_Boolean, apEnableTagCompression);
142 : }
143 :
144 1 : CHIP_ERROR AttributePathIB::Parser::GetNode(NodeId * const apNode) const
145 : {
146 1 : return GetUnsignedInteger(to_underlying(Tag::kNode), apNode);
147 : }
148 :
149 10368 : CHIP_ERROR AttributePathIB::Parser::GetEndpoint(EndpointId * const apEndpoint) const
150 : {
151 10368 : return GetUnsignedInteger(to_underlying(Tag::kEndpoint), apEndpoint);
152 : }
153 :
154 10370 : CHIP_ERROR AttributePathIB::Parser::GetCluster(ClusterId * const apCluster) const
155 : {
156 10370 : return GetUnsignedInteger(to_underlying(Tag::kCluster), apCluster);
157 : }
158 :
159 10370 : CHIP_ERROR AttributePathIB::Parser::GetAttribute(AttributeId * const apAttribute) const
160 : {
161 10370 : return GetUnsignedInteger(to_underlying(Tag::kAttribute), apAttribute);
162 : }
163 :
164 1692 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(ListIndex * const apListIndex) const
165 : {
166 1692 : return GetUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
167 : }
168 :
169 8676 : CHIP_ERROR AttributePathIB::Parser::GetListIndex(DataModel::Nullable<ListIndex> * const apListIndex) const
170 : {
171 8676 : return GetNullableUnsignedInteger(to_underlying(Tag::kListIndex), apListIndex);
172 : }
173 :
174 8678 : CHIP_ERROR AttributePathIB::Parser::GetGroupAttributePath(ConcreteDataAttributePath & aAttributePath,
175 : ValidateIdRanges aValidateRanges) const
176 : {
177 8678 : ReturnErrorOnFailure(GetCluster(&aAttributePath.mClusterId));
178 8678 : ReturnErrorOnFailure(GetAttribute(&aAttributePath.mAttributeId));
179 :
180 8676 : if (aValidateRanges == ValidateIdRanges::kYes)
181 : {
182 4969 : VerifyOrReturnError(IsValidClusterId(aAttributePath.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
183 4969 : VerifyOrReturnError(IsValidAttributeId(aAttributePath.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
184 : }
185 :
186 8676 : CHIP_ERROR err = CHIP_NO_ERROR;
187 8676 : DataModel::Nullable<ListIndex> listIndex;
188 8676 : err = GetListIndex(&(listIndex));
189 8676 : if (err == CHIP_NO_ERROR)
190 : {
191 4404 : if (listIndex.IsNull())
192 : {
193 4404 : aAttributePath.mListOp = ConcreteDataAttributePath::ListOperation::AppendItem;
194 : }
195 : else
196 : {
197 : // TODO: Add ListOperation::ReplaceItem support. (Attribute path with valid list index)
198 0 : err = CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB;
199 : }
200 : }
201 4272 : else if (CHIP_END_OF_TLV == err)
202 : {
203 : // We do not have the context for the actual data type here. We always set the list operation to not list and the users
204 : // should interpret it as ReplaceAll when the attribute type is a list.
205 4272 : aAttributePath.mListOp = ConcreteDataAttributePath::ListOperation::NotList;
206 4272 : err = CHIP_NO_ERROR;
207 : }
208 8676 : return err;
209 8676 : }
210 :
211 8678 : CHIP_ERROR AttributePathIB::Parser::GetConcreteAttributePath(ConcreteDataAttributePath & aAttributePath,
212 : ValidateIdRanges aValidateRanges) const
213 : {
214 8678 : ReturnErrorOnFailure(GetGroupAttributePath(aAttributePath, aValidateRanges));
215 :
216 : // And now read our endpoint.
217 8676 : return GetEndpoint(&aAttributePath.mEndpointId);
218 : }
219 :
220 1691 : CHIP_ERROR AttributePathIB::Parser::ParsePath(AttributePathParams & aAttribute) const
221 : {
222 1691 : CHIP_ERROR err = CHIP_NO_ERROR;
223 :
224 1691 : err = GetEndpoint(&(aAttribute.mEndpointId));
225 1691 : if (err == CHIP_NO_ERROR)
226 : {
227 1664 : VerifyOrReturnError(!aAttribute.HasWildcardEndpointId(), CHIP_IM_GLOBAL_STATUS(InvalidAction));
228 : }
229 27 : else if (err == CHIP_END_OF_TLV)
230 : {
231 27 : err = CHIP_NO_ERROR;
232 : }
233 1691 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
234 :
235 1691 : err = GetCluster(&aAttribute.mClusterId);
236 1691 : if (err == CHIP_NO_ERROR)
237 : {
238 1677 : VerifyOrReturnError(IsValidClusterId(aAttribute.mClusterId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
239 : }
240 14 : else if (err == CHIP_END_OF_TLV)
241 : {
242 14 : err = CHIP_NO_ERROR;
243 : }
244 1691 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
245 :
246 1691 : err = GetAttribute(&aAttribute.mAttributeId);
247 1691 : if (err == CHIP_NO_ERROR)
248 : {
249 1460 : VerifyOrReturnError(IsValidAttributeId(aAttribute.mAttributeId), CHIP_IM_GLOBAL_STATUS(InvalidAction));
250 : }
251 231 : else if (err == CHIP_END_OF_TLV)
252 : {
253 231 : err = CHIP_NO_ERROR;
254 : }
255 1691 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
256 :
257 : // A wildcard cluster requires that the attribute path either be
258 : // wildcard or a global attribute.
259 1691 : VerifyOrReturnError(!aAttribute.HasWildcardClusterId() || aAttribute.HasWildcardAttributeId() ||
260 : IsGlobalAttribute(aAttribute.mAttributeId),
261 : CHIP_IM_GLOBAL_STATUS(InvalidAction));
262 :
263 1691 : err = GetListIndex(&aAttribute.mListIndex);
264 1691 : if (err == CHIP_NO_ERROR)
265 : {
266 14 : VerifyOrReturnError(!aAttribute.HasWildcardAttributeId() && !aAttribute.HasWildcardListIndex(),
267 : CHIP_IM_GLOBAL_STATUS(InvalidAction));
268 : }
269 1677 : else if (err == CHIP_END_OF_TLV)
270 : {
271 1677 : err = CHIP_NO_ERROR;
272 : }
273 1691 : VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_IM_GLOBAL_STATUS(InvalidAction));
274 1691 : return CHIP_NO_ERROR;
275 : }
276 :
277 15 : AttributePathIB::Builder & AttributePathIB::Builder::EnableTagCompression(const bool aEnableTagCompression)
278 : {
279 : // skip if error has already been set
280 15 : if (mError == CHIP_NO_ERROR)
281 : {
282 15 : mError = mpWriter->PutBoolean(TLV::ContextTag(Tag::kEnableTagCompression), aEnableTagCompression);
283 : }
284 15 : return *this;
285 : }
286 :
287 40 : AttributePathIB::Builder & AttributePathIB::Builder::Node(const NodeId aNode)
288 : {
289 : // skip if error has already been set
290 40 : if (mError == CHIP_NO_ERROR)
291 : {
292 40 : mError = mpWriter->Put(TLV::ContextTag(Tag::kNode), aNode);
293 : }
294 40 : return *this;
295 : }
296 :
297 11802 : AttributePathIB::Builder & AttributePathIB::Builder::Endpoint(const EndpointId aEndpoint)
298 : {
299 : // skip if error has already been set
300 11802 : if (mError == CHIP_NO_ERROR)
301 : {
302 11784 : mError = mpWriter->Put(TLV::ContextTag(Tag::kEndpoint), aEndpoint);
303 : }
304 11802 : return *this;
305 : }
306 :
307 11811 : AttributePathIB::Builder & AttributePathIB::Builder::Cluster(const ClusterId aCluster)
308 : {
309 : // skip if error has already been set
310 11811 : if (mError == CHIP_NO_ERROR)
311 : {
312 11748 : mError = mpWriter->Put(TLV::ContextTag(Tag::kCluster), aCluster);
313 : }
314 11811 : return *this;
315 : }
316 :
317 11598 : AttributePathIB::Builder & AttributePathIB::Builder::Attribute(const AttributeId aAttribute)
318 : {
319 : // skip if error has already been set
320 11598 : if (mError == CHIP_NO_ERROR)
321 : {
322 11444 : mError = mpWriter->Put(TLV::ContextTag(Tag::kAttribute), aAttribute);
323 : }
324 11598 : return *this;
325 : }
326 :
327 5849 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const DataModel::Nullable<chip::ListIndex> & aListIndex)
328 : {
329 : // skip if error has already been set
330 5849 : if (mError == CHIP_NO_ERROR)
331 : {
332 5694 : mError = DataModel::Encode(*mpWriter, TLV::ContextTag(Tag::kListIndex), aListIndex);
333 : }
334 5849 : return *this;
335 : }
336 :
337 33 : AttributePathIB::Builder & AttributePathIB::Builder::ListIndex(const chip::ListIndex aListIndex)
338 : {
339 : // skip if error has already been set
340 33 : if (mError == CHIP_NO_ERROR)
341 : {
342 33 : mError = mpWriter->Put(TLV::ContextTag(Tag::kListIndex), aListIndex);
343 : }
344 33 : return *this;
345 : }
346 :
347 12225 : CHIP_ERROR AttributePathIB::Builder::EndOfAttributePathIB()
348 : {
349 12225 : EndOfContainer();
350 12225 : return GetError();
351 : }
352 :
353 1854 : CHIP_ERROR AttributePathIB::Builder::Encode(const AttributePathParams & aAttributePathParams)
354 : {
355 1854 : if (!(aAttributePathParams.HasWildcardEndpointId()))
356 : {
357 1431 : Endpoint(aAttributePathParams.mEndpointId);
358 : }
359 :
360 1854 : if (!(aAttributePathParams.HasWildcardClusterId()))
361 : {
362 1440 : Cluster(aAttributePathParams.mClusterId);
363 : }
364 :
365 1854 : if (!(aAttributePathParams.HasWildcardAttributeId()))
366 : {
367 1231 : Attribute(aAttributePathParams.mAttributeId);
368 : }
369 :
370 1854 : if (!(aAttributePathParams.HasWildcardListIndex()))
371 : {
372 14 : ListIndex(aAttributePathParams.mListIndex);
373 : }
374 :
375 1854 : return EndOfAttributePathIB();
376 : }
377 :
378 2494 : CHIP_ERROR AttributePathIB::Builder::Encode(const ConcreteDataAttributePath & aAttributePath)
379 : {
380 2494 : Endpoint(aAttributePath.mEndpointId);
381 2494 : Cluster(aAttributePath.mClusterId);
382 2494 : Attribute(aAttributePath.mAttributeId);
383 :
384 2494 : if (!aAttributePath.IsListOperation() || aAttributePath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll)
385 : {
386 : /* noop */
387 : }
388 2059 : else if (aAttributePath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
389 : {
390 2059 : ListIndex(DataModel::NullNullable);
391 : }
392 : else
393 : {
394 : // TODO: Add ListOperation::ReplaceItem support. (Attribute path with valid list index)
395 0 : return CHIP_ERROR_INVALID_ARGUMENT;
396 : }
397 :
398 2494 : return EndOfAttributePathIB();
399 : }
400 :
401 : } // namespace app
402 : } // namespace chip
|