| /* |
| * |
| * Copyright (c) 2013-2017 Nest Labs, Inc. |
| * 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 |
| * This file implements the Device Control Profile, which provides |
| * operations and utilities used during device setup and provisioning. |
| * |
| * The Device Control Profile facilitates client-server operations such |
| * that the client (the controlling device) can trigger specific utility |
| * functionality on the server (the device undergoing setup) to assist with |
| * and enable the device setup and provisioning process. This includes, for |
| * example, resetting the server device's configuration and enabling fail |
| * safes that define the behavior when the setup procedure is prematurely |
| * aborted. |
| * |
| */ |
| #ifndef __STDC_FORMAT_MACROS |
| #define __STDC_FORMAT_MACROS |
| #endif // __STDC_FORMAT_MACROS |
| |
| #include <Weave/Core/WeaveCore.h> |
| #include <Weave/Core/WeaveTLV.h> |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Core/WeaveEncoding.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| #include "DeviceControl.h" |
| #include <Weave/Profiles/common/CommonProfile.h> |
| #include <Weave/Profiles/echo/WeaveEcho.h> |
| #include <Weave/Profiles/device-description/DeviceDescription.h> |
| #include <Weave/Support/logging/WeaveLogging.h> |
| #include <Weave/Support/TimeUtils.h> |
| |
| namespace nl { |
| namespace Weave { |
| namespace Profiles { |
| namespace DeviceControl { |
| |
| |
| using namespace nl::Weave::Crypto; |
| using namespace nl::Weave::Encoding; |
| using namespace nl::Weave::TLV; |
| using namespace nl::Weave::Profiles::DeviceDescription; |
| |
| DeviceControlServer *DeviceControlServer::sRemotePassiveRendezvousServer = NULL; |
| |
| DeviceControlServer::DeviceControlServer() |
| { |
| FabricState = NULL; |
| ExchangeMgr = NULL; |
| mCurClientOp = NULL; |
| mDelegate = NULL; |
| mRemotePassiveRendezvousOp = NULL; |
| mFailSafeToken = 0; |
| mFailSafeArmed = false; |
| mResetFlags = 0x0000; |
| mRemotePassiveRendezvousClientCon = NULL; |
| mRemotePassiveRendezvousJoinerCon = NULL; |
| mRemotePassiveRendezvousTunnel = NULL; |
| mRemotePassiveRendezvousTimeout = 0; |
| mTunnelInactivityTimeout = 0; |
| mRemotePassiveRendezvousKeyId = 0; |
| mRemotePassiveRendezvousEncryptionType = 0; |
| } |
| |
| /** |
| * Initialize the Device Control Server state and register to receive |
| * Device Control messages. |
| * |
| * @param[in] exchangeMgr A pointer to the Weave Exchange Manager. |
| * |
| * @retval #WEAVE_ERROR_INCORRECT_STATE When a remote passive rendezvous server |
| * has already been registered. |
| * @retval #WEAVE_ERROR_TOO_MANY_UNSOLICITED_MESSAGE_HANDLERS When too many unsolicited message |
| * handlers are registered. |
| * @retval #WEAVE_NO_ERROR On success. |
| */ |
| WEAVE_ERROR DeviceControlServer::Init(WeaveExchangeManager *exchangeMgr) |
| { |
| FabricState = exchangeMgr->FabricState; |
| ExchangeMgr = exchangeMgr; |
| mCurClientOp = NULL; |
| mFailSafeToken = 0; |
| mFailSafeArmed = false; |
| mResetFlags = 0x0000; |
| |
| // Global used here, as used in DeviceManager, to get app state in WeaveMessageLayer::HandleConnectionReceived. |
| if (sRemotePassiveRendezvousServer != NULL) |
| return WEAVE_ERROR_INCORRECT_STATE; |
| |
| sRemotePassiveRendezvousServer = this; |
| |
| // Register to receive unsolicited Device Control messages from the exchange manager. |
| WEAVE_ERROR err = |
| ExchangeMgr->RegisterUnsolicitedMessageHandler(kWeaveProfile_DeviceControl, HandleClientRequest, this); |
| |
| return err; |
| } |
| |
| /** |
| * Shutdown the Device Control Server. |
| * |
| * @retval #WEAVE_NO_ERROR unconditionally. |
| */ |
| // TODO: Additional documentation detail required (i.e. how this function impacts object lifecycle). |
| WEAVE_ERROR DeviceControlServer::Shutdown() |
| { |
| if (ExchangeMgr != NULL) |
| ExchangeMgr->UnregisterUnsolicitedMessageHandler(kWeaveProfile_DeviceControl); |
| |
| CloseClientOp(); |
| |
| FabricState = NULL; |
| ExchangeMgr = NULL; |
| mFailSafeToken = 0; |
| mFailSafeArmed = false; |
| mResetFlags = 0x0000; |
| |
| // Kill any pending or completed Remote Passive Rendezvous. |
| CloseRemotePassiveRendezvous(); |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| /** |
| * Set the delegate to process Device Control Server events. |
| * |
| * @param[in] delegate A pointer to the Device Control Delegate. |
| */ |
| void DeviceControlServer::SetDelegate(DeviceControlDelegate *delegate) |
| { |
| mDelegate = delegate; |
| } |
| |
| /** |
| * Return Remote Passive Rendezvous state. |
| * |
| * @retval TRUE if Remote Passive Rendezvous in progress. |
| * @retval FALSE if Remote Passive Rendezvous is not in progress. |
| */ |
| bool DeviceControlServer::IsRemotePassiveRendezvousInProgress() const |
| { |
| return (mRemotePassiveRendezvousClientCon != NULL || mRemotePassiveRendezvousTunnel != NULL); |
| } |
| |
| /** |
| * Send a success response to a Device Control request. |
| * |
| * @retval #WEAVE_ERROR_INCORRECT_STATE If there is no request being processed. |
| * @retval #WEAVE_NO_ERROR On success. |
| * @retval other Other Weave or platform-specific error codes indicating that an error |
| * occurred preventing the success response from sending. |
| */ |
| WEAVE_ERROR DeviceControlServer::SendSuccessResponse() |
| { |
| return SendStatusReport(kWeaveProfile_Common, Common::kStatus_Success); |
| } |
| |
| /** |
| * Send a status report response to a request. |
| * |
| * @param[in] statusProfileId The Weave profile ID this status report pertains to. |
| * @param[in] statusCode The status code to be included in this response. |
| * @param[in] sysError The system error code to be included in this response. |
| * |
| * @retval #WEAVE_ERROR_INCORRECT_STATE If there is no request being processed. |
| * @retval #WEAVE_NO_ERROR On success. |
| * @retval other Other Weave or platform-specific error codes indicating that an error |
| * occurred preventing the status report from sending. |
| */ |
| WEAVE_ERROR DeviceControlServer::SendStatusReport(uint32_t statusProfileId, uint16_t statusCode, WEAVE_ERROR sysError) |
| { |
| WEAVE_ERROR err; |
| |
| VerifyOrExit(mCurClientOp != NULL, err = WEAVE_ERROR_INCORRECT_STATE); |
| |
| err = WeaveServerBase::SendStatusReport(mCurClientOp, statusProfileId, statusCode, sysError); |
| |
| exit: |
| |
| CloseClientOp(); |
| |
| return err; |
| } |
| |
| void DeviceControlServer::CloseClientOp() |
| { |
| if (mCurClientOp != NULL) |
| { |
| mCurClientOp->Close(); |
| mCurClientOp = NULL; |
| } |
| } |
| |
| void DeviceControlServer::SystemTestTimeout() |
| { |
| CloseClientOp(); |
| } |
| |
| void DeviceControlServer::HandleClientRequest(ExchangeContext *ec, const IPPacketInfo *pktInfo, |
| const WeaveMessageInfo *msgInfo, uint32_t profileId, uint8_t msgType, PacketBuffer *msgBuf) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| DeviceControlServer *server = (DeviceControlServer *) ec->AppState; |
| uint16_t dataLen; |
| uint8_t *p; |
| |
| // Fail messages for the wrong profile. This shouldn't happen, but better safe than sorry. |
| if (profileId != kWeaveProfile_DeviceControl) |
| { |
| WeaveServerBase::SendStatusReport(ec, kWeaveProfile_Common, Common::kStatus_BadRequest, WEAVE_NO_ERROR); |
| ec->Close(); |
| ExitNow(); |
| } |
| |
| // Call on the delegate to enforce message-level access control. If policy dictates the message should NOT |
| // be processed, then simply end the exchange and return. If an error response was warranted, the appropriate |
| // response will have been sent within EnforceAccessControl(). |
| if (!server->EnforceAccessControl(ec, profileId, msgType, msgInfo, server->mDelegate)) |
| { |
| ec->Close(); |
| ExitNow(); |
| } |
| |
| // Handle LookingToRendezvous messages specially, since they can be processed while another message is in progress. |
| if (msgType == kMsgType_LookingToRendezvous) |
| { |
| err = server->HandleLookingToRendezvousMessage(msgInfo, ec); |
| ExitNow(); |
| } |
| |
| // Disallow simultaneous requests. |
| if (server->mCurClientOp != NULL) |
| { |
| WeaveServerBase::SendStatusReport(ec, kWeaveProfile_Common, Common::kStatus_Busy, WEAVE_NO_ERROR); |
| ec->Close(); |
| ExitNow(); |
| } |
| |
| // Because the exchange context will be gone when we are waiting for our reset config |
| // callback, we must also check mResetFlags to disallow simultaneous requests. |
| if (server->mResetFlags != 0x0000) { |
| WeaveServerBase::SendStatusReport(ec, kWeaveProfile_Common, Common::kStatus_Busy, WEAVE_NO_ERROR); |
| ExitNow(); |
| } |
| |
| // Disallow requests over RPR client connection while listening for joiners on RPR client's behalf. |
| if (server->mRemotePassiveRendezvousClientCon != NULL && server->mRemotePassiveRendezvousClientCon == ec->Con) |
| { |
| // If client misbehaves during RPR, cancel the operation. |
| ec->Close(); |
| |
| if (ec == server->mRemotePassiveRendezvousOp) |
| { |
| server->mRemotePassiveRendezvousOp = NULL; |
| } |
| |
| server->CloseRemotePassiveRendezvous(); |
| |
| ExitNow(); |
| } |
| |
| // Record that we have a request in process. |
| server->mCurClientOp = ec; |
| |
| dataLen = msgBuf->DataLength(); |
| p = msgBuf->Start(); |
| |
| // Decode and dispatch the message. |
| switch (msgType) |
| { |
| case kMsgType_ResetConfig: |
| VerifyOrExit(dataLen == kMessageLength_ResetConfig, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleResetConfig(p, ec->Con); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_ArmFailSafe: |
| VerifyOrExit(dataLen == kMessageLength_ArmFailsafe, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleArmFailSafe(p); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_DisarmFailSafe: |
| VerifyOrExit(dataLen == kMessageLength_DisarmFailsafe, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleDisarmFailSafe(); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_EnableConnectionMonitor: |
| VerifyOrExit(dataLen == kMessageLength_EnableConnectionMonitor, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleEnableConnectionMonitor(p, msgInfo, ec); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_DisableConnectionMonitor: |
| VerifyOrExit(dataLen == kMessageLength_DisableConnectionMonitor, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleDisableConnectionMonitor(msgInfo, ec); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_RemotePassiveRendezvous: |
| VerifyOrExit(dataLen == kMessageLength_RemotePassiveRendezvous, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleRemotePassiveRendezvous(p, ec); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_StartSystemTest: |
| VerifyOrExit(dataLen == kMessageLength_StartSystemTest, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleStartSystemTest(p); |
| SuccessOrExit(err); |
| break; |
| |
| case kMsgType_StopSystemTest: |
| VerifyOrExit(dataLen == kMessageLength_StopSystemTest, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH); |
| |
| err = server->HandleStopSystemTest(); |
| SuccessOrExit(err); |
| break; |
| |
| default: |
| err = server->SendStatusReport(kWeaveProfile_Common, Common::kStatus_BadRequest); |
| ExitNow(); |
| break; |
| } |
| |
| exit: |
| if (msgBuf != NULL) |
| PacketBuffer::Free(msgBuf); |
| |
| if (err != WEAVE_NO_ERROR && server->mCurClientOp != NULL && ec == server->mCurClientOp) |
| { |
| WeaveLogError(DeviceControl, "Error handling DeviceControl client request, err = %d", err); |
| |
| if (msgType == kMsgType_RemotePassiveRendezvous) |
| { |
| server->CloseRemotePassiveRendezvous(); |
| } |
| |
| uint16_t statusCode = (err == WEAVE_ERROR_INVALID_MESSAGE_LENGTH) |
| ? Common::kStatus_BadRequest |
| : Common::kStatus_InternalError; |
| server->SendStatusReport(kWeaveProfile_Common, statusCode, err); |
| } |
| } |
| |
| void DeviceControlServer::HandleResetConfigConnectionClose(WeaveConnection *aCon, WEAVE_ERROR conErr) |
| { |
| DeviceControlServer *server = (DeviceControlServer *) aCon->AppState; |
| DeviceControlDelegate *delegate = server->mDelegate; |
| aCon->Close(); |
| |
| delegate->OnResetConfig(server->mResetFlags); |
| |
| server->mFailSafeArmed = false; |
| server->mFailSafeToken = 0; |
| |
| server->mResetFlags = 0x0000; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::SetConnectionMonitor(uint64_t peerNodeId, WeaveConnection *peerCon, uint16_t idleTimeout, uint16_t monitorInterval) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| ExchangeContext *monitorOp; |
| |
| // Search for an existing monitor exchange context for this connection. |
| // |
| monitorOp = ExchangeMgr->FindContext(peerNodeId, peerCon, this, true); |
| |
| // If a monitoring interval has been specified... |
| if (monitorInterval != 0) |
| { |
| // Create a monitoring exchange context if needed. |
| if (monitorOp == NULL) |
| { |
| monitorOp = ExchangeMgr->NewContext(peerCon, this); |
| VerifyOrExit(monitorOp != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| monitorOp->PeerNodeId = peerNodeId; |
| monitorOp->OnMessageReceived = HandleMonitorResponse; |
| monitorOp->OnConnectionClosed = HandleMonitorConnectionClose; |
| } |
| |
| // Save the monitoring interval in the context. |
| monitorOp->RetransInterval = monitorInterval; |
| |
| // Arm the interval timer to send the first monitoring request. |
| StartMonitorTimer(monitorOp); |
| } |
| |
| // Otherwise no active monitoring requested so cancel any previously created |
| // monitoring context/timer. |
| else |
| { |
| if (monitorOp != NULL) |
| { |
| CancelMonitorTimer(monitorOp); |
| monitorOp->Close(); |
| monitorOp = NULL; |
| } |
| } |
| |
| // set the idle timeout on the underlying connection. |
| err = peerCon->SetIdleTimeout(idleTimeout); |
| SuccessOrExit(err); |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && monitorOp != NULL) |
| monitorOp->Close(); |
| return err; |
| } |
| |
| void DeviceControlServer::StartMonitorTimer(ExchangeContext *monitorOp) |
| { |
| System::Layer* lSystemLayer = ExchangeMgr->MessageLayer->SystemLayer; |
| lSystemLayer->StartTimer(monitorOp->RetransInterval, HandleMonitorTimer, monitorOp); |
| } |
| |
| void DeviceControlServer::CancelMonitorTimer(ExchangeContext *monitorOp) |
| { |
| System::Layer* lSystemLayer = ExchangeMgr->MessageLayer->SystemLayer; |
| lSystemLayer->CancelTimer(HandleMonitorTimer, monitorOp); |
| } |
| |
| void DeviceControlServer::HandleMonitorTimer(System::Layer* aSystemLayer, void* aAppState, System::Error aError) |
| { |
| ExchangeContext* monitorOp = reinterpret_cast<ExchangeContext*>(aAppState); |
| DeviceControlServer* server = reinterpret_cast<DeviceControlServer*>(monitorOp->AppState); |
| PacketBuffer* msgBuf = NULL; |
| |
| WeaveLogProgress(DeviceControl, "Sending EchoRequest to device manager"); |
| |
| // Send an Echo Request message to the node at the other end of the monitored connection. |
| msgBuf = PacketBuffer::NewWithAvailableSize(0); |
| VerifyOrExit(msgBuf != NULL, aError = WEAVE_ERROR_NO_MEMORY); |
| aError = monitorOp->SendMessage(kWeaveProfile_Echo, kEchoMessageType_EchoRequest, msgBuf); |
| msgBuf = NULL; |
| |
| exit: |
| if (msgBuf != NULL) |
| PacketBuffer::Free(msgBuf); |
| |
| // If for some reason we got an error sending the EchoRequest, re-arm the interval timer and try again |
| // later. |
| if (aError != WEAVE_NO_ERROR) |
| server->StartMonitorTimer(monitorOp); |
| } |
| |
| void DeviceControlServer::HandleMonitorResponse(ExchangeContext *ec, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t profileId, |
| uint8_t msgType, PacketBuffer *payload) |
| { |
| DeviceControlServer *server = (DeviceControlServer *)ec->AppState; |
| |
| WeaveLogProgress(DeviceControl, "EchoResponse received from device manager"); |
| |
| PacketBuffer::Free(payload); |
| |
| // Re-start the monitoring interval timer. We will send another EchoRequest when this timer expires. |
| server->StartMonitorTimer(ec); |
| } |
| |
| void DeviceControlServer::HandleMonitorConnectionClose(ExchangeContext *ec, WeaveConnection *con, WEAVE_ERROR conErr) |
| { |
| DeviceControlServer *server = (DeviceControlServer *)ec->AppState; |
| |
| WeaveLogProgress(DeviceControl, "Monitored connection closed"); |
| |
| // When the underlying connection closes, discard the monitoring exchange context and cancel the interval timer. |
| server->CancelMonitorTimer(ec); |
| ec->Close(); |
| } |
| |
| void DeviceControlServer::CloseRemotePassiveRendezvous() |
| { |
| WEAVE_ERROR err; |
| |
| WeaveLogProgress(DeviceControl, "Closing RemotePassiveRendezvous."); |
| |
| // Close RPR ExchangeContext, if any. |
| if (mRemotePassiveRendezvousOp != NULL) |
| { |
| mRemotePassiveRendezvousOp->Close(); |
| mRemotePassiveRendezvousOp = NULL; |
| } |
| |
| // Close open RPR connections or tunnel, if any. |
| if (mRemotePassiveRendezvousJoinerCon != NULL) |
| { |
| if (mRemotePassiveRendezvousJoinerCon->Close() != WEAVE_NO_ERROR) |
| mRemotePassiveRendezvousJoinerCon->Abort(); |
| |
| mRemotePassiveRendezvousJoinerCon = NULL; |
| } |
| |
| if (mRemotePassiveRendezvousClientCon != NULL) |
| { |
| if (mRemotePassiveRendezvousClientCon->Close() != WEAVE_NO_ERROR) |
| mRemotePassiveRendezvousClientCon->Abort(); |
| |
| mRemotePassiveRendezvousClientCon = NULL; |
| } |
| |
| if (mRemotePassiveRendezvousTunnel != NULL) |
| { |
| mRemotePassiveRendezvousTunnel->Shutdown(); |
| mRemotePassiveRendezvousTunnel = NULL; |
| } |
| |
| // Let the application know to clean up state set when we started the Remote Passive Rendezvous, |
| // e.g. making 15.4 networks joinable. |
| if (mDelegate != NULL) |
| { |
| mDelegate->WillCloseRemotePassiveRendezvous(); |
| } |
| |
| if (ExchangeMgr && ExchangeMgr->MessageLayer) |
| { |
| // Cancel our unsecured listen, if enabled. |
| err = ExchangeMgr->MessageLayer->ClearUnsecuredConnectionListener(HandleConnectionReceived, |
| HandleUnsecuredConnectionCallbackRemoved); |
| if (err != WEAVE_NO_ERROR) |
| WeaveLogProgress(DeviceControl, "ClearUnsecuredConnectionListener failed, err = %d", err); |
| |
| if (ExchangeMgr->MessageLayer->SystemLayer) |
| { |
| // Cancel rendezvous timeout. |
| ExchangeMgr->MessageLayer->SystemLayer->CancelTimer(HandleRemotePassiveRendezvousTimeout, this); |
| } |
| } |
| |
| // Notify delegate that we're done with the Remote Passive Rendezvous. |
| if (mDelegate != NULL) |
| mDelegate->OnRemotePassiveRendezvousDone(); |
| } |
| |
| void DeviceControlServer::HandleRemotePassiveRendezvousConnectionClosed(ExchangeContext *ec, WeaveConnection *con, |
| WEAVE_ERROR conErr) |
| { |
| DeviceControlServer *server = (DeviceControlServer *)ec->AppState; |
| |
| WeaveLogProgress(DeviceControl, "RemotePassiveRendezvous connection closed"); |
| |
| server->mRemotePassiveRendezvousClientCon = NULL; |
| server->CloseRemotePassiveRendezvous(); |
| } |
| |
| WEAVE_ERROR DeviceControlServer::CompleteRemotePassiveRendezvous(WeaveConnection *con) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| PacketBuffer *msgBuf = NULL; |
| |
| VerifyOrExit(con != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| if (mRemotePassiveRendezvousOp == NULL || mRemotePassiveRendezvousTunnel != NULL) |
| { |
| if (mRemotePassiveRendezvousOp == NULL) |
| WeaveLogError(DeviceControl, "null mRemotePassiveRendezvousOp"); |
| else |
| WeaveLogError(DeviceControl, "Tunnel already established"); |
| err = WEAVE_ERROR_INCORRECT_STATE; |
| ExitNow(); |
| } |
| |
| // Capture rendezvoused connection to joiner. |
| mRemotePassiveRendezvousJoinerCon = con; |
| con = NULL; // Set con to NULL so we don't close client-half of tunnel at exit. |
| |
| // Send RemoteConnectionComplete message to client. Expect no response, as client knows all future data it sends |
| // over this connection will be forwarded to the rendezvoused device. |
| msgBuf = PacketBuffer::NewWithAvailableSize(0); |
| VerifyOrExit(msgBuf != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| |
| // Send RemoteConnectionComplete. |
| err = mRemotePassiveRendezvousOp->SendMessage(kWeaveProfile_DeviceControl, kMsgType_RemoteConnectionComplete, |
| msgBuf, 0); |
| msgBuf = NULL; |
| SuccessOrExit(err); |
| |
| mRemotePassiveRendezvousOp->Close(); |
| mRemotePassiveRendezvousOp = NULL; |
| |
| // As we've completed the Remote Passive Rendezvous, stop listening for connections accepted on the |
| // unsecured Weave port. |
| err = ExchangeMgr->MessageLayer->ClearUnsecuredConnectionListener(HandleConnectionReceived, |
| HandleUnsecuredConnectionCallbackRemoved); |
| if (err != WEAVE_NO_ERROR) |
| WeaveLogProgress(DeviceControl, "ClearUnsecuredConnectionListener failed, err = %d", err); |
| |
| // Bind connections between Device Control client and rendezvoused device inside of WeaveMessageLayer, creating |
| // WeaveConnectionTunnel to facilitate remote provisioning. |
| WeaveLogProgress(DeviceControl, "Creating WeaveConnectionTunnnel..."); |
| |
| if (mRemotePassiveRendezvousJoinerCon == NULL || mRemotePassiveRendezvousClientCon == NULL) |
| { |
| if (mRemotePassiveRendezvousJoinerCon == NULL) |
| WeaveLogError(DeviceControl, "null RPR joiner connection"); |
| else |
| WeaveLogError(DeviceControl, "null RPR client connection"); |
| err = WEAVE_ERROR_INCORRECT_STATE; |
| ExitNow(); |
| } |
| |
| err = ExchangeMgr->MessageLayer->CreateTunnel(&mRemotePassiveRendezvousTunnel, |
| *mRemotePassiveRendezvousJoinerCon, *mRemotePassiveRendezvousClientCon, |
| secondsToMilliseconds(mTunnelInactivityTimeout)); |
| mRemotePassiveRendezvousJoinerCon = NULL; |
| mRemotePassiveRendezvousClientCon = NULL; |
| SuccessOrExit(err); |
| WeaveLogProgress(DeviceControl, "Tunnel created successfully."); |
| |
| // Hang pointer to DeviceControlServer off new WeaveConnectionTunenl for use in HandleTunnelShutdown. |
| mRemotePassiveRendezvousTunnel->AppState = this; |
| |
| // Hang callback for tunnel shutdown, i.e. full closure of underlying TCPEndPoints by WeaveMessageLayer. |
| mRemotePassiveRendezvousTunnel->OnShutdown = HandleTunnelShutdown; |
| |
| // Cancel rendezvous timeout. |
| ExchangeMgr->MessageLayer->SystemLayer->CancelTimer(HandleRemotePassiveRendezvousTimeout, this); |
| |
| exit: |
| if (msgBuf != NULL) |
| { |
| PacketBuffer::Free(msgBuf); |
| } |
| |
| if (con != NULL) |
| { |
| con->Close(); |
| } |
| |
| if (err != WEAVE_NO_ERROR) |
| { |
| WeaveLogProgress(DeviceControl, "Failed to complete Remote Passive Rendezvous, err = %d", err); |
| |
| // If anything fails during tunnel setup, kill whole Remote Passive Rendezvous interaction. |
| CloseRemotePassiveRendezvous(); |
| } |
| |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleResetConfig(uint8_t *p, WeaveConnection *curCon) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| uint16_t resetFlags = LittleEndian::Get16(p); |
| |
| if (mDelegate->IsResetAllowed(resetFlags)) |
| { |
| // If there is a connection, find out if it needs to be closed before |
| // calling the OnResetConfig delegate method. If it does, ensure the response |
| // is sent and the connection is closed before calling OnResetConfig. |
| if (curCon != NULL && mDelegate->ShouldCloseConBeforeResetConfig(resetFlags)) { |
| // We must wait until the connection successfully shuts down to perform the reset. |
| // So we cache the reset flags in mResetFlags, and register the callback so the |
| // reset will be performed. |
| mResetFlags = resetFlags; |
| |
| curCon->AppState = this; |
| curCon->OnConnectionClosed = HandleResetConfigConnectionClose; |
| |
| // Send the response that indicates the connection will close, then |
| // shut down the connection to ensure the client receives the response |
| // and closes the connection. |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_ResetSuccessCloseCon); |
| SuccessOrExit(err); |
| |
| curCon->Shutdown(); |
| } else { |
| err = mDelegate->OnResetConfig(resetFlags); |
| if (err == WEAVE_ERROR_NOT_IMPLEMENTED) |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_UnsupportedFailSafeMode); |
| ExitNow(); |
| } |
| SuccessOrExit(err); |
| |
| mFailSafeArmed = false; |
| mFailSafeToken = 0; |
| |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| } |
| } |
| else |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_ResetNotAllowed); |
| ExitNow(); |
| } |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| // Make sure we don't get stuck in a busy state. |
| mResetFlags = 0x0000; |
| } |
| |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleArmFailSafe(uint8_t *p) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| uint8_t armMode = Read8(p); |
| uint32_t failSafeToken = LittleEndian::Read32(p); |
| |
| switch (armMode) |
| { |
| case kArmMode_New: |
| if (mFailSafeArmed) |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_FailSafeAlreadyActive); |
| ExitNow(); |
| } |
| break; |
| |
| case kArmMode_Reset: |
| if (mDelegate != NULL) |
| { |
| if (mDelegate->IsResetAllowed(kResetConfigFlag_All)) |
| { |
| err = mDelegate->OnResetConfig(kResetConfigFlag_All); |
| SuccessOrExit(err); |
| } |
| else |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_ResetNotAllowed); |
| ExitNow(); |
| } |
| } |
| break; |
| |
| case kArmMode_ResumeExisting: |
| if (mFailSafeArmed) |
| { |
| if (failSafeToken != mFailSafeToken) |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_NoMatchingFailSafeActive); |
| } |
| else |
| { |
| err = SendSuccessResponse(); |
| } |
| ExitNow(); |
| } |
| break; |
| |
| default: |
| SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_UnsupportedFailSafeMode); |
| ExitNow(); |
| break; |
| } |
| |
| mFailSafeArmed = true; |
| mFailSafeToken = failSafeToken; |
| |
| if (mDelegate != NULL) |
| { |
| err = mDelegate->OnFailSafeArmed(); |
| SuccessOrExit(err); |
| } |
| |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleDisarmFailSafe() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| if (!mFailSafeArmed) |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_NoFailSafeActive); |
| ExitNow(); |
| } |
| |
| mFailSafeArmed = false; |
| mFailSafeToken = 0; |
| |
| if (mDelegate != NULL) |
| { |
| err = mDelegate->OnFailSafeDisarmed(); |
| SuccessOrExit(err); |
| } |
| |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleEnableConnectionMonitor(uint8_t *p, const WeaveMessageInfo *msgInfo, |
| ExchangeContext *ec) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| // Parse the monitoring interval and timeout from the message. |
| uint16_t idleTimeout = LittleEndian::Read16(p); |
| uint16_t monitorInterval = LittleEndian::Read16(p); |
| |
| err = SetConnectionMonitor(msgInfo->SourceNodeId, ec->Con, idleTimeout, monitorInterval); |
| SuccessOrExit(err); |
| |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleDisableConnectionMonitor(const WeaveMessageInfo *msgInfo, |
| ExchangeContext *ec) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| err = SetConnectionMonitor(msgInfo->SourceNodeId, ec->Con, 0, 0); |
| SuccessOrExit(err); |
| |
| err = SendSuccessResponse(); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleRemotePassiveRendezvous(uint8_t *p, ExchangeContext *ec) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| // Fail if we're already listening for a renendezvous connection on behalf of another client, or if we're |
| // currently monitoring an active tunnel. |
| if (IsRemotePassiveRendezvousInProgress()) |
| { |
| WeaveLogProgress(DeviceControl, "RemotePassiveRendezvous already in progress, sending busy status reply"); |
| err = SendStatusReport(kWeaveProfile_Common, Common::kStatus_Busy); |
| ExitNow(); |
| } |
| |
| // RPR request's ExchangeContext must have an open WeaveConnection. |
| if (ec->Con == NULL) |
| { |
| WeaveLogProgress(DeviceControl, "RemotePassiveRendezvous requires WeaveConnection"); |
| err = SendStatusReport(kWeaveProfile_Common, Common::kStatus_UnexpectedMessage); |
| ExitNow(); |
| } |
| |
| // Clear mCurClientOp. We eventually close the referenced exchange as mRemotePassiveRendezvousOp. |
| mCurClientOp = NULL; |
| |
| // Capture connection over which this message was received. |
| mRemotePassiveRendezvousClientCon = ec->Con; |
| |
| // Capture ExchangeContext over which to eventually send RemoteConnectionComplete. |
| mRemotePassiveRendezvousOp = ec; |
| ec->OnConnectionClosed = HandleRemotePassiveRendezvousConnectionClosed; |
| |
| // Parse Remote Passive Rendezvous request body. |
| WeaveLogProgress(DeviceControl, "Parsing RPR request"); |
| mRemotePassiveRendezvousTimeout = LittleEndian::Read16(p); |
| mTunnelInactivityTimeout = LittleEndian::Read16(p); |
| |
| // Decode joiner filter address. |
| IPAddress::ReadAddress(p, mRemotePassiveRendezvousJoinerAddr); |
| |
| WeaveLogProgress(DeviceControl, "Got rendezvous timeout = %d, inactivity timeout = %d", |
| mRemotePassiveRendezvousTimeout, mTunnelInactivityTimeout); |
| |
| // Arm timer to reset our connection to the client if no rendezvous connection has been accepted after |
| // a client-specified interval. |
| err = ArmRemotePassiveRendezvousTimer(); |
| SuccessOrExit(err); |
| |
| // Set up callback to intercept new connections received on the unsecured Weave port. Fail if someone else |
| // such as the Device Manager has already set this callback. |
| err = ExchangeMgr->MessageLayer->SetUnsecuredConnectionListener(HandleConnectionReceived, |
| HandleUnsecuredConnectionCallbackRemoved, false, this); |
| SuccessOrExit(err); |
| |
| if (mDelegate != NULL) |
| { |
| // Let delegate know to set up any state required for Remote Passive Rendezvous, e.g. making 15.4 |
| // networks joinable. |
| mDelegate->WillStartRemotePassiveRendezvous(); |
| SuccessOrExit(err); |
| } |
| |
| err = WeaveServerBase::SendStatusReport(ec, kWeaveProfile_Common, Common::kStatus_Success, WEAVE_NO_ERROR); |
| SuccessOrExit(err); |
| |
| // Inform delegate that we've started the Remote Passive Rendezvous. |
| if (mDelegate != NULL) |
| mDelegate->OnRemotePassiveRendezvousStarted(); |
| |
| exit: |
| if (err != WEAVE_NO_ERROR) |
| { |
| WeaveLogError(DeviceControl, "HandleRemotePassiveRendezvousFailed, err = %d", err); |
| |
| // If we nulled mCurClientOp earlier in this function, we started a new RPR which we now must close. |
| // If we failed at IsRemotePassiveRendezvousInProgress(), mCurClientOp will not be NULL, and we must |
| // NOT close the RPR already in progress. |
| if (mCurClientOp == NULL) |
| { |
| CloseRemotePassiveRendezvous(); |
| } |
| } |
| |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleStartSystemTest(uint8_t *p) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| uint32_t profileId = LittleEndian::Read32(p); |
| uint32_t testId = LittleEndian::Read32(p); |
| |
| if (mDelegate != NULL) |
| { |
| err = mDelegate->OnSystemTestStarted(profileId, testId); |
| } |
| else |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_NoSystemTestDelegate); |
| } |
| |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleStopSystemTest() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| if (mDelegate != NULL) |
| { |
| err = mDelegate->OnSystemTestStopped(); |
| } |
| else |
| { |
| err = SendStatusReport(kWeaveProfile_DeviceControl, kStatusCode_NoSystemTestDelegate); |
| } |
| |
| return err; |
| } |
| |
| WEAVE_ERROR DeviceControlServer::HandleLookingToRendezvousMessage(const WeaveMessageInfo *msgInfo, ExchangeContext *ec) |
| { |
| WEAVE_ERROR err = WEAVE_ERROR_INCORRECT_STATE; |
| System::Layer* lSystemLayer = ExchangeMgr->MessageLayer->SystemLayer; |
| |
| // We are going to be dealing with the connection closing here rather than in the timer close |
| lSystemLayer->CancelTimer(HandleLookingToRendezvousTimeout, ec->Con); |
| |
| // LookingToRendezvous message is not authenticated |
| // but we only pay attention to it while: |
| if (IsRemotePassiveRendezvousInProgress() && // in remote passive rendezvous |
| (mRemotePassiveRendezvousJoinerCon == NULL) && // and before we completed the tunnel |
| (ec->Con != NULL) && // and it has an associated connection |
| (ec->Con != mRemotePassiveRendezvousClientCon)) // sanity: the request did not come from the client |
| { |
| // && of course, we actually match the RPR joiner address |
| if (mRemotePassiveRendezvousJoinerAddr == nl::Inet::IPAddress::MakeLLA(WeaveNodeIdToIPv6InterfaceId(msgInfo->SourceNodeId))) |
| { |
| WeaveLogProgress(DeviceControl, "LookingToRendezvous successfully matched client filter"); |
| err = CompleteRemotePassiveRendezvous(ec->Con); |
| SuccessOrExit(err); |
| |
| ec->Close(); |
| ec = NULL; |
| } |
| else |
| { |
| #if WEAVE_DETAIL_LOGGING |
| char joinerAddr[INET6_ADDRSTRLEN] = { 0 }; |
| mRemotePassiveRendezvousJoinerAddr.ToString(joinerAddr, sizeof(joinerAddr)); |
| WeaveLogProgress(DeviceControl, "LookingToRendezvous failed filter: Joiner node id: %" PRIX64 " expected address %s", msgInfo->SourceNodeId, joinerAddr); |
| #else |
| WeaveLogProgress(DeviceControl, "LookingToRendezvous failed to matched client filter"); |
| #endif |
| } |
| } |
| else |
| { |
| WeaveLogProgress(DeviceControl, "LookingToRendezvous message received in unexpected state"); |
| } |
| |
| exit: |
| if (ec != NULL) |
| { |
| if ((err != WEAVE_NO_ERROR) && (ec->Con != NULL)) |
| { |
| ec->Con->Close(); |
| } |
| ec->Close(); |
| } |
| |
| return err; |
| } |
| |
| |
| void DeviceControlServer::HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| DeviceControlServer *server = sRemotePassiveRendezvousServer; |
| |
| VerifyOrExit(server->mRemotePassiveRendezvousJoinerCon == NULL, err = WEAVE_ERROR_INCORRECT_STATE); |
| |
| // Steal new connection received on the unsecured Weave port. |
| if (server->mRemotePassiveRendezvousJoinerAddr != IPAddress::Any) |
| { |
| if (server->mRemotePassiveRendezvousJoinerAddr == con->PeerAddr) |
| { |
| WeaveLogProgress(DeviceControl, "Remote device addr successfully matched client filter"); |
| err = server->CompleteRemotePassiveRendezvous(con); |
| con = NULL; // Downstack call transfers responsibility for WeaveConnection object. |
| SuccessOrExit(err); |
| } |
| else |
| { |
| System::Layer* lSystemLayer = server->ExchangeMgr->MessageLayer->SystemLayer; |
| |
| WeaveLogProgress(DeviceControl, "Remote device addr failed to match client filter"); |
| WeaveLogProgress(DeviceControl, "Awaiting looking to rendezvous message"); |
| server->ExchangeMgr->AllowUnsolicitedMessages(con); |
| err = lSystemLayer->StartTimer(secondsToMilliseconds(server->mTunnelInactivityTimeout), HandleLookingToRendezvousTimeout, con); |
| SuccessOrExit(err); |
| con = NULL; |
| } |
| } |
| else |
| { |
| // If we're not filtering rendezvoused devices, immediately complete Remote Passive Rendezvous |
| // connection. |
| err = server->CompleteRemotePassiveRendezvous(con); |
| con = NULL; // Downstack call transfers responsibility for WeaveConnection object. |
| SuccessOrExit(err); |
| } |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && con != NULL) |
| { |
| // Close connection. |
| con->Close(); |
| } |
| } |
| |
| void DeviceControlServer::HandleLookingToRendezvousTimeout(System::Layer* aSystemLayer, void* aAppState, System::Error aError) |
| { |
| WeaveConnection * con = static_cast<WeaveConnection *>(aAppState); |
| DeviceControlServer *_this = sRemotePassiveRendezvousServer; |
| |
| if (con != _this->mRemotePassiveRendezvousJoinerCon) |
| { |
| WeaveLogProgress(DeviceControl, "Failed to receive a matching LookingToRendezvous message"); |
| con->Close(); |
| } |
| } |
| |
| /** |
| * Send a LookingToRendezvous message to the peer. |
| * |
| * @param[in] ec ExchangeContext to use to send the message |
| * |
| * @retval #WEAVE_NO_ERROR On success. |
| * |
| * @retval #WEAVE_ERROR_NO_MEMORY If we could not allocate a buffer for the message. |
| * |
| * @retval other Other errors returned by nl::Weave::ExchangeContext::SendMessage |
| */ |
| WEAVE_ERROR SendLookingToRendezvous(ExchangeContext *ec) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| PacketBuffer *buf = NULL; |
| |
| buf = PacketBuffer::NewWithAvailableSize(0); |
| VerifyOrExit(buf != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| |
| err = ec->SendMessage(kWeaveProfile_DeviceControl, kMsgType_LookingToRendezvous, buf); |
| buf = NULL; |
| |
| exit: |
| if (buf == NULL) |
| { |
| PacketBuffer::Free(buf); |
| } |
| return err; |
| } |
| |
| void DeviceControlServer::HandleUnsecuredConnectionCallbackRemoved(void *appState) |
| { |
| WeaveLogProgress(DeviceControl, "OnUnsecuredConnectionReceived callback pre-empted"); |
| |
| DeviceControlServer *server = static_cast<DeviceControlServer *>(appState); |
| |
| server->WeaveServerBase::SendStatusReport(server->mRemotePassiveRendezvousOp, kWeaveProfile_DeviceControl, |
| kStatusCode_UnsecuredListenPreempted, WEAVE_NO_ERROR); |
| |
| server->CloseRemotePassiveRendezvous(); |
| } |
| |
| void DeviceControlServer::HandleRemotePassiveRendezvousTimeout(System::Layer* aSystemLayer, void* aAppState, System::Error aError) |
| { |
| DeviceControlServer* server = reinterpret_cast<DeviceControlServer*>(aAppState); |
| WeaveLogProgress(DeviceControl, "Remote Passive Rendezvous timed out"); |
| |
| server->WeaveServerBase::SendStatusReport(server->mRemotePassiveRendezvousOp, kWeaveProfile_DeviceControl, |
| kStatusCode_RemotePassiveRendezvousTimedOut, WEAVE_NO_ERROR); |
| |
| // Close Remote Passive Rendezvous, but leave connection open for additional messages from client. |
| server->mRemotePassiveRendezvousClientCon = NULL; |
| server->CloseRemotePassiveRendezvous(); |
| } |
| |
| WEAVE_ERROR DeviceControlServer::ArmRemotePassiveRendezvousTimer() |
| { |
| System::Layer* lSystemLayer = ExchangeMgr->MessageLayer->SystemLayer; |
| uint32_t mRemotePassiveRendezvousTimeoutMs = |
| static_cast<uint32_t>(secondsToMilliseconds(mRemotePassiveRendezvousTimeout)); |
| |
| WeaveLogProgress(DeviceControl, "Arming Remote Passive Rendezvous timer %lu ms", |
| static_cast<unsigned long>(mRemotePassiveRendezvousTimeoutMs)); |
| |
| return lSystemLayer->StartTimer(mRemotePassiveRendezvousTimeoutMs, HandleRemotePassiveRendezvousTimeout, this); |
| } |
| |
| void DeviceControlServer::HandleTunnelShutdown(WeaveConnectionTunnel *tun) |
| { |
| WeaveLogProgress(DeviceControl, "Remote Passive Rendezvous tunnel shut down."); |
| DeviceControlServer *server = (DeviceControlServer *)tun->AppState; |
| |
| if (tun != server->mRemotePassiveRendezvousTunnel) |
| return; |
| |
| // Avoid double-shutdown. |
| server->mRemotePassiveRendezvousTunnel = NULL; |
| |
| server->CloseRemotePassiveRendezvous(); |
| } |
| |
| void DeviceControlDelegate::EnforceAccessControl(ExchangeContext *ec, uint32_t msgProfileId, uint8_t msgType, |
| const WeaveMessageInfo *msgInfo, AccessControlResult& result) |
| { |
| // If the result has not already been determined by a subclass... |
| if (result == kAccessControlResult_NotDetermined) |
| { |
| WeaveAuthMode authMode = msgInfo->PeerAuthMode; |
| |
| switch (msgType) |
| { |
| #if WEAVE_CONFIG_REQUIRE_AUTH_DEVICE_CONTROL |
| |
| case kMsgType_ResetConfig: |
| case kMsgType_ArmFailSafe: |
| if (authMode == kWeaveAuthMode_CASE_AccessToken || |
| (authMode == kWeaveAuthMode_PASE_PairingCode && !IsPairedToAccount())) |
| { |
| result = kAccessControlResult_Accepted; |
| } |
| break; |
| |
| case kMsgType_DisarmFailSafe: |
| case kMsgType_EnableConnectionMonitor: |
| case kMsgType_DisableConnectionMonitor: |
| if (authMode == kWeaveAuthMode_CASE_AccessToken || authMode == kWeaveAuthMode_PASE_PairingCode) |
| { |
| result = kAccessControlResult_Accepted; |
| } |
| break; |
| |
| case kMsgType_RemotePassiveRendezvous: |
| case kMsgType_StartSystemTest: |
| case kMsgType_StopSystemTest: |
| if (authMode == kWeaveAuthMode_CASE_AccessToken) |
| { |
| result = kAccessControlResult_Accepted; |
| } |
| break; |
| |
| #else // WEAVE_CONFIG_REQUIRE_AUTH_DEVICE_CONTROL |
| |
| case kMsgType_ResetConfig: |
| case kMsgType_ArmFailSafe: |
| case kMsgType_DisarmFailSafe: |
| case kMsgType_EnableConnectionMonitor: |
| case kMsgType_DisableConnectionMonitor: |
| case kMsgType_RemotePassiveRendezvous: |
| case kMsgType_StartSystemTest: |
| case kMsgType_StopSystemTest: |
| result = kAccessControlResult_Accepted; |
| break; |
| |
| #endif // WEAVE_CONFIG_REQUIRE_AUTH_DEVICE_CONTROL |
| |
| case kMsgType_LookingToRendezvous: |
| if (authMode == kWeaveAuthMode_None) |
| { |
| result = kAccessControlResult_Accepted; |
| } |
| else |
| { |
| WeaveServerBase::SendStatusReport(ec, kWeaveProfile_Common, Common::kStatus_BadRequest, WEAVE_NO_ERROR); |
| result = kAccessControlResult_Rejected_RespSent; |
| } |
| break; |
| |
| default: |
| WeaveServerBase::SendStatusReport(ec, kWeaveProfile_Common, Common::kStatus_UnsupportedMessage, WEAVE_NO_ERROR); |
| result = kAccessControlResult_Rejected_RespSent; |
| break; |
| } |
| } |
| |
| // Call up to the base class. |
| WeaveServerDelegateBase::EnforceAccessControl(ec, msgProfileId, msgType, msgInfo, result); |
| } |
| |
| // TODO: eliminate this method when device code provides appropriate implementations. |
| bool DeviceControlDelegate::IsPairedToAccount() const |
| { |
| return false; |
| } |
| |
| } // namespace DeviceControl |
| } // namespace Profiles |
| } // namespace Weave |
| } // namespace nl |