Skip to content

Commit

Permalink
Fix 32957 : Matter TV: commissioner passcode flow does not accept Com…
Browse files Browse the repository at this point in the history
…missionerPasscodeReady flag (project-chip#32958)

* Temp fix for 32875

* Clarify comments

* Fix commissioner passcode flow

* Make test shell commands for commissionerpasscode always trigger passcode dialog

* Make commissioner passcode commissioning work for casting app using shell commands

* Fix CI, address comments, wire CDC callback to CastingServer

* Fix CI

* Fix CI

* Restyled by clang-format (project-chip#32968)

Co-authored-by: Restyled.io <[email protected]>

* Fix CI

---------

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
3 people authored Apr 15, 2024
1 parent 25d4643 commit 03d2fa8
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 41 deletions.
7 changes: 7 additions & 0 deletions examples/platform/linux/CommissionerMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,13 @@ void PairingCommand::OnStatusUpdate(DevicePairingDelegate::Status status)
break;
case DevicePairingDelegate::Status::SecurePairingFailed:
ChipLogError(AppServer, "Secure Pairing Failed");
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController();
if (cdc != nullptr)
{
cdc->CommissioningFailed(CHIP_ERROR_CONNECTION_ABORTED);
}
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
break;
}
}
Expand Down
35 changes: 35 additions & 0 deletions examples/tv-casting-app/linux/CastingShellCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "CastingServer.h"
#include "CastingUtils.h"
#include "app/clusters/bindings/BindingManager.h"
#include <CommissionableInit.h>
#include <inttypes.h>
#include <lib/core/CHIPCore.h>
#include <lib/shell/Commands.h>
Expand All @@ -34,6 +35,13 @@
#include <lib/support/CodeUtils.h>
#include <platform/CHIPDeviceLayer.h>

using namespace chip;
using namespace chip::DeviceLayer;

namespace {
LinuxCommissionableDataProvider gCommissionableDataProvider;
}

namespace chip {
namespace Shell {

Expand Down Expand Up @@ -120,6 +128,17 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv)
int index = (int) strtol(argv[1], &eptr, 10);
return RequestCommissioning(index);
}
if (strcmp(argv[0], "setusecommissionerpasscode") == 0)
{
ChipLogProgress(DeviceLayer, "setusecommissionerpasscode");
if (argc < 2)
{
return PrintAllCommands();
}
char * eptr;
int useCP = (int) strtol(argv[1], &eptr, 10);
CastingServer::GetInstance()->SetCommissionerPasscodeEnabled(useCP == 1);
}
if (strcmp(argv[0], "launch") == 0)
{
ChipLogProgress(DeviceLayer, "launch");
Expand Down Expand Up @@ -179,6 +198,8 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv)

Protocols::UserDirectedCommissioning::IdentificationDeclaration id;
id.SetCommissionerPasscode(true);
id.SetVendorId(1244); // set non-standard vid-pid to prevent dummy content apps from returning a passcode
id.SetProductId(2234);
if (argc > 3)
{
id.SetCommissionerPasscodeReady(strcmp(argv[3], "t") == 0);
Expand All @@ -202,6 +223,20 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv)
return Server::GetInstance().SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress::UDP(commissioner, port),
id);
}
if (strcmp(argv[0], "setcommissionerpasscode") == 0)
{

char * eptr;
uint32_t passcode = (uint32_t) strtol(argv[1], &eptr, 10);
LinuxDeviceOptions::GetInstance().payload.setUpPINCode = passcode;

VerifyOrDie(chip::examples::InitCommissionableDataProvider(gCommissionableDataProvider,
LinuxDeviceOptions::GetInstance()) == CHIP_NO_ERROR);

DeviceLayer::SetCommissionableDataProvider(&gCommissionableDataProvider);

CastingServer::GetInstance()->SetCommissionerPasscodeReady();
}
if (strcmp(argv[0], "testudc") == 0)
{
char * eptr;
Expand Down
17 changes: 17 additions & 0 deletions examples/tv-casting-app/tv-casting-common/include/CastingServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ inline constexpr chip::System::Clock::Seconds16 kCommissioningWindowTimeout = ch
* as a singleton and is to be used across Linux, Android and iOS.
*/
class CastingServer : public AppDelegate
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
,
chip::Protocols::UserDirectedCommissioning::CommissionerDeclarationHandler
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
{
public:
CastingServer(CastingServer & other) = delete;
Expand All @@ -61,6 +65,13 @@ class CastingServer : public AppDelegate
CHIP_ERROR InitBindingHandlers();
void InitAppDelegation();

#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
void SetCommissionerPasscodeEnabled(bool enabled) { mUdcCommissionerPasscodeEnabled = enabled; };
void SetCommissionerPasscodeReady() { mUdcCommissionerPasscodeReady = true; };
void OnCommissionerDeclarationMessage(const chip::Transport::PeerAddress & source,
chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd) override;
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT

CHIP_ERROR DiscoverCommissioners(chip::Controller::DeviceDiscoveryDelegate * deviceDiscoveryDelegate = nullptr);
const chip::Dnssd::DiscoveredNodeData *
GetDiscoveredCommissioner(int index, chip::Optional<TargetVideoPlayerInfo *> & outAssociatedConnectableVideoPlayer);
Expand Down Expand Up @@ -470,6 +481,12 @@ class CastingServer : public AppDelegate
PersistenceManager mPersistenceManager;
bool mInited = false;
bool mUdcInProgress = false;
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
bool mUdcCommissionerPasscodeEnabled = false;
bool mUdcCommissionerPasscodeReady = false;
char mUdcCommissionerPasscodeInstanceName[chip::Dnssd::Commission::kInstanceNameMaxLength + 1] = "";
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT

chip::Dnssd::DiscoveredNodeData mStrNodeDataList[kMaxCachedVideoPlayers];
TargetVideoPlayerInfo mActiveTargetVideoPlayerInfo;
TargetVideoPlayerInfo mCachedTargetVideoPlayerInfo[kMaxCachedVideoPlayers];
Expand Down
35 changes: 35 additions & 0 deletions examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "ConversionUtils.h"

#include "app/clusters/bindings/BindingManager.h"
#include <app/server/Dnssd.h>

using namespace chip;
using namespace chip::Controller;
Expand Down Expand Up @@ -67,6 +68,10 @@ CHIP_ERROR CastingServer::Init(AppParams * AppParams)
// Add callback to send Content casting commands after commissioning completes
ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().AddEventHandler(DeviceEventCallback, 0));

#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
Server::GetInstance().GetUserDirectedCommissioningClient()->SetCommissionerDeclarationHandler(this);
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT

mInited = true;
return CHIP_NO_ERROR;
}
Expand Down Expand Up @@ -189,10 +194,40 @@ void CastingServer::OnCommissioningSessionEstablishmentStarted()
}

#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
void CastingServer::OnCommissionerDeclarationMessage(const chip::Transport::PeerAddress & source,
chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd)
{
ChipLogProgress(AppServer, "CastingServer::OnCommissionerDeclarationMessage");
// TODO: call a mCommissioningCallbacks
}

CHIP_ERROR CastingServer::SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner)
{
// TODO: expose options to the higher layer
Protocols::UserDirectedCommissioning::IdentificationDeclaration id;
if (mUdcCommissionerPasscodeEnabled)
{
id.SetCommissionerPasscode(true);
if (mUdcCommissionerPasscodeReady)
{
id.SetCommissionerPasscodeReady(true);
id.SetInstanceName(mUdcCommissionerPasscodeInstanceName);
mUdcCommissionerPasscodeReady = false;
}
else
{
CHIP_ERROR err = app::DnssdServer::Instance().GetCommissionableInstanceName(
mUdcCommissionerPasscodeInstanceName, sizeof(mUdcCommissionerPasscodeInstanceName));
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to get mdns instance name error: %" CHIP_ERROR_FORMAT, err.Format());
}
else
{
id.SetInstanceName(mUdcCommissionerPasscodeInstanceName);
}
}
}
return Server::GetInstance().SendUserDirectedCommissioningRequest(commissioner, id);
}

Expand Down
129 changes: 90 additions & 39 deletions src/controller/CommissionerDiscoveryController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,53 +61,98 @@ void CommissionerDiscoveryController::ValidateSession()
ResetState();
}

void CommissionerDiscoveryController::OnUserDirectedCommissioningRequest(UDCClientState state)
void CommissionerDiscoveryController::OnCancel(UDCClientState state)
{
ValidateSession();
if (mReady)
{
// if state was ready for a new session,
// then we have lost our discovery controller context and can't perform the commissioning request
ChipLogDetail(Controller, "CommissionerDiscoveryController::OnCancel received when no current instance.");
return;
}

if (!mReady)
if (strncmp(mCurrentInstance, state.GetInstanceName(), sizeof(mCurrentInstance)) != 0)
{
ChipLogDetail(Controller, "CommissionerDiscoveryController not ready. Current instance=%s", mCurrentInstance);
// if the instance doesn't match the one in our discovery controller context,
// then we can't perform the commissioning request
ChipLogDetail(Controller, "CommissionerDiscoveryController::OnCancel received mismatched instance. Current instance=%s",
mCurrentInstance);
return;
}
// first check if this is a cancel
if (state.GetCancelPasscode())

ChipLogDetail(Controller, "------PROMPT USER: %s cancelled commissioning [" ChipLogFormatMEI "," ChipLogFormatMEI ",%s]",
state.GetDeviceName(), ChipLogValueMEI(state.GetVendorId()), ChipLogValueMEI(state.GetProductId()),
state.GetInstanceName());
if (mUserPrompter != nullptr)
{
ChipLogDetail(Controller, "------PROMPT USER: %s cancelled commissioning [" ChipLogFormatMEI "," ChipLogFormatMEI ",%s]",
state.GetDeviceName(), ChipLogValueMEI(state.GetVendorId()), ChipLogValueMEI(state.GetProductId()),
state.GetInstanceName());
if (mUserPrompter != nullptr)
{
mUserPrompter->HidePromptsOnCancel(state.GetVendorId(), state.GetProductId(), state.GetDeviceName());
}
mUserPrompter->HidePromptsOnCancel(state.GetVendorId(), state.GetProductId(), state.GetDeviceName());
}
return;
}

void CommissionerDiscoveryController::OnCommissionerPasscodeReady(UDCClientState state)
{
if (mReady)
{
// if state was ready for a new session,
// then we have lost our discovery controller context and can't perform the commissioning request
ChipLogDetail(Controller,
"CommissionerDiscoveryController::OnCommissionerPasscodeReady received when no current instance.");
return;
}
if (state.GetCommissionerPasscodeReady() && state.GetCdPort() != 0)

if (strncmp(mCurrentInstance, state.GetInstanceName(), sizeof(mCurrentInstance)) != 0)
{
uint32_t passcode = state.GetCachedCommissionerPasscode();
if (!mReady || passcode == 0)
{
ChipLogError(AppServer, "On UDC: commissioner passcode ready but no passcode");
CommissionerDeclaration cd;
cd.SetErrorCode(CommissionerDeclaration::CdError::kUnexpectedCommissionerPasscodeReady);
// if the instance doesn't match the one in our discovery controller context,
// then we can't perform the commissioning request
ChipLogDetail(
Controller,
"CommissionerDiscoveryController::OnCommissionerPasscodeReady received mismatched instance. Current instance=%s",
mCurrentInstance);
return;
}

if (mUdcServer == nullptr)
{
ChipLogError(AppServer, "On UDC: no udc server");
return;
}
mUdcServer->SendCDCMessage(cd, Transport::PeerAddress::UDP(state.GetPeerAddress().GetIPAddress(), state.GetCdPort()));
return;
}
else
{
// can only get here is ok() has already been called
ChipLogDetail(AppServer, "On UDC: commissioner passcode ready with passcode - commissioning");
if (state.GetCdPort() == 0)
{
ChipLogDetail(Controller, "CommissionerDiscoveryController::OnCommissionerPasscodeReady no port");
return;
}

// start commissioning using the cached passcode
CommissionWithPasscode(passcode);
uint32_t passcode = state.GetCachedCommissionerPasscode();
if (passcode == 0)
{
ChipLogError(AppServer, "On UDC: commissioner passcode ready but no passcode");
CommissionerDeclaration cd;
cd.SetErrorCode(CommissionerDeclaration::CdError::kUnexpectedCommissionerPasscodeReady);

if (mUdcServer == nullptr)
{
ChipLogError(AppServer, "On UDC: no udc server");
return;
}
mUdcServer->SendCDCMessage(cd, Transport::PeerAddress::UDP(state.GetPeerAddress().GetIPAddress(), state.GetCdPort()));
return;
}
else
{
// can only get here is ok() has already been called
ChipLogDetail(AppServer, "On UDC: commissioner passcode ready with passcode - commissioning");

// start commissioning using the cached passcode
CommissionWithPasscode(passcode);
return;
}
}

void CommissionerDiscoveryController::OnUserDirectedCommissioningRequest(UDCClientState state)
{
ValidateSession();

if (!mReady)
{
// we must currently have discovery controller context (a UDC prompt under way)
ChipLogDetail(Controller, "CommissionerDiscoveryController not ready. Current instance=%s", mCurrentInstance);
return;
}

mReady = false;
Expand Down Expand Up @@ -398,6 +443,7 @@ void CommissionerDiscoveryController::InternalHandleContentAppPasscodeResponse()
return;
}
client->SetCachedCommissionerPasscode(passcode);
client->SetUDCClientProcessingState(UDCClientProcessingState::kWaitingForCommissionerPasscodeReady);

CommissionerDeclaration cd;
cd.SetCommissionerPasscode(true);
Expand Down Expand Up @@ -482,7 +528,7 @@ void CommissionerDiscoveryController::InternalCommissionWithPasscode()

if (!mPendingConsent)
{
ChipLogError(AppServer, "UX Cancel: no current instance");
ChipLogError(AppServer, "UX CommissionWithPasscode: no current instance");
return;
}
if (mUdcServer == nullptr)
Expand All @@ -493,7 +539,7 @@ void CommissionerDiscoveryController::InternalCommissionWithPasscode()
UDCClientState * client = mUdcServer->GetUDCClients().FindUDCClientState(mCurrentInstance);
if (client == nullptr)
{
ChipLogError(AppServer, "UX Ok: could not find instance=%s", mCurrentInstance);
ChipLogError(AppServer, "UX CommissionWithPasscode: could not find instance=%s", mCurrentInstance);
return;
}
// state needs to be either kPromptingUser or kObtainingOnboardingPayload
Expand Down Expand Up @@ -566,13 +612,18 @@ void CommissionerDiscoveryController::CommissioningFailed(CHIP_ERROR error)
}
if (mUdcServer == nullptr)
{
ChipLogError(AppServer, "UX Cancel: no udc server");
ChipLogError(AppServer, "UX CommissioningFailed: no udc server");
return;
}
UDCClientState * client = mUdcServer->GetUDCClients().FindUDCClientState(mCurrentInstance);
if (client == nullptr || client->GetUDCClientProcessingState() != UDCClientProcessingState::kCommissioningNode)
if (client == nullptr)
{
ChipLogError(AppServer, "UX Cancel: invalid state for cancel");
ChipLogError(AppServer, "UX CommissioningFailed: no client");
return;
}
if (client->GetUDCClientProcessingState() != UDCClientProcessingState::kCommissioningNode)
{
ChipLogError(AppServer, "UX CommissioningFailed: invalid state");
return;
}
client->SetUDCClientProcessingState(UDCClientProcessingState::kCommissioningFailed);
Expand Down
18 changes: 18 additions & 0 deletions src/controller/CommissionerDiscoveryController.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,24 @@ class CommissionerDiscoveryController : public chip::Protocols::UserDirectedComm
*/
void OnUserDirectedCommissioningRequest(UDCClientState state) override;

/**
* UserConfirmationProvider callback.
*
* Notification that a Cancel UDC protocol message was received.
*
* This code will call the registered UserPrompter's HidePromptsOnCancel
*/
void OnCancel(UDCClientState state) override;

/**
* UserConfirmationProvider callback.
*
* Notification that a CommissionerPasscodeReady UDC protocol message was received.
*
* This code will trigger the Commissioner to begin commissioning
*/
void OnCommissionerPasscodeReady(UDCClientState state) override;

/**
* This method should be called after the user has given consent for commissioning of the client
* indicated in the UserPrompter's PromptForCommissionOKPermission callback
Expand Down
1 change: 1 addition & 0 deletions src/protocols/user_directed_commissioning/UDCClientState.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum class UDCClientProcessingState : uint8_t
kPromptingUser,
kUserDeclined,
kObtainingOnboardingPayload,
kWaitingForCommissionerPasscodeReady,
kCommissioningNode,
kCommissioningFailed,
};
Expand Down
Loading

0 comments on commit 03d2fa8

Please sign in to comment.