blob: 6469b3768cb05e6cc247d84251f9478a8ae22615 [file] [log] [blame]
/*
*
* Copyright (c) 2025 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 "JFAManager.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/ConcreteAttributePath.h>
#include <controller/CHIPCluster.h>
#include <lib/support/logging/CHIPLogging.h>
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::Controller;
JFAManager JFAManager::sJFA;
CHIP_ERROR JFAManager::Init(Server & server)
{
mServer = &server;
mCASESessionManager = server.GetCASESessionManager();
return CHIP_NO_ERROR;
}
CHIP_ERROR JFAManager::FinalizeCommissioning(NodeId nodeId)
{
if (jfFabricIndex == kUndefinedFabricId)
{
return CHIP_ERROR_INCORRECT_STATE;
}
ScopedNodeId scopedNodeId = ScopedNodeId(nodeId, jfFabricIndex);
ConnectToNode(scopedNodeId, kStandardCommissioningComplete);
return CHIP_NO_ERROR;
}
void JFAManager::HandleCommissioningCompleteEvent()
{
for (const auto & fb : mServer->GetFabricTable())
{
FabricIndex fabricIndex = fb.GetFabricIndex();
CATValues cats;
if ((jfFabricIndex == kUndefinedFabricIndex) && mServer->GetFabricTable().FetchCATs(fabricIndex, cats) == CHIP_NO_ERROR)
{
/* When JFA is commissioned, it has to be issued a NOC with Anchor CAT and Administrator CAT */
if (cats.ContainsIdentifier(kAdminCATIdentifier) && cats.ContainsIdentifier(kAnchorCATIdentifier))
{
(void) app::Clusters::JointFabricAdministrator::Attributes::AdministratorFabricIndex::Set(1, fabricIndex);
jfFabricIndex = fabricIndex;
}
}
}
}
void JFAManager::ReleaseSession()
{
auto optionalSessionHandle = mSessionHolder.Get();
if (optionalSessionHandle.HasValue())
{
if (optionalSessionHandle.Value()->IsActiveSession())
{
optionalSessionHandle.Value()->AsSecureSession()->MarkAsDefunct();
}
}
mSessionHolder.Release();
}
void JFAManager::ConnectToNode(ScopedNodeId scopedNodeId, OnConnectedAction onConnectedAction)
{
VerifyOrDie(mServer != nullptr);
if ((scopedNodeId.GetFabricIndex() == kUndefinedFabricIndex) || (scopedNodeId.GetNodeId() == kUndefinedNodeId))
{
ChipLogError(JointFabric, "Invalid node location!");
return;
}
// Set the action to take once connection is successfully established
mOnConnectedAction = onConnectedAction;
ChipLogDetail(JointFabric, "Establishing session to node ID 0x" ChipLogFormatX64 " on fabric index %d",
ChipLogValueX64(scopedNodeId.GetNodeId()), scopedNodeId.GetFabricIndex());
mCASESessionManager->FindOrEstablishSession(scopedNodeId, &mOnConnectedCallback, &mOnConnectionFailureCallback);
}
void JFAManager::OnConnected(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
{
JFAManager * jfaManager = static_cast<JFAManager *>(context);
VerifyOrDie(jfaManager != nullptr);
jfaManager->mSessionHolder.Grab(sessionHandle);
jfaManager->mExchangeMgr = &exchangeMgr;
ChipLogProgress(JointFabric, "Established CASE");
switch (jfaManager->mOnConnectedAction)
{
case kStandardCommissioningComplete: {
jfaManager->SendCommissioningComplete();
break;
}
default:
break;
}
}
void JFAManager::OnConnectionFailure(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
{
JFAManager * jfaManager = static_cast<JFAManager *>(context);
VerifyOrDie(jfaManager != nullptr);
ChipLogError(JointFabric, "Failed to establish connection to 0x" ChipLogFormatX64 " on fabric index %d",
ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex());
jfaManager->ReleaseSession();
}
CHIP_ERROR JFAManager::SendCommissioningComplete()
{
GeneralCommissioning::Commands::CommissioningComplete::Type request;
if (!mExchangeMgr)
{
return CHIP_ERROR_UNINITIALIZED;
}
ChipLogProgress(JointFabric, "SendCommissioningComplete: invoke cluster command.");
Controller::ClusterBase cluster(*mExchangeMgr, mSessionHolder.Get().Value(), kRootEndpointId);
return cluster.InvokeCommand(request, this, OnCommissioningCompleteResponse, OnCommissioningCompleteFailure);
}
void JFAManager::OnCommissioningCompleteResponse(
void * context, const GeneralCommissioning::Commands::CommissioningCompleteResponse::DecodableType & data)
{
JFAManager * jfaManagerCore = static_cast<JFAManager *>(context);
VerifyOrDie(jfaManagerCore != nullptr);
jfaManagerCore->ReleaseSession();
ChipLogProgress(JointFabric, "OnCommissioningCompleteResponse, Code=%u", to_underlying(data.errorCode));
if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
{
// TODO
}
else
{
// TODO
}
jfaManagerCore->ReleaseSession();
}
void JFAManager::OnCommissioningCompleteFailure(void * context, CHIP_ERROR error)
{
JFAManager * jfaManagerCore = static_cast<JFAManager *>(context);
VerifyOrDie(jfaManagerCore != nullptr);
jfaManagerCore->ReleaseSession();
ChipLogError(JointFabric, "Received failure response %s\n", chip::ErrorStr(error));
}