|  | /* | 
|  | * | 
|  | *    Copyright (c) 2021 Project CHIP Authors | 
|  | *    All rights reserved. | 
|  | * | 
|  | *    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. | 
|  | */ | 
|  |  | 
|  | #include <controller/CurrentFabricRemover.h> | 
|  |  | 
|  | #include <app-common/zap-generated/cluster-objects.h> | 
|  |  | 
|  | using namespace chip::app::Clusters; | 
|  |  | 
|  | namespace chip { | 
|  | namespace Controller { | 
|  |  | 
|  | CHIP_ERROR CurrentFabricRemover::RemoveCurrentFabric(NodeId remoteNodeId, Callback::Callback<OnCurrentFabricRemove> * callback) | 
|  | { | 
|  | mRemoteNodeId                = remoteNodeId; | 
|  | mCurrentFabricRemoveCallback = callback; | 
|  | mNextStep                    = Step::kReadCurrentFabricIndex; | 
|  |  | 
|  | return mController->GetConnectedDevice(remoteNodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR CurrentFabricRemover::ReadCurrentFabricIndex(Messaging::ExchangeManager & exchangeMgr, | 
|  | const SessionHandle & sessionHandle) | 
|  | { | 
|  | using TypeInfo = OperationalCredentials::Attributes::CurrentFabricIndex::TypeInfo; | 
|  | ClusterBase cluster(exchangeMgr, sessionHandle, kRootEndpointId); | 
|  |  | 
|  | return cluster.ReadAttribute<TypeInfo>(this, OnSuccessReadCurrentFabricIndex, OnReadAttributeFailure); | 
|  | } | 
|  |  | 
|  | CHIP_ERROR CurrentFabricRemover::SendRemoveFabricIndex(Messaging::ExchangeManager & exchangeMgr, | 
|  | const SessionHandle & sessionHandle) | 
|  | { | 
|  | if (mFabricIndex == kUndefinedFabricIndex) | 
|  | { | 
|  | return CHIP_ERROR_INVALID_FABRIC_INDEX; | 
|  | } | 
|  |  | 
|  | OperationalCredentials::Commands::RemoveFabric::Type request; | 
|  | request.fabricIndex = mFabricIndex; | 
|  |  | 
|  | ClusterBase cluster(exchangeMgr, sessionHandle, 0); | 
|  |  | 
|  | return cluster.InvokeCommand(request, this, OnSuccessRemoveFabric, OnCommandFailure); | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr, | 
|  | const SessionHandle & sessionHandle) | 
|  | { | 
|  | CHIP_ERROR err = CHIP_NO_ERROR; | 
|  | auto * self    = static_cast<CurrentFabricRemover *>(context); | 
|  | VerifyOrReturn(self != nullptr, ChipLogProgress(Controller, "Device connected callback with null context. Ignoring")); | 
|  |  | 
|  | switch (self->mNextStep) | 
|  | { | 
|  | case Step::kReadCurrentFabricIndex: { | 
|  | err = self->ReadCurrentFabricIndex(exchangeMgr, sessionHandle); | 
|  | break; | 
|  | } | 
|  | case Step::kSendRemoveFabric: { | 
|  | err = self->SendRemoveFabricIndex(exchangeMgr, sessionHandle); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | err = CHIP_ERROR_INCORRECT_STATE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | ChipLogError(Controller, "Current Fabric Remover failure : %" CHIP_ERROR_FORMAT, err.Format()); | 
|  | FinishRemoveCurrentFabric(context, err); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR err) | 
|  | { | 
|  | ChipLogProgress(Controller, "OnDeviceConnectionFailureFn: %" CHIP_ERROR_FORMAT, err.Format()); | 
|  |  | 
|  | auto * self = static_cast<CurrentFabricRemover *>(context); | 
|  | VerifyOrReturn(self != nullptr, ChipLogProgress(Controller, "Device connected failure callback with null context. Ignoring")); | 
|  |  | 
|  | FinishRemoveCurrentFabric(context, err); | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::OnSuccessReadCurrentFabricIndex(void * context, FabricIndex fabricIndex) | 
|  | { | 
|  | auto * self = static_cast<CurrentFabricRemover *>(context); | 
|  | VerifyOrReturn(self != nullptr, | 
|  | ChipLogProgress(Controller, "Success Read Current Fabric index callback with null context. Ignoring")); | 
|  | self->mFabricIndex = fabricIndex; | 
|  | self->mNextStep    = Step::kSendRemoveFabric; | 
|  | CHIP_ERROR err     = self->mController->GetConnectedDevice(self->mRemoteNodeId, &self->mOnDeviceConnectedCallback, | 
|  | &self->mOnDeviceConnectionFailureCallback); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | FinishRemoveCurrentFabric(context, err); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::OnReadAttributeFailure(void * context, CHIP_ERROR err) | 
|  | { | 
|  | ChipLogProgress(Controller, "OnReadAttributeFailure %" CHIP_ERROR_FORMAT, err.Format()); | 
|  |  | 
|  | auto * self = static_cast<CurrentFabricRemover *>(context); | 
|  | VerifyOrReturn(self != nullptr, ChipLogProgress(Controller, "Read Attribute failure callback with null context. Ignoring")); | 
|  |  | 
|  | FinishRemoveCurrentFabric(context, err); | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::OnSuccessRemoveFabric(void * context, | 
|  | const OperationalCredentials::Commands::NOCResponse::DecodableType & data) | 
|  | { | 
|  | auto * self = static_cast<CurrentFabricRemover *>(context); | 
|  | VerifyOrReturn(self != nullptr, | 
|  | ChipLogProgress(Controller, "Success Remove Fabric command callback with null context. Ignoring")); | 
|  |  | 
|  | FinishRemoveCurrentFabric(context, CHIP_NO_ERROR); | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::OnCommandFailure(void * context, CHIP_ERROR err) | 
|  | { | 
|  | ChipLogProgress(Controller, "OnCommandFailure %" CHIP_ERROR_FORMAT, err.Format()); | 
|  |  | 
|  | auto * self = static_cast<CurrentFabricRemover *>(context); | 
|  | VerifyOrReturn(self != nullptr, ChipLogProgress(Controller, "Send command failure callback with null context. Ignoring")); | 
|  |  | 
|  | FinishRemoveCurrentFabric(context, err); | 
|  | } | 
|  |  | 
|  | void CurrentFabricRemover::FinishRemoveCurrentFabric(void * context, CHIP_ERROR err) | 
|  | { | 
|  | ChipLogError(Controller, "Remove Current Fabric Result : %" CHIP_ERROR_FORMAT, err.Format()); | 
|  | auto * self     = static_cast<CurrentFabricRemover *>(context); | 
|  | self->mNextStep = Step::kAcceptRemoveFabricStart; | 
|  | if (self->mCurrentFabricRemoveCallback != nullptr) | 
|  | { | 
|  | self->mCurrentFabricRemoveCallback->mCall(self->mCurrentFabricRemoveCallback->mContext, self->mRemoteNodeId, err); | 
|  | } | 
|  | } | 
|  |  | 
|  | AutoCurrentFabricRemover::AutoCurrentFabricRemover(DeviceController * controller) : | 
|  | CurrentFabricRemover(controller), mOnRemoveCurrentFabricCallback(OnRemoveCurrentFabric, this) | 
|  | {} | 
|  |  | 
|  | CHIP_ERROR AutoCurrentFabricRemover::RemoveCurrentFabric(DeviceController * controller, NodeId remoteNodeId) | 
|  | { | 
|  | // Not using Platform::New because we want to keep our constructor private. | 
|  | auto * remover = new (std::nothrow) AutoCurrentFabricRemover(controller); | 
|  | if (remover == nullptr) | 
|  | { | 
|  | return CHIP_ERROR_NO_MEMORY; | 
|  | } | 
|  |  | 
|  | CHIP_ERROR err = remover->CurrentFabricRemover::RemoveCurrentFabric(remoteNodeId, &remover->mOnRemoveCurrentFabricCallback); | 
|  | if (err != CHIP_NO_ERROR) | 
|  | { | 
|  | delete remover; | 
|  | } | 
|  | // Else will clean up when the callback is called. | 
|  | return err; | 
|  | } | 
|  |  | 
|  | void AutoCurrentFabricRemover::OnRemoveCurrentFabric(void * context, NodeId remoteNodeId, CHIP_ERROR status) | 
|  | { | 
|  | auto * self = static_cast<AutoCurrentFabricRemover *>(context); | 
|  | delete self; | 
|  | } | 
|  | } // namespace Controller | 
|  | } // namespace chip |