blob: e214bedde72eb78e0ec94d3127585ee8e419ed27 [file] [log] [blame]
/*
*
* Copyright (c) 2021 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
* Declaration of SetUp Code Pairer, a class that parses a given
* setup code and uses the extracted informations to discover and
* filter commissionables nodes, before initiating the pairing process.
*
*/
#pragma once
#include <controller/DevicePairingDelegate.h>
#include <lib/core/CHIPError.h>
#include <lib/core/NodeId.h>
#include <lib/support/DLLUtil.h>
#include <platform/CHIPDeviceConfig.h>
#include <protocols/secure_channel/RendezvousParameters.h>
#include <setup_payload/ManualSetupPayloadParser.h>
#include <setup_payload/QRCodeSetupPayloadParser.h>
#if CONFIG_NETWORK_LAYER_BLE
#include <ble/Ble.h>
#endif // CONFIG_NETWORK_BLE
#if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
#include <nfc/NFC.h>
#endif // CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
#include <controller/DeviceDiscoveryDelegate.h>
#include <deque>
#include <optional>
#include <vector>
namespace chip {
namespace Controller {
class DeviceCommissioner;
/**
* A class that represents a discovered device. This includes both the inputs to discovery (via the
* RendezvousParameters super-class), and the outputs from discovery (the PeerAddress in
* RendezvousParameters but also some of our members like mHostName, mInterfaceId,
* mLongDiscriminator).
*/
class SetUpCodePairerParameters : public RendezvousParameters
{
public:
SetUpCodePairerParameters() = default;
SetUpCodePairerParameters(const Dnssd::CommonResolutionData & data, std::optional<uint16_t> longDiscriminator, size_t index);
#if CONFIG_NETWORK_LAYER_BLE
SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj, std::optional<uint16_t> longDiscriminator, bool connected = true);
#endif // CONFIG_NETWORK_LAYER_BLE
char mHostName[Dnssd::kHostNameMaxLength + 1] = {};
Inet::InterfaceId mInterfaceId;
// The long discriminator of the device that was actually discovered, if this is known. This
// differs from the mSetupDiscriminator member of RendezvousParameters in that the latter may be
// a short discriminator from a numeric setup code (which may match multiple devices), while
// this member, if set, is always a long discriminator that was actually advertised by the
// device represented by our PeerAddress.
std::optional<uint16_t> mLongDiscriminator = std::nullopt;
};
enum class SetupCodePairerBehaviour : uint8_t
{
kCommission,
kPaseOnly,
};
enum class DiscoveryType : uint8_t
{
kDiscoveryNetworkOnly,
kDiscoveryNetworkOnlyWithoutPASEAutoRetry,
kAll,
};
class DLL_EXPORT SetUpCodePairer : public DevicePairingDelegate
#if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
,
public Nfc::NFCReaderTransportDelegate
#endif
{
public:
SetUpCodePairer(DeviceCommissioner * commissioner) : mCommissioner(commissioner) {}
virtual ~SetUpCodePairer() {}
CHIP_ERROR PairDevice(chip::NodeId remoteId, const char * setUpCode,
SetupCodePairerBehaviour connectionType = SetupCodePairerBehaviour::kCommission,
DiscoveryType discoveryType = DiscoveryType::kAll,
Optional<Dnssd::CommonResolutionData> resolutionData = NullOptional);
// Called by the DeviceCommissioner to notify that we have discovered a new device.
void NotifyCommissionableDeviceDiscovered(const chip::Dnssd::DiscoveredNodeData & nodeData);
void SetSystemLayer(System::Layer * systemLayer) { mSystemLayer = systemLayer; };
#if CONFIG_NETWORK_LAYER_BLE
void SetBleLayer(Ble::BleLayer * bleLayer) { mBleLayer = bleLayer; };
#endif // CONFIG_NETWORK_LAYER_BLE
// Stop ongoing discovery / pairing of the specified node, or of
// whichever node we're pairing if kUndefinedNodeId is passed.
bool StopPairing(NodeId remoteId = kUndefinedNodeId);
private:
// DevicePairingDelegate implementation.
void OnStatusUpdate(DevicePairingDelegate::Status status) override;
void OnPairingComplete(CHIP_ERROR error, const std::optional<RendezvousParameters> & rendezvousParameters,
const std::optional<SetupPayload> & setupPayload) override;
void OnPairingDeleted(CHIP_ERROR error) override;
void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override;
#if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
// Nfc::NFCReaderTransportDelegate implementation
void OnTagDiscovered(const chip::Nfc::NFCTag::Identifier & identifer) override;
void OnTagDiscoveryFailed(CHIP_ERROR error) override;
#endif
CHIP_ERROR Connect();
CHIP_ERROR StartDiscoveryOverBLE();
CHIP_ERROR StopDiscoveryOverBLE();
CHIP_ERROR StartDiscoveryOverDNSSD();
CHIP_ERROR StopDiscoveryOverDNSSD();
CHIP_ERROR StartDiscoveryOverWiFiPAF();
CHIP_ERROR StopDiscoveryOverWiFiPAF();
CHIP_ERROR StartDiscoveryOverNFC();
CHIP_ERROR StopDiscoveryOverNFC();
// Returns whether we have kicked off a new connection attempt.
bool ConnectToDiscoveredDevice();
// Stop attempts to discover more things to connect to, but keep trying to
// connect to the ones we have already discovered.
void StopAllDiscoveryAttempts();
// Reset our mWaitingForDiscovery/mDiscoveredParameters state to indicate no
// pending work.
void ResetDiscoveryState();
// Get ready to start PASE establishment via mCommissioner. Sets up
// whatever state is needed for that.
void ExpectPASEEstablishment();
// PASE establishment by mCommissioner has completed: we either have a PASE
// session now or we failed to set one up, but we are done waiting on
// mCommissioner.
void PASEEstablishmentComplete();
// Called when PASE establishment fails.
//
// May start a new PASE establishment.
//
// Will return whether we might in fact have more rendezvous parameters to
// try (e.g. because we started a new PASE establishment or are waiting on
// more device discovery).
//
// The commissioner can use the return value to decide whether pairing has
// actually failed or not.
bool TryNextRendezvousParameters();
// True if we are still waiting on discovery to possibly produce new
// RendezvousParameters in the future.
bool DiscoveryInProgress() const;
// Not an enum class because we use this for indexing into arrays.
enum TransportTypes
{
kBLETransport = 0,
kIPTransport,
kWiFiPAFTransport,
#if CHIP_DEVICE_CONFIG_ENABLE_NFC_BASED_COMMISSIONING
kNFCTransport,
#endif
kTransportTypeCount,
};
void NotifyCommissionableDeviceDiscovered(const chip::Dnssd::CommonResolutionData & resolutionData,
std::optional<uint16_t> matchedLongDiscriminator);
static void OnDeviceDiscoveredTimeoutCallback(System::Layer * layer, void * context);
#if CONFIG_NETWORK_LAYER_BLE
Ble::BleLayer * mBleLayer = nullptr;
void OnDiscoveredDeviceOverBle(BLE_CONNECTION_OBJECT connObj, std::optional<uint16_t> matchedLongDiscriminator);
void OnBLEDiscoveryError(CHIP_ERROR err);
/////////// BLEConnectionDelegate Callbacks /////////
static void OnDiscoveredDeviceOverBleSuccess(void * appState, BLE_CONNECTION_OBJECT connObj);
static void OnDiscoveredDeviceWithDiscriminatorOverBleSuccess(void * appState, uint16_t matchedLongDiscriminator,
BLE_CONNECTION_OBJECT connObj);
static void OnDiscoveredDeviceOverBleError(void * appState, CHIP_ERROR err);
#endif // CONFIG_NETWORK_LAYER_BLE
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
void OnDiscoveredDeviceOverWifiPAF();
void OnWifiPAFDiscoveryError(CHIP_ERROR err);
static void OnWiFiPAFSubscribeComplete(void * appState);
static void OnWiFiPAFSubscribeError(void * appState, CHIP_ERROR err);
#endif
bool NodeMatchesCurrentFilter(const Dnssd::DiscoveredNodeData & nodeData) const;
static bool IdIsPresent(uint16_t vendorOrProductID);
bool ShouldDiscoverUsing(RendezvousInformationFlag commissioningChannel) const;
// kNotAvailable represents unavailable vendor/product ID values in setup payloads.
static constexpr uint16_t kNotAvailable = 0;
DeviceCommissioner * mCommissioner = nullptr;
System::Layer * mSystemLayer = nullptr;
chip::NodeId mRemoteId = kUndefinedNodeId;
SetupCodePairerBehaviour mConnectionType = SetupCodePairerBehaviour::kCommission;
DiscoveryType mDiscoveryType = DiscoveryType::kAll;
std::vector<SetupPayload> mSetupPayloads;
// The payload we are using for our current PASE connection attempt. Only
// set while we are attempting PASE.
std::optional<SetupPayload> mCurrentPASEPayload;
// While we are trying to pair, we intercept the DevicePairingDelegate
// notifications from mCommissioner. We want to make sure we send them on
// to the original pairing delegate, if any.
DevicePairingDelegate * mPairingDelegate = nullptr;
// Boolean will be set to true if we currently have an async discovery
// process happening via the relevant transport.
bool mWaitingForDiscovery[kTransportTypeCount] = { false };
// Double ended-queue of things we have discovered but not tried connecting to yet. The
// general discovery/pairing process will terminate once this queue is empty
// and all the booleans in mWaitingForDiscovery are false.
std::deque<SetUpCodePairerParameters> mDiscoveredParameters;
// Current thing we are trying to connect to over UDP. If a PASE connection fails with
// a CHIP_ERROR_TIMEOUT, the discovered parameters will be used to ask the
// mdns daemon to invalidate its caches.
Optional<SetUpCodePairerParameters> mCurrentPASEParameters;
// mWaitingForPASE is true if we have called either
// EstablishPASEConnection or PairDevice on mCommissioner and are now just
// waiting to see whether that works.
bool mWaitingForPASE = false;
// mLastPASEError is the error from the last OnPairingComplete call we got.
CHIP_ERROR mLastPASEError = CHIP_NO_ERROR;
};
} // namespace Controller
} // namespace chip