blob: 0b11f622d850b5a3eee443d72370bbb618cbc9e9 [file] [log] [blame]
/*
*
* Copyright (c) 2021-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.
*/
/**
* @file
* This file implements an object for a Matter User Directed Commissioning unsolicited
* recipient (server).
*
*/
#include "UserDirectedCommissioning.h"
#include <lib/core/CHIPSafeCasts.h>
namespace chip {
namespace Protocols {
namespace UserDirectedCommissioning {
void UserDirectedCommissioningServer::OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msg)
{
ChipLogProgress(AppServer, "UserDirectedCommissioningServer::OnMessageReceived");
PacketHeader packetHeader;
ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
if (packetHeader.IsEncrypted())
{
ChipLogError(AppServer, "UDC encryption flag set - ignoring");
return;
}
PayloadHeader payloadHeader;
ReturnOnFailure(payloadHeader.DecodeAndConsume(msg));
char instanceName[Dnssd::Commission::kInstanceNameMaxLength + 1];
size_t instanceNameLength = std::min<size_t>(msg->DataLength(), Dnssd::Commission::kInstanceNameMaxLength);
msg->Read(Uint8::from_char(instanceName), instanceNameLength);
instanceName[instanceNameLength] = '\0';
ChipLogProgress(AppServer, "UDC instance=%s", instanceName);
UDCClientState * client = mUdcClients.FindUDCClientState(instanceName);
if (client == nullptr)
{
ChipLogProgress(AppServer, "UDC new instance state received");
CHIP_ERROR err;
err = mUdcClients.CreateNewUDCClientState(instanceName, &client);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "UDC error creating new connection state");
return;
}
// Call the registered InstanceNameResolver, if any.
if (mInstanceNameResolver != nullptr)
{
mInstanceNameResolver->FindCommissionableNode(instanceName);
}
else
{
ChipLogError(AppServer, "UserDirectedCommissioningServer::OnMessageReceived no mInstanceNameResolver registered");
}
}
mUdcClients.MarkUDCClientActive(client);
}
void UserDirectedCommissioningServer::SetUDCClientProcessingState(char * instanceName, UDCClientProcessingState state)
{
UDCClientState * client = mUdcClients.FindUDCClientState(instanceName);
if (client == nullptr)
{
// printf("SetUDCClientProcessingState new instance state received\n");
CHIP_ERROR err;
err = mUdcClients.CreateNewUDCClientState(instanceName, &client);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer,
"UserDirectedCommissioningServer::SetUDCClientProcessingState error creating new connection state");
return;
}
}
ChipLogDetail(AppServer, "SetUDCClientProcessingState instance=%s new state=%d", StringOrNullMarker(instanceName), (int) state);
client->SetUDCClientProcessingState(state);
mUdcClients.MarkUDCClientActive(client);
}
void UserDirectedCommissioningServer::OnCommissionableNodeFound(const Dnssd::DiscoveredNodeData & nodeData)
{
if (nodeData.resolutionData.numIPs == 0)
{
ChipLogError(AppServer, "OnCommissionableNodeFound no IP addresses returned for instance name=%s",
nodeData.commissionData.instanceName);
return;
}
if (nodeData.resolutionData.port == 0)
{
ChipLogError(AppServer, "OnCommissionableNodeFound no port returned for instance name=%s",
nodeData.commissionData.instanceName);
return;
}
UDCClientState * client = mUdcClients.FindUDCClientState(nodeData.commissionData.instanceName);
if (client != nullptr && client->GetUDCClientProcessingState() == UDCClientProcessingState::kDiscoveringNode)
{
ChipLogDetail(AppServer, "OnCommissionableNodeFound instance: name=%s old_state=%d new_state=%d", client->GetInstanceName(),
(int) client->GetUDCClientProcessingState(), (int) UDCClientProcessingState::kPromptingUser);
client->SetUDCClientProcessingState(UDCClientProcessingState::kPromptingUser);
#if INET_CONFIG_ENABLE_IPV4
// prefer IPv4 if its an option
bool foundV4 = false;
for (unsigned i = 0; i < nodeData.resolutionData.numIPs; ++i)
{
if (nodeData.resolutionData.ipAddress[i].IsIPv4())
{
foundV4 = true;
client->SetPeerAddress(
chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[i], nodeData.resolutionData.port));
break;
}
}
// use IPv6 as last resort
if (!foundV4)
{
client->SetPeerAddress(
chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[0], nodeData.resolutionData.port));
}
#else // INET_CONFIG_ENABLE_IPV4
// if we only support V6, then try to find a v6 address
bool foundV6 = false;
for (unsigned i = 0; i < nodeData.resolutionData.numIPs; ++i)
{
if (nodeData.resolutionData.ipAddress[i].IsIPv6())
{
foundV6 = true;
client->SetPeerAddress(
chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[i], nodeData.resolutionData.port));
break;
}
}
// last resort, try with what we have
if (!foundV6)
{
ChipLogError(AppServer, "OnCommissionableNodeFound no v6 returned for instance name=%s",
nodeData.commissionData.instanceName);
client->SetPeerAddress(
chip::Transport::PeerAddress::UDP(nodeData.resolutionData.ipAddress[0], nodeData.resolutionData.port));
}
#endif // INET_CONFIG_ENABLE_IPV4
client->SetDeviceName(nodeData.commissionData.deviceName);
client->SetLongDiscriminator(nodeData.commissionData.longDiscriminator);
client->SetVendorId(nodeData.commissionData.vendorId);
client->SetProductId(nodeData.commissionData.productId);
client->SetRotatingId(nodeData.commissionData.rotatingId, nodeData.commissionData.rotatingIdLen);
// Call the registered mUserConfirmationProvider, if any.
if (mUserConfirmationProvider != nullptr)
{
mUserConfirmationProvider->OnUserDirectedCommissioningRequest(*client);
}
}
}
void UserDirectedCommissioningServer::PrintUDCClients()
{
for (uint8_t i = 0; i < kMaxUDCClients; i++)
{
UDCClientState * state = GetUDCClients().GetUDCClientState(i);
if (state == nullptr)
{
ChipLogProgress(AppServer, "UDC Client[%d] null", i);
}
else
{
char addrBuffer[chip::Transport::PeerAddress::kMaxToStringSize];
state->GetPeerAddress().ToString(addrBuffer);
char rotatingIdString[chip::Dnssd::kMaxRotatingIdLen * 2 + 1] = "";
Encoding::BytesToUppercaseHexString(state->GetRotatingId(), chip::Dnssd::kMaxRotatingIdLen, rotatingIdString,
sizeof(rotatingIdString));
ChipLogProgress(AppServer, "UDC Client[%d] instance=%s deviceName=%s address=%s, vid/pid=%d/%d disc=%d rid=%s", i,
state->GetInstanceName(), state->GetDeviceName(), addrBuffer, state->GetVendorId(),
state->GetProductId(), state->GetLongDiscriminator(), rotatingIdString);
}
}
}
} // namespace UserDirectedCommissioning
} // namespace Protocols
} // namespace chip