/* * * Copyright (c) 2021 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // THIS FILE IS GENERATED BY ZAP #include #include #include "app/common/gen/af-structs.h" #include "app/common/gen/callback.h" #include "app/common/gen/ids/Clusters.h" #include "app/common/gen/ids/Commands.h" #include "app/util/util.h" #include // Currently we need some work to keep compatible with ember lib. #include namespace chip { namespace app { // Cluster specific command parsing namespace clusters { namespace ColorControl { void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. CHIP_ERROR TLVError = CHIP_NO_ERROR; CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; uint32_t validArgumentCount = 0; uint32_t expectArgumentCount = 0; uint32_t currentDecodeTagId = 0; bool wasHandled = false; { switch (aCommandId) { case Clusters::ColorControl::Commands::Ids::ColorLoopSet: { expectArgumentCount = 7; uint8_t updateFlags; uint8_t action; uint8_t direction; uint16_t time; uint16_t startHue; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[7]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 7) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(updateFlags); break; case 1: TLVUnpackError = aDataTlv.Get(action); break; case 2: TLVUnpackError = aDataTlv.Get(direction); break; case 3: TLVUnpackError = aDataTlv.Get(time); break; case 4: TLVUnpackError = aDataTlv.Get(startHue); break; case 5: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 6: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 7 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterColorLoopSetCallback(apCommandObj, updateFlags, action, direction, time, startHue, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::EnhancedMoveHue: { expectArgumentCount = 4; uint8_t moveMode; uint16_t rate; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(moveMode); break; case 1: TLVUnpackError = aDataTlv.Get(rate); break; case 2: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterEnhancedMoveHueCallback(apCommandObj, moveMode, rate, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::EnhancedMoveToHue: { expectArgumentCount = 5; uint16_t enhancedHue; uint8_t direction; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(enhancedHue); break; case 1: TLVUnpackError = aDataTlv.Get(direction); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterEnhancedMoveToHueCallback(apCommandObj, enhancedHue, direction, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::EnhancedMoveToHueAndSaturation: { expectArgumentCount = 5; uint16_t enhancedHue; uint8_t saturation; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(enhancedHue); break; case 1: TLVUnpackError = aDataTlv.Get(saturation); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterEnhancedMoveToHueAndSaturationCallback( apCommandObj, enhancedHue, saturation, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::EnhancedStepHue: { expectArgumentCount = 5; uint8_t stepMode; uint16_t stepSize; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepMode); break; case 1: TLVUnpackError = aDataTlv.Get(stepSize); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterEnhancedStepHueCallback(apCommandObj, stepMode, stepSize, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveColor: { expectArgumentCount = 4; int16_t rateX; int16_t rateY; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(rateX); break; case 1: TLVUnpackError = aDataTlv.Get(rateY); break; case 2: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveColorCallback(apCommandObj, rateX, rateY, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveColorTemperature: { expectArgumentCount = 6; uint8_t moveMode; uint16_t rate; uint16_t colorTemperatureMinimum; uint16_t colorTemperatureMaximum; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[6]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 6) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(moveMode); break; case 1: TLVUnpackError = aDataTlv.Get(rate); break; case 2: TLVUnpackError = aDataTlv.Get(colorTemperatureMinimum); break; case 3: TLVUnpackError = aDataTlv.Get(colorTemperatureMaximum); break; case 4: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 5: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 6 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveColorTemperatureCallback( apCommandObj, moveMode, rate, colorTemperatureMinimum, colorTemperatureMaximum, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveHue: { expectArgumentCount = 4; uint8_t moveMode; uint8_t rate; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(moveMode); break; case 1: TLVUnpackError = aDataTlv.Get(rate); break; case 2: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveHueCallback(apCommandObj, moveMode, rate, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveSaturation: { expectArgumentCount = 4; uint8_t moveMode; uint8_t rate; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(moveMode); break; case 1: TLVUnpackError = aDataTlv.Get(rate); break; case 2: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveSaturationCallback(apCommandObj, moveMode, rate, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveToColor: { expectArgumentCount = 5; uint16_t colorX; uint16_t colorY; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(colorX); break; case 1: TLVUnpackError = aDataTlv.Get(colorY); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveToColorCallback(apCommandObj, colorX, colorY, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveToColorTemperature: { expectArgumentCount = 4; uint16_t colorTemperature; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(colorTemperature); break; case 1: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 2: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveToColorTemperatureCallback(apCommandObj, colorTemperature, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveToHue: { expectArgumentCount = 5; uint8_t hue; uint8_t direction; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(hue); break; case 1: TLVUnpackError = aDataTlv.Get(direction); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveToHueCallback(apCommandObj, hue, direction, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveToHueAndSaturation: { expectArgumentCount = 5; uint8_t hue; uint8_t saturation; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(hue); break; case 1: TLVUnpackError = aDataTlv.Get(saturation); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveToHueAndSaturationCallback(apCommandObj, hue, saturation, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::MoveToSaturation: { expectArgumentCount = 4; uint8_t saturation; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(saturation); break; case 1: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 2: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterMoveToSaturationCallback(apCommandObj, saturation, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::StepColor: { expectArgumentCount = 5; int16_t stepX; int16_t stepY; uint16_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepX); break; case 1: TLVUnpackError = aDataTlv.Get(stepY); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterStepColorCallback(apCommandObj, stepX, stepY, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::StepColorTemperature: { expectArgumentCount = 7; uint8_t stepMode; uint16_t stepSize; uint16_t transitionTime; uint16_t colorTemperatureMinimum; uint16_t colorTemperatureMaximum; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[7]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 7) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepMode); break; case 1: TLVUnpackError = aDataTlv.Get(stepSize); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(colorTemperatureMinimum); break; case 4: TLVUnpackError = aDataTlv.Get(colorTemperatureMaximum); break; case 5: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 6: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 7 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterStepColorTemperatureCallback( apCommandObj, stepMode, stepSize, transitionTime, colorTemperatureMinimum, colorTemperatureMaximum, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::StepHue: { expectArgumentCount = 5; uint8_t stepMode; uint8_t stepSize; uint8_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepMode); break; case 1: TLVUnpackError = aDataTlv.Get(stepSize); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterStepHueCallback(apCommandObj, stepMode, stepSize, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::StepSaturation: { expectArgumentCount = 5; uint8_t stepMode; uint8_t stepSize; uint8_t transitionTime; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepMode); break; case 1: TLVUnpackError = aDataTlv.Get(stepSize); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterStepSaturationCallback(apCommandObj, stepMode, stepSize, transitionTime, optionsMask, optionsOverride); } break; } case Clusters::ColorControl::Commands::Ids::StopMoveStep: { expectArgumentCount = 2; uint8_t optionsMask; uint8_t optionsOverride; bool argExists[2]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 2) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(optionsMask); break; case 1: TLVUnpackError = aDataTlv.Get(optionsOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfColorControlClusterStopMoveStepCallback(apCommandObj, optionsMask, optionsOverride); } break; } default: { // Unrecognized command ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::ColorControl::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::ColorControl::Id); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::ColorControl::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogProgress(Zcl, "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); } } } // namespace ColorControl namespace GeneralCommissioning { void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. CHIP_ERROR TLVError = CHIP_NO_ERROR; CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; uint32_t validArgumentCount = 0; uint32_t expectArgumentCount = 0; uint32_t currentDecodeTagId = 0; bool wasHandled = false; { switch (aCommandId) { case Clusters::GeneralCommissioning::Commands::Ids::ArmFailSafe: { expectArgumentCount = 3; uint16_t expiryLengthSeconds; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(expiryLengthSeconds); break; case 1: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfGeneralCommissioningClusterArmFailSafeCallback(apCommandObj, expiryLengthSeconds, breadcrumb, timeoutMs); } break; } case Clusters::GeneralCommissioning::Commands::Ids::CommissioningComplete: { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfGeneralCommissioningClusterCommissioningCompleteCallback(apCommandObj); break; } case Clusters::GeneralCommissioning::Commands::Ids::SetRegulatoryConfig: { expectArgumentCount = 4; uint8_t location; const uint8_t * countryCode; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(location); break; case 1: // TODO(#5542): The cluster handlers should accept a ByteSpan for all string types. TLVUnpackError = aDataTlv.GetDataPtr(countryCode); break; case 2: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 3: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback( apCommandObj, location, const_cast(countryCode), breadcrumb, timeoutMs); } break; } default: { // Unrecognized command ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::GeneralCommissioning::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::GeneralCommissioning::Id); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::GeneralCommissioning::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogProgress(Zcl, "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); } } } // namespace GeneralCommissioning namespace LevelControl { void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. CHIP_ERROR TLVError = CHIP_NO_ERROR; CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; uint32_t validArgumentCount = 0; uint32_t expectArgumentCount = 0; uint32_t currentDecodeTagId = 0; bool wasHandled = false; { switch (aCommandId) { case Clusters::LevelControl::Commands::Ids::Move: { expectArgumentCount = 4; uint8_t moveMode; uint8_t rate; uint8_t optionMask; uint8_t optionOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(moveMode); break; case 1: TLVUnpackError = aDataTlv.Get(rate); break; case 2: TLVUnpackError = aDataTlv.Get(optionMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterMoveCallback(apCommandObj, moveMode, rate, optionMask, optionOverride); } break; } case Clusters::LevelControl::Commands::Ids::MoveToLevel: { expectArgumentCount = 4; uint8_t level; uint16_t transitionTime; uint8_t optionMask; uint8_t optionOverride; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(level); break; case 1: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 2: TLVUnpackError = aDataTlv.Get(optionMask); break; case 3: TLVUnpackError = aDataTlv.Get(optionOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterMoveToLevelCallback(apCommandObj, level, transitionTime, optionMask, optionOverride); } break; } case Clusters::LevelControl::Commands::Ids::MoveToLevelWithOnOff: { expectArgumentCount = 2; uint8_t level; uint16_t transitionTime; bool argExists[2]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 2) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(level); break; case 1: TLVUnpackError = aDataTlv.Get(transitionTime); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterMoveToLevelWithOnOffCallback(apCommandObj, level, transitionTime); } break; } case Clusters::LevelControl::Commands::Ids::MoveWithOnOff: { expectArgumentCount = 2; uint8_t moveMode; uint8_t rate; bool argExists[2]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 2) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(moveMode); break; case 1: TLVUnpackError = aDataTlv.Get(rate); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterMoveWithOnOffCallback(apCommandObj, moveMode, rate); } break; } case Clusters::LevelControl::Commands::Ids::Step: { expectArgumentCount = 5; uint8_t stepMode; uint8_t stepSize; uint16_t transitionTime; uint8_t optionMask; uint8_t optionOverride; bool argExists[5]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 5) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepMode); break; case 1: TLVUnpackError = aDataTlv.Get(stepSize); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; case 3: TLVUnpackError = aDataTlv.Get(optionMask); break; case 4: TLVUnpackError = aDataTlv.Get(optionOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterStepCallback(apCommandObj, stepMode, stepSize, transitionTime, optionMask, optionOverride); } break; } case Clusters::LevelControl::Commands::Ids::StepWithOnOff: { expectArgumentCount = 3; uint8_t stepMode; uint8_t stepSize; uint16_t transitionTime; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(stepMode); break; case 1: TLVUnpackError = aDataTlv.Get(stepSize); break; case 2: TLVUnpackError = aDataTlv.Get(transitionTime); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterStepWithOnOffCallback(apCommandObj, stepMode, stepSize, transitionTime); } break; } case Clusters::LevelControl::Commands::Ids::Stop: { expectArgumentCount = 2; uint8_t optionMask; uint8_t optionOverride; bool argExists[2]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 2) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(optionMask); break; case 1: TLVUnpackError = aDataTlv.Get(optionOverride); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterStopCallback(apCommandObj, optionMask, optionOverride); } break; } case Clusters::LevelControl::Commands::Ids::StopWithOnOff: { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfLevelControlClusterStopWithOnOffCallback(apCommandObj); break; } default: { // Unrecognized command ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::LevelControl::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::LevelControl::Id); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::LevelControl::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogProgress(Zcl, "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); } } } // namespace LevelControl namespace NetworkCommissioning { void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. CHIP_ERROR TLVError = CHIP_NO_ERROR; CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; uint32_t validArgumentCount = 0; uint32_t expectArgumentCount = 0; uint32_t currentDecodeTagId = 0; bool wasHandled = false; { switch (aCommandId) { case Clusters::NetworkCommissioning::Commands::Ids::AddThreadNetwork: { expectArgumentCount = 3; chip::ByteSpan operationalDataset; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); operationalDataset = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterAddThreadNetworkCallback(apCommandObj, operationalDataset, breadcrumb, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::AddWiFiNetwork: { expectArgumentCount = 4; chip::ByteSpan ssid; chip::ByteSpan credentials; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); ssid = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); credentials = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 2: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 3: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterAddWiFiNetworkCallback(apCommandObj, ssid, credentials, breadcrumb, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::DisableNetwork: { expectArgumentCount = 3; chip::ByteSpan networkID; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); networkID = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterDisableNetworkCallback(apCommandObj, networkID, breadcrumb, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::EnableNetwork: { expectArgumentCount = 3; chip::ByteSpan networkID; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); networkID = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterEnableNetworkCallback(apCommandObj, networkID, breadcrumb, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::GetLastNetworkCommissioningResult: { expectArgumentCount = 1; uint32_t timeoutMs; bool argExists[1]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 1) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterGetLastNetworkCommissioningResultCallback(apCommandObj, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::RemoveNetwork: { expectArgumentCount = 3; chip::ByteSpan NetworkID; uint64_t Breadcrumb; uint32_t TimeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); NetworkID = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: TLVUnpackError = aDataTlv.Get(Breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(TimeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterRemoveNetworkCallback(apCommandObj, NetworkID, Breadcrumb, TimeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::ScanNetworks: { expectArgumentCount = 3; chip::ByteSpan ssid; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); ssid = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterScanNetworksCallback(apCommandObj, ssid, breadcrumb, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::UpdateThreadNetwork: { expectArgumentCount = 3; chip::ByteSpan operationalDataset; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); operationalDataset = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 2: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterUpdateThreadNetworkCallback(apCommandObj, operationalDataset, breadcrumb, timeoutMs); } break; } case Clusters::NetworkCommissioning::Commands::Ids::UpdateWiFiNetwork: { expectArgumentCount = 4; chip::ByteSpan ssid; chip::ByteSpan credentials; uint64_t breadcrumb; uint32_t timeoutMs; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); ssid = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); credentials = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 2: TLVUnpackError = aDataTlv.Get(breadcrumb); break; case 3: TLVUnpackError = aDataTlv.Get(timeoutMs); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfNetworkCommissioningClusterUpdateWiFiNetworkCallback(apCommandObj, ssid, credentials, breadcrumb, timeoutMs); } break; } default: { // Unrecognized command ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::NetworkCommissioning::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::NetworkCommissioning::Id); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::NetworkCommissioning::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogProgress(Zcl, "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); } } } // namespace NetworkCommissioning namespace OnOff { void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. CHIP_ERROR TLVError = CHIP_NO_ERROR; CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; uint32_t validArgumentCount = 0; uint32_t expectArgumentCount = 0; uint32_t currentDecodeTagId = 0; bool wasHandled = false; { switch (aCommandId) { case Clusters::OnOff::Commands::Ids::Off: { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOnOffClusterOffCallback(apCommandObj); break; } case Clusters::OnOff::Commands::Ids::On: { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOnOffClusterOnCallback(apCommandObj); break; } case Clusters::OnOff::Commands::Ids::Toggle: { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOnOffClusterToggleCallback(apCommandObj); break; } default: { // Unrecognized command ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::OnOff::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::OnOff::Id); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::OnOff::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogProgress(Zcl, "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); } } } // namespace OnOff namespace OperationalCredentials { void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) { // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. // Any error value TLVUnpackError means we have received an illegal value. // The following variables are used for all commands to save code size. CHIP_ERROR TLVError = CHIP_NO_ERROR; CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; uint32_t validArgumentCount = 0; uint32_t expectArgumentCount = 0; uint32_t currentDecodeTagId = 0; bool wasHandled = false; { switch (aCommandId) { case Clusters::OperationalCredentials::Commands::Ids::AddOpCert: { expectArgumentCount = 4; chip::ByteSpan NOCArray; chip::ByteSpan IPKValue; chip::NodeId CaseAdminNode; uint16_t AdminVendorId; bool argExists[4]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 4) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); NOCArray = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 1: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); IPKValue = chip::ByteSpan(data, aDataTlv.GetLength()); } break; case 2: TLVUnpackError = aDataTlv.Get(CaseAdminNode); break; case 3: TLVUnpackError = aDataTlv.Get(AdminVendorId); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterAddOpCertCallback(apCommandObj, NOCArray, IPKValue, CaseAdminNode, AdminVendorId); } break; } case Clusters::OperationalCredentials::Commands::Ids::AddTrustedRootCertificate: { expectArgumentCount = 1; chip::ByteSpan RootCertificate; bool argExists[1]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 1) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); RootCertificate = chip::ByteSpan(data, aDataTlv.GetLength()); } break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterAddTrustedRootCertificateCallback(apCommandObj, RootCertificate); } break; } case Clusters::OperationalCredentials::Commands::Ids::OpCSRRequest: { expectArgumentCount = 1; chip::ByteSpan CSRNonce; bool argExists[1]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 1) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); CSRNonce = chip::ByteSpan(data, aDataTlv.GetLength()); } break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterOpCSRRequestCallback(apCommandObj, CSRNonce); } break; } case Clusters::OperationalCredentials::Commands::Ids::RemoveAllFabrics: { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterRemoveAllFabricsCallback(apCommandObj); break; } case Clusters::OperationalCredentials::Commands::Ids::RemoveFabric: { expectArgumentCount = 3; chip::FabricId FabricId; chip::NodeId NodeId; uint16_t VendorId; bool argExists[3]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 3) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(FabricId); break; case 1: TLVUnpackError = aDataTlv.Get(NodeId); break; case 2: TLVUnpackError = aDataTlv.Get(VendorId); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterRemoveFabricCallback(apCommandObj, FabricId, NodeId, VendorId); } break; } case Clusters::OperationalCredentials::Commands::Ids::RemoveTrustedRootCertificate: { expectArgumentCount = 1; chip::ByteSpan TrustedRootIdentifier; bool argExists[1]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 1) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: { const uint8_t * data = nullptr; TLVUnpackError = aDataTlv.GetDataPtr(data); TrustedRootIdentifier = chip::ByteSpan(data, aDataTlv.GetLength()); } break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterRemoveTrustedRootCertificateCallback(apCommandObj, TrustedRootIdentifier); } break; } case Clusters::OperationalCredentials::Commands::Ids::SetFabric: { expectArgumentCount = 1; uint16_t VendorId; bool argExists[1]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 1) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: TLVUnpackError = aDataTlv.Get(VendorId); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterSetFabricCallback(apCommandObj, VendorId); } break; } case Clusters::OperationalCredentials::Commands::Ids::UpdateFabricLabel: { expectArgumentCount = 1; const uint8_t * Label; bool argExists[1]; memset(argExists, 0, sizeof argExists); while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) { // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. if (!TLV::IsContextTag(aDataTlv.GetTag())) { continue; } currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); if (currentDecodeTagId < 1) { if (argExists[currentDecodeTagId]) { ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; break; } else { argExists[currentDecodeTagId] = true; validArgumentCount++; } } switch (currentDecodeTagId) { case 0: // TODO(#5542): The cluster handlers should accept a ByteSpan for all string types. TLVUnpackError = aDataTlv.GetDataPtr(Label); break; default: // Unsupported tag, ignore it. ChipLogProgress(Zcl, "Unknown TLV tag during processing."); break; } if (CHIP_NO_ERROR != TLVUnpackError) { break; } } if (CHIP_END_OF_TLV == TLVError) { // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. TLVError = CHIP_NO_ERROR; } if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount) { // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks. wasHandled = emberAfOperationalCredentialsClusterUpdateFabricLabelCallback(apCommandObj, const_cast(Label)); } break; } default: { // Unrecognized command ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::OperationalCredentials::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::OperationalCredentials::Id); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { chip::app::CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::OperationalCredentials::Id, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogProgress(Zcl, "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, validArgumentCount, expectArgumentCount, TLVError, TLVUnpackError, currentDecodeTagId); } } } // namespace OperationalCredentials } // namespace clusters void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId, chip::TLV::TLVReader & aReader, Command * apCommandObj) { ChipLogDetail(Zcl, "Received Cluster Command: Cluster=%" PRIx32 " Command=%" PRIx32 " Endpoint=%" PRIx16, aClusterId, aCommandId, aEndPointId); Compatibility::SetupEmberAfObjects(apCommandObj, aClusterId, aCommandId, aEndPointId); TLV::TLVType dataTlvType; SuccessOrExit(aReader.EnterContainer(dataTlvType)); switch (aClusterId) { case Clusters::ColorControl::Id: clusters::ColorControl::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; case Clusters::GeneralCommissioning::Id: clusters::GeneralCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; case Clusters::LevelControl::Id: clusters::LevelControl::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; case Clusters::NetworkCommissioning::Id: clusters::NetworkCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; case Clusters::OnOff::Id: clusters::OnOff::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; case Clusters::OperationalCredentials::Id: clusters::OperationalCredentials::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; default: // Unrecognized cluster ID, error status will apply. chip::app::CommandPathParams returnStatusParam = { aEndPointId, 0, // GroupId aClusterId, aCommandId, (chip::app::CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogError(Zcl, "Unknown cluster %" PRIx32, aClusterId); break; } exit: Compatibility::ResetEmberAfObjects(); aReader.ExitContainer(dataTlvType); } } // namespace app } // namespace chip