/* * * 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 { namespace { void ReportCommandUnsupported(Command * aCommandObj, EndpointId aEndpointId, ClusterId aClusterId, CommandId aCommandId) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId aClusterId, aCommandId, (CommandPathFlags::kEndpointIdValid) }; aCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand); ChipLogError(Zcl, "Unknown command " ChipLogFormatMEI " for cluster " ChipLogFormatMEI, ChipLogValueMEI(aCommandId), ChipLogValueMEI(aClusterId)); } } // anonymous namespace // Cluster specific command parsing namespace clusters { namespace AdministratorCommissioning { void DispatchServerCommand(CommandHandler * 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::AdministratorCommissioning::Commands::Ids::OpenBasicCommissioningWindow: { expectArgumentCount = 1; uint16_t CommissioningTimeout; 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(CommissioningTimeout); 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) { wasHandled = emberAfAdministratorCommissioningClusterOpenBasicCommissioningWindowCallback(aEndpointId, apCommandObj, CommissioningTimeout); } break; } case Clusters::AdministratorCommissioning::Commands::Ids::OpenCommissioningWindow: { expectArgumentCount = 6; uint16_t CommissioningTimeout; chip::ByteSpan PAKEVerifier; uint16_t Discriminator; uint32_t Iterations; chip::ByteSpan Salt; uint16_t PasscodeID; 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(CommissioningTimeout); break; case 1: TLVUnpackError = aDataTlv.Get(PAKEVerifier); break; case 2: TLVUnpackError = aDataTlv.Get(Discriminator); break; case 3: TLVUnpackError = aDataTlv.Get(Iterations); break; case 4: TLVUnpackError = aDataTlv.Get(Salt); break; case 5: TLVUnpackError = aDataTlv.Get(PasscodeID); 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) { wasHandled = emberAfAdministratorCommissioningClusterOpenCommissioningWindowCallback( aEndpointId, apCommandObj, CommissioningTimeout, PAKEVerifier, Discriminator, Iterations, Salt, PasscodeID); } break; } case Clusters::AdministratorCommissioning::Commands::Ids::RevokeCommissioning: { wasHandled = emberAfAdministratorCommissioningClusterRevokeCommissioningCallback(aEndpointId, apCommandObj); break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::AdministratorCommissioning::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::AdministratorCommissioning::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace AdministratorCommissioning namespace ColorControl { void DispatchServerCommand(CommandHandler * 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) { wasHandled = emberAfColorControlClusterColorLoopSetCallback( aEndpointId, 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) { wasHandled = emberAfColorControlClusterEnhancedMoveHueCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterEnhancedMoveToHueCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterEnhancedMoveToHueAndSaturationCallback( aEndpointId, 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) { wasHandled = emberAfColorControlClusterEnhancedStepHueCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveColorCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveColorTemperatureCallback( aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveHueCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveSaturationCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveToColorCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveToColorTemperatureCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveToHueCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveToHueAndSaturationCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterMoveToSaturationCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterStepColorCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterStepColorTemperatureCallback( aEndpointId, 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) { wasHandled = emberAfColorControlClusterStepHueCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterStepSaturationCallback(aEndpointId, 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) { wasHandled = emberAfColorControlClusterStopMoveStepCallback(aEndpointId, apCommandObj, optionsMask, optionsOverride); } break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::ColorControl::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::ColorControl::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace ColorControl namespace GeneralCommissioning { void DispatchServerCommand(CommandHandler * 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) { wasHandled = emberAfGeneralCommissioningClusterArmFailSafeCallback(aEndpointId, apCommandObj, expiryLengthSeconds, breadcrumb, timeoutMs); } break; } case Clusters::GeneralCommissioning::Commands::Ids::CommissioningComplete: { wasHandled = emberAfGeneralCommissioningClusterCommissioningCompleteCallback(aEndpointId, 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) { wasHandled = emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback( aEndpointId, apCommandObj, location, const_cast(countryCode), breadcrumb, timeoutMs); } break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::GeneralCommissioning::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::GeneralCommissioning::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace GeneralCommissioning namespace LevelControl { void DispatchServerCommand(CommandHandler * 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) { wasHandled = emberAfLevelControlClusterMoveCallback(aEndpointId, 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) { wasHandled = emberAfLevelControlClusterMoveToLevelCallback(aEndpointId, 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) { wasHandled = emberAfLevelControlClusterMoveToLevelWithOnOffCallback(aEndpointId, 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) { wasHandled = emberAfLevelControlClusterMoveWithOnOffCallback(aEndpointId, 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) { wasHandled = emberAfLevelControlClusterStepCallback(aEndpointId, 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) { wasHandled = emberAfLevelControlClusterStepWithOnOffCallback(aEndpointId, 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) { wasHandled = emberAfLevelControlClusterStopCallback(aEndpointId, apCommandObj, optionMask, optionOverride); } break; } case Clusters::LevelControl::Commands::Ids::StopWithOnOff: { wasHandled = emberAfLevelControlClusterStopWithOnOffCallback(aEndpointId, apCommandObj); break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::LevelControl::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::LevelControl::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace LevelControl namespace NetworkCommissioning { void DispatchServerCommand(CommandHandler * 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: TLVUnpackError = aDataTlv.Get(operationalDataset); 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) { wasHandled = emberAfNetworkCommissioningClusterAddThreadNetworkCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(ssid); break; case 1: TLVUnpackError = aDataTlv.Get(credentials); 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) { wasHandled = emberAfNetworkCommissioningClusterAddWiFiNetworkCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(networkID); 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) { wasHandled = emberAfNetworkCommissioningClusterDisableNetworkCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(networkID); 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) { wasHandled = emberAfNetworkCommissioningClusterEnableNetworkCallback(aEndpointId, 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) { wasHandled = emberAfNetworkCommissioningClusterGetLastNetworkCommissioningResultCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(NetworkID); 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) { wasHandled = emberAfNetworkCommissioningClusterRemoveNetworkCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(ssid); 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) { wasHandled = emberAfNetworkCommissioningClusterScanNetworksCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(operationalDataset); 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) { wasHandled = emberAfNetworkCommissioningClusterUpdateThreadNetworkCallback( aEndpointId, 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: TLVUnpackError = aDataTlv.Get(ssid); break; case 1: TLVUnpackError = aDataTlv.Get(credentials); 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) { wasHandled = emberAfNetworkCommissioningClusterUpdateWiFiNetworkCallback(aEndpointId, apCommandObj, ssid, credentials, breadcrumb, timeoutMs); } break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::NetworkCommissioning::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::NetworkCommissioning::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace NetworkCommissioning namespace OnOff { void DispatchServerCommand(CommandHandler * 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: { wasHandled = emberAfOnOffClusterOffCallback(aEndpointId, apCommandObj); break; } case Clusters::OnOff::Commands::Ids::On: { wasHandled = emberAfOnOffClusterOnCallback(aEndpointId, apCommandObj); break; } case Clusters::OnOff::Commands::Ids::Toggle: { wasHandled = emberAfOnOffClusterToggleCallback(aEndpointId, apCommandObj); break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::OnOff::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::OnOff::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace OnOff namespace OperationalCredentials { void DispatchServerCommand(CommandHandler * 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::AddNOC: { 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: TLVUnpackError = aDataTlv.Get(NOCArray); break; case 1: TLVUnpackError = aDataTlv.Get(IPKValue); 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) { wasHandled = emberAfOperationalCredentialsClusterAddNOCCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(RootCertificate); 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) { wasHandled = emberAfOperationalCredentialsClusterAddTrustedRootCertificateCallback(aEndpointId, 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: TLVUnpackError = aDataTlv.Get(CSRNonce); 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) { wasHandled = emberAfOperationalCredentialsClusterOpCSRRequestCallback(aEndpointId, apCommandObj, CSRNonce); } break; } case Clusters::OperationalCredentials::Commands::Ids::RemoveFabric: { expectArgumentCount = 1; uint8_t FabricIndex; 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(FabricIndex); 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) { wasHandled = emberAfOperationalCredentialsClusterRemoveFabricCallback(aEndpointId, apCommandObj, FabricIndex); } 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: TLVUnpackError = aDataTlv.Get(TrustedRootIdentifier); 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) { wasHandled = emberAfOperationalCredentialsClusterRemoveTrustedRootCertificateCallback(aEndpointId, apCommandObj, TrustedRootIdentifier); } 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) { wasHandled = emberAfOperationalCredentialsClusterUpdateFabricLabelCallback(aEndpointId, apCommandObj, const_cast(Label)); } break; } case Clusters::OperationalCredentials::Commands::Ids::UpdateNOC: { expectArgumentCount = 1; chip::ByteSpan NOCArray; 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(NOCArray); 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) { wasHandled = emberAfOperationalCredentialsClusterUpdateNOCCallback(aEndpointId, apCommandObj, NOCArray); } break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::OperationalCredentials::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::OperationalCredentials::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace OperationalCredentials namespace WiFiNetworkDiagnostics { void DispatchServerCommand(CommandHandler * 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::WiFiNetworkDiagnostics::Commands::Ids::ResetCounts: { wasHandled = emberAfWiFiNetworkDiagnosticsClusterResetCountsCallback(aEndpointId, apCommandObj); break; } default: { // Unrecognized command ID, error status will apply. ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::WiFiNetworkDiagnostics::Id, aCommandId); return; } } } if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) { CommandPathParams returnStatusParam = { aEndpointId, 0, // GroupId Clusters::WiFiNetworkDiagnostics::Id, aCommandId, (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.Format(), TLVUnpackError.Format(), currentDecodeTagId); // A command with no arguments would never write currentDecodeTagId. If // progress logging is also disabled, it would look unused. Silence that // warning. UNUSED_VAR(currentDecodeTagId); } } } // namespace WiFiNetworkDiagnostics } // namespace clusters void DispatchSingleClusterCommand(ClusterId aClusterId, CommandId aCommandId, EndpointId aEndPointId, TLV::TLVReader & aReader, CommandHandler * apCommandObj) { ChipLogDetail(Zcl, "Received Cluster Command: Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI " Endpoint=%" PRIx16, ChipLogValueMEI(aClusterId), ChipLogValueMEI(aCommandId), aEndPointId); Compatibility::SetupEmberAfObjects(apCommandObj, aClusterId, aCommandId, aEndPointId); TLV::TLVType dataTlvType; SuccessOrExit(aReader.EnterContainer(dataTlvType)); switch (aClusterId) { case Clusters::AdministratorCommissioning::Id: clusters::AdministratorCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; 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; case Clusters::WiFiNetworkDiagnostics::Id: clusters::WiFiNetworkDiagnostics::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); break; default: // Unrecognized cluster ID, error status will apply. CommandPathParams returnStatusParam = { aEndPointId, 0, // GroupId aClusterId, aCommandId, (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); } void DispatchSingleClusterResponseCommand(ClusterId aClusterId, CommandId aCommandId, EndpointId aEndPointId, TLV::TLVReader & aReader, CommandSender * 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) { default: // Unrecognized cluster ID, error status will apply. CommandPathParams returnStatusParam = { aEndPointId, 0, // GroupId aClusterId, aCommandId, (CommandPathFlags::kEndpointIdValid) }; apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); ChipLogError(Zcl, "Unknown cluster " ChipLogFormatMEI, ChipLogValueMEI(aClusterId)); break; } exit: Compatibility::ResetEmberAfObjects(); aReader.ExitContainer(dataTlvType); } } // namespace app } // namespace chip