Skip to content

Commit

Permalink
Enable pairing of multiple admins with a device
Browse files Browse the repository at this point in the history
  • Loading branch information
pan-apple committed Feb 8, 2021
1 parent f4980c1 commit e44a446
Show file tree
Hide file tree
Showing 20 changed files with 758 additions and 35 deletions.
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(true);
}
}

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
2 changes: 2 additions & 0 deletions src/app/server/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ class AppDelegate
virtual void OnReceiveError(){};
virtual void OnRendezvousStarted(){};
virtual void OnRendezvousStopped(){};
virtual void OnPairingWindowOpened(){};
virtual void OnPairingWindowClosed(){};
};
153 changes: 140 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,68 @@ bool isRendezvousBypassed()
return rendezvousMode == RendezvousInformationFlags::kNone;
}

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);
}

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 +135,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 +178,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, DeviceLayer::ProfileTag(reader.ImplicitProfileId, 1)));
SuccessOrExit(reader.Get(timeout));

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

err = reader.Next(kTLVType_ByteString, DeviceLayer::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(false));
}
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 +325,36 @@ SecureSessionMgr & chip::SessionManager()
return gSessions;
}

CHIP_ERROR OpenDefaultPairingWindow()
CHIP_ERROR OpenDefaultPairingWindow(bool 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)
{
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 +367,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 +409,7 @@ void InitServer(AppDelegate * delegate)
}
else
{
SuccessOrExit(err = OpenDefaultPairingWindow());
SuccessOrExit(err = OpenDefaultPairingWindow(true));
}

#if CHIP_ENABLE_MDNS
Expand Down
2 changes: 1 addition & 1 deletion src/app/server/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ void InitServer(AppDelegate * delegate = nullptr);
/**
* Open the pairing window using default configured parameters.
*/
CHIP_ERROR OpenDefaultPairingWindow();
CHIP_ERROR OpenDefaultPairingWindow(bool resetAdmins);
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(0);
System::PacketBufferTLVWriter writer;

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

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

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

PASEVerifier verifier;
ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, setupPayload.setUpPINCode));
ReturnErrorOnFailure(writer.PutBytes(DeviceLayer::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
26 changes: 26 additions & 0 deletions src/controller/CHIPDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <app/util/basic-types.h>
#include <core/CHIPCallback.h>
#include <core/CHIPCore.h>
#include <setup_payload/SetupPayload.h>
#include <support/Base64.h>
#include <support/DLLUtil.h>
#include <transport/PASESession.h>
Expand Down Expand Up @@ -231,6 +232,23 @@ class DLL_EXPORT Device
void OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, SecureSessionHandle session,
System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr);

/**
* @brief
* Trigger a paired device to re-enter the pairing mode. If an onboarding token is provided, the device will use
* the provided setup PIN code and the discriminator to advertise itself for pairing availability. If the token
* is not provided, the device will use the manufacturer assigned setup PIN code and discriminator.
*
* The device will exit the pairing mode after a successful pairing, or after the given `timeout` time.
*
* @param[in] timeout The pairing mode should terminate after this much time.
* @param[in] useToken The device should use the provided onboarding token instead of the default
* pairing setup PIN and discriminator.
* @param[in] discriminator The discriminator that the device should use for advertising and pairing.
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
*/
CHIP_ERROR OpenPairingWindow(uint32_t timeout, bool useToken, uint16_t discriminator, SetupPayload & setupPayload);

/**
* @brief
* Return whether the current device object is actively associated with a paired CHIP
Expand Down Expand Up @@ -355,6 +373,14 @@ class DLL_EXPORT DeviceStatusDelegate
*/
virtual void OnMessage(System::PacketBufferHandle msg) = 0;

/**
* @brief
* Called when response to OpenPairingWindow is received from the device.
*
* @param[in] status CHIP_NO_ERROR on success, or corresponding error.
*/
virtual void OnPairingWindowOpenStatus(CHIP_ERROR status){};

/**
* @brief
* Called when device status is updated.
Expand Down
Loading

0 comments on commit e44a446

Please sign in to comment.