blob: 4e170ce78db043c8f7f39c93c232a8fc3586e26a [file] [log] [blame]
/*
* Copyright (c) 2024 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 "FabricAdmin.h"
using namespace ::chip;
namespace admin {
namespace {
constexpr uint32_t kCommissionPrepareTimeMs = 500;
} // namespace
FabricAdmin FabricAdmin::sInstance;
FabricAdmin & FabricAdmin::Instance()
{
if (!sInstance.mInitialized)
{
sInstance.Init();
}
return sInstance;
}
CHIP_ERROR FabricAdmin::OpenCommissioningWindow(Controller::CommissioningWindowVerifierParams params, FabricIndex fabricIndex)
{
ScopedNodeId scopedNodeId(params.GetNodeId(), fabricIndex);
uint32_t iterations = params.GetIteration();
uint16_t discriminator = params.GetDiscriminator();
uint16_t commissioningTimeoutSec = static_cast<uint16_t>(params.GetTimeout().count());
// Log request details for debugging purposes
ChipLogProgress(NotSpecified,
"Received OpenCommissioningWindow request: NodeId " ChipLogFormatX64
", Timeout: %u, Iterations: %u, Discriminator: %u",
ChipLogValueX64(scopedNodeId.GetNodeId()), commissioningTimeoutSec, iterations, discriminator);
// Open the device commissioning window with provided salt and verifier data
DeviceManager::Instance().OpenDeviceCommissioningWindow(scopedNodeId, iterations, commissioningTimeoutSec, discriminator,
ByteSpan(params.GetSalt().data(), params.GetSalt().size()),
ByteSpan(params.GetVerifier().data(), params.GetVerifier().size()));
return CHIP_NO_ERROR;
}
CHIP_ERROR
FabricAdmin::CommissionRemoteBridge(Controller::CommissioningWindowPasscodeParams params, VendorId vendorId, uint16_t productId)
{
char saltHex[Crypto::kSpake2p_Max_PBKDF_Salt_Length * 2 + 1];
Encoding::BytesToHex(params.GetSalt().data(), params.GetSalt().size(), saltHex, sizeof(saltHex),
Encoding::HexFlags::kNullTerminate);
ChipLogProgress(NotSpecified, "Received CommissionNode request");
SetupPayload setupPayload = SetupPayload();
setupPayload.setUpPINCode = params.GetSetupPIN();
setupPayload.version = 0;
setupPayload.vendorID = vendorId;
setupPayload.productID = productId;
setupPayload.rendezvousInformation.SetValue(RendezvousInformationFlag::kOnNetwork);
SetupDiscriminator discriminator{};
discriminator.SetLongValue(params.GetDiscriminator());
setupPayload.discriminator = discriminator;
QRCodeSetupPayloadGenerator generator(setupPayload);
std::string code;
CHIP_ERROR err = generator.payloadBase38RepresentationWithAutoTLVBuffer(code);
if (err == CHIP_NO_ERROR)
{
NodeId nodeId = DeviceManager::Instance().GetNextAvailableNodeId();
// After responding with RequestCommissioningApproval to the node where the client initiated the
// RequestCommissioningApproval, you need to wait for it to open a commissioning window on its bridge.
usleep(kCommissionPrepareTimeMs * 1000);
DeviceManager::Instance().PairRemoteDevice(nodeId, code.c_str());
}
else
{
ChipLogError(NotSpecified, "Unable to generate pairing code for setup payload: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR FabricAdmin::KeepActive(ScopedNodeId scopedNodeId, uint32_t stayActiveDurationMs, uint32_t timeoutMs)
{
ChipLogProgress(NotSpecified, "Received KeepActive request: Id[%d, 0x" ChipLogFormatX64 "], %u", scopedNodeId.GetFabricIndex(),
ChipLogValueX64(scopedNodeId.GetNodeId()), stayActiveDurationMs);
KeepActiveWorkData * data = Platform::New<KeepActiveWorkData>(this, scopedNodeId, stayActiveDurationMs, timeoutMs);
VerifyOrReturnError(data != nullptr, CHIP_ERROR_NO_MEMORY);
DeviceLayer::PlatformMgr().ScheduleWork(KeepActiveWork, reinterpret_cast<intptr_t>(data));
return CHIP_NO_ERROR;
}
void FabricAdmin::ScheduleSendingKeepActiveOnCheckIn(ScopedNodeId scopedNodeId, uint32_t stayActiveDurationMs, uint32_t timeoutMs)
{
// Accessing mPendingCheckIn should only be done while holding ChipStackLock
assertChipStackLockedByCurrentThread();
auto timeNow = System::SystemClock().GetMonotonicTimestamp();
System::Clock::Timestamp expiryTimestamp = timeNow + System::Clock::Milliseconds64(timeoutMs);
KeepActiveDataForCheckIn checkInData = { .mStayActiveDurationMs = stayActiveDurationMs,
.mRequestExpiryTimestamp = expiryTimestamp };
auto it = mPendingCheckIn.find(scopedNodeId);
if (it != mPendingCheckIn.end())
{
checkInData.mStayActiveDurationMs = std::max(checkInData.mStayActiveDurationMs, it->second.mStayActiveDurationMs);
checkInData.mRequestExpiryTimestamp = std::max(checkInData.mRequestExpiryTimestamp, it->second.mRequestExpiryTimestamp);
}
mPendingCheckIn[scopedNodeId] = checkInData;
}
} // namespace admin