blob: 6b81304740a5fc5c1de79083fcae6225fcc13c30 [file] [log] [blame]
/*
*
* Copyright (c) 2015-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 defines API's and platform abstractions
* for Nest Labs' Weave Address and Routing Module (WARM).
*
* \page Weave Address Assignment
* \section intro Introduction:
* Because there are a number of inter-dependencies between interfaces and because
* different Device configurations can require different TCP/IP address and route
* assignment, it was deemed essential that the logic for controlling IP address
* and Route assignment be consolidated into a single module. WARM serves the purpose
* of properly adding and removing TCP/IP addresses and Routes to Weave related IP interfaces
* as those interfaces transition from active<->inactive.
*
* WARM is intended to be configured at compile time via WarmProjectConfig.h and WarmConfig.h.
* WarmProjectConfig.h must accurately reflect the supported features of the device upon which
* WARM will execute.
*
* WARM is a portable module that limits its dependency on how a TCP/IP stack and Thread Interface
* are configured. For this purpose WARM relies on a Set of Platform API's which
* must be implemented by the Platform Integrator. Furthermore, the Platform Integrator is
* responsible for making the various nl::Warm API calls from appropriate execution points within
* the Platform code base.
*
* \section theory Theory of Operation:
* The Platform code base will call nl::Warm API's to announce a change of State for related
* features such as the WiFi interface and Thread interface. A call to any of these nl::Warm API's
* may result in a call by WARM to Platform::RequestInvokeActions(). Platform::RequestInvokeActions()
* must be implemented to perform the necessary operations that will call Warm::InvokeActions(). This
* process at first glance may appear un-necessarily indirect. Why wouldn't WARM call InvokeActions
* directly? The answer to that question, is to allow for any task in a multi-tasking system to call
* the nl::Warm State Change API's, and to provide a mechanism so that only a specific task will call
* the Platform:: API's. After taking the Platform requirements into consideration, the Platform
* Integrator may choose to implement Platform::RequestInvokeActions() so that it posts an event to
* the appropriate task that will react by calling Warm::InvokeActions(). If, for a given platform, it is
* decided that no such multi-tasking concerns exist, Platform::RequestInvokeActions() can be implemented
* to call Warm::InvokeActions() directly.
*
* When Warm::InvokeActions() is called the WARM logic will examine the current System State and
* make any necessary Platform:: API calls in order to bring the address and routing State in line
* with the System and Configuration State. These calls are made in a pre-defined order and if any of these API's
* return kPlatformResultInProgress, execution of the ordered list will suspend and exit. Furthermore, when
* one of these API's returns kPlatformResultInProgress, it is interpreted that the operation
* will complete asynchronously and that the WARM logic should wait for that operation to complete.
* Upon operation completion, the Platform code should call Warm::ReportActionComplete(), passing in a
* result of kPlatformResultSuccess or kPlatformResultFailure. Upon receiving this call the WARM
* logic will again call Platform::RequestInvokeActions() in order to restart execution of the
* ordered action list.
*
* In this way WARM does not require its own task but can instead rely on another task to call into Warm
* as appropriate. Additionally, any task may call one or more of the System State change API's, thus
* simplifying integration.
*
*/
#ifndef WARM_H_
#define WARM_H_
#include <Warm/WarmConfig.h>
#include <InetLayer/IPAddress.h>
#include <InetLayer/IPPrefix.h>
#include <Weave/Core/WeaveCore.h>
#if WARM_CONFIG_SUPPORT_WEAVE_TUNNEL
#include <Weave/Profiles/weave-tunneling/WeaveTunnelAgent.h>
#endif
using namespace nl::Weave;
/**
* @namespace nl::Weave::Warm
*
* @brief
* This namespace includes interfaces for the Weave Address and Routing Module, a
* portable Module for configuring Weave IP addresses and Routes.
*/
namespace nl {
namespace Weave {
namespace Warm {
/**
* An enum of possible platform API return values.
*
*/
typedef enum {
kPlatformResultSuccess = 0, // The API completed successfully.
kPlatformResultFailure, // The API execution failed.
kPlatformResultInProgress // The operation is in-progress and will complete asynchronously.
} PlatformResult;
/**
* An enum of possible interface types.
*
* @note
* Do not change the elements in this enum as it is used as an index into arrays.
* Products will typically support a subset of these possible interfaces.
*
*/
typedef enum {
kInterfaceTypeLegacy6LoWPAN = 0, // Thread alarm interface.
kInterfaceTypeThread, // Thread interface.
kInterfaceTypeWiFi, // The WiFi interface.
kInterfaceTypeTunnel, // The Tunnel interface.
kInterfaceTypeCellular, // The Cellular interface.
kInterfaceTypeMax
} InterfaceType;
/**
* An enum of possible route priorities so that one route can be given priority over another.
*
*/
typedef enum {
kRoutePriorityLow = 0,
kRoutePriorityMedium,
kRoutePriorityHigh
} RoutePriority;
/**
* An enum of possible Interface State values.
*
*/
typedef enum {
kInterfaceStateUp = true,
kInterfaceStateDown = false
} InterfaceState;
/**
* @class WarmFabricStateDelegate
*
* @brief
* This is an internal class to WarmCore. It implements the FabricStateDelegate interface.
* An instance of this class (namely sWarmFabricStateDelegate), is set as the delegate of
* WeaveFabricState. Warm uses this to be notified of Fabric state changes.
*/
class WarmFabricStateDelegate
: public FabricStateDelegate
{
public:
/**
* This method is invoked by WeaveFabricState when joining/creating a new fabric.
*
* @param[in] fabricState The WeaveFabricState which is changed
* @param[in] newFabricId The new fabric id
*
* @return none.
*/
virtual void DidJoinFabric(WeaveFabricState *fabricState, uint64_t newFabricId);
/**
* This method is invoked by WeaveFabricState when leaving/clearing a fabric.
*
* @param[in] fabricState The WeaveFabricState which is changed
* @param[in] oldFabricId The old/previous fabric id
*
* @return none.
*/
virtual void DidLeaveFabric(WeaveFabricState *fabricState, uint64_t oldFabricId);
};
/**
* @namespace nl::Warm::Platform
*
* @brief
* This namespace includes all interfaces within Warm. Functions in this
* namespace are to be implemented by platforms that use Warm,
* according to the needs/constraints of the particular environment.
*
*/
namespace Platform {
/**
* A platform API that Warm will call as part of nl::Warm::Init execution.
*
* @note
* Any Platform specific initialization for Warm should be performed by this function.
* Initializing an object to support CriticalSectionEnter is one expected action of this API.
*
* @param[in] inFabricStateDelegate A pointer to the fabricStateDelegate object used by Warm
* to receive updates for the fabric state.
*
* @return WEAVE_NO_ERROR on success, error code otherwise.
*
*/
extern WEAVE_ERROR Init(WarmFabricStateDelegate *inFabricStateDelegate);
/**
* A platform API that Warm will call to protect access to internal State.
*
* @note
* Compliments CriticalSectionExit.
* If all Warm execution occurs in a single Task context this API can be stubbed.
*
* @return none.
*
*/
extern void CriticalSectionEnter(void);
/**
* A platform API that Warm will call to release protected access to internal State.
*
* @note
* Compliments CriticalSectionEnter.
* If all Warm execution occurs in a single Task context this API can be stubbed.
*
* @return none.
*
*/
extern void CriticalSectionExit(void);
/**
* A platform API that Warm will call to announce that the platform should call InvokeActions.
*
* @note
* In order to allow Platform API's to be called from a dedicated task, Warm will call this
* API when it desires the Platform to call InvokeActions. If no multi-task concerns exist,
* the Platform can call InvokeActions directly.
*
* @return none.
*
*/
extern void RequestInvokeActions(void);
/**
* A platform API that Warm will call to add / remove a host IP address to the specified interface on the Host TCP/IP stack.
*
* @note
* This function must be able to acquire access to the specified interface.
*
* @param[in] inInterfaceType The Interface to be modified.
*
* @param[in] inAddress The IP address to be added/removed.
*
* @param[in] inPrefixLength The Prefix length of the inAddress.
*
* @param[in] inAdd true to add the address, false to remove the address.
*
* @return kPlatformResultSuccess - If the operation completed successfully.
* @return kPlatformResultFailure - If the operation failed.
* @return kPlatformResultInProgress - If the operation will complete asynchronously.
* The platform must then call ReportActionComplete with the final result.
*
*/
extern PlatformResult AddRemoveHostAddress (InterfaceType inInterfaceType, const Inet::IPAddress &inAddress, uint8_t inPrefixLength, bool inAdd);
/**
* A platform API that Warm will call to add / remove a IP address to the specified interface on the Thread TCP/IP stack.
*
* @note
* This function must be able to acquire access to the specified interface.
*
* @param[in] inInterfaceType The Interface to be modified.
*
* @param[in] inAddress The IP address to be added/removed.
*
* @param[in] inPrefixLength The Prefix length of the inAddress.
*
* @param[in] inAdd true to add the address, false to remove the address.
*
* @return kPlatformResultSuccess - If the operation completed successfully.
* @return kPlatformResultFailure - If the operation failed.
* @return kPlatformResultInProgress - If the operation will complete asynchronously.
* The platform must then call ReportActionComplete with the final result.
*
*/
extern PlatformResult AddRemoveThreadAddress (InterfaceType inInterfaceType, const Inet::IPAddress &inAddress, bool inAdd);
/**
* A platform API that Warm will call to start / stop advertisement of a IP prefix on the Thread interface.
*
* @note
* This function must be able to acquire access to the specified interface.
*
* @param[in] inInterfaceType The Interface to be modified.
*
* @param[in] inPrefix The IP prefix for which advertising should be started / stopped.
*
* @param[in] inStart true to start advertising, false to stop advertising.
*
* @return kPlatformResultSuccess - If the operation completed successfully.
* @return kPlatformResultFailure - If the operation failed.
* @return kPlatformResultInProgress - If the operation will complete asynchronously.
* The platform must then call ReportActionComplete with the final result.
*
*/
extern PlatformResult StartStopThreadAdvertisement (InterfaceType inInterfaceType, const Inet::IPPrefix &inPrefix, bool inStart);
/**
* A platform API that Warm will call to add / remove a IP route for the specified interface on the host TCP/IP stack.
*
* @note
* This function must be able to acquire access to the specified interface.
*
* @param[in] inInterfaceType The Interface to be modified.
*
* @param[in] inPrefix The IP prefix to add / remove.
*
* @param[in] inPriority The priority to use when the route is assigned.
*
* @param[in] inAdd true to add the prefix as a route, false to remove the prefix as a route.
*
* @return kPlatformResultSuccess - If the operation completed successfully.
* @return kPlatformResultFailure - If the operation failed.
* @return kPlatformResultInProgress - If the operation will complete asynchronously.
* The platform must then call ReportActionComplete with the final result.
*
*/
extern PlatformResult AddRemoveHostRoute (InterfaceType inInterfaceType, const Inet::IPPrefix &inPrefix, RoutePriority inPriority, bool inAdd);
/**
* A platform API that Warm will call to add / remove a IP route for the specified interface on the Thread TCP/IP stack.
*
* @note
* This function must be able to acquire access to the specified interface.
*
* @param[in] inInterfaceType The Interface to be modified.
*
* @param[in] inPrefix The IP prefix to assign / remove.
*
* @param[in] inPriority The priority to use when the route is assigned.
*
* @param[in] inAdd true to add the prefix as a route, false to remove the prefix as a route.
*
* @return kPlatformResultSuccess - If the operation completed successfully.
* @return kPlatformResultFailure - If the operation failed.
* @return kPlatformResultInProgress - If the operation will complete asynchronously.
* The platform must then call ReportActionComplete with the final result.
*/
extern PlatformResult AddRemoveThreadRoute (InterfaceType inInterfaceType, const Inet::IPPrefix &inPrefix, RoutePriority inPriority, bool inAdd);
/**
* A platform API that Warm will call to change the priority of an existing IP route for the specified interface on the Thread TCP/IP stack.
*
* @note
* This function must be able to acquire access to the specified interface.
*
* @param[in] inInterfaceType The Interface to be modified.
*
* @param[in] inPrefix The IP prefix to modify.
*
* @param[in] inPriority The new priority to apply to the route.
*
* @return kPlatformResultSuccess - If the operation completed successfully.
* @return kPlatformResultFailure - If the operation failed.
* @return kPlatformResultInProgress - If the operation will complete asynchronously.
* The platform must then call ReportActionComplete with the final result.
*
*/
extern PlatformResult SetThreadRoutePriority (InterfaceType inInterfaceType, const Inet::IPPrefix &inPrefix, RoutePriority inPriority);
}; // namespace Platform
/**
* A WARM API to perform one time module initialization.
*
* @note
* It must be called prior to any other nl::Warm API calls.
*
* @param[in] inFabricState A reference to a valid WeaveFabricState.
*
* @return WEAVE_NO_ERROR on success, error code otherwise.
*
*/
WEAVE_ERROR Init(WeaveFabricState &inFabricState);
/**
* A WARM API called by a dedicated task to perform various platform API actions.
*
* @brief
* This represents the entry point to perform the actions necessary which will satisfy
* the current System State. If for example the Thread stack transitioned from
* disabled to enabled, then this function would make the necessary platform calls
* to assign the thread host address etc. This function should be called by platform
* code only in response to a Warm call to RequestInvokeActions. Calling InvokeActions
* will result in one or more calls to nl::Warm::Platform API's.
* Developers should therefore implement RequestInvokeActions and the caller of
* InvokeActions() appropriately. It might be appropriate for RequestInvokeActions to post
* an event to the task which would call InvokeActions() for example. Conversely, if the system
* is single threaded, then RequestInvokeActions could be implemented to call InvokeActions()
* directly. See this documentation \ref warmpage1 for more information.
*
* @return none.
*
*/
void InvokeActions(void);
/**
* A WARM API called to announce the completion of a previous asynchronous platform API call.
*
* @brief
* It is assumed that platform action API's may need to perform asynchronous operations.
* If this is true then the platform API will return kPlatformResultInProgress.
* When this happens new Address and Routing Actions will be suspended until the system
* calls ReportActionComplete to announce the completion of the operation.
*
* @param[in] inResult The result of the pending action. must be one of: {kPlatformResultSuccess | kPlatformResultFailure}
*
* @return none.
*
*/
void ReportActionComplete(PlatformResult inResult);
/**
* A WARM API called to announce a State change for the WiFi interface.
*
* @note
* Platform code should call this function when the WiFi interface transitions between up <-> down.
* If this call results in a change of State WARM will call RequestInvokeActions.
*
* @param[in] inState kInterfaceStateUp if the WiFi interface is up, kInterfaceStateDown otherwise.
*
* @return none.
*
*/
void WiFiInterfaceStateChange(InterfaceState inState);
/**
* A WARM API called to announce a State change for the Thread interface.
*
* @note
* Platform code should call this function when the Thread interface transitions between up <-> down.
* If this call results in a change of State WARM will call RequestInvokeActions.
*
* @param[in] inState kInterfaceStateUp if the Thread interface is up, kInterfaceStateDown otherwise.
*
* @return none.
*
*/
void ThreadInterfaceStateChange(InterfaceState inState);
/**
* A WARM API called to announce a State change for the Cellular interface.
*
* @note
* Platform code should call this function when the Cellular interface transitions between up <-> down.
* If this call results in a change of State WARM will call RequestInvokeActions.
*
* @param[in] inState kInterfaceStateUp if the Cellular interface is up, kInterfaceStateDown otherwise.
*
* @return none.
*
*/
void CellularInterfaceStateChange(InterfaceState inState);
/**
* A WARM API called to announce a State change for the Thread Routing feature.
*
* @note
* Platform code should call this function when the ThreadRouting feature transitions between active <-> deactive.
* If this call results in a change of State WARM will call RequestInvokeActions.
*
* @param[in] inState kInterfaceStateUp if the Thread routing feature is up, kInterfaceStateDown otherwise.
*
* @return none.
*
*/
void ThreadRoutingStateChange(InterfaceState inState);
/**
* A WARM API called to announce a State change for the Border router feature.
*
* @note
* Platform code should call this when the Border Routing feature transitions between active <-> deactive.
* If this call results in a change of State WARM will call RequestInvokeActions.
*
* @param[in] inState kInterfaceStateUp if the Border router feature is up, kInterfaceStateDown otherwise.
*
* @return none.
*
*/
void BorderRouterStateChange(InterfaceState inState);
/**
* A WARM API to acquire a ULA for a specified interface type.
*
* @note
* Platform code should call this only after WARM has been initialized. Calling this API
* prior to initialization will result in an error.
*
* @param[in] inInterfaceType The type of interface for which a ULA is desired.
*
* @param[out] outAddress An address object used to hold the resulting ULA.
*
* @return WEAVE_NO_ERROR - On success.
* WEAVE_ERROR_INCORRECT_STATE - If this API is called while WARM is
* not a member of a Fabric.
* WEAVE_ERROR_INVALID_ARGUMENT - If this API is called with an invalid Interface Type.
*
*/
WEAVE_ERROR GetULA(InterfaceType inInterfaceType, Inet::IPAddress &outAddress);
/**
* A WARM API to acquire the FabricState object that was provided to Warm during Init.
*
* @note
* Platform code should call this only after WARM has been initialized. Calling this API
* prior to initialization will result in an error.
*
* @param[out] outFabricState A pointer reference to a fabricState object.
*
* @return WEAVE_NO_ERROR - On success.
* WEAVE_ERROR_INCORRECT_STATE - If this API is called before WARM
* has been initialized.
*
*/
WEAVE_ERROR GetFabricState(const WeaveFabricState *&outFabricState);
} /* namespace Warm */
} /* namespace Weave */
} /* namespace nl */
#endif /* WARM_H_ */