blob: 7cf0dde53f525e60357a7f678af82bc32235cf23 [file] [log] [blame]
/*
* Copyright (c) 2022 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 "DiscoveryCommands.h"
#include <lib/support/SafeInt.h>
#include <platform/CHIPDeviceLayer.h>
CHIP_ERROR
DiscoveryCommands::FindCommissionable(const char * identity,
const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionable::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kNone, (uint64_t) 0);
return mDNSResolver.DiscoverCommissionableNodes(filter);
}
CHIP_ERROR DiscoveryCommands::FindCommissionableByShortDiscriminator(
const char * identity,
const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionableByShortDiscriminator::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
uint64_t shortDiscriminator = static_cast<uint64_t>((value.value >> 8) & 0x0F);
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kShortDiscriminator, shortDiscriminator);
return mDNSResolver.DiscoverCommissionableNodes(filter);
}
CHIP_ERROR DiscoveryCommands::FindCommissionableByLongDiscriminator(
const char * identity,
const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionableByLongDiscriminator::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kLongDiscriminator, value.value);
return mDNSResolver.DiscoverCommissionableNodes(filter);
}
CHIP_ERROR DiscoveryCommands::FindCommissionableByCommissioningMode(
const char * identity,
const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionableByCommissioningMode::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kCommissioningMode);
return mDNSResolver.DiscoverCommissionableNodes(filter);
}
CHIP_ERROR DiscoveryCommands::FindCommissionableByVendorId(
const char * identity, const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionableByVendorId::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kVendorId, value.value);
return mDNSResolver.DiscoverCommissionableNodes(filter);
}
CHIP_ERROR DiscoveryCommands::FindCommissionableByDeviceType(
const char * identity, const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionableByDeviceType::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kDeviceType, value.value);
return mDNSResolver.DiscoverCommissionableNodes(filter);
}
CHIP_ERROR
DiscoveryCommands::FindCommissioner(const char * identity,
const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissioner::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kCommissioner, 1);
return mDNSResolver.DiscoverCommissioners(filter);
}
CHIP_ERROR
DiscoveryCommands::FindCommissionerByVendorId(
const char * identity, const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionerByVendorId::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kVendorId, value.value);
return mDNSResolver.DiscoverCommissioners(filter);
}
CHIP_ERROR DiscoveryCommands::FindCommissionerByDeviceType(
const char * identity, const chip::app::Clusters::DiscoveryCommands::Commands::FindCommissionerByDeviceType::Type & value)
{
ReturnErrorOnFailure(SetupDiscoveryCommands());
chip::Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kDeviceType, value.value);
return mDNSResolver.DiscoverCommissioners(filter);
}
CHIP_ERROR DiscoveryCommands::SetupDiscoveryCommands()
{
ReturnErrorOnFailure(TearDownDiscoveryCommands());
if (!mReady)
{
ReturnErrorOnFailure(mDNSResolver.Init(chip::DeviceLayer::UDPEndPointManager()));
mReady = true;
}
mDNSResolver.SetOperationalDelegate(this);
mDNSResolver.SetCommissioningDelegate(this);
return CHIP_NO_ERROR;
}
CHIP_ERROR DiscoveryCommands::TearDownDiscoveryCommands()
{
mDNSResolver.StopDiscovery();
mDNSResolver.SetOperationalDelegate(nullptr);
mDNSResolver.SetCommissioningDelegate(nullptr);
return CHIP_NO_ERROR;
}
void DiscoveryCommands::OnNodeDiscovered(const chip::Dnssd::DiscoveredNodeData & nodeData)
{
// TODO: If multiple results are found for the same filter, then the test result depends
// on which result comes first. At the moment, the code assume that there is only
// a single match on the network, but if that's not enough, there may be a need
// to implement some sort of list that is built for a given duration before returning
ReturnOnFailure(TearDownDiscoveryCommands());
nodeData.LogDetail();
chip::DiscoveryCommandResponse data;
data.hostName = chip::CharSpan(nodeData.resolutionData.hostName, strlen(nodeData.resolutionData.hostName));
data.instanceName = chip::CharSpan(nodeData.commissionData.instanceName, strlen(nodeData.commissionData.instanceName));
data.longDiscriminator = nodeData.commissionData.longDiscriminator;
data.shortDiscriminator = ((nodeData.commissionData.longDiscriminator >> 8) & 0x0F);
data.vendorId = nodeData.commissionData.vendorId;
data.productId = nodeData.commissionData.productId;
data.commissioningMode = nodeData.commissionData.commissioningMode;
data.deviceType = nodeData.commissionData.deviceType;
data.deviceName = chip::CharSpan(nodeData.commissionData.deviceName, strlen(nodeData.commissionData.deviceName));
data.rotatingId = chip::ByteSpan(nodeData.commissionData.rotatingId, nodeData.commissionData.rotatingIdLen);
data.rotatingIdLen = nodeData.commissionData.rotatingIdLen;
data.pairingHint = nodeData.commissionData.pairingHint;
data.pairingInstruction =
chip::CharSpan(nodeData.commissionData.pairingInstruction, strlen(nodeData.commissionData.pairingInstruction));
data.supportsTcp = nodeData.resolutionData.supportsTcp;
data.port = nodeData.resolutionData.port;
if (!chip::CanCastTo<uint8_t>(nodeData.resolutionData.numIPs))
{
ChipLogError(chipTool, "Too many ips.");
return;
}
data.numIPs = static_cast<uint8_t>(nodeData.resolutionData.numIPs);
if (nodeData.resolutionData.mrpRetryIntervalIdle.HasValue())
{
data.mrpRetryIntervalIdle.SetValue(nodeData.resolutionData.mrpRetryIntervalIdle.Value().count());
}
if (nodeData.resolutionData.mrpRetryIntervalActive.HasValue())
{
data.mrpRetryIntervalActive.SetValue(nodeData.resolutionData.mrpRetryIntervalActive.Value().count());
}
chip::app::StatusIB status;
status.mStatus = chip::Protocols::InteractionModel::Status::Success;
constexpr uint32_t kMaxDataLen = 4096;
uint8_t * buffer = static_cast<uint8_t *>(chip::Platform::MemoryCalloc(sizeof(uint8_t), kMaxDataLen));
if (buffer == nullptr)
{
ChipLogError(chipTool, "Can not dispatch mdns data: %s", chip::ErrorStr(CHIP_ERROR_NO_MEMORY));
return;
}
chip::TLV::TLVWriter writer;
writer.Init(buffer, kMaxDataLen);
CHIP_ERROR err = data.Encode(writer, chip::TLV::AnonymousTag());
if (CHIP_NO_ERROR != err)
{
ChipLogError(chipTool, "Can not encode mdns data: %s", chip::ErrorStr(err));
return;
}
uint32_t dataLen = writer.GetLengthWritten();
writer.Finalize();
chip::TLV::TLVReader reader;
reader.Init(buffer, dataLen);
reader.Next();
OnResponse(status, &reader);
chip::Platform::MemoryFree(buffer);
}