Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable pairing of multiple admins with a device #4738

Merged
merged 8 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions examples/all-clusters-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ class SetupListModel : public ListScreen::Model
if (i == 0)
{
ConnectivityMgr().ClearWiFiStationProvision();
OpenDefaultPairingWindow();
OpenDefaultPairingWindow(ResetAdmins::kYes);
}
}

Expand Down Expand Up @@ -435,12 +435,20 @@ std::string createSetupPayload()
return result;
};

WiFiWidget pairingWindowLED;

class AppCallbacks : public AppDelegate
{
public:
void OnReceiveError() override { statusLED1.BlinkOnError(); }
void OnRendezvousStarted() override { bluetoothLED.Set(true); }
void OnRendezvousStopped() override { bluetoothLED.Set(false); }
void OnRendezvousStopped() override
{
bluetoothLED.Set(false);
pairingWindowLED.Set(false);
}
void OnPairingWindowOpened() override { pairingWindowLED.Set(true); }
void OnPairingWindowClosed() override { pairingWindowLED.Set(false); }
};

} // namespace
Expand Down Expand Up @@ -493,6 +501,7 @@ extern "C" void app_main()
statusLED2.Init(GPIO_NUM_MAX);
bluetoothLED.Init();
wifiLED.Init();
pairingWindowLED.Init();

// Init ZCL Data Model and CHIP App Server
AppCallbacks callbacks;
Expand Down Expand Up @@ -585,6 +594,7 @@ extern "C" void app_main()

bluetoothLED.SetVLED(ScreenManager::AddVLED(TFT_BLUE));
wifiLED.SetVLED(ScreenManager::AddVLED(TFT_YELLOW));
pairingWindowLED.SetVLED(ScreenManager::AddVLED(TFT_ORANGE));
}

#endif // CONFIG_HAVE_DISPLAY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <string>

using namespace ::chip;
using namespace ::chip::SetupPayload;
using namespace ::chip::SetupPayloadData;

CHIP_ERROR AdditionalDataParseCommand::Run(PersistentStorage & storage, NodeId localId, NodeId remoteId)
{
Expand Down
8 changes: 5 additions & 3 deletions src/app/server/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class AppDelegate
{
public:
virtual ~AppDelegate() {}
virtual void OnReceiveError(){};
virtual void OnRendezvousStarted(){};
virtual void OnRendezvousStopped(){};
virtual void OnReceiveError() {}
virtual void OnRendezvousStarted() {}
virtual void OnRendezvousStopped() {}
virtual void OnPairingWindowOpened() {}
virtual void OnPairingWindowClosed() {}
};
158 changes: 145 additions & 13 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <support/logging/CHIPLogging.h>
#include <sys/param.h>
#include <system/SystemPacketBuffer.h>
#include <system/TLVPacketBufferBackingStore.h>
#include <transport/AdminPairingTable.h>
#include <transport/SecureSessionMgr.h>

Expand All @@ -62,11 +63,73 @@ bool isRendezvousBypassed()
return rendezvousMode == RendezvousInformationFlags::kNone;
}

// TODO: The following class is setting the discriminator in Persistent Storage. This is
// is needed since BLE reads the discriminator using ConfigurationMgr APIs. The
// better solution will be to pass the discriminator to BLE without changing it
// in the persistent storage.
// https://github.com/project-chip/connectedhomeip/issues/4767
class DeviceDiscriminatorCache
{
public:
CHIP_ERROR UpdateDiscriminator(uint16_t discriminator)
{
if (!mOriginalDiscriminatorCached)
{
// Cache the original discriminator
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSetupDiscriminator(mOriginalDiscriminator));
mOriginalDiscriminatorCached = true;
}

return DeviceLayer::ConfigurationMgr().StoreSetupDiscriminator(discriminator);
pan-apple marked this conversation as resolved.
Show resolved Hide resolved
}

CHIP_ERROR RestoreDiscriminator()
{
if (mOriginalDiscriminatorCached)
{
// Restore the original discriminator
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().StoreSetupDiscriminator(mOriginalDiscriminator));
mOriginalDiscriminatorCached = false;
}

return CHIP_NO_ERROR;
}

private:
bool mOriginalDiscriminatorCached = false;
uint16_t mOriginalDiscriminator = 0;
};

DeviceDiscriminatorCache gDeviceDiscriminatorCache;

class ServerRendezvousAdvertisementDelegate : public RendezvousAdvertisementDelegate
{
public:
CHIP_ERROR StartAdvertisement() const override { return chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(true); }
CHIP_ERROR StopAdvertisement() const override { return chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false); }
CHIP_ERROR StartAdvertisement() const override
{
ReturnErrorOnFailure(chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(true));
if (mDelegate != nullptr)
{
mDelegate->OnPairingWindowOpened();
}
return CHIP_NO_ERROR;
}
CHIP_ERROR StopAdvertisement() const override
{
gDeviceDiscriminatorCache.RestoreDiscriminator();

ReturnErrorOnFailure(chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false));
if (mDelegate != nullptr)
{
mDelegate->OnPairingWindowClosed();
}
return CHIP_NO_ERROR;
}

void SetDelegate(AppDelegate * delegate) { mDelegate = delegate; }

private:
AppDelegate * mDelegate = nullptr;
};

DemoTransportMgr gTransports;
Expand All @@ -77,20 +140,19 @@ AdminId gNextAvailableAdminId = 0;

ServerRendezvousAdvertisementDelegate gAdvDelegate;

static CHIP_ERROR OpenPairingWindow(uint32_t pinCode, uint16_t discriminator)
static CHIP_ERROR OpenPairingWindowUsingVerifier(uint16_t discriminator, PASEVerifier & verifier)
{
RendezvousParameters params;

ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().StoreSetupDiscriminator(discriminator));
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().StoreSetupPinCode(pinCode));
ReturnErrorOnFailure(gDeviceDiscriminatorCache.UpdateDiscriminator(discriminator));

#if CONFIG_NETWORK_LAYER_BLE
params.SetSetupPINCode(pinCode)
params.SetPASEVerifier(verifier)
.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer())
.SetPeerAddress(Transport::PeerAddress::BLE())
.SetAdvertisementDelegate(&gAdvDelegate);
#else
params.SetSetupPINCode(pinCode);
params.SetPASEVerifier(verifier);
#endif // CONFIG_NETWORK_LAYER_BLE

AdminId admin = gNextAvailableAdminId;
Expand Down Expand Up @@ -121,7 +183,53 @@ class ServerCallback : public SecureSessionMgrDelegate

ChipLogProgress(AppServer, "Packet received from %s: %zu bytes", src_addr, static_cast<size_t>(data_len));

HandleDataModelMessage(header.GetSourceNodeId().Value(), std::move(buffer));
// TODO: This code is temporary, and must be updated to use the Cluster API.
// Issue: https://github.com/project-chip/connectedhomeip/issues/4725
if (payloadHeader.GetProtocolID() == chip::Protocols::kProtocol_ServiceProvisioning)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint32_t timeout;
uint16_t discriminator;
PASEVerifier verifier;

ChipLogProgress(AppServer, "Received service provisioning message. Treating it as OpenPairingWindow request");
chip::System::PacketBufferTLVReader reader;
reader.Init(std::move(buffer));
reader.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning;

SuccessOrExit(reader.Next(kTLVType_UnsignedInteger, TLV::ProfileTag(reader.ImplicitProfileId, 1)));
SuccessOrExit(reader.Get(timeout));

err = reader.Next(kTLVType_UnsignedInteger, TLV::ProfileTag(reader.ImplicitProfileId, 2));
if (err == CHIP_NO_ERROR)
{
SuccessOrExit(reader.Get(discriminator));

err = reader.Next(kTLVType_ByteString, TLV::ProfileTag(reader.ImplicitProfileId, 3));
if (err == CHIP_NO_ERROR)
{
SuccessOrExit(reader.GetBytes(reinterpret_cast<uint8_t *>(verifier), sizeof(verifier)));
}
}

ChipLogProgress(AppServer, "Pairing Window timeout %d seconds", timeout);

if (err != CHIP_NO_ERROR)
{
SuccessOrExit(err = OpenDefaultPairingWindow(ResetAdmins::kNo));
}
else
{
ChipLogProgress(AppServer, "Pairing Window discriminator %d", discriminator);
err = OpenPairingWindowUsingVerifier(discriminator, verifier);
SuccessOrExit(err);
}
ChipLogProgress(AppServer, "Opened the pairing window");
}
else
{
HandleDataModelMessage(header.GetSourceNodeId().Value(), std::move(buffer));
}

exit:;
}
Expand Down Expand Up @@ -222,13 +330,36 @@ SecureSessionMgr & chip::SessionManager()
return gSessions;
}

CHIP_ERROR OpenDefaultPairingWindow()
CHIP_ERROR OpenDefaultPairingWindow(ResetAdmins resetAdmins)
{
gDeviceDiscriminatorCache.RestoreDiscriminator();

uint32_t pinCode;
uint16_t discriminator;
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSetupPinCode(pinCode));
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSetupDiscriminator(discriminator));
return OpenPairingWindow(pinCode, discriminator);

RendezvousParameters params;

#if CONFIG_NETWORK_LAYER_BLE
params.SetSetupPINCode(pinCode)
.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer())
.SetPeerAddress(Transport::PeerAddress::BLE())
.SetAdvertisementDelegate(&gAdvDelegate);
#else
params.SetSetupPINCode(pinCode);
#endif // CONFIG_NETWORK_LAYER_BLE

if (resetAdmins == ResetAdmins::kYes)
{
gNextAvailableAdminId = 0;
gAdminPairings.Reset();
}

AdminId admin = gNextAvailableAdminId;
AdminPairingInfo * adminInfo = gAdminPairings.AssignAdminId(admin);
VerifyOrReturnError(adminInfo != nullptr, CHIP_ERROR_NO_MEMORY);
gNextAvailableAdminId++;

return gRendezvousServer.Init(std::move(params), &gTransports, &gSessions, adminInfo);
}

// The function will initialize datamodel handler and then start the server
Expand All @@ -241,6 +372,7 @@ void InitServer(AppDelegate * delegate)
InitDataModelHandler();
gCallbacks.SetDelegate(delegate);
gRendezvousServer.SetDelegate(delegate);
gAdvDelegate.SetDelegate(delegate);

// Init transport before operations with secure session mgr.
#if INET_CONFIG_ENABLE_IPV4
Expand Down Expand Up @@ -282,7 +414,7 @@ void InitServer(AppDelegate * delegate)
}
else
{
SuccessOrExit(err = OpenDefaultPairingWindow());
SuccessOrExit(err = OpenDefaultPairingWindow(ResetAdmins::kYes));
}

#if CHIP_ENABLE_MDNS
Expand Down
12 changes: 11 additions & 1 deletion src/app/server/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,17 @@ using DemoTransportMgr = chip::TransportMgr<chip::Transport::UDP>;
*/
void InitServer(AppDelegate * delegate = nullptr);

namespace chip {

enum class ResetAdmins
{
kYes,
kNo,
};

} // namespace chip

/**
* Open the pairing window using default configured parameters.
*/
CHIP_ERROR OpenDefaultPairingWindow();
CHIP_ERROR OpenDefaultPairingWindow(chip::ResetAdmins resetAdmins);
1 change: 1 addition & 0 deletions src/controller/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static_library("controller") {
"${chip_root}/src/lib/support",
"${chip_root}/src/messaging",
"${chip_root}/src/platform",
"${chip_root}/src/setup_payload",
"${chip_root}/src/transport",
]

Expand Down
41 changes: 41 additions & 0 deletions src/controller/CHIPDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <support/ReturnMacros.h>
#include <support/SafeInt.h>
#include <support/logging/CHIPLogging.h>
#include <system/TLVPacketBufferBackingStore.h>

using namespace chip::Inet;
using namespace chip::System;
Expand Down Expand Up @@ -247,6 +248,46 @@ void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader
}
}

CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, bool useToken, uint16_t discriminator, SetupPayload & setupPayload)
{
// TODO: This code is temporary, and must be updated to use the Cluster API.
// Issue: https://github.com/project-chip/connectedhomeip/issues/4725

// Construct and send "open pairing window" message to the device
System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::kMaxPacketBufferSize);
System::PacketBufferTLVWriter writer;

writer.Init(std::move(buf));
writer.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning;

ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 1), timeout));

if (useToken)
{
ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 2), discriminator));

PASEVerifier verifier;
ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, setupPayload.setUpPINCode));
ReturnErrorOnFailure(writer.PutBytes(TLV::ProfileTag(writer.ImplicitProfileId, 3),
reinterpret_cast<const uint8_t *>(verifier), sizeof(verifier)));
}

System::PacketBufferHandle outBuffer;
ReturnErrorOnFailure(writer.Finalize(&outBuffer));

PayloadHeader header;

header.SetMessageType(chip::Protocols::kProtocol_ServiceProvisioning, 0);

ReturnErrorOnFailure(SendMessage(std::move(outBuffer), header));

setupPayload.version = 1;
setupPayload.rendezvousInformation = RendezvousInformationFlags::kBLE;
setupPayload.discriminator = discriminator;

return CHIP_NO_ERROR;
}

CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down
Loading