| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * |
| * 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. |
| */ |
| |
| #include <inttypes.h> |
| |
| #include <app/server/Server.h> |
| |
| #include <app/InteractionModelEngine.h> |
| #include <app/server/EchoHandler.h> |
| #include <app/server/RendezvousServer.h> |
| #include <app/server/StorablePeerConnection.h> |
| #include <app/util/DataModelHandler.h> |
| |
| #include <ble/BLEEndPoint.h> |
| #include <core/CHIPPersistentStorageDelegate.h> |
| #include <inet/IPAddress.h> |
| #include <inet/InetError.h> |
| #include <inet/InetLayer.h> |
| #include <mdns/ServiceNaming.h> |
| #include <messaging/ExchangeMgr.h> |
| #include <platform/CHIPDeviceLayer.h> |
| #include <platform/KeyValueStoreManager.h> |
| #include <protocols/secure_channel/CASEServer.h> |
| #include <protocols/secure_channel/MessageCounterManager.h> |
| #include <setup_payload/SetupPayload.h> |
| #include <support/CodeUtils.h> |
| #include <support/ErrorStr.h> |
| #include <support/logging/CHIPLogging.h> |
| #include <sys/param.h> |
| #include <system/SystemPacketBuffer.h> |
| #include <system/TLVPacketBufferBackingStore.h> |
| #include <transport/FabricTable.h> |
| #include <transport/SecureSessionMgr.h> |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT || CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
| #include <protocols/user_directed_commissioning/UserDirectedCommissioning.h> |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT || CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_MDNS |
| #include <app/server/Mdns.h> |
| #endif |
| |
| using namespace ::chip; |
| using namespace ::chip::Inet; |
| using namespace ::chip::Transport; |
| using namespace ::chip::DeviceLayer; |
| using namespace ::chip::Messaging; |
| |
| namespace { |
| |
| constexpr bool isRendezvousBypassed() |
| { |
| #if defined(CHIP_BYPASS_RENDEZVOUS) && CHIP_BYPASS_RENDEZVOUS |
| return true; |
| #elif defined(CONFIG_RENDEZVOUS_MODE) |
| return static_cast<RendezvousInformationFlag>(CONFIG_RENDEZVOUS_MODE) == RendezvousInformationFlag::kNone; |
| #else |
| return false; |
| #endif |
| } |
| |
| constexpr bool useTestPairing() |
| { |
| // Use the test pairing whenever rendezvous is bypassed. Otherwise, there wouldn't be |
| // any way to communicate with the device using CHIP protocol. |
| // This is used to bypass BLE in the cirque test. |
| // Only in the cirque test this is enabled with --args='bypass_rendezvous=true'. |
| return isRendezvousBypassed(); |
| } |
| |
| class ServerStorageDelegate : public PersistentStorageDelegate |
| { |
| CHIP_ERROR SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override |
| { |
| ChipLogProgress(AppServer, "Retrieved value from server storage."); |
| return PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size); |
| } |
| |
| CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override |
| { |
| ChipLogProgress(AppServer, "Stored value in server storage"); |
| return PersistedStorage::KeyValueStoreMgr().Put(key, value, size); |
| } |
| |
| CHIP_ERROR SyncDeleteKeyValue(const char * key) override |
| { |
| ChipLogProgress(AppServer, "Delete value in server storage"); |
| return PersistedStorage::KeyValueStoreMgr().Delete(key); |
| } |
| }; |
| |
| ServerStorageDelegate gServerStorage; |
| SessionIDAllocator gSessionIDAllocator; |
| |
| CHIP_ERROR PersistFabricToKVS(FabricInfo * fabric, FabricIndex nextAvailableId) |
| { |
| ReturnErrorCodeIf(fabric == nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| ChipLogProgress(AppServer, "Persisting fabric ID %d, next available %d", fabric->GetFabricIndex(), nextAvailableId); |
| |
| ReturnErrorOnFailure(GetGlobalFabricTable().Store(fabric->GetFabricIndex())); |
| ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kFabricTableCountKey, &nextAvailableId, sizeof(nextAvailableId))); |
| |
| ChipLogProgress(AppServer, "Persisting fabric ID successfully"); |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR RestoreAllFabricsFromKVS(FabricTable & fabrics, FabricIndex & nextAvailableId) |
| { |
| // It's not an error if the key doesn't exist. Just return right away. |
| VerifyOrReturnError(PersistedStorage::KeyValueStoreMgr().Get(kFabricTableCountKey, &nextAvailableId) == CHIP_NO_ERROR, |
| CHIP_NO_ERROR); |
| ChipLogProgress(AppServer, "Next available fabric ID is %d", nextAvailableId); |
| |
| // TODO: The fabric ID space allocation should be re-evaluated. With the current approach, the space could be |
| // exhausted while IDs are still available (e.g. if the fabric IDs are allocated and freed over a period of time). |
| // Also, the current approach can make ID lookup slower as more IDs are allocated and freed. |
| for (FabricIndex id = 0; id < nextAvailableId; id++) |
| { |
| // Recreate the binding if one exists in persistent storage. Else skip to the next ID |
| if (fabrics.LoadFromStorage(id) == CHIP_NO_ERROR) |
| { |
| FabricInfo * fabric = fabrics.FindFabricWithIndex(id); |
| if (fabric != nullptr) |
| { |
| ChipLogProgress(AppServer, "Found fabric pairing for %d, node ID 0x" ChipLogFormatX64, fabric->GetFabricIndex(), |
| ChipLogValueX64(fabric->GetNodeId())); |
| } |
| } |
| } |
| ChipLogProgress(AppServer, "Restored all fabric pairings from KVS."); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| void EraseAllFabricsUpTo(FabricIndex nextAvailableId) |
| { |
| PersistedStorage::KeyValueStoreMgr().Delete(kFabricTableCountKey); |
| |
| for (FabricIndex id = 0; id < nextAvailableId; id++) |
| { |
| GetGlobalFabricTable().Delete(id); |
| } |
| } |
| |
| static CHIP_ERROR RestoreAllSessionsFromKVS(SecureSessionMgr & sessionMgr) |
| { |
| uint16_t nextSessionKeyId = 0; |
| // It's not an error if the key doesn't exist. Just return right away. |
| VerifyOrReturnError(PersistedStorage::KeyValueStoreMgr().Get(kStorablePeerConnectionCountKey, &nextSessionKeyId) == |
| CHIP_NO_ERROR, |
| CHIP_NO_ERROR); |
| ChipLogProgress(AppServer, "Found %d stored connections", nextSessionKeyId); |
| |
| PASESession * session = chip::Platform::New<PASESession>(); |
| VerifyOrReturnError(session != nullptr, CHIP_ERROR_NO_MEMORY); |
| |
| for (uint16_t keyId = 0; keyId < nextSessionKeyId; keyId++) |
| { |
| StorablePeerConnection connection; |
| if (CHIP_NO_ERROR == connection.FetchFromKVS(gServerStorage, keyId)) |
| { |
| connection.GetPASESession(session); |
| |
| ChipLogProgress(AppServer, "Fetched the session information: from 0x" ChipLogFormatX64, |
| ChipLogValueX64(session->PeerConnection().GetPeerNodeId())); |
| if (gSessionIDAllocator.Reserve(keyId) == CHIP_NO_ERROR) |
| { |
| sessionMgr.NewPairing(Optional<Transport::PeerAddress>::Value(session->PeerConnection().GetPeerAddress()), |
| session->PeerConnection().GetPeerNodeId(), session, SecureSession::SessionRole::kResponder, |
| connection.GetFabricIndex()); |
| } |
| else |
| { |
| ChipLogProgress(AppServer, "Session Key ID %" PRIu16 " cannot be used. Skipping over this session", keyId); |
| } |
| session->Clear(); |
| } |
| } |
| |
| chip::Platform::Delete(session); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| void EraseAllSessionsUpTo(uint16_t nextSessionKeyId) |
| { |
| PersistedStorage::KeyValueStoreMgr().Delete(kStorablePeerConnectionCountKey); |
| |
| for (uint16_t keyId = 0; keyId < nextSessionKeyId; keyId++) |
| { |
| gSessionIDAllocator.Free(keyId); |
| StorablePeerConnection::DeleteFromKVS(gServerStorage, keyId); |
| } |
| } |
| |
| // 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); |
| } |
| |
| 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; |
| FabricTable gFabrics; |
| FabricIndex gNextAvailableFabricIndex = 0; |
| bool gPairingWindowOpen = false; |
| |
| class ServerRendezvousAdvertisementDelegate : public RendezvousAdvertisementDelegate |
| { |
| public: |
| CHIP_ERROR StartAdvertisement() const override |
| { |
| if (isBLE) |
| { |
| ReturnErrorOnFailure(chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(true)); |
| } |
| if (mDelegate != nullptr) |
| { |
| mDelegate->OnPairingWindowOpened(); |
| } |
| gPairingWindowOpen = true; |
| return CHIP_NO_ERROR; |
| } |
| CHIP_ERROR StopAdvertisement() const override |
| { |
| gDeviceDiscriminatorCache.RestoreDiscriminator(); |
| |
| gPairingWindowOpen = false; |
| |
| if (isBLE) |
| { |
| ReturnErrorOnFailure(chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false)); |
| } |
| |
| if (mDelegate != nullptr) |
| { |
| mDelegate->OnPairingWindowClosed(); |
| } |
| |
| FabricInfo * fabric = gFabrics.FindFabricWithIndex(mFabric); |
| if (fabric != nullptr) |
| { |
| ReturnErrorOnFailure(PersistFabricToKVS(fabric, gNextAvailableFabricIndex)); |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| void SetDelegate(AppDelegate * delegate) { mDelegate = delegate; } |
| void SetBLE(bool ble) { isBLE = ble; } |
| void SetFabricIndex(FabricIndex id) { mFabric = id; } |
| |
| private: |
| AppDelegate * mDelegate = nullptr; |
| FabricIndex mFabric; |
| bool isBLE = true; |
| }; |
| |
| DemoTransportMgr gTransports; |
| SecureSessionMgr gSessions; |
| RendezvousServer gRendezvousServer; |
| CASEServer gCASEServer; |
| Messaging::ExchangeManager gExchangeMgr; |
| ServerRendezvousAdvertisementDelegate gAdvDelegate; |
| |
| class ServerCallback : public ExchangeDelegate |
| { |
| public: |
| CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * exchangeContext, const PacketHeader & packetHeader, |
| const PayloadHeader & payloadHeader, System::PacketBufferHandle && buffer) override |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| // as soon as a client connects, assume it is connected |
| VerifyOrExit(!buffer.IsNull(), ChipLogError(AppServer, "Received data but couldn't process it...")); |
| VerifyOrExit(packetHeader.GetSourceNodeId().HasValue(), ChipLogError(AppServer, "Unknown source for received message")); |
| |
| VerifyOrExit(mSessionMgr != nullptr, ChipLogError(AppServer, "SecureSessionMgr is not initilized yet")); |
| |
| VerifyOrExit(packetHeader.GetSourceNodeId().Value() != kUndefinedNodeId, |
| ChipLogError(AppServer, "Unknown source for received message")); |
| |
| ChipLogProgress(AppServer, "Packet received from Node 0x" ChipLogFormatX64 ": %u bytes", |
| ChipLogValueX64(packetHeader.GetSourceNodeId().Value()), buffer->DataLength()); |
| |
| HandleDataModelMessage(exchangeContext, std::move(buffer)); |
| |
| exit: |
| return err; |
| } |
| |
| void OnResponseTimeout(ExchangeContext * ec) override |
| { |
| ChipLogProgress(AppServer, "Failed to receive response"); |
| if (mDelegate != nullptr) |
| { |
| mDelegate->OnReceiveError(); |
| } |
| } |
| |
| void SetDelegate(AppDelegate * delegate) { mDelegate = delegate; } |
| void SetSessionMgr(SecureSessionMgr * mgr) { mSessionMgr = mgr; } |
| |
| private: |
| AppDelegate * mDelegate = nullptr; |
| SecureSessionMgr * mSessionMgr = nullptr; |
| }; |
| |
| secure_channel::MessageCounterManager gMessageCounterManager; |
| ServerCallback gCallbacks; |
| SecurePairingUsingTestSecret gTestPairing; |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT |
| |
| chip::Protocols::UserDirectedCommissioning::UserDirectedCommissioningClient gUDCClient; |
| |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT |
| |
| void HandlePairingWindowTimeout(System::Layer * aSystemLayer, void * aAppState, CHIP_ERROR aError) |
| { |
| ClosePairingWindow(); |
| } |
| |
| } // namespace |
| |
| CHIP_ERROR OpenDefaultPairingWindow(ResetFabrics resetFabrics, uint16_t commissioningTimeoutSeconds, |
| chip::PairingWindowAdvertisement advertisementMode) |
| { |
| // TODO(cecille): If this is re-called when the window is already open, what should happen? |
| gDeviceDiscriminatorCache.RestoreDiscriminator(); |
| |
| uint32_t pinCode; |
| ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSetupPinCode(pinCode)); |
| |
| RendezvousParameters params; |
| |
| params.SetSetupPINCode(pinCode); |
| #if CONFIG_NETWORK_LAYER_BLE |
| gAdvDelegate.SetBLE(advertisementMode == chip::PairingWindowAdvertisement::kBle); |
| params.SetAdvertisementDelegate(&gAdvDelegate); |
| if (advertisementMode == chip::PairingWindowAdvertisement::kBle) |
| { |
| params.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer()).SetPeerAddress(Transport::PeerAddress::BLE()); |
| } |
| #endif // CONFIG_NETWORK_LAYER_BLE |
| |
| if (resetFabrics == ResetFabrics::kYes) |
| { |
| EraseAllFabricsUpTo(gNextAvailableFabricIndex); |
| EraseAllSessionsUpTo(gSessionIDAllocator.Peek()); |
| // Only resetting gNextAvailableFabricIndex at reboot otherwise previously paired device with fabricID 0 |
| // can continue sending messages to accessory as next available fabric will also be 0. |
| // This logic is not up to spec, will be implemented up to spec once AddOptCert is implemented. |
| gFabrics.Reset(); |
| } |
| |
| FabricIndex fabricIndex = gNextAvailableFabricIndex; |
| FabricInfo * fabricInfo = gFabrics.AssignFabricIndex(fabricIndex); |
| VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_NO_MEMORY); |
| gNextAvailableFabricIndex++; |
| |
| ReturnErrorOnFailure(gRendezvousServer.WaitForPairing( |
| std::move(params), kSpake2p_Iteration_Count, |
| ByteSpan(reinterpret_cast<const uint8_t *>(kSpake2pKeyExchangeSalt), strlen(kSpake2pKeyExchangeSalt)), 0, &gExchangeMgr, |
| &gTransports, &gSessions, fabricInfo)); |
| |
| if (commissioningTimeoutSeconds != kNoCommissioningTimeout) |
| { |
| ReturnErrorOnFailure( |
| DeviceLayer::SystemLayer.StartTimer(commissioningTimeoutSeconds * 1000, HandlePairingWindowTimeout, nullptr)); |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR OpenPairingWindowUsingVerifier(uint16_t commissioningTimeoutSeconds, uint16_t discriminator, PASEVerifier & verifier, |
| uint32_t iterations, ByteSpan salt, uint16_t passcodeID) |
| { |
| RendezvousParameters params; |
| |
| ReturnErrorOnFailure(gDeviceDiscriminatorCache.UpdateDiscriminator(discriminator)); |
| |
| gAdvDelegate.SetBLE(false); |
| params.SetPASEVerifier(verifier).SetAdvertisementDelegate(&gAdvDelegate); |
| |
| FabricIndex fabricIndex = gNextAvailableFabricIndex; |
| FabricInfo * fabricInfo = gFabrics.AssignFabricIndex(fabricIndex); |
| VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_NO_MEMORY); |
| gNextAvailableFabricIndex++; |
| |
| ReturnErrorOnFailure(gRendezvousServer.WaitForPairing(std::move(params), iterations, salt, passcodeID, &gExchangeMgr, |
| &gTransports, &gSessions, fabricInfo)); |
| |
| if (commissioningTimeoutSeconds != kNoCommissioningTimeout) |
| { |
| ReturnErrorOnFailure( |
| DeviceLayer::SystemLayer.StartTimer(commissioningTimeoutSeconds * 1000, HandlePairingWindowTimeout, nullptr)); |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| void ClosePairingWindow() |
| { |
| if (gPairingWindowOpen) |
| { |
| ChipLogProgress(AppServer, "Closing pairing window"); |
| gRendezvousServer.Cleanup(); |
| } |
| } |
| |
| bool IsPairingWindowOpen() |
| { |
| return gPairingWindowOpen; |
| } |
| |
| // The function will initialize datamodel handler and then start the server |
| // The server assumes the platform's networking has been setup already |
| void InitServer(AppDelegate * delegate) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| chip::Platform::MemoryInit(); |
| |
| InitDataModelHandler(&gExchangeMgr); |
| gCallbacks.SetDelegate(delegate); |
| |
| #if CHIP_DEVICE_LAYER_TARGET_DARWIN |
| err = PersistedStorage::KeyValueStoreMgrImpl().Init("chip.store"); |
| SuccessOrExit(err); |
| #elif CHIP_DEVICE_LAYER_TARGET_LINUX |
| PersistedStorage::KeyValueStoreMgrImpl().Init(CHIP_CONFIG_KVS_PATH); |
| #endif |
| |
| err = gRendezvousServer.Init(delegate, &gServerStorage, &gSessionIDAllocator); |
| SuccessOrExit(err); |
| |
| gAdvDelegate.SetDelegate(delegate); |
| |
| err = gFabrics.Init(&gServerStorage); |
| SuccessOrExit(err); |
| |
| // Init transport before operations with secure session mgr. |
| err = gTransports.Init(UdpListenParameters(&DeviceLayer::InetLayer).SetAddressType(kIPAddressType_IPv6) |
| |
| #if INET_CONFIG_ENABLE_IPV4 |
| , |
| UdpListenParameters(&DeviceLayer::InetLayer).SetAddressType(kIPAddressType_IPv4) |
| #endif |
| #if CONFIG_NETWORK_LAYER_BLE |
| , |
| BleListenParameters(DeviceLayer::ConnectivityMgr().GetBleLayer()) |
| #endif |
| ); |
| |
| SuccessOrExit(err); |
| |
| err = gSessions.Init(&DeviceLayer::SystemLayer, &gTransports, &gFabrics, &gMessageCounterManager); |
| SuccessOrExit(err); |
| |
| err = gExchangeMgr.Init(&gSessions); |
| SuccessOrExit(err); |
| err = gMessageCounterManager.Init(&gExchangeMgr); |
| SuccessOrExit(err); |
| |
| err = chip::app::InteractionModelEngine::GetInstance()->Init(&gExchangeMgr, nullptr); |
| SuccessOrExit(err); |
| |
| #if defined(CHIP_APP_USE_ECHO) |
| err = InitEchoHandler(&gExchangeMgr); |
| SuccessOrExit(err); |
| #endif |
| |
| if (useTestPairing()) |
| { |
| ChipLogProgress(AppServer, "Rendezvous and secure pairing skipped"); |
| SuccessOrExit(err = AddTestPairing()); |
| } |
| else if (DeviceLayer::ConnectivityMgr().IsWiFiStationProvisioned() || DeviceLayer::ConnectivityMgr().IsThreadProvisioned()) |
| { |
| // If the network is already provisioned, proactively disable BLE advertisement. |
| ChipLogProgress(AppServer, "Network already provisioned. Disabling BLE advertisement"); |
| chip::DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(false); |
| |
| // Restore any previous fabric pairings |
| VerifyOrExit(CHIP_NO_ERROR == RestoreAllFabricsFromKVS(gFabrics, gNextAvailableFabricIndex), |
| ChipLogError(AppServer, "Could not restore fabric table")); |
| |
| VerifyOrExit(CHIP_NO_ERROR == RestoreAllSessionsFromKVS(gSessions), |
| ChipLogError(AppServer, "Could not restore previous sessions")); |
| } |
| else |
| { |
| #if CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART |
| SuccessOrExit(err = OpenDefaultPairingWindow(ResetFabrics::kYes)); |
| #endif |
| } |
| |
| // ESP32 and Mbed OS examples have a custom logic for enabling DNS-SD |
| #if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !CHIP_DEVICE_LAYER_TARGET_ESP32 && !CHIP_DEVICE_LAYER_TARGET_MBED |
| app::Mdns::StartServer(); |
| #endif |
| |
| gCallbacks.SetSessionMgr(&gSessions); |
| |
| // Register to receive unsolicited legacy ZCL messages from the exchange manager. |
| err = gExchangeMgr.RegisterUnsolicitedMessageHandlerForProtocol(Protocols::TempZCL::Id, &gCallbacks); |
| SuccessOrExit(err); |
| |
| // Register to receive unsolicited Service Provisioning messages from the exchange manager. |
| err = gExchangeMgr.RegisterUnsolicitedMessageHandlerForProtocol(Protocols::ServiceProvisioning::Id, &gCallbacks); |
| SuccessOrExit(err); |
| |
| err = gCASEServer.ListenForSessionEstablishment(&gExchangeMgr, &gTransports, &gSessions, &GetGlobalFabricTable(), |
| &gSessionIDAllocator); |
| SuccessOrExit(err); |
| |
| exit: |
| if (err != CHIP_NO_ERROR) |
| { |
| ChipLogError(AppServer, "ERROR setting up transport: %s", ErrorStr(err)); |
| } |
| else |
| { |
| ChipLogProgress(AppServer, "Server Listening..."); |
| } |
| } |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT |
| // NOTE: UDC client is located in Server.cpp because it really only makes sense |
| // to send UDC from a Matter device. The UDC message payload needs to include the device's |
| // randomly generated service name. |
| |
| CHIP_ERROR SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner) |
| { |
| ChipLogDetail(AppServer, "SendUserDirectedCommissioningRequest2"); |
| |
| CHIP_ERROR err; |
| char nameBuffer[chip::Mdns::kMaxInstanceNameSize + 1]; |
| err = app::Mdns::GetCommissionableInstanceName(nameBuffer, sizeof(nameBuffer)); |
| if (err != CHIP_NO_ERROR) |
| { |
| ChipLogError(AppServer, "Failed to get mdns instance name error: %s", ErrorStr(err)); |
| return err; |
| } |
| ChipLogDetail(AppServer, "instanceName=%s", nameBuffer); |
| |
| chip::System::PacketBufferHandle payloadBuf = chip::MessagePacketBuffer::NewWithData(nameBuffer, strlen(nameBuffer)); |
| if (payloadBuf.IsNull()) |
| { |
| ChipLogError(AppServer, "Unable to allocate packet buffer\n"); |
| return CHIP_ERROR_NO_MEMORY; |
| } |
| |
| err = gUDCClient.SendUDCMessage(&gTransports, std::move(payloadBuf), commissioner); |
| if (err == CHIP_NO_ERROR) |
| { |
| ChipLogDetail(AppServer, "Send UDC request success"); |
| } |
| else |
| { |
| ChipLogError(AppServer, "Send UDC request failed, err: %s\n", chip::ErrorStr(err)); |
| } |
| return err; |
| } |
| |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT |
| |
| CHIP_ERROR AddTestPairing() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| FabricInfo * fabricInfo = nullptr; |
| PASESession * testSession = nullptr; |
| PASESessionSerializable serializedTestSession; |
| |
| for (const FabricInfo & fabric : gFabrics) |
| if (fabric.IsInitialized() && fabric.GetNodeId() == chip::kTestDeviceNodeId) |
| ExitNow(); |
| |
| fabricInfo = gFabrics.AssignFabricIndex(gNextAvailableFabricIndex); |
| VerifyOrExit(fabricInfo != nullptr, err = CHIP_ERROR_NO_MEMORY); |
| |
| fabricInfo->SetNodeId(chip::kTestDeviceNodeId); |
| gTestPairing.ToSerializable(serializedTestSession); |
| |
| testSession = chip::Platform::New<PASESession>(); |
| testSession->FromSerializable(serializedTestSession); |
| SuccessOrExit(err = gSessions.NewPairing(Optional<PeerAddress>{ PeerAddress::Uninitialized() }, chip::kTestControllerNodeId, |
| testSession, SecureSession::SessionRole::kResponder, gNextAvailableFabricIndex)); |
| ++gNextAvailableFabricIndex; |
| |
| exit: |
| if (testSession) |
| { |
| testSession->Clear(); |
| chip::Platform::Delete(testSession); |
| } |
| |
| if (err != CHIP_NO_ERROR && fabricInfo != nullptr) |
| gFabrics.ReleaseFabricIndex(gNextAvailableFabricIndex); |
| |
| return err; |
| } |
| |
| FabricTable & GetGlobalFabricTable() |
| { |
| return gFabrics; |
| } |