diff --git a/etc/visual-studio/openthread.sln b/etc/visual-studio/openthread.sln index 9b5a1cdce..bb79d12d3 100644 --- a/etc/visual-studio/openthread.sln +++ b/etc/visual-studio/openthread.sln @@ -46,6 +46,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "drivers", "drivers", "{61E8 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otLwf", "otLwf.vcxproj", "{3F1F7F6C-2A33-4635-9880-08FC5BC4E435}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otApi", "otApi.vcxproj", "{ED0EA262-C222-42C7-98D3-E70C72978ED2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -166,6 +168,14 @@ Global {3F1F7F6C-2A33-4635-9880-08FC5BC4E435}.Release|x86.ActiveCfg = Release|Win32 {3F1F7F6C-2A33-4635-9880-08FC5BC4E435}.Release|x86.Build.0 = Release|Win32 {3F1F7F6C-2A33-4635-9880-08FC5BC4E435}.Release|x86.Deploy.0 = Release|Win32 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Debug|x64.ActiveCfg = Debug|x64 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Debug|x64.Build.0 = Debug|x64 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Debug|x86.ActiveCfg = Debug|Win32 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Debug|x86.Build.0 = Debug|Win32 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x64.ActiveCfg = Release|x64 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x64.Build.0 = Release|x64 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x86.ActiveCfg = Release|Win32 + {ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -184,5 +194,6 @@ Global {B4C744EC-B662-46C6-A076-FB58FA8FDF1B} = {76EA541E-CAB1-4DB5-A39F-E3DB2A78CDDD} {9EEF9DCD-EA8F-4154-BD02-AB2B31CEC324} = {76EA541E-CAB1-4DB5-A39F-E3DB2A78CDDD} {3F1F7F6C-2A33-4635-9880-08FC5BC4E435} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133} + {ED0EA262-C222-42C7-98D3-E70C72978ED2} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133} EndGlobalSection EndGlobal diff --git a/etc/visual-studio/otApi.vcxproj b/etc/visual-studio/otApi.vcxproj new file mode 100644 index 000000000..62ae8086f --- /dev/null +++ b/etc/visual-studio/otApi.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {ED0EA262-C222-42C7-98D3-E70C72978ED2} + Win32Proj + otApi + $(LatestTargetPlatformVersion) + + + + DynamicLibrary + true + WindowsApplicationForDrivers10.0 + Unicode + + + DynamicLibrary + false + WindowsApplicationForDrivers10.0 + true + Unicode + + + DynamicLibrary + true + WindowsApplicationForDrivers10.0 + Unicode + false + + + DynamicLibrary + false + WindowsApplicationForDrivers10.0 + true + Unicode + false + + + + + + + + + + + + + + + + + + + + + true + ..\..\build\bin\$(Platform)\$(Configuration)\dll\ + ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset + true + + + true + ..\..\build\bin\$(Platform)\$(Configuration)\dll\ + ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset + true + + + false + ..\..\build\bin\$(Platform)\$(Configuration)\dll\ + ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset + true + + + false + ..\..\build\bin\$(Platform)\$(Configuration)\dll\ + ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\ + C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset + true + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;OTAPI_EXPORTS;%(PreprocessorDefinitions) + true + ..\..\include;..\..\examples\drivers\windows\include;..\..\examples\drivers\windows\otApi;%(AdditionalIncludeDirectories) + precomp.h + true + ..\..\include\platform\logging-windows.h + otApi + true + + + Windows + true + ntdll.lib;iphlpapi.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + _DEBUG;_WINDOWS;_USRDLL;OTAPI_EXPORTS;%(PreprocessorDefinitions) + true + ..\..\include;..\..\examples\drivers\windows\include;..\..\examples\drivers\windows\otApi;%(AdditionalIncludeDirectories) + precomp.h + true + ..\..\include\platform\logging-windows.h + otApi + true + + + Windows + true + ntdll.lib;iphlpapi.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;OTAPI_EXPORTS;%(PreprocessorDefinitions) + true + ..\..\include;..\..\examples\drivers\windows\include;..\..\examples\drivers\windows\otApi;%(AdditionalIncludeDirectories) + precomp.h + true + ..\..\include\platform\logging-windows.h + otApi + true + + + Windows + true + true + true + ntdll.lib;iphlpapi.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + NDEBUG;_WINDOWS;_USRDLL;OTAPI_EXPORTS;%(PreprocessorDefinitions) + true + ..\..\include;..\..\examples\drivers\windows\include;..\..\examples\drivers\windows\otApi;%(AdditionalIncludeDirectories) + precomp.h + true + ..\..\include\platform\logging-windows.h + otApi + true + + + Windows + true + true + true + ntdll.lib;iphlpapi.lib;%(AdditionalDependencies) + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/visual-studio/otApi.vcxproj.filters b/etc/visual-studio/otApi.vcxproj.filters new file mode 100644 index 000000000..ce2de0616 --- /dev/null +++ b/etc/visual-studio/otApi.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/examples/apps/cli/main.c b/examples/apps/cli/main.c index 6400f03a7..b0c99faac 100644 --- a/examples/apps/cli/main.c +++ b/examples/apps/cli/main.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/examples/apps/ncp/main.c b/examples/apps/ncp/main.c index a5496e0e0..97dfe1d98 100644 --- a/examples/apps/ncp/main.c +++ b/examples/apps/ncp/main.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/examples/drivers/windows/otApi/dllmain.cpp b/examples/drivers/windows/otApi/dllmain.cpp new file mode 100644 index 000000000..63d2326c1 --- /dev/null +++ b/examples/drivers/windows/otApi/dllmain.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "precomp.h" +#include "dllmain.tmh" + +BOOL +__stdcall +DllMain( + HINSTANCE hinstDll, + DWORD dwReason, + LPVOID /* lpvReserved */ + ) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDll); + WPP_INIT_TRACING(L"otApi"); + break; + + case DLL_PROCESS_DETACH: + WPP_CLEANUP(); + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} + diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp new file mode 100644 index 000000000..be7595169 --- /dev/null +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -0,0 +1,3490 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "precomp.h" +#include "otApi.tmh" + +//#define DEBUG_ASYNC_IO + +using namespace std; + +// The maximum time we will wait for an overlapped result. Essentially, the maximum +// amount of time each synchronous IOCTL should take. +const DWORD c_MaxOverlappedWaitTimeMS = 10 * 1000; + +// Version string returned by the API +const char c_Version[] = "Windows"; // TODO - What should we really put here? + +template +class otCallback +{ +public: + RTL_REFERENCE_COUNT CallbackRefCount; + HANDLE CallbackCompleteEvent; + GUID InterfaceGuid; + CallbackT Callback; + PVOID CallbackContext; + + otCallback( + CallbackT _Callback, + PVOID _CallbackContext + ) : + CallbackRefCount(1), + CallbackCompleteEvent(CreateEvent(nullptr, FALSE, FALSE, nullptr)), + Callback(_Callback), + CallbackContext(_CallbackContext) + { + } + + otCallback( + const GUID& _InterfaceGuid, + CallbackT _Callback, + PVOID _CallbackContext + ) : + CallbackRefCount(1), + CallbackCompleteEvent(CreateEvent(nullptr, FALSE, FALSE, nullptr)), + InterfaceGuid(_InterfaceGuid), + Callback(_Callback), + CallbackContext(_CallbackContext) + { + } + + ~otCallback() + { + if (CallbackCompleteEvent) CloseHandle(CallbackCompleteEvent); + } + + void AddRef() + { + RtlIncrementReferenceCount(&CallbackRefCount); + } + + void Release(bool waitForShutdown = false) + { + if (RtlDecrementReferenceCount(&CallbackRefCount)) + { + // Set completion event if there are no more refs + SetEvent(CallbackCompleteEvent); + } + + if (waitForShutdown) + { + WaitForSingleObject(CallbackCompleteEvent, INFINITE); + } + } +}; + +typedef otCallback otApiDeviceAvailabilityCallback; +typedef otCallback otApiActiveScanCallback; +typedef otCallback otApiEnergyScanCallback; +typedef otCallback otApiStateChangeCallback; +typedef otCallback otApiCommissionerEnergyReportCallback; +typedef otCallback otApiCommissionerPanIdConflictCallback; + +typedef struct otApiInstance +{ + // Handle to the driver + HANDLE DeviceHandle; + + // Async IO variables + OVERLAPPED Overlapped; + PTP_WAIT ThreadpoolWait; + + // Notification variables + CRITICAL_SECTION CallbackLock; + OTLWF_NOTIFICATION NotificationBuffer; + + // Callbacks + otApiDeviceAvailabilityCallback* DeviceAvailabilityCallbacks; + vector ActiveScanCallbacks; + vector EnergyScanCallbacks; + vector DiscoverCallbacks; + vector StateChangedCallbacks; + vector CommissionerEnergyReportCallbacks; + vector CommissionerPanIdConflictCallbacks; + + // Constructor + otApiInstance() : + DeviceHandle(INVALID_HANDLE_VALUE), + Overlapped({0}), + ThreadpoolWait(nullptr), + DeviceAvailabilityCallbacks(nullptr) + { + InitializeCriticalSection(&CallbackLock); + } + + ~otApiInstance() + { + DeleteCriticalSection(&CallbackLock); + } + + // Helper function to set a callback + template + bool + SetCallback( + vector*> &Callbacks, + const GUID& InterfaceGuid, + CallbackT Callback, + PVOID CallbackContext + ) + { + bool alreadyExists = false; + otCallback* CallbackToRelease = nullptr; + + EnterCriticalSection(&CallbackLock); + + if (Callback == nullptr) + { + for (size_t i = 0; i < Callbacks.size(); i++) + { + if (Callbacks[i]->InterfaceGuid == InterfaceGuid) + { + CallbackToRelease = Callbacks[i]; + Callbacks.erase(Callbacks.begin() + i); + break; + } + } + } + else + { + for (size_t i = 0; i < Callbacks.size(); i++) + { + if (Callbacks[i]->InterfaceGuid == InterfaceGuid) + { + alreadyExists = true; + break; + } + } + + if (!alreadyExists) + { + Callbacks.push_back(new otCallback(InterfaceGuid, Callback, CallbackContext)); + } + } + + LeaveCriticalSection(&CallbackLock); + + if (CallbackToRelease) + { + CallbackToRelease->Release(true); + delete CallbackToRelease; + } + + return !alreadyExists; + } + +} otApiInstance; + +typedef struct otInstance +{ + otApiInstance *ApiHandle; // Pointer to the Api handle + NET_IFINDEX InterfaceIndex; // Interface Index + NET_LUID InterfaceLuid; // Interface Luid + GUID InterfaceGuid; // Interface guid + ULONG CompartmentID; // Interface Compartment ID + +} otInstance; + +// otpool wait callback for async IO completion +VOID CALLBACK +otIoComplete( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _Inout_ PTP_WAIT Wait, + _In_ TP_WAIT_RESULT WaitResult + ); + +OTAPI +otApiInstance * +OTCALL +otApiInit( + ) +{ + DWORD dwError = ERROR_SUCCESS; + otApiInstance *aApitInstance = nullptr; + + otLogFuncEntry(); + + aApitInstance = new(std::nothrow)otApiInstance(); + if (aApitInstance == nullptr) + { + dwError = GetLastError(); + otLogWarnApi("Failed to allocate otApiInstance"); + goto error; + } + + // Open the pipe to the OpenThread driver + aApitInstance->DeviceHandle = + CreateFile( + OTLWF_IOCLT_PATH, + GENERIC_READ | GENERIC_WRITE, + 0, + nullptr, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + FILE_FLAG_OVERLAPPED, // Allow asynchronous requests + nullptr + ); + if (aApitInstance->DeviceHandle == INVALID_HANDLE_VALUE) + { + dwError = GetLastError(); + otLogCritApi("CreateFile failed, %!WINERROR!", dwError); + goto error; + } + + // Create event for completion of async IO + aApitInstance->Overlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (aApitInstance->Overlapped.hEvent == nullptr) + { + dwError = GetLastError(); + otLogCritApi("CreateEvent (Overlapped.hEvent) failed, %!WINERROR!", dwError); + goto error; + } + + // Create the otpool wait + aApitInstance->ThreadpoolWait = + CreateThreadpoolWait( + otIoComplete, + aApitInstance, + nullptr + ); + if (aApitInstance->ThreadpoolWait == nullptr) + { + dwError = GetLastError(); + otLogCritApi("CreateThreadpoolWait failed, %!WINERROR!", dwError); + goto error; + } + + // Start the otpool waiting on the overlapped event + SetThreadpoolWait(aApitInstance->ThreadpoolWait, aApitInstance->Overlapped.hEvent, nullptr); + +#ifdef DEBUG_ASYNC_IO + otLogDebgApi("Querying for 1st notification"); +#endif + + // Request first notification asynchronously + if (!DeviceIoControl( + aApitInstance->DeviceHandle, + IOCTL_OTLWF_QUERY_NOTIFICATION, + nullptr, 0, + &aApitInstance->NotificationBuffer, sizeof(OTLWF_NOTIFICATION), + nullptr, + &aApitInstance->Overlapped)) + { + dwError = GetLastError(); + if (dwError != ERROR_IO_PENDING) + { + otLogCritApi("DeviceIoControl for first notification failed, %!WINERROR!", dwError); + goto error; + } + dwError = ERROR_SUCCESS; + } + +error: + + if (dwError != ERROR_SUCCESS) + { + otApiFinalize(aApitInstance); + aApitInstance = nullptr; + } + + otLogFuncExit(); + + return aApitInstance; +} + +OTAPI +void +OTCALL +otApiFinalize( + _In_ otApiInstance *aApitInstance +) +{ + if (aApitInstance == nullptr) return; + + otLogFuncEntry(); + + // If we never got the handle, nothing left to clean up + if (aApitInstance->DeviceHandle != INVALID_HANDLE_VALUE) + { + // + // Make sure we unregister callbacks + // + + EnterCriticalSection(&aApitInstance->CallbackLock); + + otApiDeviceAvailabilityCallback* DeviceAvailabilityCallbacks = aApitInstance->DeviceAvailabilityCallbacks; + aApitInstance->DeviceAvailabilityCallbacks = nullptr; + + vector ActiveScanCallbacks(aApitInstance->ActiveScanCallbacks); + aApitInstance->ActiveScanCallbacks.clear(); + + vector EnergyScanCallbacks(aApitInstance->EnergyScanCallbacks); + aApitInstance->EnergyScanCallbacks.clear(); + + vector DiscoverCallbacks(aApitInstance->DiscoverCallbacks); + aApitInstance->DiscoverCallbacks.clear(); + + vector StateChangedCallbacks(aApitInstance->StateChangedCallbacks); + aApitInstance->StateChangedCallbacks.clear(); + + vector CommissionerEnergyReportCallbacks(aApitInstance->CommissionerEnergyReportCallbacks); + aApitInstance->CommissionerEnergyReportCallbacks.clear(); + + vector CommissionerPanIdConflictCallbacks(aApitInstance->CommissionerPanIdConflictCallbacks); + aApitInstance->CommissionerPanIdConflictCallbacks.clear(); + + #ifdef DEBUG_ASYNC_IO + otLogDebgApi("Clearing Threadpool Wait"); + #endif + + // Clear the threadpool wait to prevent further waits from being scheduled + PTP_WAIT tpWait = aApitInstance->ThreadpoolWait; + aApitInstance->ThreadpoolWait = nullptr; + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Clear all callbacks + if (DeviceAvailabilityCallbacks) + { + DeviceAvailabilityCallbacks->Release(true); + delete DeviceAvailabilityCallbacks; + } + for (size_t i = 0; i < ActiveScanCallbacks.size(); i++) + { + ActiveScanCallbacks[i]->Release(true); + delete ActiveScanCallbacks[i]; + } + for (size_t i = 0; i < EnergyScanCallbacks.size(); i++) + { + EnergyScanCallbacks[i]->Release(true); + delete EnergyScanCallbacks[i]; + } + for (size_t i = 0; i < DiscoverCallbacks.size(); i++) + { + DiscoverCallbacks[i]->Release(true); + delete DiscoverCallbacks[i]; + } + for (size_t i = 0; i < StateChangedCallbacks.size(); i++) + { + StateChangedCallbacks[i]->Release(true); + delete StateChangedCallbacks[i]; + } + for (size_t i = 0; i < CommissionerEnergyReportCallbacks.size(); i++) + { + CommissionerEnergyReportCallbacks[i]->Release(true); + delete CommissionerEnergyReportCallbacks[i]; + } + for (size_t i = 0; i < CommissionerPanIdConflictCallbacks.size(); i++) + { + CommissionerPanIdConflictCallbacks[i]->Release(true); + delete CommissionerPanIdConflictCallbacks[i]; + } + + // Clean up threadpool wait + if (tpWait) + { + #ifdef DEBUG_ASYNC_IO + otLogDebgApi("Waiting for outstanding threadpool callbacks to compelte"); + #endif + + // Cancel any queued waits and wait for any outstanding calls to compelte + WaitForThreadpoolWaitCallbacks(tpWait, TRUE); + + #ifdef DEBUG_ASYNC_IO + otLogDebgApi("Cancelling any pending IO"); + #endif + + // Cancel any async IO + CancelIoEx(aApitInstance->DeviceHandle, &aApitInstance->Overlapped); + + // Free the threadpool wait + CloseThreadpoolWait(tpWait); + } + + // Clean up overlapped event + if (aApitInstance->Overlapped.hEvent) + { + CloseHandle(aApitInstance->Overlapped.hEvent); + } + + // Close the device handle + CloseHandle(aApitInstance->DeviceHandle); + } + + delete aApitInstance; + + otLogFuncExit(); +} + +OTAPI +void +OTCALL +otFreeMemory( + _In_ const void *mem + ) +{ + free((void*)mem); +} + +// Handles cleanly invoking the register callback +VOID +ProcessNotification( + _In_ otApiInstance *aApitInstance, + _In_ POTLWF_NOTIFICATION Notif + ) +{ + if (Notif->NotifType == OTLWF_NOTIF_DEVICE_AVAILABILITY) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + if (aApitInstance->DeviceAvailabilityCallbacks != nullptr) + { + aApitInstance->DeviceAvailabilityCallbacks->AddRef(); + Callback = aApitInstance->DeviceAvailabilityCallbacks; + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->DeviceAvailabilityPayload.Available != FALSE, + &Notif->InterfaceGuid, + Callback->CallbackContext); + + Callback->Release(); + } + } + else if (Notif->NotifType == OTLWF_NOTIF_STATE_CHANGE) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + for (size_t i = 0; i < aApitInstance->StateChangedCallbacks.size(); i++) + { + if (aApitInstance->StateChangedCallbacks[i]->InterfaceGuid == Notif->InterfaceGuid) + { + aApitInstance->StateChangedCallbacks[i]->AddRef(); + Callback = aApitInstance->StateChangedCallbacks[i]; + break; + } + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->StateChangePayload.Flags, + Callback->CallbackContext); + + Callback->Release(); + } + } + else if (Notif->NotifType == OTLWF_NOTIF_DISCOVER) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + for (size_t i = 0; i < aApitInstance->DiscoverCallbacks.size(); i++) + { + if (aApitInstance->DiscoverCallbacks[i]->InterfaceGuid == Notif->InterfaceGuid) + { + aApitInstance->DiscoverCallbacks[i]->AddRef(); + Callback = aApitInstance->DiscoverCallbacks[i]; + break; + } + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->DiscoverPayload.Valid ? &Notif->DiscoverPayload.Results : nullptr, + Callback->CallbackContext); + + Callback->Release(); + } + } + else if (Notif->NotifType == OTLWF_NOTIF_ACTIVE_SCAN) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + for (size_t i = 0; i < aApitInstance->ActiveScanCallbacks.size(); i++) + { + if (aApitInstance->ActiveScanCallbacks[i]->InterfaceGuid == Notif->InterfaceGuid) + { + aApitInstance->ActiveScanCallbacks[i]->AddRef(); + Callback = aApitInstance->ActiveScanCallbacks[i]; + break; + } + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->ActiveScanPayload.Valid ? &Notif->ActiveScanPayload.Results : nullptr, + Callback->CallbackContext); + + Callback->Release(); + } + } + else if (Notif->NotifType == OTLWF_NOTIF_ENERGY_SCAN) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + for (size_t i = 0; i < aApitInstance->EnergyScanCallbacks.size(); i++) + { + if (aApitInstance->EnergyScanCallbacks[i]->InterfaceGuid == Notif->InterfaceGuid) + { + aApitInstance->EnergyScanCallbacks[i]->AddRef(); + Callback = aApitInstance->EnergyScanCallbacks[i]; + break; + } + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->EnergyScanPayload.Valid ? &Notif->EnergyScanPayload.Results : nullptr, + Callback->CallbackContext); + + Callback->Release(); + } + } + else if (Notif->NotifType == OTLWF_NOTIF_COMMISSIONER_ENERGY_REPORT) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + for (size_t i = 0; i < aApitInstance->CommissionerEnergyReportCallbacks.size(); i++) + { + if (aApitInstance->CommissionerEnergyReportCallbacks[i]->InterfaceGuid == Notif->InterfaceGuid) + { + aApitInstance->CommissionerEnergyReportCallbacks[i]->AddRef(); + Callback = aApitInstance->CommissionerEnergyReportCallbacks[i]; + break; + } + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->CommissionerEnergyReportPayload.ChannelMask, + Notif->CommissionerEnergyReportPayload.EnergyList, + Notif->CommissionerEnergyReportPayload.EnergyListLength, + Callback->CallbackContext); + + Callback->Release(); + } + } + else if (Notif->NotifType == OTLWF_NOTIF_COMMISSIONER_PANID_QUERY) + { + otCallback* Callback = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + for (size_t i = 0; i < aApitInstance->CommissionerPanIdConflictCallbacks.size(); i++) + { + if (aApitInstance->CommissionerPanIdConflictCallbacks[i]->InterfaceGuid == Notif->InterfaceGuid) + { + aApitInstance->CommissionerPanIdConflictCallbacks[i]->AddRef(); + Callback = aApitInstance->CommissionerPanIdConflictCallbacks[i]; + break; + } + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + // Invoke the callback outside the lock and release ref when done + if (Callback) + { + Callback->Callback( + Notif->CommissionerPanIdQueryPayload.PanId, + Notif->CommissionerPanIdQueryPayload.ChannelMask, + Callback->CallbackContext); + + Callback->Release(); + } + } + else + { + // Unexpected notif type + } +} + +// Threadpool wait callback for async IO completion +VOID CALLBACK +otIoComplete( + _Inout_ PTP_CALLBACK_INSTANCE /* Instance */, + _Inout_opt_ PVOID Context, + _Inout_ PTP_WAIT /* Wait */, + _In_ TP_WAIT_RESULT /* WaitResult */ + ) +{ +#ifdef DEBUG_ASYNC_IO + otLogFuncEntry(); +#endif + + otApiInstance *aApitInstance = (otApiInstance*)Context; + if (aApitInstance == nullptr) return; + + // Get the result of the IO operation + DWORD dwBytesTransferred = 0; + if (!GetOverlappedResult( + aApitInstance->DeviceHandle, + &aApitInstance->Overlapped, + &dwBytesTransferred, + FALSE)) + { + DWORD dwError = GetLastError(); + otLogCritApi("GetOverlappedResult for notification failed, %!WINERROR!", dwError); + } + else + { + otLogDebgApi("Received successful callback for notification, type=%d", + aApitInstance->NotificationBuffer.NotifType); + + // Invoke the callback if set + ProcessNotification(aApitInstance, &aApitInstance->NotificationBuffer); + + // Try to get the threadpool wait to see if we are allowed to continue processing notifications + EnterCriticalSection(&aApitInstance->CallbackLock); + PTP_WAIT tpWait = aApitInstance->ThreadpoolWait; + LeaveCriticalSection(&aApitInstance->CallbackLock); + + if (tpWait) + { + // Start waiting for next notification + SetThreadpoolWait(tpWait, aApitInstance->Overlapped.hEvent, nullptr); + +#ifdef DEBUG_ASYNC_IO + otLogDebgApi("Querying for next notification"); +#endif + + // Request next notification + if (!DeviceIoControl( + aApitInstance->DeviceHandle, + IOCTL_OTLWF_QUERY_NOTIFICATION, + nullptr, 0, + &aApitInstance->NotificationBuffer, sizeof(OTLWF_NOTIFICATION), + nullptr, + &aApitInstance->Overlapped)) + { + DWORD dwError = GetLastError(); + if (dwError != ERROR_IO_PENDING) + { + otLogCritApi("DeviceIoControl for new notification failed, %!WINERROR!", dwError); + } + } + } + } + +#ifdef DEBUG_ASYNC_IO + otLogFuncExit(); +#endif +} + +DWORD +SendIOCTL( + _In_ otApiInstance *aApitInstance, + _In_ DWORD dwIoControlCode, + _In_reads_bytes_opt_(nInBufferSize) LPVOID lpInBuffer, + _In_ DWORD nInBufferSize, + _Out_writes_bytes_opt_(nOutBufferSize) LPVOID lpOutBuffer, + _In_ DWORD nOutBufferSize + ) +{ + DWORD dwError = ERROR_SUCCESS; + OVERLAPPED Overlapped = { 0 }; + DWORD dwBytesReturned = 0; + + Overlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (Overlapped.hEvent == nullptr) + { + dwError = GetLastError(); + otLogCritApi("CreateEvent (Overlapped.hEvent) failed, %!WINERROR!", dwError); + goto error; + } + + // Send the IOCTL the OpenThread driver + if (!DeviceIoControl( + aApitInstance->DeviceHandle, + dwIoControlCode, + lpInBuffer, nInBufferSize, + lpOutBuffer, nOutBufferSize, + nullptr, + &Overlapped)) + { + dwError = GetLastError(); + if (dwError != ERROR_IO_PENDING) + { + otLogCritApi("DeviceIoControl(0x%x) failed, %!WINERROR!", dwIoControlCode, dwError); + goto error; + } + dwError = ERROR_SUCCESS; + } + + // Get the result of the IO operation + if (!GetOverlappedResultEx( + aApitInstance->DeviceHandle, + &Overlapped, + &dwBytesReturned, + c_MaxOverlappedWaitTimeMS, + FALSE + )) + { + dwError = GetLastError(); + if (dwError == WAIT_TIMEOUT) + { + dwError = ERROR_TIMEOUT; + CancelIoEx(aApitInstance->DeviceHandle, &Overlapped); + } + otLogCritApi("GetOverlappedResult failed, %!WINERROR!", dwError); + goto error; + } + + if (dwBytesReturned != nOutBufferSize) + { + dwError = ERROR_INVALID_DATA; + otLogCritApi("GetOverlappedResult returned invalid output size, expected=%u actual=%u", + nOutBufferSize, dwBytesReturned); + goto error; + } + +error: + + if (Overlapped.hEvent) + { + CloseHandle(Overlapped.hEvent); + } + + return dwError; +} + +__pragma(pack(push,1)) +template +struct PackedBuffer2 +{ + T1 data1; T2 data2; + PackedBuffer2(const T1 &d1, const T2 &d2) : data1(d1), data2(d2) { } +}; +template +struct PackedBuffer3 +{ + T1 data1; T2 data2; T3 data3; + PackedBuffer3(const T1 &d1, const T2 &d2, const T3 &d3) : data1(d1), data2(d2), data3(d3) { } +}; +template +struct PackedBuffer4 +{ + T1 data1; T2 data2; T3 data3; T4 data4; + PackedBuffer4(const T1 &d1, const T2 &d2, const T3 &d3, const T4 &d4) : data1(d1), data2(d2), data3(d3), data4(d4) { } +}; +template +struct PackedBuffer5 +{ + T1 data1; T2 data2; T3 data3; T4 data4; T5 data5; + PackedBuffer5(const T1 &d1, const T2 &d2, const T3 &d3, const T4 &d4, const T5 &d5) : data1(d1), data2(d2), data3(d3), data4(d4), data5(d5) { } +}; +template +struct PackedBuffer6 +{ + T1 data1; T2 data2; T3 data3; T4 data4; T5 data5; T6 data6; + PackedBuffer6(const T1 &d1, const T2 &d2, const T3 &d3, const T4 &d4, const T5 &d5, const T6 &d6) : data1(d1), data2(d2), data3(d3), data4(d4), data5(d5), data6(d6) { } +}; + __pragma(pack(pop)) + +template +DWORD +QueryIOCTL( + _In_ otInstance *aInstance, + _In_ DWORD dwIoControlCode, + _In_ const in *input, + _Out_ out* output + ) +{ + PackedBuffer2 Buffer(aInstance->InterfaceGuid, *input); + return SendIOCTL(aInstance->ApiHandle, dwIoControlCode, &Buffer, sizeof(Buffer), output, sizeof(out)); +} + +template +DWORD +QueryIOCTL( + _In_ otInstance *aInstance, + _In_ DWORD dwIoControlCode, + _Out_ out* output + ) +{ + return SendIOCTL(aInstance->ApiHandle, dwIoControlCode, &aInstance->InterfaceGuid, sizeof(GUID), output, sizeof(out)); +} + +template +DWORD +SetIOCTL( + _In_ otInstance *aInstance, + _In_ DWORD dwIoControlCode, + _In_ const in* input + ) +{ + PackedBuffer2 Buffer(aInstance->InterfaceGuid, *input); + return SendIOCTL(aInstance->ApiHandle, dwIoControlCode, &Buffer, sizeof(Buffer), nullptr, 0); +} + +template +DWORD +SetIOCTL( + _In_ otInstance *aInstance, + _In_ DWORD dwIoControlCode, + _In_ const in input + ) +{ + PackedBuffer2 Buffer(aInstance->InterfaceGuid, input); + return SendIOCTL(aInstance->ApiHandle, dwIoControlCode, &Buffer, sizeof(Buffer), nullptr, 0); +} + +DWORD +SetIOCTL( + _In_ otInstance *aInstance, + _In_ DWORD dwIoControlCode + ) +{ + return SendIOCTL(aInstance->ApiHandle, dwIoControlCode, &aInstance->InterfaceGuid, sizeof(GUID), nullptr, 0); +} + +ThreadError +DwordToThreadError( + DWORD dwError + ) +{ + if (((int)dwError) > 0) + { + return kThreadError_Error; + } + else + { + return (ThreadError)(-(int)dwError); + } +} + +OTAPI +void +OTCALL +otSetDeviceAvailabilityChangedCallback( + _In_ otApiInstance *aApitInstance, + _In_ otDeviceAvailabilityChangedCallback aCallback, + _In_ void *aCallbackContext + ) +{ + otApiDeviceAvailabilityCallback* CallbackToRelease = nullptr; + + EnterCriticalSection(&aApitInstance->CallbackLock); + + if (aApitInstance->DeviceAvailabilityCallbacks != nullptr) + { + CallbackToRelease = aApitInstance->DeviceAvailabilityCallbacks; + aApitInstance->DeviceAvailabilityCallbacks = nullptr; + } + + if (aCallback != nullptr) + { + aApitInstance->DeviceAvailabilityCallbacks = + new otApiDeviceAvailabilityCallback(aCallback, aCallbackContext); + } + + LeaveCriticalSection(&aApitInstance->CallbackLock); + + if (CallbackToRelease) + { + CallbackToRelease->Release(true); + delete CallbackToRelease; + } +} + +OTAPI +otDeviceList* +OTCALL +otEnumerateDevices( + _In_ otApiInstance *aApitInstance + ) +{ + DWORD dwError = ERROR_SUCCESS; + OVERLAPPED Overlapped = { 0 }; + DWORD dwBytesReturned = 0; + otDeviceList* pDeviceList = nullptr; + DWORD cbDeviceList = sizeof(otDeviceList); + + otLogFuncEntry(); + + Overlapped.hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (Overlapped.hEvent == nullptr) + { + dwError = GetLastError(); + otLogCritApi("CreateEvent (Overlapped.hEvent) failed, %!WINERROR!", dwError); + goto error; + } + + pDeviceList = (otDeviceList*)malloc(cbDeviceList); + if (pDeviceList == nullptr) + { + otLogWarnApi("Failed to allocate otDeviceList of %u bytes.", cbDeviceList); + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto error; + } + RtlZeroMemory(pDeviceList, cbDeviceList); + + // Query in a loop to account for it changing between calls + while (true) + { + // Send the IOCTL to query the interfaces + if (!DeviceIoControl( + aApitInstance->DeviceHandle, + IOCTL_OTLWF_ENUMERATE_DEVICES, + nullptr, 0, + pDeviceList, cbDeviceList, + nullptr, + &Overlapped)) + { + dwError = GetLastError(); + if (dwError != ERROR_IO_PENDING) + { + otLogCritApi("DeviceIoControl(IOCTL_OTLWF_ENUMERATE_DEVICES) failed, %!WINERROR!", dwError); + goto error; + } + dwError = ERROR_SUCCESS; + } + + // Get the result of the IO operation + if (!GetOverlappedResultEx( + aApitInstance->DeviceHandle, + &Overlapped, + &dwBytesReturned, + c_MaxOverlappedWaitTimeMS, + TRUE)) + { + dwError = GetLastError(); + if (dwError == WAIT_TIMEOUT) + { + dwError = ERROR_TIMEOUT; + CancelIoEx(aApitInstance->DeviceHandle, &Overlapped); + } + otLogCritApi("GetOverlappedResult for notification failed, %!WINERROR!", dwError); + goto error; + } + + // Calculate the expected size of the full buffer + cbDeviceList = + FIELD_OFFSET(otDeviceList, aDevices) + + pDeviceList->aDevicesLength * sizeof(otDeviceList::aDevices); + + // Make sure they returned a complete buffer + if (dwBytesReturned != sizeof(otDeviceList::aDevicesLength)) break; + + // If we get here that means we didn't have a big enough buffer + // Reallocate a new buffer + free(pDeviceList); + pDeviceList = (otDeviceList*)malloc(cbDeviceList); + if (pDeviceList == nullptr) + { + otLogCritApi("Failed to allocate otDeviceList of %u bytes.", cbDeviceList); + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto error; + } + RtlZeroMemory(pDeviceList, cbDeviceList); + } + +error: + + if (dwError != ERROR_SUCCESS) + { + free(pDeviceList); + pDeviceList = nullptr; + } + + if (Overlapped.hEvent) + { + CloseHandle(Overlapped.hEvent); + } + + otLogFuncExitMsg("%d devices", pDeviceList == nullptr ? -1 : (int)pDeviceList->aDevicesLength); + + return pDeviceList; +} + +OTAPI +otInstance * +OTCALL +otInstanceInit( + _In_ otApiInstance *aApitInstance, + _In_ const GUID *aDeviceGuid + ) +{ + otInstance *aInstance = nullptr; + + OTLWF_DEVICE Result = {0}; + if (aApitInstance && + SendIOCTL( + aApitInstance, + IOCTL_OTLWF_QUERY_DEVICE, + (LPVOID)aDeviceGuid, + sizeof(GUID), + &Result, + sizeof(Result) + ) == ERROR_SUCCESS) + { + aInstance = (otInstance*)malloc(sizeof(otInstance)); + if (aInstance) + { + aInstance->ApiHandle = aApitInstance; + aInstance->InterfaceGuid = *aDeviceGuid; + aInstance->CompartmentID = Result.CompartmentID; + + if (ConvertInterfaceGuidToLuid(aDeviceGuid, &aInstance->InterfaceLuid) != ERROR_SUCCESS || + ConvertInterfaceLuidToIndex(&aInstance->InterfaceLuid, &aInstance->InterfaceIndex) != ERROR_SUCCESS) + { + otLogCritApi("Failed to convert interface guid to index!"); + free(aInstance); + aInstance = nullptr; + } + } + } + + return aInstance; +} + +OTAPI +GUID +OTCALL +otGetDeviceGuid( + otInstance *aInstance + ) +{ + if (aInstance == nullptr) return {}; + return aInstance->InterfaceGuid; +} + +OTAPI +uint32_t +OTCALL +otGetDeviceIfIndex( + otInstance *aInstance + ) +{ + if (aInstance == nullptr) return (uint32_t)-1; + return aInstance->InterfaceIndex; +} + +OTAPI +uint32_t +OTCALL +otGetCompartmentId( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return (uint32_t)-1; + return aInstance->CompartmentID; +} + +OTAPI +const char * +OTCALL +otGetVersionString() +{ + char* szVersion = (char*)malloc(sizeof(c_Version)); + if (szVersion) + { + memcpy_s(szVersion, sizeof(c_Version), c_Version, sizeof(c_Version)); + } + return szVersion; +} + +OTAPI +ThreadError +OTCALL +otInterfaceUp( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_INTERFACE, (BOOLEAN)TRUE)); +} + +OTAPI +ThreadError +OTCALL +otInterfaceDown( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_INTERFACE, (BOOLEAN)FALSE)); +} + +OTAPI +bool +OTCALL +otIsInterfaceUp( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = FALSE; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_INTERFACE, &Result); + return Result != FALSE; +} + +OTAPI +ThreadError +OTCALL +otThreadStart( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_THREAD, (BOOLEAN)TRUE)); +} + +OTAPI +ThreadError +OTCALL +otThreadStop( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_THREAD, (BOOLEAN)FALSE)); +} + +OTAPI +bool +OTCALL +otIsSingleton( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = FALSE; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_SINGLETON, &Result); + return Result != FALSE; +} + +OTAPI +ThreadError +OTCALL +otActiveScan( + _In_ otInstance *aInstance, + uint32_t aScanChannels, + uint16_t aScanDuration, + otHandleActiveScanResult aCallback, + _In_ void *aCallbackContext + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->ActiveScanCallbacks, + aInstance->InterfaceGuid, aCallback, aCallbackContext + ); + + PackedBuffer3 Buffer(aInstance->InterfaceGuid, aScanChannels, aScanDuration); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_ACTIVE_SCAN, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +bool +OTCALL +otIsActiveScanInProgress( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = FALSE; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ACTIVE_SCAN, &Result); + return Result != FALSE; +} + +OTAPI +ThreadError +OTCALL +otEnergyScan( + _In_ otInstance *aInstance, + uint32_t aScanChannels, + uint16_t aScanDuration, + _In_ otHandleEnergyScanResult aCallback, + _In_ void *aCallbackContext + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->EnergyScanCallbacks, + aInstance->InterfaceGuid, aCallback, aCallbackContext + ); + + PackedBuffer3 Buffer(aInstance->InterfaceGuid, aScanChannels, aScanDuration); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_ENERGY_SCAN, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +bool +OTCALL +otIsEnergyScanInProgress( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = FALSE; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ENERGY_SCAN, &Result); + return Result != FALSE; +} + +OTAPI +ThreadError +OTCALL +otDiscover( + _In_ otInstance *aInstance, + uint32_t aScanChannels, + uint16_t aScanDuration, + uint16_t aPanid, + otHandleActiveScanResult aCallback, + void *aCallbackContext + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->DiscoverCallbacks, + aInstance->InterfaceGuid, aCallback, aCallbackContext + ); + + PackedBuffer4 Buffer(aInstance->InterfaceGuid, aScanChannels, aScanDuration, aPanid); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_DISCOVER, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +bool +OTCALL +otIsDiscoverInProgress( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = FALSE; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_DISCOVER, &Result); + return Result != FALSE; +} + +OTAPI +uint8_t +OTCALL +otGetChannel( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0xFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_CHANNEL, &Result); + return Result; +} + +OTAPI +ThreadError +OTCALL +otSetChannel( + _In_ otInstance *aInstance, + uint8_t aChannel + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_CHANNEL, aChannel)); +} + +OTAPI +uint8_t +OTCALL +otGetMaxAllowedChildren( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAX_CHILDREN, &Result); + return Result; +} + +OTAPI +ThreadError +OTCALL +otSetMaxAllowedChildren( + _In_ otInstance *aInstance, + uint8_t aMaxChildren + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_MAX_CHILDREN, aMaxChildren)); +} + +OTAPI +uint32_t +OTCALL +otGetChildTimeout( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_CHILD_TIMEOUT, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetChildTimeout( + _In_ otInstance *aInstance, + uint32_t aTimeout + ) +{ + if (aInstance == nullptr) return; + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_CHILD_TIMEOUT, aTimeout); +} + +OTAPI +const +uint8_t * +OTCALL +otGetExtendedAddress( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return nullptr; + + otExtAddress *Result = (otExtAddress*)malloc(sizeof(otExtAddress)); + if (Result && QueryIOCTL(aInstance, IOCTL_OTLWF_OT_EXTENDED_ADDRESS, Result) != ERROR_SUCCESS) + { + free(Result); + Result = nullptr; + } + return (uint8_t*)Result; +} + +OTAPI +ThreadError +OTCALL +otSetExtendedAddress( + _In_ otInstance *aInstance, + const otExtAddress *aExtendedAddress + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_EXTENDED_ADDRESS, aExtendedAddress)); +} + +OTAPI +const uint8_t * +OTCALL +otGetExtendedPanId( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return nullptr; + + otExtendedPanId *Result = (otExtendedPanId*)malloc(sizeof(otExtendedPanId)); + if (Result && QueryIOCTL(aInstance, IOCTL_OTLWF_OT_EXTENDED_PANID, Result) != ERROR_SUCCESS) + { + free(Result); + Result = nullptr; + } + return (uint8_t*)Result; +} + +OTAPI +void +OTCALL +otSetExtendedPanId( + _In_ otInstance *aInstance, + const uint8_t *aExtendedPanId + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_EXTENDED_PANID, (const otExtendedPanId*)aExtendedPanId); +} + +OTAPI +void +OTCALL +otGetFactoryAssignedIeeeEui64( + _In_ otInstance *aInstance, + _Out_ otExtAddress *aEui64 +) +{ + if (aInstance == nullptr) return; + (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_FACTORY_EUI64, aEui64); +} + +OTAPI +void +OTCALL +otGetHashMacAddress( + _In_ otInstance *aInstance, + _Out_ otExtAddress *aHashMacAddress + ) +{ + if (aInstance == nullptr) return; + (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_HASH_MAC_ADDRESS, aHashMacAddress); +} + +OTAPI +ThreadError +OTCALL +otGetLeaderRloc( + _In_ otInstance *aInstance, + _Out_ otIp6Address *aLeaderRloc + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LEADER_RLOC, aLeaderRloc)); +} + +OTAPI +otLinkModeConfig +OTCALL +otGetLinkMode( + _In_ otInstance *aInstance + ) +{ + otLinkModeConfig Result = {0}; + static_assert(sizeof(otLinkModeConfig) == 4, "The size of otLinkModeConfig should be 4 bytes"); + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LINK_MODE, &Result); + return Result; +} + +OTAPI +ThreadError +OTCALL +otSetLinkMode( + _In_ otInstance *aInstance, + otLinkModeConfig aConfig + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + static_assert(sizeof(otLinkModeConfig) == 4, "The size of otLinkModeConfig should be 4 bytes"); + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_LINK_MODE, aConfig)); +} + +OTAPI +const uint8_t * +OTCALL +otGetMasterKey( + _In_ otInstance *aInstance, + _Out_ uint8_t *aKeyLength + ) +{ + if (aInstance == nullptr || aKeyLength == nullptr) return nullptr; + + *aKeyLength = 0; + + struct otMasterKeyAndLength + { + otMasterKey Key; + uint8_t Length; + }; + otMasterKeyAndLength *Result = (otMasterKeyAndLength*)malloc(sizeof(otMasterKeyAndLength)); + if (Result == nullptr) return nullptr; + if (QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MASTER_KEY, Result) != ERROR_SUCCESS) + { + free(Result); + return nullptr; + } + else + { + *aKeyLength = Result->Length; + } + return (uint8_t*)Result; +} + +OTAPI +ThreadError +OTCALL +otSetMasterKey( + _In_ otInstance *aInstance, + const uint8_t *aKey, + uint8_t aKeyLength + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + BYTE Buffer[sizeof(GUID) + sizeof(otMasterKey) + sizeof(uint8_t)]; + memcpy_s(Buffer, sizeof(Buffer), &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), sizeof(Buffer) - sizeof(GUID), aKey, aKeyLength); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otMasterKey), sizeof(Buffer) - sizeof(GUID) - sizeof(otMasterKey), &aKeyLength, sizeof(aKeyLength)); + + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_MASTER_KEY, Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +int8_t +OTCALL +otGetMaxTransmitPower( + _In_ otInstance *aInstance + ) +{ + int8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAX_TRANSMIT_POWER, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetMaxTransmitPower( + _In_ otInstance *aInstance, + int8_t aPower + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_MAX_TRANSMIT_POWER, aPower); +} + +OTAPI +const otIp6Address * +OTCALL +otGetMeshLocalEid( + _In_ otInstance *aInstance + ) +{ + otIp6Address *Result = (otIp6Address*)malloc(sizeof(otIp6Address)); + if (Result && QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MESH_LOCAL_EID, Result) != ERROR_SUCCESS) + { + free(Result); + Result = nullptr; + } + return Result; +} + +OTAPI +const uint8_t * +OTCALL +otGetMeshLocalPrefix( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return nullptr; + + otMeshLocalPrefix *Result = (otMeshLocalPrefix*)malloc(sizeof(otMeshLocalPrefix)); + if (Result && QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MESH_LOCAL_PREFIX, Result) != ERROR_SUCCESS) + { + free(Result); + Result = nullptr; + } + return (uint8_t*)Result; +} + +OTAPI +ThreadError +OTCALL +otSetMeshLocalPrefix( + _In_ otInstance *aInstance, + const uint8_t *aMeshLocalPrefix + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_MESH_LOCAL_PREFIX, (const otMeshLocalPrefix*)aMeshLocalPrefix)); +} + +OTAPI +ThreadError +OTCALL +otGetNetworkDataLeader( + _In_ otInstance *aInstance, + bool aStable, + _Out_ uint8_t *aData, + _Out_ uint8_t *aDataLength + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + UNREFERENCED_PARAMETER(aInstance); + UNREFERENCED_PARAMETER(aStable); + UNREFERENCED_PARAMETER(aData); + UNREFERENCED_PARAMETER(aDataLength); + return kThreadError_NotImplemented; // TODO +} + +OTAPI +ThreadError +OTCALL +otGetNetworkDataLocal( + _In_ otInstance *aInstance, + bool aStable, + _Out_ uint8_t *aData, + _Out_ uint8_t *aDataLength + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + UNREFERENCED_PARAMETER(aInstance); + UNREFERENCED_PARAMETER(aStable); + UNREFERENCED_PARAMETER(aData); + UNREFERENCED_PARAMETER(aDataLength); + return kThreadError_NotImplemented; // TODO +} + +OTAPI +const char * +OTCALL +otGetNetworkName( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return nullptr; + + otNetworkName *Result = (otNetworkName*)malloc(sizeof(otNetworkName)); + if (Result && QueryIOCTL(aInstance, IOCTL_OTLWF_OT_NETWORK_NAME, Result) != ERROR_SUCCESS) + { + free(Result); + Result = nullptr; + } + return (char*)Result; +} + +OTAPI +ThreadError +OTCALL +otSetNetworkName( + _In_ otInstance *aInstance, + _In_ const char *aNetworkName + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + otNetworkName Buffer = {0}; + strcpy_s(Buffer.m8, sizeof(Buffer), aNetworkName); + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_NETWORK_NAME, (const otNetworkName*)&Buffer)); +} + +OTAPI +ThreadError +OTCALL +otGetNextOnMeshPrefix( + _In_ otInstance *aInstance, + bool _aLocal, + _Inout_ otNetworkDataIterator *aIterator, + _Out_ otBorderRouterConfig *aConfig + ) +{ + if (aInstance == nullptr || aConfig == nullptr) return kThreadError_InvalidArgs; + + BOOLEAN aLocal = _aLocal ? TRUE : FALSE; + PackedBuffer3 InBuffer(aInstance->InterfaceGuid, aLocal, *aIterator); + BYTE OutBuffer[sizeof(uint8_t) + sizeof(otBorderRouterConfig)]; + + ThreadError aError = + DwordToThreadError( + SendIOCTL( + aInstance->ApiHandle, + IOCTL_OTLWF_OT_NEXT_ON_MESH_PREFIX, + &InBuffer, sizeof(InBuffer), + OutBuffer, sizeof(OutBuffer))); + + if (aError == kThreadError_None) + { + memcpy(aIterator, OutBuffer, sizeof(uint8_t)); + memcpy(aConfig, OutBuffer + sizeof(uint8_t), sizeof(otBorderRouterConfig)); + } + else + { + ZeroMemory(aConfig, sizeof(otBorderRouterConfig)); + } + + return aError; +} + +OTAPI +otPanId +OTCALL +otGetPanId( + _In_ otInstance *aInstance + ) +{ + otPanId Result = {0}; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_PAN_ID, &Result); + return Result; +} + +OTAPI +ThreadError +OTCALL +otSetPanId( + _In_ otInstance *aInstance, + otPanId aPanId + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_PAN_ID, aPanId)); +} + +OTAPI +bool +OTCALL +otIsRouterRoleEnabled( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = {0}; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED, &Result); + return Result != FALSE; +} + +OTAPI +void +OTCALL +otSetRouterRoleEnabled( + _In_ otInstance *aInstance, + bool aEnabled + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED, (BOOLEAN)aEnabled); +} + +OTAPI +otShortAddress +OTCALL +otGetShortAddress( + _In_ otInstance *aInstance + ) +{ + otShortAddress Result = {0}; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_SHORT_ADDRESS, &Result); + return Result; +} + +BOOL +GetAdapterAddresses( + PIP_ADAPTER_ADDRESSES * ppIAA +) +{ + PIP_ADAPTER_ADDRESSES pIAA = NULL; + DWORD len = 0; + DWORD flags; + + flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + if (GetAdaptersAddresses(AF_INET6, flags, NULL, NULL, &len) != ERROR_BUFFER_OVERFLOW) + return FALSE; + + pIAA = (PIP_ADAPTER_ADDRESSES)malloc(len); + if (pIAA) { + GetAdaptersAddresses(AF_INET6, flags, NULL, pIAA, &len); + *ppIAA = pIAA; + return TRUE; + } + return FALSE; +} + +OTAPI +const otNetifAddress * +OTCALL +otGetUnicastAddresses( + _In_ otInstance *aInstance + ) +{ + otLogFuncEntry(); + if (aInstance == nullptr) + { + otLogFuncExit(); + return nullptr; + } + + // Put the current thead in the correct compartment + bool RevertCompartmentOnExit = false; + ULONG OriginalCompartmentID = GetCurrentThreadCompartmentId(); + if (OriginalCompartmentID != aInstance->CompartmentID) + { + DWORD dwError = ERROR_SUCCESS; + if ((dwError = SetCurrentThreadCompartmentId(aInstance->CompartmentID)) != ERROR_SUCCESS) + { + otLogCritApi("SetCurrentThreadCompartmentId failed, %!WINERROR!", dwError); + return nullptr; + } + RevertCompartmentOnExit = true; + } + + otNetifAddress *addrs = nullptr; + ULONG AddrCount = 0; + + // Query the current adapter addresses and format them in the proper output format + PIP_ADAPTER_ADDRESSES pIAAList; + if (GetAdapterAddresses(&pIAAList)) + { + // Loop through all the interfaces + for (auto pIAA = pIAAList; pIAA != nullptr; pIAA = pIAA->Next) + { + // Look for the right interface + if (pIAA->Ipv6IfIndex != aInstance->InterfaceIndex) continue; + + // Look through all unicast addresses + for (auto pUnicastAddr = pIAA->FirstUnicastAddress; + pUnicastAddr != nullptr; + pUnicastAddr = pUnicastAddr->Next) + { + AddrCount++; + } + + break; + } + + // If we didn't find any addresses, just break out + if (AddrCount == 0) goto error; + + // Allocate the addresses + addrs = (otNetifAddress*)malloc(AddrCount * sizeof(otNetifAddress)); + if (addrs == nullptr) + { + otLogWarnApi("Not enough memory to alloc otNetifAddress array"); + goto error; + } + ZeroMemory(addrs, AddrCount * sizeof(otNetifAddress)); + + // Initialize the next pointers + for (ULONG i = 0; i < AddrCount; i++) + { + addrs[i].mNext = (i + 1 == AddrCount) ? nullptr : &addrs[i + 1]; + } + + AddrCount = 0; + + // Loop through all the interfaces + for (auto pIAA = pIAAList; pIAA != nullptr; pIAA = pIAA->Next) + { + // Look for the right interface + if (pIAA->Ipv6IfIndex != aInstance->InterfaceIndex) continue; + + // Look through all unicast addresses + for (auto pUnicastAddr = pIAA->FirstUnicastAddress; + pUnicastAddr != nullptr; + pUnicastAddr = pUnicastAddr->Next) + { + LPSOCKADDR_IN6 pAddr = (LPSOCKADDR_IN6)pUnicastAddr->Address.lpSockaddr; + + // Copy the necessary parameters + memcpy(&addrs[AddrCount].mAddress, &pAddr->sin6_addr, sizeof(pAddr->sin6_addr)); + addrs[AddrCount].mPreferredLifetime = pUnicastAddr->PreferredLifetime; + addrs[AddrCount].mValidLifetime = pUnicastAddr->ValidLifetime; + addrs[AddrCount].mPrefixLength = pUnicastAddr->OnLinkPrefixLength; + + AddrCount++; + } + + break; + } + + error: + free(pIAAList); + } + else + { + otLogCritApi("GetAdapterAddresses failed!"); + } + + // Revert the comparment if necessary + if (RevertCompartmentOnExit) + { + (VOID)SetCurrentThreadCompartmentId(OriginalCompartmentID); + } + + otLogFuncExitMsg("%d addrs", AddrCount); + return addrs; +} + +OTAPI +ThreadError +OTCALL +otAddUnicastAddress( + _In_ otInstance *aInstance, + const otNetifAddress *aAddress + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + // Put the current thead in the correct compartment + bool RevertCompartmentOnExit = false; + ULONG OriginalCompartmentID = GetCurrentThreadCompartmentId(); + if (OriginalCompartmentID != aInstance->CompartmentID) + { + DWORD dwError = ERROR_SUCCESS; + if ((dwError = SetCurrentThreadCompartmentId(aInstance->CompartmentID)) != ERROR_SUCCESS) + { + otLogCritApi("SetCurrentThreadCompartmentId failed, %!WINERROR!", dwError); + return kThreadError_Failed; + } + RevertCompartmentOnExit = true; + } + + MIB_UNICASTIPADDRESS_ROW newRow; + InitializeUnicastIpAddressEntry(&newRow); + + newRow.InterfaceIndex = aInstance->InterfaceIndex; + newRow.InterfaceLuid = aInstance->InterfaceLuid; + newRow.Address.si_family = AF_INET6; + newRow.Address.Ipv6.sin6_family = AF_INET6; + + static_assert(sizeof(IN6_ADDR) == sizeof(otIp6Address), "Windows and OpenThread IPv6 Addr Structs must be same size"); + + memcpy(&newRow.Address.Ipv6.sin6_addr, &aAddress->mAddress, sizeof(IN6_ADDR)); + newRow.OnLinkPrefixLength = aAddress->mPrefixLength; + newRow.PreferredLifetime = aAddress->mPreferredLifetime; + newRow.ValidLifetime = aAddress->mValidLifetime; + newRow.PrefixOrigin = IpPrefixOriginOther; // Derived from network XPANID + newRow.SkipAsSource = FALSE; // Allow automatic binding to this address (default) + + if (IN6_IS_ADDR_LINKLOCAL(&newRow.Address.Ipv6.sin6_addr)) + { + newRow.SuffixOrigin = IpSuffixOriginLinkLayerAddress; // Derived from Extended MAC address + } + else + { + newRow.SuffixOrigin = IpSuffixOriginRandom; // Was created randomly + } + + DWORD dwError = CreateUnicastIpAddressEntry(&newRow); + + // Revert the comparment if necessary + if (RevertCompartmentOnExit) + { + (VOID)SetCurrentThreadCompartmentId(OriginalCompartmentID); + } + + if (dwError != ERROR_SUCCESS) + { + otLogCritApi("CreateUnicastIpAddressEntry failed %!WINERROR!", dwError); + return kThreadError_Failed; + } + + return kThreadError_None; +} + +OTAPI +ThreadError +OTCALL +otRemoveUnicastAddress( + _In_ otInstance *aInstance, + const otIp6Address *aAddress + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + // Put the current thead in the correct compartment + bool RevertCompartmentOnExit = false; + ULONG OriginalCompartmentID = GetCurrentThreadCompartmentId(); + if (OriginalCompartmentID != aInstance->CompartmentID) + { + DWORD dwError = ERROR_SUCCESS; + if ((dwError = SetCurrentThreadCompartmentId(aInstance->CompartmentID)) != ERROR_SUCCESS) + { + otLogCritApi("SetCurrentThreadCompartmentId failed, %!WINERROR!", dwError); + return kThreadError_Failed; + } + RevertCompartmentOnExit = true; + } + + MIB_UNICASTIPADDRESS_ROW deleteRow; + InitializeUnicastIpAddressEntry(&deleteRow); + + deleteRow.InterfaceIndex = aInstance->InterfaceIndex; + deleteRow.InterfaceLuid = aInstance->InterfaceLuid; + deleteRow.Address.si_family = AF_INET6; + + memcpy(&deleteRow.Address.Ipv6.sin6_addr, aAddress, sizeof(IN6_ADDR)); + + DWORD dwError = DeleteUnicastIpAddressEntry(&deleteRow); + + // Revert the comparment if necessary + if (RevertCompartmentOnExit) + { + (VOID)SetCurrentThreadCompartmentId(OriginalCompartmentID); + } + + if (dwError != ERROR_SUCCESS) + { + otLogCritApi("DeleteUnicastIpAddressEntry failed %!WINERROR!", dwError); + return kThreadError_Failed; + } + + return kThreadError_None; +} + +OTAPI +ThreadError +OTCALL +otSetStateChangedCallback( + _In_ otInstance *aInstance, + _In_ otStateChangedCallback aCallback, + _In_ void *aContext + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + bool success = + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->StateChangedCallbacks, + aInstance->InterfaceGuid, aCallback, aContext + ); + return success ? kThreadError_None : kThreadError_Already; +} + +OTAPI +void +OTCALL +otRemoveStateChangeCallback( + _In_ otInstance *aInstance, + _In_ otStateChangedCallback /* aCallback */, + _In_ void *aContext + ) +{ + if (aInstance == nullptr) return; + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->StateChangedCallbacks, + aInstance->InterfaceGuid, (otStateChangedCallback)nullptr, aContext + ); +} + +OTAPI +ThreadError +OTCALL +otGetActiveDataset( + _In_ otInstance *aInstance, + _Out_ otOperationalDataset *aDataset + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ACTIVE_DATASET, aDataset)); +} + +OTAPI +ThreadError +OTCALL +otSetActiveDataset( + _In_ otInstance *aInstance, + const otOperationalDataset *aDataset + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_ACTIVE_DATASET, aDataset)); +} + +OTAPI +ThreadError +OTCALL +otGetPendingDataset( + _In_ otInstance *aInstance, + _Out_ otOperationalDataset *aDataset + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_PENDING_DATASET, aDataset)); +} + +OTAPI +ThreadError +OTCALL +otSetPendingDataset( + _In_ otInstance *aInstance, + const otOperationalDataset *aDataset + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_PENDING_DATASET, aDataset)); +} + +OTAPI +ThreadError +OTCALL +otSendActiveGet( + _In_ otInstance *aInstance, + const uint8_t *aTlvTypes, + uint8_t aLength, + _In_opt_ const otIp6Address *aAddress + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + if (aTlvTypes == nullptr && aLength != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(uint8_t) + aLength; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), &aLength, sizeof(aLength)); + if (aLength > 0) + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(uint8_t), aTlvTypes, aLength); + + // TODO - include aAddress + UNREFERENCED_PARAMETER(aAddress); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_ACTIVE_GET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otSendActiveSet( + _In_ otInstance *aInstance, + const otOperationalDataset *aDataset, + const uint8_t *aTlvs, + uint8_t aLength + ) +{ + if (aInstance == nullptr || aDataset == nullptr) return kThreadError_InvalidArgs; + if (aTlvs == nullptr && aLength != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(otOperationalDataset) + sizeof(uint8_t) + aLength; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), aDataset, sizeof(otOperationalDataset)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otOperationalDataset), BufferSize - sizeof(GUID) - sizeof(otOperationalDataset), &aLength, sizeof(aLength)); + if (aLength > 0) + memcpy_s(Buffer + sizeof(GUID) + sizeof(otOperationalDataset) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(otOperationalDataset) - sizeof(uint8_t), aTlvs, aLength); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_ACTIVE_SET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otSendPendingGet( + _In_ otInstance *aInstance, + const uint8_t *aTlvTypes, + uint8_t aLength, + _In_opt_ const otIp6Address *aAddress + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + if (aTlvTypes == nullptr && aLength != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(uint8_t) + aLength; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), &aLength, sizeof(aLength)); + if (aLength > 0) + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(uint8_t), aTlvTypes, aLength); + + // TODO - include aAddress + UNREFERENCED_PARAMETER(aAddress); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_PENDING_GET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otSendPendingSet( + _In_ otInstance *aInstance, + const otOperationalDataset *aDataset, + const uint8_t *aTlvs, + uint8_t aLength + ) +{ + if (aInstance == nullptr || aDataset == nullptr) return kThreadError_InvalidArgs; + if (aTlvs == nullptr && aLength != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(otOperationalDataset) + sizeof(uint8_t) + aLength; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), aDataset, sizeof(otOperationalDataset)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otOperationalDataset), BufferSize - sizeof(GUID) - sizeof(otOperationalDataset), &aLength, sizeof(aLength)); + if (aLength > 0) + memcpy_s(Buffer + sizeof(GUID) + sizeof(otOperationalDataset) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(otOperationalDataset) - sizeof(uint8_t), aTlvs, aLength); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_PENDING_SET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +uint32_t +OTCALL +otGetPollPeriod( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_POLL_PERIOD, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetPollPeriod( + _In_ otInstance *aInstance, + uint32_t aPollPeriod + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_POLL_PERIOD, aPollPeriod); +} + +OTAPI +uint8_t +OTCALL +otGetLocalLeaderWeight( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LOCAL_LEADER_WEIGHT, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetLocalLeaderWeight( + _In_ otInstance *aInstance, + uint8_t aWeight + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_LOCAL_LEADER_WEIGHT, aWeight); +} + +OTAPI +uint32_t +OTCALL +otGetLocalLeaderPartitionId( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LOCAL_LEADER_PARTITION_ID, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetLocalLeaderPartitionId( + _In_ otInstance *aInstance, + uint32_t aPartitionId + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_LOCAL_LEADER_PARTITION_ID, aPartitionId); +} + +OTAPI +uint16_t +OTCALL +otGetJoinerUdpPort( + _In_ otInstance *aInstance +) +{ + uint16_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_JOINER_UDP_PORT, &Result); + return Result; +} + +OTAPI +ThreadError +OTCALL +otSetJoinerUdpPort( + _In_ otInstance *aInstance, + uint16_t aJoinerUdpPort + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_JOINER_UDP_PORT, aJoinerUdpPort)); +} + +OTAPI +ThreadError +OTCALL +otAddBorderRouter( + _In_ otInstance *aInstance, + const otBorderRouterConfig *aConfig + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_ADD_BORDER_ROUTER, aConfig)); +} + +OTAPI +ThreadError +OTCALL +otRemoveBorderRouter( + _In_ otInstance *aInstance, + const otIp6Prefix *aPrefix + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_REMOVE_BORDER_ROUTER, aPrefix)); +} + +OTAPI +ThreadError +OTCALL +otAddExternalRoute( + _In_ otInstance *aInstance, + const otExternalRouteConfig *aConfig + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_ADD_EXTERNAL_ROUTE, aConfig)); +} + +OTAPI +ThreadError +OTCALL +otRemoveExternalRoute( + _In_ otInstance *aInstance, + const otIp6Prefix *aPrefix + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_REMOVE_EXTERNAL_ROUTE, aPrefix)); +} + +OTAPI +ThreadError +OTCALL +otSendServerData( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_SEND_SERVER_DATA)); +} + +OTAPI +uint32_t +OTCALL +otGetContextIdReuseDelay( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_CONTEXT_ID_REUSE_DELAY, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetContextIdReuseDelay( + _In_ otInstance *aInstance, + uint32_t aDelay + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_CONTEXT_ID_REUSE_DELAY, aDelay); +} + +OTAPI +uint32_t +OTCALL +otGetKeySequenceCounter( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_KEY_SEQUENCE_COUNTER, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetKeySequenceCounter( + _In_ otInstance *aInstance, + uint32_t aKeySequenceCounter + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_KEY_SEQUENCE_COUNTER, aKeySequenceCounter); +} + +OTAPI +uint32_t +OTCALL +otGetKeySwitchGuardTime( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetKeySwitchGuardTime( + _In_ otInstance *aInstance, + uint32_t aKeySwitchGuardTime + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME, aKeySwitchGuardTime); +} + +OTAPI +uint8_t +OTCALL +otGetNetworkIdTimeout( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_NETWORK_ID_TIMEOUT, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetNetworkIdTimeout( + _In_ otInstance *aInstance, + uint8_t aTimeout + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_NETWORK_ID_TIMEOUT, aTimeout); +} + +OTAPI +uint8_t +OTCALL +otGetRouterUpgradeThreshold( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_UPGRADE_THRESHOLD, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetRouterUpgradeThreshold( + _In_ otInstance *aInstance, + uint8_t aThreshold + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_UPGRADE_THRESHOLD, aThreshold); +} + +OTAPI +uint8_t +OTCALL +otGetRouterDowngradeThreshold( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_DOWNGRADE_THRESHOLD, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetRouterDowngradeThreshold( + _In_ otInstance *aInstance, + uint8_t aThreshold + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_DOWNGRADE_THRESHOLD, aThreshold); +} + +OTAPI +uint8_t +OTCALL +otGetRouterSelectionJitter( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_SELECTION_JITTER, &Result); + return Result; +} + +OTAPI +void +OTCALL +otSetRouterSelectionJitter( + _In_ otInstance *aInstance, + uint8_t aRouterJitter + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_SELECTION_JITTER, aRouterJitter); +} + +OTAPI +ThreadError +OTCALL +otReleaseRouterId( + _In_ otInstance *aInstance, + uint8_t aRouterId + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_RELEASE_ROUTER_ID, aRouterId)); +} + +OTAPI +ThreadError +OTCALL +otAddMacWhitelist( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_ADD_MAC_WHITELIST, (const otExtAddress*)aExtAddr)); +} + +OTAPI +ThreadError +OTCALL +otAddMacWhitelistRssi( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr, + int8_t aRssi + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + PackedBuffer3 Buffer(aInstance->InterfaceGuid, *(otExtAddress*)aExtAddr, aRssi); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_ADD_MAC_WHITELIST, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +void +OTCALL +otRemoveMacWhitelist( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_REMOVE_MAC_WHITELIST, (const otExtAddress*)aExtAddr); +} + +OTAPI +ThreadError +OTCALL +otGetMacWhitelistEntry( + _In_ otInstance *aInstance, + uint8_t aIndex, + _Out_ otMacWhitelistEntry *aEntry + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_WHITELIST_ENTRY, &aIndex, aEntry)); +} + +OTAPI +void +OTCALL +otClearMacWhitelist( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_CLEAR_MAC_WHITELIST); +} + +OTAPI +void +OTCALL +otDisableMacWhitelist( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED, (BOOLEAN)FALSE); +} + +OTAPI +void +OTCALL +otEnableMacWhitelist( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED, (BOOLEAN)TRUE); +} + +OTAPI +bool +OTCALL +otIsMacWhitelistEnabled( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED, &Result); + return Result != FALSE; +} + +OTAPI +ThreadError +OTCALL +otBecomeDetached( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_DEVICE_ROLE, (uint8_t)kDeviceRoleDetached)); +} + +OTAPI +ThreadError +OTCALL +otBecomeChild( + _In_ otInstance *aInstance, + otMleAttachFilter aFilter + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + uint8_t Role = kDeviceRoleDetached; + uint8_t Filter = (uint8_t)aFilter; + + PackedBuffer3 Buffer(aInstance->InterfaceGuid, Role, Filter); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_DEVICE_ROLE, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otBecomeRouter( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_DEVICE_ROLE, (uint8_t)kDeviceRoleRouter)); +} + +OTAPI +ThreadError +OTCALL +otBecomeLeader( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_DEVICE_ROLE, (uint8_t)kDeviceRoleLeader)); +} + +OTAPI +ThreadError +OTCALL +otAddMacBlacklist( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_ADD_MAC_BLACKLIST, (const otExtAddress*)aExtAddr)); +} + +OTAPI +void +OTCALL +otRemoveMacBlacklist( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_REMOVE_MAC_BLACKLIST, (const otExtAddress*)aExtAddr); +} + +OTAPI +ThreadError +OTCALL +otGetMacBlacklistEntry( + _In_ otInstance *aInstance, + uint8_t aIndex, + _Out_ otMacBlacklistEntry *aEntry + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_BLACKLIST_ENTRY, &aIndex, aEntry)); +} + +OTAPI +void +OTCALL +otClearMacBlacklist( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_CLEAR_MAC_BLACKLIST); +} + +OTAPI +void +OTCALL +otDisableMacBlacklist( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED, (BOOLEAN)FALSE); +} + +OTAPI +void +OTCALL +otEnableMacBlacklist( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED, (BOOLEAN)TRUE); +} + +OTAPI +bool +OTCALL +otIsMacBlacklistEnabled( + _In_ otInstance *aInstance + ) +{ + BOOLEAN Result = 0; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED, &Result); + return Result != FALSE; +} + +OTAPI +ThreadError +OTCALL +otGetAssignLinkQuality( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr, + _Out_ uint8_t *aLinkQuality + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ASSIGN_LINK_QUALITY, (otExtAddress*)aExtAddr, aLinkQuality)); +} + +OTAPI +void +OTCALL +otSetAssignLinkQuality( + _In_ otInstance *aInstance, + const uint8_t *aExtAddr, + uint8_t aLinkQuality + ) +{ + if (aInstance == nullptr) return; + PackedBuffer3 Buffer(aInstance->InterfaceGuid, *(otExtAddress*)aExtAddr, aLinkQuality); + (void)SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_ASSIGN_LINK_QUALITY, &Buffer, sizeof(Buffer), nullptr, 0); +} + +OTAPI +void +OTCALL +otPlatformReset( + _In_ otInstance *aInstance + ) +{ + if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_PLATFORM_RESET); +} + +OTAPI +ThreadError +OTCALL +otGetChildInfoById( + _In_ otInstance *aInstance, + uint16_t aChildId, + _Out_ otChildInfo *aChildInfo + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_CHILD_INFO_BY_ID, &aChildId, aChildInfo)); +} + +OTAPI +ThreadError +OTCALL +otGetChildInfoByIndex( + _In_ otInstance *aInstance, + uint8_t aChildIndex, + _Out_ otChildInfo *aChildInfo + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_CHILD_INFO_BY_INDEX, &aChildIndex, aChildInfo)); +} + +OTAPI +otDeviceRole +OTCALL +otGetDeviceRole( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = kDeviceRoleOffline; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_DEVICE_ROLE, &Result); + return (otDeviceRole)Result; +} + +OTAPI +ThreadError +OTCALL +otGetEidCacheEntry( + _In_ otInstance *aInstance, + uint8_t aIndex, + _Out_ otEidCacheEntry *aEntry + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_EID_CACHE_ENTRY, &aIndex, aEntry)); +} + +OTAPI +ThreadError +OTCALL +otGetLeaderData( + _In_ otInstance *aInstance, + _Out_ otLeaderData *aLeaderData + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LEADER_DATA, aLeaderData)); +} + +OTAPI +uint8_t +OTCALL +otGetLeaderRouterId( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0xFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LEADER_ROUTER_ID, &Result); + return Result; +} + +OTAPI +uint8_t +OTCALL +otGetLeaderWeight( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0xFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_LEADER_WEIGHT, &Result); + return Result; +} + +OTAPI +uint8_t +OTCALL +otGetNetworkDataVersion( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0xFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_NETWORK_DATA_VERSION, &Result); + return Result; +} + +OTAPI +uint32_t +OTCALL +otGetPartitionId( + _In_ otInstance *aInstance + ) +{ + uint32_t Result = 0xFFFFFFFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_PARTITION_ID, &Result); + return Result; +} + +OTAPI +uint16_t +OTCALL +otGetRloc16( + _In_ otInstance *aInstance + ) +{ + uint16_t Result = 0xFFFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_RLOC16, &Result); + return Result; +} + +OTAPI +uint8_t +OTCALL +otGetRouterIdSequence( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0xFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_ID_SEQUENCE, &Result); + return Result; +} + +OTAPI +ThreadError +OTCALL +otGetRouterInfo( + _In_ otInstance *aInstance, + uint16_t aRouterId, + _Out_ otRouterInfo *aRouterInfo + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_INFO, &aRouterId, aRouterInfo)); +} + +OTAPI +ThreadError +OTCALL +otGetParentInfo( + _In_ otInstance *aInstance, + _Out_ otRouterInfo *aParentInfo + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + static_assert(sizeof(otRouterInfo) == 20, "The size of otRouterInfo should be 20 bytes"); + return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_PARENT_INFO, aParentInfo)); +} + +OTAPI +uint8_t +OTCALL +otGetStableNetworkDataVersion( + _In_ otInstance *aInstance + ) +{ + uint8_t Result = 0xFF; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_STABLE_NETWORK_DATA_VERSION, &Result); + return Result; +} + +OTAPI +const otMacCounters* +OTCALL +otGetMacCounters( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return nullptr; + + otMacCounters* aCounters = (otMacCounters*)malloc(sizeof(otMacCounters)); + if (aCounters) + { + if (ERROR_SUCCESS != QueryIOCTL(aInstance, IOCTL_OTLWF_OT_MAC_COUNTERS, aCounters)) + { + free(aCounters); + aCounters = nullptr; + } + } + return aCounters; +} + +OTAPI +bool +OTCALL +otIsIp6AddressEqual( + const otIp6Address *a, + const otIp6Address *b + ) +{ + return memcmp(a->mFields.m8, b->mFields.m8, sizeof(otIp6Address)) == 0; +} + +OTAPI +ThreadError +OTCALL +otIp6AddressFromString( + const char *str, + otIp6Address *address + ) +{ + ThreadError error = kThreadError_None; + uint8_t *dst = reinterpret_cast(address->mFields.m8); + uint8_t *endp = reinterpret_cast(address->mFields.m8 + 15); + uint8_t *colonp = NULL; + uint16_t val = 0; + uint8_t count = 0; + bool first = true; + char ch; + uint8_t d; + + memset(address->mFields.m8, 0, 16); + + dst--; + + for (;;) + { + ch = *str++; + d = ch & 0xf; + + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')) + { + d += 9; + } + else if (ch == ':' || ch == '\0' || ch == ' ') + { + if (count) + { + if (dst + 2 > endp) + { + error = kThreadError_Parse; + goto exit; + } + *(dst + 1) = static_cast(val >> 8); + *(dst + 2) = static_cast(val); + dst += 2; + count = 0; + val = 0; + } + else if (ch == ':') + { + if (!(colonp == nullptr || first)) + { + error = kThreadError_Parse; + goto exit; + } + colonp = dst; + } + + if (ch == '\0' || ch == ' ') + { + break; + } + + continue; + } + else + { + if (!('0' <= ch && ch <= '9')) + { + error = kThreadError_Parse; + goto exit; + } + } + + first = false; + val = static_cast((val << 4) | d); + if (!(++count <= 4)) + { + error = kThreadError_Parse; + goto exit; + } + } + + while (colonp && dst > colonp) + { + *endp-- = *dst--; + } + + while (endp > dst) + { + *endp-- = 0; + } + +exit: + return error; +} + +OTAPI +uint8_t +OTCALL +otIp6PrefixMatch( + const otIp6Address *aFirst, + const otIp6Address *aSecond + ) +{ + uint8_t rval = 0; + uint8_t diff; + + for (uint8_t i = 0; i < sizeof(otIp6Address); i++) + { + diff = aFirst->mFields.m8[i] ^ aSecond->mFields.m8[i]; + + if (diff == 0) + { + rval += 8; + } + else + { + while ((diff & 0x80) == 0) + { + rval++; + diff <<= 1; + } + + break; + } + } + + return rval; +} + +OTAPI +ThreadError +OTCALL +otSendDiagnosticGet( + _In_ otInstance *aInstance, + const otIp6Address *aDestination, + const uint8_t aTlvTypes[], + uint8_t aCount + ) +{ + if (aInstance == nullptr || aDestination == nullptr) return kThreadError_InvalidArgs; + if (aTlvTypes == nullptr && aCount != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(otIp6Address) + sizeof(uint8_t) + aCount; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), aDestination, sizeof(otIp6Address)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otIp6Address), BufferSize - sizeof(GUID) - sizeof(otIp6Address), &aCount, sizeof(aCount)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otIp6Address) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(otIp6Address) - sizeof(uint8_t), aTlvTypes, aCount); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_GET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otSendDiagnosticReset( + _In_ otInstance *aInstance, + const otIp6Address *aDestination, + const uint8_t aTlvTypes[], + uint8_t aCount + ) +{ + if (aInstance == nullptr || aDestination == nullptr) return kThreadError_InvalidArgs; + if (aTlvTypes == nullptr && aCount != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(otIp6Address) + sizeof(uint8_t) + aCount; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), aDestination, sizeof(otIp6Address)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otIp6Address), BufferSize - sizeof(GUID) - sizeof(otIp6Address), &aCount, sizeof(aCount)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otIp6Address) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(otIp6Address) - sizeof(uint8_t), aTlvTypes, aCount); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_RESET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otCommissionerStart( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_COMMISIONER_START)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerAddJoiner( + _In_ otInstance *aInstance, + const otExtAddress *aExtAddress, + const char *aPSKd + ) +{ + if (aInstance == nullptr || aPSKd == nullptr) return kThreadError_InvalidArgs; + + size_t aPSKdLength = strnlen(aPSKd, OPENTHREAD_PSK_MAX_LENGTH + 1); + if (aPSKdLength > OPENTHREAD_PSK_MAX_LENGTH) + { + return kThreadError_InvalidArgs; + } + + uint8_t aExtAddressValid = aExtAddress ? 1 : 0; + + const ULONG BufferLength = sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + (ULONG)aPSKdLength + 1; + BYTE Buffer[sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + OPENTHREAD_PSK_MAX_LENGTH + 1] = {0}; + memcpy_s(Buffer, sizeof(Buffer), &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), sizeof(Buffer) - sizeof(GUID), &aExtAddressValid, sizeof(aExtAddressValid)); + if (aExtAddressValid) + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t), sizeof(Buffer) - sizeof(GUID) - sizeof(uint8_t), aExtAddress, sizeof(otExtAddress)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress), sizeof(Buffer) - sizeof(GUID) - sizeof(uint8_t) - sizeof(otExtAddress), aPSKd, aPSKdLength); + + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISIONER_ADD_JOINER, Buffer, BufferLength, nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerRemoveJoiner( + _In_ otInstance *aInstance, + const otExtAddress *aExtAddress + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + uint8_t aExtAddressValid = aExtAddress ? 1 : 0; + + BYTE Buffer[sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress)] = {0}; + memcpy_s(Buffer, sizeof(Buffer), &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), sizeof(Buffer) - sizeof(GUID), &aExtAddressValid, sizeof(aExtAddressValid)); + if (aExtAddressValid) + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t), sizeof(Buffer) - sizeof(GUID) - sizeof(uint8_t), aExtAddress, sizeof(otExtAddress)); + + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISIONER_REMOVE_JOINER, Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerSetProvisioningUrl( + _In_ otInstance *aInstance, + const char *aProvisioningUrl + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + size_t aProvisioningUrlLength = aProvisioningUrl ? strnlen(aProvisioningUrl, OPENTHREAD_PROV_URL_MAX_LENGTH + 1) : 0; + if (aProvisioningUrlLength > OPENTHREAD_PROV_URL_MAX_LENGTH) + { + return kThreadError_InvalidArgs; + } + + const ULONG BufferLength = sizeof(GUID) + (ULONG)aProvisioningUrlLength + 1; + BYTE Buffer[sizeof(GUID) + OPENTHREAD_PROV_URL_MAX_LENGTH + 1] = {0}; + memcpy_s(Buffer, sizeof(Buffer), &aInstance->InterfaceGuid, sizeof(GUID)); + if (aProvisioningUrlLength > 0) + memcpy_s(Buffer + sizeof(GUID), sizeof(Buffer) - sizeof(GUID), aProvisioningUrl, aProvisioningUrlLength); + + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISIONER_PROVISIONING_URL, Buffer, BufferLength, nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerAnnounceBegin( + otInstance *aInstance, + uint32_t aChannelMask, + uint8_t aCount, + uint16_t aPeriod, + const otIp6Address *aAddress + ) +{ + if (aInstance == nullptr || aAddress == nullptr) return kThreadError_InvalidArgs; + + PackedBuffer5 Buffer(aInstance->InterfaceGuid, aChannelMask, aCount, aPeriod, *aAddress); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISIONER_ANNOUNCE_BEGIN, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerStop( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_COMMISIONER_STOP)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerEnergyScan( + _In_ otInstance *aInstance, + uint32_t aChannelMask, + uint8_t aCount, + uint16_t aPeriod, + uint16_t aScanDuration, + const otIp6Address *aAddress, + _In_ otCommissionerEnergyReportCallback aCallback, + _In_ void *aContext + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->CommissionerEnergyReportCallbacks, + aInstance->InterfaceGuid, aCallback, aContext + ); + + PackedBuffer6 Buffer(aInstance->InterfaceGuid, aChannelMask, aCount, aPeriod, aScanDuration, *aAddress); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISSIONER_ENERGY_SCAN, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otCommissionerPanIdQuery( + _In_ otInstance *aInstance, + uint16_t aPanId, + uint32_t aChannelMask, + const otIp6Address *aAddress, + _In_ otCommissionerPanIdConflictCallback aCallback, + _In_ void *aContext + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + + aInstance->ApiHandle->SetCallback( + aInstance->ApiHandle->CommissionerPanIdConflictCallbacks, + aInstance->InterfaceGuid, aCallback, aContext + ); + + PackedBuffer4 Buffer(aInstance->InterfaceGuid, aPanId, aChannelMask, *aAddress); + return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISSIONER_PANID_QUERY, &Buffer, sizeof(Buffer), nullptr, 0)); +} + +OTAPI +ThreadError +OTCALL +otSendMgmtCommissionerGet( + _In_ otInstance *aInstance, + const uint8_t *aTlvs, + uint8_t aLength +) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + if (aTlvs == nullptr && aLength != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(uint8_t) + aLength; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), &aLength, sizeof(aLength)); + if (aLength > 0) + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(uint8_t), aTlvs, aLength); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otSendMgmtCommissionerSet( + _In_ otInstance *aInstance, + const otCommissioningDataset *aDataset, + const uint8_t *aTlvs, + uint8_t aLength + ) +{ + if (aInstance == nullptr || aDataset == nullptr) return kThreadError_InvalidArgs; + if (aTlvs == nullptr && aLength != 0) return kThreadError_InvalidArgs; + + DWORD BufferSize = sizeof(GUID) + sizeof(otCommissioningDataset) + sizeof(uint8_t) + aLength; + PBYTE Buffer = (PBYTE)malloc(BufferSize); + if (Buffer == nullptr) return kThreadError_NoBufs; + + memcpy_s(Buffer, BufferSize, &aInstance->InterfaceGuid, sizeof(GUID)); + memcpy_s(Buffer + sizeof(GUID), BufferSize - sizeof(GUID), aDataset, sizeof(otCommissioningDataset)); + memcpy_s(Buffer + sizeof(GUID) + sizeof(otCommissioningDataset), BufferSize - sizeof(GUID) - sizeof(otCommissioningDataset), &aLength, sizeof(aLength)); + if (aLength > 0) + memcpy_s(Buffer + sizeof(GUID) + sizeof(otCommissioningDataset) + sizeof(uint8_t), BufferSize - sizeof(GUID) - sizeof(otCommissioningDataset) - sizeof(uint8_t), aTlvs, aLength); + + ThreadError result = + DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET, Buffer, BufferSize, nullptr, 0)); + + free(Buffer); + return result; +} + +OTAPI +ThreadError +OTCALL +otJoinerStart( + _In_ otInstance *aInstance, + const char *aPSKd, + const char *aProvisioningUrl + ) +{ + if (aInstance == nullptr || aPSKd == nullptr) return kThreadError_InvalidArgs; + + otCommissionConfig config = {0}; + + size_t aPSKdLength = strlen(aPSKd); + size_t aProvisioningUrlLength = aProvisioningUrl == nullptr ? 0 : strlen(aProvisioningUrl); + + if (aPSKdLength > OPENTHREAD_PSK_MAX_LENGTH || + aProvisioningUrlLength > OPENTHREAD_PROV_URL_MAX_LENGTH) + { + return kThreadError_InvalidArgs; + } + + memcpy_s(config.PSKd, sizeof(config.PSKd), aPSKd, aPSKdLength); + memcpy_s(config.ProvisioningUrl, sizeof(config.ProvisioningUrl), aProvisioningUrl, aProvisioningUrlLength); + + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_JOINER_START, (const otCommissionConfig*)&config)); +} + +OTAPI +ThreadError +OTCALL +otJoinerStop( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_JOINER_STOP)); +} diff --git a/examples/drivers/windows/otApi/precomp.h b/examples/drivers/windows/otApi/precomp.h new file mode 100644 index 000000000..0e2419b63 --- /dev/null +++ b/examples/drivers/windows/otApi/precomp.h @@ -0,0 +1,31 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#pragma warning(disable:28301) // No annotations for first declaration of * + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Define to export necessary functions +#define OTDLL +#define OTAPI EXTERN_C __declspec(dllexport) + +#include +#include +#include +#include + +#include +#include +#include diff --git a/examples/drivers/windows/otLwf/device.c b/examples/drivers/windows/otLwf/device.c index 83f5f15d0..6bd72870f 100644 --- a/examples/drivers/windows/otLwf/device.c +++ b/examples/drivers/windows/otLwf/device.c @@ -175,6 +175,7 @@ otLwfDeviceClientCleanup( } // Free all pending notifications + NT_ASSERT(DeviceClient->NotificationSize <= OTLWF_MAX_PENDING_NOTIFICATIONS_PER_CLIENT); for (UCHAR i = 0; i < DeviceClient->NotificationSize; i++) { UCHAR index = (DeviceClient->NotificationOffset + i) % OTLWF_MAX_PENDING_NOTIFICATIONS_PER_CLIENT; @@ -515,6 +516,7 @@ otLwfIndicateNotification( // If there are other pending notifications or we don't have a pending IRP saved // then just go ahead and add the notification to the list + NT_ASSERT(DeviceClient->NotificationSize <= OTLWF_MAX_PENDING_NOTIFICATIONS_PER_CLIENT); if (DeviceClient->NotificationSize != 0 || DeviceClient->PendingNotificationIRP == NULL ) @@ -530,11 +532,15 @@ otLwfIndicateNotification( { LogWarning(DRIVER_IOCTL, "Dropping old notification!"); otLwfReleaseNotification(DeviceClient->PendingNotifications[DeviceClient->NotificationOffset]); + DeviceClient->NotificationOffset++; + } + else + { + DeviceClient->NotificationSize++; } // Copy the notification to the next space DeviceClient->PendingNotifications[Index] = NotifEntry; - DeviceClient->NotificationSize++; } else { diff --git a/examples/drivers/windows/otLwf/filter.c b/examples/drivers/windows/otLwf/filter.c index 74f8a2e5b..4fb65702f 100644 --- a/examples/drivers/windows/otLwf/filter.c +++ b/examples/drivers/windows/otLwf/filter.c @@ -523,8 +523,11 @@ Return Value: --*/ { - NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; - PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; + NTSTATUS NtStatus = STATUS_SUCCESS; + NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; + PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; + NL_INTERFACE_KEY key = {0}; + NL_INTERFACE_RW interfaceRw; PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; @@ -554,6 +557,28 @@ Return Value: // NdisGeneralAttributes->LookaheadSize = 128; } + + key.Luid = pFilter->InterfaceLuid; + NlInitializeInterfaceRw(&interfaceRw); + interfaceRw.DadTransmits = 0; + interfaceRw.SendUnsolicitedNeighborAdvertisementOnDad = FALSE; + + NtStatus = + NsiSetAllParameters( + NsiActive, + NsiSetDefault, + &NPI_MS_IPV6_MODULEID, + NlInterfaceObject, + &key, + sizeof(key), + &interfaceRw, + sizeof(interfaceRw)); + if (!NT_SUCCESS(NtStatus)) + { + LogError(DRIVER_DEFAULT, "NsiSetAllParameters (NlInterfaceObject) failed, %!STATUS!", NtStatus); + NdisStatus = NDIS_STATUS_FAILURE; + goto exit; + } // // Enable the data path @@ -567,6 +592,8 @@ Return Value: otLwfNotifyDeviceAvailabilityChange(pFilter, TRUE); LogInfo(DRIVER_DEFAULT, "Interface %!GUID! arrival, Filter=%p", &pFilter->InterfaceGuid, pFilter); +exit: + // // Ensure the state is Paused if restart failed. // diff --git a/examples/drivers/windows/otLwf/nsihelper.h b/examples/drivers/windows/otLwf/nsihelper.h index 5c6dc30ea..c3831995e 100644 --- a/examples/drivers/windows/otLwf/nsihelper.h +++ b/examples/drivers/windows/otLwf/nsihelper.h @@ -47,6 +47,17 @@ typedef enum _NSI_STORE { NsiBootFirmwareTable } NSI_STORE; +typedef enum _NSI_SET_ACTION { + NsiSetDefault, + NsiSetCreateOnly, + NsiSetCreateOrSet, + NsiSetDelete, + NsiSetReset, + NsiSetClear, + NsiSetCreateOrSetWithReference, + NsiSetDeleteWithReference, +} NSI_SET_ACTION; + typedef enum _NSI_STRUCT_TYPE { NsiStructRw, NsiStructRoDynamic, @@ -54,6 +65,160 @@ typedef enum _NSI_STRUCT_TYPE { NsiMaximumStructType } NSI_STRUCT_TYPE; +typedef struct _NL_INTERFACE_KEY { + IF_LUID Luid; +} NL_INTERFACE_KEY, *PNL_INTERFACE_KEY; + +typedef enum _NL_TYPE_OF_INTERFACE { + InterfaceAllowAll = 0, + InterfaceDisallowUnicast, + InterfaceDisallowMulticast, + InterfaceDisallowAll, + InterfaceUnchanged = -1 +} NL_TYPE_OF_INTERFACE; + +typedef enum _NL_DOMAIN_NETWORK_LOCATION { + DomainNetworkLocationRemote = 0, // connect to a domain network remotely via DA i.e. outside corp network. + DomainNetworkCategoryLink = 1, // connect to a domain network directly i.e. inside corp network. + DomainNetworkUnchanged = -1 +} NL_DOMAIN_NETWORK_LOCATION; + +typedef enum _NL_DOMAIN_TYPE { + DomainTypeNonDomainNetwork = 0, // connected to non-domain network. + DomainTypeDomainNetwork = 1, // connected to a network that has active directory. + DomainTypeDomainAuthenticated = 2, // connected to AD network and machine is authenticated against it. + DomainTypeUnchanged = -1 +} NL_DOMAIN_TYPE; + +typedef enum _NL_INTERFACE_ECN_CAPABILITY { + NlInterfaceEcnUnchanged = -1, + NlInterfaceEcnDisabled = 0, + NlInterfaceEcnUseEct1 = 1, + NlInterfaceEcnUseEct0 = 2, + NlInterfaceEcnAppDecide = 3 +} NL_INTERFACE_ECN_CAPABILITY, *PNL_INTERFACE_ECN_CAPABILITY; + +typedef enum _NL_INTERNET_CONNECTIVITY_STATUS { + NlNoInternetConnectivity, + NlNoInternetDnsResolutionSucceeded, + NlInternetConnectivityDetected, + NlInternetConnectivityUnknown = -1 +} NL_INTERNET_CONNECTIVITY_STATUS, *PNL_INTERNET_CONNECTIVITY_STATUS; + +typedef union _IP_ADDRESS_STORAGE { + IN_ADDR Ipv4; + IN6_ADDR Ipv6; + UCHAR Buffer[sizeof(IN6_ADDR)]; +} IP_ADDRESS_STORAGE, *PIP_ADDRESS_STORAGE; + +typedef struct _NL_INTERFACE_RW { + BOOLEAN AdvertisingEnabled; + BOOLEAN ForwardingEnabled; + BOOLEAN MulticastForwardingEnabled; + BOOLEAN WeakHostSend; + BOOLEAN WeakHostReceive; + BOOLEAN UseNeighborUnreachabilityDetection; + BOOLEAN UseAutomaticMetric; + BOOLEAN UseZeroBroadcastAddress; + BOOLEAN UseBroadcastForRouterDiscovery; + BOOLEAN DhcpRouterDiscoveryEnabled; + BOOLEAN ManagedAddressConfigurationSupported; + BOOLEAN OtherStatefulConfigurationSupported; + BOOLEAN AdvertiseDefaultRoute; + NL_NETWORK_CATEGORY NetworkCategory; + NL_ROUTER_DISCOVERY_BEHAVIOR RouterDiscoveryBehavior; + NL_TYPE_OF_INTERFACE TypeOfInterface; + ULONG Metric; + ULONG BaseReachableTime; // Base for random ReachableTime (in ms). + ULONG RetransmitTime; // Neighbor Solicitation timeout (in ms). + ULONG PathMtuDiscoveryTimeout; // Path MTU discovery timeout (in ms). + ULONG DadTransmits; // DupAddrDetectTransmits in RFC 2462. + NL_LINK_LOCAL_ADDRESS_BEHAVIOR LinkLocalAddressBehavior; + ULONG LinkLocalAddressTimeout; // In ms. + ULONG ZoneIndices[ScopeLevelCount]; // Zone part of a SCOPE_ID. + ULONG NlMtu; + ULONG SitePrefixLength; + ULONG MulticastForwardingHopLimit; + ULONG CurrentHopLimit; + IP_ADDRESS_STORAGE LinkLocalAddress; + BOOLEAN DisableDefaultRoutes; + ULONG AdvertisedRouterLifetime; + BOOLEAN SendUnsolicitedNeighborAdvertisementOnDad; + BOOLEAN LimitedLinkConnectivity; + BOOLEAN ForceARPNDPattern; + BOOLEAN EnableDirectMACPattern; + BOOLEAN EnableWol; + BOOLEAN ForceTunneling; + NL_DOMAIN_NETWORK_LOCATION DomainNetworkLocation; + ULONGLONG RandomizedEpoch; + NL_INTERFACE_ECN_CAPABILITY EcnCapability; + NL_DOMAIN_TYPE DomainType; + GUID NetworkSignature; + NL_INTERNET_CONNECTIVITY_STATUS InternetConnectivityDetected; + BOOLEAN ProxyDetected; + ULONG DadRetransmitTime; + BOOLEAN PrefixSharing; + BOOLEAN DisableUnconstrainedRouteLookup; + ULONG NetworkContext; + BOOLEAN ResetAutoconfigurationOnOperStatusDown; + BOOLEAN ClampMssEnabled; + +} NL_INTERFACE_RW, *PNL_INTERFACE_RW; + +__inline +VOID +NlInitializeInterfaceRw( + IN OUT PNL_INTERFACE_RW Rw + ) +{ + // + // Initialize all fields to values that indicate "no change". + // + memset(Rw, 0xff, sizeof(*Rw)); + Rw->BaseReachableTime = 0; + Rw->RetransmitTime = 0; + Rw->PathMtuDiscoveryTimeout = 0; + Rw->NlMtu = 0; + Rw->DadRetransmitTime = 0; +} + +typedef enum { + NlBestRouteObject, + NlCompartmentForwardingObject, + NlCompartmentObject, + NlControlProtocolObject, + NlEchoRequestObject, + NlEchoSequenceRequestObject, + NlGlobalObject, + NlInterfaceObject, + NlLocalAnycastAddressObject, + NlLocalMulticastAddressObject, + NlLocalUnicastAddressObject, + NlNeighborObject, + NlPathObject, + NlPotentialRouterObject, + NlPrefixPolicyObject, + NlProxyNeighborObject, + NlRouteObject, + NlSitePrefixObject, + NlSubInterfaceObject, + NlWakeUpPatternObject, + NlResolveNeighborObject, + NlSortAddressesObject, + NlMfeObject, + NlMfeNotifyObject, + NlInterfaceHopObject, + NlInterfaceUnprivilegedObject, + NlTunnelPhysicalInterfaceObject, + NlLocalityObject, + NlLocalityDataObject, + NlLocalityPrivateObject, + NlLocalBottleneckObject, + NlTimerObject, + NlDisconnectInterface, + NlMaximumObject +} NL_OBJECT_TYPE, *PNL_OBJECT_TYPE; + NSISTATUS NsiGetParameter( __in NSI_STORE Store, @@ -67,6 +232,18 @@ NsiGetParameter( __in ULONG ParameterOffset ); +NSISTATUS +NsiSetAllParameters( + __in NSI_STORE Store, + __in NSI_SET_ACTION Action, + __in PNPI_MODULEID ModuleId, + __in ULONG ObjectIndex, + __in_bcount_opt(KeyStructLength) PVOID KeyStruct, + __in ULONG KeyStructLength, + __in_bcount_opt(RwParameterStructLength) PVOID RwParameterStruct, + __in ULONG RwParameterStructLength + ); + extern CONST NPI_MODULEID NPI_MS_NDIS_MODULEID; typedef enum _NDIS_NSI_OBJECT_INDEX diff --git a/examples/drivers/windows/otLwf/precomp.h b/examples/drivers/windows/otLwf/precomp.h index b2501cc37..be0dec0ff 100644 --- a/examples/drivers/windows/otLwf/precomp.h +++ b/examples/drivers/windows/otLwf/precomp.h @@ -61,6 +61,8 @@ RtlCopyBufferToMdl( #include #include +#include +#include #include #include #include diff --git a/examples/platforms/posix/platform.c b/examples/platforms/posix/platform.c index e83ee60bc..eb181eea5 100644 --- a/examples/platforms/posix/platform.c +++ b/examples/platforms/posix/platform.c @@ -42,6 +42,7 @@ #include #include +#include #include #include diff --git a/include/Makefile.am b/include/Makefile.am index 1095e1b48..32d0e531e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -60,10 +60,14 @@ PRETTY_SUBDIRS = \ include_HEADERS = \ openthread.h \ - openthread-diag.h \ - openthread-crypto.h \ - openthread-types.h \ openthread-coap.h \ + openthread-crypto.h \ + openthread-diag.h \ + openthread-ip6.h \ + openthread-message.h \ + openthread-tasklet.h \ + openthread-types.h \ + openthread-udp.h \ $(NULL) install-headers: install-includeHEADERS diff --git a/include/commissioning/commissioner.h b/include/commissioning/commissioner.h index a919ad3c9..42f809819 100644 --- a/include/commissioning/commissioner.h +++ b/include/commissioning/commissioner.h @@ -35,6 +35,8 @@ #ifndef OPENTHREAD_COMMISSIONER_H_ #define OPENTHREAD_COMMISSIONER_H_ +#include + #ifdef __cplusplus extern "C" { #endif @@ -54,7 +56,7 @@ extern "C" { * @retval kThreadError_None Successfully started the Commissioner role. * */ -ThreadError otCommissionerStart(otInstance *aInstance); +OTAPI ThreadError OTCALL otCommissionerStart(otInstance *aInstance); /** * This function disables the Thread Commissioner role. @@ -64,7 +66,7 @@ ThreadError otCommissionerStart(otInstance *aInstance); * @retval kThreadError_None Successfully started the Commissioner role. * */ -ThreadError otCommissionerStop(otInstance *aInstance); +OTAPI ThreadError OTCALL otCommissionerStop(otInstance *aInstance); /** * This function adds a Joiner entry. @@ -78,7 +80,8 @@ ThreadError otCommissionerStop(otInstance *aInstance); * @retval kThreadError_InvalidArgs @p aExtAddress or @p aPSKd is invalid. * */ -ThreadError otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aExtAddress, const char *aPSKd); +OTAPI ThreadError OTCALL otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aExtAddress, + const char *aPSKd); /** * This function removes a Joiner entry. @@ -91,7 +94,7 @@ ThreadError otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *a * @retval kThreadError_InvalidArgs @p aExtAddress is invalid. * */ -ThreadError otCommissionerRemoveJoiner(otInstance *aIntsance, const otExtAddress *aExtAddress); +OTAPI ThreadError OTCALL otCommissionerRemoveJoiner(otInstance *aIntsance, const otExtAddress *aExtAddress); /** * This function sets the Provisioning URL. @@ -102,7 +105,7 @@ ThreadError otCommissionerRemoveJoiner(otInstance *aIntsance, const otExtAddress * @retval kThreadError_InvalidArgs @p aProvisioningUrl is invalid. * */ -ThreadError otCommissionerSetProvisioningUrl(otInstance *aInstance, const char *aProvisioningUrl); +OTAPI ThreadError OTCALL otCommissionerSetProvisioningUrl(otInstance *aInstance, const char *aProvisioningUrl); /** * This function sends an Announce Begin message. @@ -117,8 +120,9 @@ ThreadError otCommissionerSetProvisioningUrl(otInstance *aInstance, const char * * @retval kThreadError_NoBufs Insufficient buffers to generate an Announce Begin message. * */ -ThreadError otCommissionerAnnounceBegin(otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod, - const otIp6Address *aAddress); +OTAPI ThreadError OTCALL otCommissionerAnnounceBegin(otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, + uint16_t aPeriod, + const otIp6Address *aAddress); /** * This function pointer is called when the Commissioner receives an Energy Report. @@ -129,8 +133,8 @@ ThreadError otCommissionerAnnounceBegin(otInstance *aInstance, uint32_t aChannel * @param[in] aContext A pointer to application-specific context. * */ -typedef void (*otCommissionerEnergyReportCallback)(uint32_t aChannelMask, const uint8_t *aEnergyList, - uint8_t aEnergyListLength, void *aContext); +typedef void (OTCALL *otCommissionerEnergyReportCallback)(uint32_t aChannelMask, const uint8_t *aEnergyList, + uint8_t aEnergyListLength, void *aContext); /** * This function sends an Energy Scan Query message. @@ -148,9 +152,9 @@ typedef void (*otCommissionerEnergyReportCallback)(uint32_t aChannelMask, const * @retval kThreadError_NoBufs Insufficient buffers to generate an Energy Scan Query message. * */ -ThreadError otCommissionerEnergyScan(otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod, - uint16_t aScanDuration, const otIp6Address *aAddress, - otCommissionerEnergyReportCallback aCallback, void *aContext); +OTAPI ThreadError OTCALL otCommissionerEnergyScan(otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, + uint16_t aPeriod, uint16_t aScanDuration, const otIp6Address *aAddress, + otCommissionerEnergyReportCallback aCallback, void *aContext); /** * This function pointer is called when the Commissioner receives a PAN ID Conflict message. @@ -160,7 +164,7 @@ ThreadError otCommissionerEnergyScan(otInstance *aInstance, uint32_t aChannelMas * @param[in] aContext A pointer to application-specific context. * */ -typedef void (*otCommissionerPanIdConflictCallback)(uint16_t aPanId, uint32_t aChannelMask, void *aContext); +typedef void (OTCALL *otCommissionerPanIdConflictCallback)(uint16_t aPanId, uint32_t aChannelMask, void *aContext); /** * This function sends a PAN ID Query message. @@ -176,9 +180,9 @@ typedef void (*otCommissionerPanIdConflictCallback)(uint16_t aPanId, uint32_t aC * @retval kThreadError_NoBufs Insufficient buffers to generate a PAN ID Query message. * */ -ThreadError otCommissionerPanIdQuery(otInstance *aInstance, uint16_t aPanId, uint32_t aChannelMask, - const otIp6Address *aAddress, - otCommissionerPanIdConflictCallback aCallback, void *aContext); +OTAPI ThreadError OTCALL otCommissionerPanIdQuery(otInstance *aInstance, uint16_t aPanId, uint32_t aChannelMask, + const otIp6Address *aAddress, + otCommissionerPanIdConflictCallback aCallback, void *aContext); /** * This function sends MGMT_COMMISSIONER_GET. @@ -191,7 +195,7 @@ ThreadError otCommissionerPanIdQuery(otInstance *aInstance, uint16_t aPanId, uin * @retval kThreadError_NoBufs Insufficient buffer space to send. * */ -ThreadError otSendMgmtCommissionerGet(otInstance *, const uint8_t *aTlvs, uint8_t aLength); +OTAPI ThreadError OTCALL otSendMgmtCommissionerGet(otInstance *, const uint8_t *aTlvs, uint8_t aLength); /** * This function sends MGMT_COMMISSIONER_SET. @@ -205,8 +209,8 @@ ThreadError otSendMgmtCommissionerGet(otInstance *, const uint8_t *aTlvs, uint8_ * @retval kThreadError_NoBufs Insufficient buffer space to send. * */ -ThreadError otSendMgmtCommissionerSet(otInstance *, const otCommissioningDataset *aDataset, - const uint8_t *aTlvs, uint8_t aLength); +OTAPI ThreadError OTCALL otSendMgmtCommissionerSet(otInstance *, const otCommissioningDataset *aDataset, + const uint8_t *aTlvs, uint8_t aLength); /** * @} diff --git a/include/commissioning/joiner.h b/include/commissioning/joiner.h index db46bab8e..011797978 100644 --- a/include/commissioning/joiner.h +++ b/include/commissioning/joiner.h @@ -35,6 +35,8 @@ #ifndef OPENTHREAD_JOINER_H_ #define OPENTHREAD_JOINER_H_ +#include + #ifdef __cplusplus extern "C" { #endif @@ -57,7 +59,7 @@ extern "C" { * @retval kThreadError_InvalidArgs @p aPSKd or @p aProvisioningUrl is invalid. * */ -ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl); +OTAPI ThreadError OTCALL otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl); /** * This function disables the Thread Joiner role. @@ -65,7 +67,7 @@ ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char * * @param[in] aInstance A pointer to an OpenThread instance. * */ -ThreadError otJoinerStop(otInstance *aInstance); +OTAPI ThreadError OTCALL otJoinerStop(otInstance *aInstance); /** * @} diff --git a/include/openthread-ip6.h b/include/openthread-ip6.h new file mode 100644 index 000000000..63904d77a --- /dev/null +++ b/include/openthread-ip6.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines the top-level ip6 functions for the OpenThread library. + */ + +#ifndef OPENTHREAD_IP6_H_ +#define OPENTHREAD_IP6_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup api API + * @brief + * This module includes the application programming interface to the OpenThread stack. + * + * @{ + * + * @defgroup execution Execution + * @defgroup commands Commands + * @defgroup config Configuration + * @defgroup diags Diagnostics + * @defgroup messages Message Buffers + * @defgroup ip6 IPv6 + * @defgroup udp UDP + * @defgroup coap CoAP + * + * @} + * + */ + +/** + * @addtogroup diags Diagnostics + * + * @brief + * This module includes functions that expose internal state. + * + * @{ + * + */ + +/** + * This function pointer is called when an IEEE 802.15.4 frame is received. + * + * @note This callback is called after FCS processing and @p aFrame may not contain the actual FCS that was received. + * + * @note This callback is called before IEEE 802.15.4 security processing and mSecurityValid in @p aFrame will + * always be false. + * + * @param[in] aFrame A pointer to the received IEEE 802.15.4 frame. + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (*otLinkPcapCallback)(const RadioPacket *aFrame, void *aContext); + +/** + * This function registers a callback to provide received raw IEEE 802.15.4 frames. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aPcapCallback A pointer to a function that is called when receiving an IEEE 802.15.4 link frame or + * NULL to disable the callback. + * @param[in] aCallbackContext A pointer to application-specific context. + * + */ +void otSetLinkPcapCallback(otInstance *aInstance, otLinkPcapCallback aPcapCallback, void *aCallbackContext); + +/** + * This function indicates whether or not promiscuous mode is enabled at the link layer. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval true Promiscuous mode is enabled. + * @retval false Promiscuous mode is not enabled. + * + */ +bool otIsLinkPromiscuous(otInstance *aInstance); + +/** + * This function enables or disables the link layer promiscuous mode. + * + * @note Promiscuous mode may only be enabled when the Thread interface is disabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aPromiscuous true to enable promiscuous mode, or false otherwise. + * + * @retval kThreadError_None Successfully enabled promiscuous mode. + * @retval kThreadError_InvalidState Could not enable promiscuous mode because + * the Thread interface is enabled. + * + */ +ThreadError otSetLinkPromiscuous(otInstance *aInstance, bool aPromiscuous); + +/** + * @} + * + */ + +/** + * @addtogroup ip6 IPv6 + * + * @brief + * This module includes functions that control IPv6 communication. + * + * @{ + * + */ + +/** + * Allocate a new message buffer for sending an IPv6 message. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aLinkSecurityEnabled TRUE if the message should be secured at Layer 2 + * + * @returns A pointer to the message buffer or NULL if no message buffers are available. + * + * @sa otFreeMessage + */ +otMessage otNewIp6Message(otInstance *aInstance, bool aLinkSecurityEnabled); + +/** + * This function pointer is called when an IPv6 datagram is received. + * + * @param[in] aMessage A pointer to the message buffer containing the received IPv6 datagram. + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (*otReceiveIp6DatagramCallback)(otMessage aMessage, void *aContext); + +/** + * This function registers a callback to provide received IPv6 datagrams. + * + * By default, this callback does not pass Thread control traffic. See otSetReceiveIp6DatagramFilterEnabled() to + * change the Thread control traffic filter setting. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCallback A pointer to a function that is called when an IPv6 datagram is received or + * NULL to disable the callback. + * @param[in] aCallbackContext A pointer to application-specific context. + * + * @sa otIsReceiveIp6DatagramFilterEnabled + * @sa otSetReceiveIp6DatagramFilterEnabled + * + */ +void otSetReceiveIp6DatagramCallback(otInstance *aInstance, otReceiveIp6DatagramCallback aCallback, + void *aCallbackContext); + +/** + * This function indicates whether or not Thread control traffic is filtered out when delivering IPv6 datagrams + * via the callback specified in otSetReceiveIp6DatagramCallback(). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns TRUE if Thread control traffic is filtered out, FALSE otherwise. + * + * @sa otSetReceiveIp6DatagramCallback + * @sa otSetReceiveIp6DatagramFilterEnabled + * + */ +bool otIsReceiveIp6DatagramFilterEnabled(otInstance *aInstance); + +/** + * This function sets whether or not Thread control traffic is filtered out when delivering IPv6 datagrams + * via the callback specified in otSetReceiveIp6DatagramCallback(). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aEnabled TRUE if Thread control traffic is filtered out, FALSE otherwise. + * + * @sa otSetReceiveIp6DatagramCallback + * @sa otIsReceiveIp6DatagramFilterEnabled + * + */ +void otSetReceiveIp6DatagramFilterEnabled(otInstance *aInstance, bool aEnabled); + +/** + * This function sends an IPv6 datagram via the Thread interface. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMessage A pointer to the message buffer containing the IPv6 datagram. + * + */ +ThreadError otSendIp6Datagram(otInstance *aInstance, otMessage aMessage); + +/** + * This function indicates whether or not ICMPv6 Echo processing is enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE ICMPv6 Echo processing is enabled. + * @retval FALSE ICMPv6 Echo processing is disabled. + * + */ +bool otIsIcmpEchoEnabled(otInstance *aInstance); + +/** + * This function sets whether or not ICMPv6 Echo processing is enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aEnabled TRUE to enable ICMPv6 Echo processing, FALSE otherwise. + * + */ +void otSetIcmpEchoEnabled(otInstance *aInstance, bool aEnabled); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_IP6_H_ diff --git a/include/openthread-message.h b/include/openthread-message.h new file mode 100644 index 000000000..382c40241 --- /dev/null +++ b/include/openthread-message.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines the top-level ip6 functions for the OpenThread library. + */ + +#ifndef OPENTHREAD_MESSAGE_H_ +#define OPENTHREAD_MESSAGE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup api API + * @brief + * This module includes the application programming interface to the OpenThread stack. + * + * @{ + * + * @defgroup execution Execution + * @defgroup commands Commands + * @defgroup config Configuration + * @defgroup diags Diagnostics + * @defgroup messages Message Buffers + * @defgroup ip6 IPv6 + * @defgroup udp UDP + * @defgroup coap CoAP + * + * @} + * + */ + +/** + * @addtogroup messages Message Buffers + * + * @brief + * This module includes functions that manipulate OpenThread message buffers + * + * @{ + * + */ + +/** + * Free an allocated message buffer. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @retval kThreadErrorNone Successfully freed the message buffer. + * + * @sa otNewUdpMessage + * @sa otAppendMessage + * @sa otGetMessageLength + * @sa otSetMessageLength + * @sa otGetMessageOffset + * @sa otSetMessageOffset + * @sa otReadMessage + * @sa otWriteMessage + */ +ThreadError otFreeMessage(otMessage aMessage); + +/** + * Get the message length in bytes. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @returns The message length in bytes. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otAppendMessage + * @sa otSetMessageLength + * @sa otGetMessageOffset + * @sa otSetMessageOffset + * @sa otReadMessage + * @sa otWriteMessage + * @sa otSetMessageLength + */ +uint16_t otGetMessageLength(otMessage aMessage); + +/** + * Set the message length in bytes. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aLength A length in bytes. + * + * @retval kThreadErrorNone Successfully set the message length. + * @retval kThreadErrorNoBufs No available buffers to grow the message. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otAppendMessage + * @sa otGetMessageLength + * @sa otGetMessageOffset + * @sa otSetMessageOffset + * @sa otReadMessage + * @sa otWriteMessage + */ +ThreadError otSetMessageLength(otMessage aMessage, uint16_t aLength); + +/** + * Get the message offset in bytes. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @returns The message offset value. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otAppendMessage + * @sa otGetMessageLength + * @sa otSetMessageLength + * @sa otSetMessageOffset + * @sa otReadMessage + * @sa otWriteMessage + */ +uint16_t otGetMessageOffset(otMessage aMessage); + +/** + * Set the message offset in bytes. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aOffset An offset in bytes. + * + * @retval kThreadErrorNone Successfully set the message offset. + * @retval kThreadErrorInvalidArg The offset is beyond the message length. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otAppendMessage + * @sa otGetMessageLength + * @sa otSetMessageLength + * @sa otGetMessageOffset + * @sa otReadMessage + * @sa otWriteMessage + */ +ThreadError otSetMessageOffset(otMessage aMessage, uint16_t aOffset); + +/** + * Append bytes to a message. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aBuf A pointer to the data to append. + * @param[in] aLength Number of bytes to append. + * + * @retval kThreadErrorNone Successfully appended to the message + * @retval kThreadErrorNoBufs No available buffers to grow the message. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otGetMessageLength + * @sa otSetMessageLength + * @sa otGetMessageOffset + * @sa otSetMessageOffset + * @sa otReadMessage + * @sa otWriteMessage + */ +ThreadError otAppendMessage(otMessage aMessage, const void *aBuf, uint16_t aLength); + +/** + * Read bytes from a message. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aOffset An offset in bytes. + * @param[in] aBuf A pointer to a buffer that message bytes are read to. + * @param[in] aLength Number of bytes to read. + * + * @returns The number of bytes read. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otAppendMessage + * @sa otGetMessageLength + * @sa otSetMessageLength + * @sa otGetMessageOffset + * @sa otSetMessageOffset + * @sa otWriteMessage + */ +int otReadMessage(otMessage aMessage, uint16_t aOffset, void *aBuf, uint16_t aLength); + +/** + * Write bytes to a message. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aOffset An offset in bytes. + * @param[in] aBuf A pointer to a buffer that message bytes are written from. + * @param[in] aLength Number of bytes to write. + * + * @returns The number of bytes written. + * + * @sa otNewUdpMessage + * @sa otFreeMessage + * @sa otAppendMessage + * @sa otGetMessageLength + * @sa otSetMessageLength + * @sa otGetMessageOffset + * @sa otSetMessageOffset + * @sa otReadMessage + */ +int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint16_t aLength); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_MESSAGE_H_ diff --git a/include/openthread-tasklet.h b/include/openthread-tasklet.h new file mode 100644 index 000000000..eed8ee167 --- /dev/null +++ b/include/openthread-tasklet.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file includes the platform abstraction for the tasklet service. + */ + +#ifndef OPENTHREAD_TASKLET_H_ +#define OPENTHREAD_TASKLET_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup execution Execution + * + * @brief + * This module includes functions that control the Thread stack's execution. + * + * @{ + * + */ + +/** + * Run all queued OpenThread tasklets at the time this is called. + * + * @param[in] aInstance A pointer to an OpenThread instance. + */ +void otProcessQueuedTasklets(otInstance *aInstance); + +/** + * Indicates whether or not OpenThread has tasklets pending. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE If there are tasklets pending. + * @retval FALSE If there are no tasklets pending. + */ +bool otAreTaskletsPending(otInstance *aInstance); + +/** + * OpenThread calls this function when the tasklet queue transitions from empty to non-empty. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +extern void otSignalTaskletPending(otInstance *aInstance); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_TASKLET_H_ diff --git a/include/openthread-types.h b/include/openthread-types.h index 609e42b5d..b810f8386 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -37,6 +37,9 @@ #include #include +#ifdef OTDLL +#include +#endif #include @@ -61,14 +64,32 @@ extern "C" { #define myoffsetof(s,m) (((size_t)&(((s*)BASE)->m))-BASE) #define CONTAINING_RECORD(address, type, field) \ ((type *)((uint8_t*)(address) - myoffsetof(type, field))) -#endif -#endif +#endif /* CONTAINING_RECORD */ +#endif /* _WIN32 */ /** * This type represents the OpenThread instance structure. */ typedef struct otInstance otInstance; +#ifdef OTDLL + +/** + * This type represents the handle to the OpenThread API. + */ +typedef struct otApiInstance otApiInstance; + +/** + * This type represents a list of device GUIDs. + */ +typedef struct otDeviceList +{ + uint16_t aDevicesLength; + GUID aDevices[1]; +} otDeviceList; + +#endif + /** * This enumeration represents error codes used throughout OpenThread. */ @@ -489,6 +510,7 @@ typedef enum otMeshcopTlvType /** * This structure represents an MLE Link Mode configuration. */ +OT_TOOL_ALIGN(4) typedef struct otLinkModeConfig { /** @@ -709,6 +731,7 @@ typedef struct otMacBlacklistEntry */ typedef enum { + kDeviceRoleOffline, ///< The Thread device is offline and unavailable. kDeviceRoleDisabled, ///< The Thread stack is disabled. kDeviceRoleDetached, ///< Not currently participating in a Thread network/partition. kDeviceRoleChild, ///< The Thread Child role. @@ -764,6 +787,7 @@ typedef struct * This structure holds diagnostic information for a Thread Router * */ +OT_TOOL_ALIGN(4) typedef struct { otExtAddress mExtAddress; ///< IEEE 802.15.4 Extended Address diff --git a/include/openthread-udp.h b/include/openthread-udp.h new file mode 100644 index 000000000..7281a49d5 --- /dev/null +++ b/include/openthread-udp.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines the top-level ip6 functions for the OpenThread library. + */ + +#ifndef OPENTHREAD_UDP_H_ +#define OPENTHREAD_UDP_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup api API + * @brief + * This module includes the application programming interface to the OpenThread stack. + * + * @{ + * + * @defgroup execution Execution + * @defgroup commands Commands + * @defgroup config Configuration + * @defgroup diags Diagnostics + * @defgroup messages Message Buffers + * @defgroup ip6 IPv6 + * @defgroup udp UDP + * @defgroup coap CoAP + * + * @} + * + */ + +/** + * @addtogroup udp UDP + * + * @brief + * This module includes functions that control UDP communication. + * + * @{ + * + */ + +/** + * Allocate a new message buffer for sending a UDP message. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aLinkSecurityEnabled TRUE if the message should be secured at Layer 2. + * + * @returns A pointer to the message buffer or NULL if no message buffers are available. + * + * @sa otFreeMessage + */ +otMessage otNewUdpMessage(otInstance *aInstance, bool aLinkSecurityEnabled); + +/** + * Open a UDP/IPv6 socket. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aSocket A pointer to a UDP socket structure. + * @param[in] aCallback A pointer to the application callback function. + * @param[in] aContext A pointer to application-specific context. + * + * @retval kThreadErrorNone Successfully opened the socket. + * @retval kThreadErrorInvalidArgs Given socket structure was already opened. + * + * @sa otNewUdpMessage + * @sa otCloseUdpSocket + * @sa otBindUdpSocket + * @sa otSendUdp + */ +ThreadError otOpenUdpSocket(otInstance *aInstance, otUdpSocket *aSocket, otUdpReceive aCallback, void *aContext); + +/** + * Close a UDP/IPv6 socket. + * + * @param[in] aSocket A pointer to a UDP socket structure. + * + * @retval kThreadErrorNone Successfully closed the socket. + * + * @sa otNewUdpMessage + * @sa otOpenUdpSocket + * @sa otBindUdpSocket + * @sa otSendUdp + */ +ThreadError otCloseUdpSocket(otUdpSocket *aSocket); + +/** + * Bind a UDP/IPv6 socket. + * + * @param[in] aSocket A pointer to a UDP socket structure. + * @param[in] aSockName A pointer to an IPv6 socket address structure. + * + * @retval kThreadErrorNone Bind operation was successful. + * + * @sa otNewUdpMessage + * @sa otOpenUdpSocket + * @sa otCloseUdpSocket + * @sa otSendUdp + */ +ThreadError otBindUdpSocket(otUdpSocket *aSocket, otSockAddr *aSockName); + +/** + * Send a UDP/IPv6 message. + * + * @param[in] aSocket A pointer to a UDP socket structure. + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aMessageInfo A pointer to a message info structure. + * + * @sa otNewUdpMessage + * @sa otOpenUdpSocket + * @sa otCloseUdpSocket + * @sa otBindUdpSocket + * @sa otSendUdp + */ +ThreadError otSendUdp(otUdpSocket *aSocket, otMessage aMessage, const otMessageInfo *aMessageInfo); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_UDP_H_ diff --git a/include/openthread.h b/include/openthread.h index c5345b402..35d25388d 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -35,11 +35,7 @@ #ifndef OPENTHREAD_H_ #define OPENTHREAD_H_ -#include -#include - #include -#include #ifdef __cplusplus extern "C" { @@ -104,46 +100,6 @@ extern "C" { * */ -/** - * @addtogroup execution Execution - * - * @brief - * This module includes functions that control the Thread stack's execution. - * - * @{ - * - */ - -/** - * Run all queued OpenThread tasklets at the time this is called. - * - * @param[in] aInstance A pointer to an OpenThread instance. - */ -void otProcessQueuedTasklets(otInstance *aInstance); - -/** - * Indicates whether or not OpenThread has tasklets pending. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @retval TRUE If there are tasklets pending. - * @retval FALSE If there are no tasklets pending. - */ -bool otAreTaskletsPending(otInstance *aInstance); - -/** - * OpenThread calls this function when the tasklet queue transitions from empty to non-empty. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - */ -extern void otSignalTaskletPending(otInstance *aInstance); - -/** - * @} - * - */ - /** * @addtogroup commands Commands * @@ -160,11 +116,116 @@ extern void otSignalTaskletPending(otInstance *aInstance); * @returns A pointer to the OpenThread version. * */ -const char *otGetVersionString(void); +OTAPI const char *OTCALL otGetVersionString(void); + +#ifdef OTDLL + +/** + * This function initializes a new instance of the OpenThread library. + * + * @retval otApiInstance* The new OpenThread context structure. + * + * @sa otApiFinalize + * + */ +OTAPI otApiInstance *OTCALL otApiInit(); + +/** + * This function uninitializes the OpenThread library. + * + * Call this function when OpenThread is no longer in use. + * + * @param[in] aApiInstance The OpenThread api instance. + * + */ +OTAPI void OTCALL otApiFinalize(otApiInstance *aApiInstance); + +/** + * This function frees any memory returned/allocated by the library. + * + * @param[in] aMem The memory to free. + * + */ +OTAPI void OTCALL otFreeMemory(const void *aMem); + +/** + * This function pointer is called to notify addition and removal of OpenThread devices. + * + * @param[in] aAdded A flag indicating if the device was added or removed. + * @param[in] aDeviceGuid A GUID indicating which device state changed. + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (OTCALL *otDeviceAvailabilityChangedCallback)(bool aAdded, const GUID *aDeviceGuid, void *aContext); + +/** + * This function registers a callback to indicate OpenThread devices come and go. + * + * @param[in] aApiInstance The OpenThread api instance. + * @param[in] aCallback A pointer to a function that is called with the state changes. + * @param[in] aContextContext A pointer to application-specific context. + * + */ +OTAPI void OTCALL otSetDeviceAvailabilityChangedCallback(otApiInstance *aApiInstance, + otDeviceAvailabilityChangedCallback aCallback, void *aCallbackContext); + +/** + * This function querys the list of OpenThread device contexts on the system. + * + * @param[in] aApiInstance The OpenThread api instance. + * + * @sa otFreeMemory + */ +OTAPI otDeviceList *OTCALL otEnumerateDevices(otApiInstance *aApiInstance); + +/** + * This function initializes an OpenThread context for a device. + * + * @param[in] aApiInstance The OpenThread api instance. + * @param[in] aDeviceGuid The device guid to create an OpenThread context for. + * + * @retval otInstance* The new OpenThread device instance structure for the device. + * + * @sa otFreeMemory + * + */ +OTAPI otInstance *OTCALL otInstanceInit(otApiInstance *aApiInstance, const GUID *aDeviceGuid); + +/** + * This queries the Windows device/interface GUID for the otContext. + * + * @param[in] aContext The OpenThread context structure. + * + * @retval GUID The device GUID. + * + */ +OTAPI GUID OTCALL otGetDeviceGuid(otInstance *aInstance); + +/** + * This queries the Windows device/interface IfIndex for the otContext. + * + * @param[in] aContext The OpenThread context structure. + * + * @retval uint32_t The device IfIndex. + * + */ +OTAPI uint32_t OTCALL otGetDeviceIfIndex(otInstance *aInstance); + +/** + * This queries the Windows Compartment ID for the otContext. + * + * @param[in] aContext The OpenThread context structure. + * + * @retval uint32_t The compartment ID. + * + */ +OTAPI uint32_t OTCALL otGetCompartmentId(otInstance *aInstance); + +#else #ifdef OPENTHREAD_MULTIPLE_INSTANCE /** - * This function initializes a new instance of the OpenThread library. + * This function initializes the OpenThread library. * * This function initializes OpenThread and prepares it for subsequent OpenThread API calls. This function must be * called before any other calls to OpenThread. By default, OpenThread is initialized in the 'enabled' state. @@ -175,6 +236,8 @@ const char *otGetVersionString(void); * * @retval otInstance* The new OpenThread instance structure. * + * @sa otContextFinalize + * */ otInstance *otInstanceInit(void *aInstanceBuffer, size_t *aInstanceBufferSize); #else @@ -200,6 +263,8 @@ otInstance *otInstanceInit(void); */ void otInstanceFinalize(otInstance *aInstance); +#endif + /** * This function brings up the IPv6 interface. * @@ -211,7 +276,7 @@ void otInstanceFinalize(otInstance *aInstance); * or the interface was already enabled. * */ -ThreadError otInterfaceUp(otInstance *aInstance); +OTAPI ThreadError OTCALL otInterfaceUp(otInstance *aInstance); /** * This function brings down the IPv6 interface. @@ -224,7 +289,7 @@ ThreadError otInterfaceUp(otInstance *aInstance); * or the interface was already down. * */ -ThreadError otInterfaceDown(otInstance *aInstance); +OTAPI ThreadError OTCALL otInterfaceDown(otInstance *aInstance); /** * This function indicates whether or not the IPv6 interface is up. @@ -235,7 +300,7 @@ ThreadError otInterfaceDown(otInstance *aInstance); * @retval FALSE The IPv6 interface is down. * */ -bool otIsInterfaceUp(otInstance *aInstance); +OTAPI bool OTCALL otIsInterfaceUp(otInstance *aInstance); /** * This function starts Thread protocol operation. @@ -248,7 +313,7 @@ bool otIsInterfaceUp(otInstance *aInstance); * @retval kThreadError_InvalidState The network interface was not not up. * */ -ThreadError otThreadStart(otInstance *aInstance); +OTAPI ThreadError OTCALL otThreadStart(otInstance *aInstance); /** * This function stops Thread protocol operation. @@ -258,7 +323,7 @@ ThreadError otThreadStart(otInstance *aInstance); * @retval kThreadError_None Successfully stopped Thread protocol operation. * */ -ThreadError otThreadStop(otInstance *aInstance); +OTAPI ThreadError OTCALL otThreadStop(otInstance *aInstance); /** * This function indicates whether a node is the only router on the network. @@ -269,7 +334,7 @@ ThreadError otThreadStop(otInstance *aInstance); * @retval FALSE It is a child or is not a single router in the network. * */ -bool otIsSingleton(otInstance *aInstance); +OTAPI bool OTCALL otIsSingleton(otInstance *aInstance); /** * This function pointer is called during an IEEE 802.15.4 Active Scan when an IEEE 802.15.4 Beacon is received or @@ -279,7 +344,7 @@ bool otIsSingleton(otInstance *aInstance); * @param[in] aContext A pointer to application-specific context. * */ -typedef void (*otHandleActiveScanResult)(otActiveScanResult *aResult, void *aContext); +typedef void (OTCALL *otHandleActiveScanResult)(otActiveScanResult *aResult, void *aContext); /** * This function starts an IEEE 802.15.4 Active Scan @@ -294,8 +359,8 @@ typedef void (*otHandleActiveScanResult)(otActiveScanResult *aResult, void *aCon * @retval kThreadError_Busy Already performing an Active Scan. * */ -ThreadError otActiveScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, - otHandleActiveScanResult aCallback, void *aCallbackContext); +OTAPI ThreadError OTCALL otActiveScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, + otHandleActiveScanResult aCallback, void *aCallbackContext); /** * This function indicates whether or not an IEEE 802.15.4 Active Scan is currently in progress. @@ -304,7 +369,7 @@ ThreadError otActiveScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t * * @returns true if an IEEE 802.15.4 Active Scan is in progress, false otherwise. */ -bool otIsActiveScanInProgress(otInstance *aInstance); +OTAPI bool OTCALL otIsActiveScanInProgress(otInstance *aInstance); /** * This function pointer is called during an IEEE 802.15.4 Energy Scan when the result for a channel is ready or the @@ -314,7 +379,7 @@ bool otIsActiveScanInProgress(otInstance *aInstance); * @param[in] aContext A pointer to application-specific context. * */ -typedef void (*otHandleEnergyScanResult)(otEnergyScanResult *aResult, void *aContext); +typedef void (OTCALL *otHandleEnergyScanResult)(otEnergyScanResult *aResult, void *aContext); /** * This function starts an IEEE 802.15.4 Energy Scan @@ -329,8 +394,8 @@ typedef void (*otHandleEnergyScanResult)(otEnergyScanResult *aResult, void *aCon * @retval kThreadError_Busy Could not start the energy scan. * */ -ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, - otHandleEnergyScanResult aCallback, void *aCallbackContext); +OTAPI ThreadError OTCALL otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, + otHandleEnergyScanResult aCallback, void *aCallbackContext); /** * This function indicates whether or not an IEEE 802.15.4 Energy Scan is currently in progress. @@ -340,7 +405,7 @@ ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t * @returns true if an IEEE 802.15.4 Energy Scan is in progress, false otherwise. * */ -bool otIsEnergyScanInProgress(otInstance *aInstance); +OTAPI bool OTCALL otIsEnergyScanInProgress(otInstance *aInstance); /** * This function starts a Thread Discovery scan. @@ -356,8 +421,9 @@ bool otIsEnergyScanInProgress(otInstance *aInstance); * @retval kThreadError_Busy Already performing an Thread Discovery. * */ -ThreadError otDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanid, - otHandleActiveScanResult aCallback, void *aCallbackContext); +OTAPI ThreadError OTCALL otDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, + uint16_t aPanid, + otHandleActiveScanResult aCallback, void *aCallbackContext); /** * This function determines if an MLE Thread Discovery is currently in progress. @@ -365,7 +431,7 @@ ThreadError otDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t a * @param[in] aInstance A pointer to an OpenThread instance. * */ -bool otIsDiscoverInProgress(otInstance *aInstance); +OTAPI bool OTCALL otIsDiscoverInProgress(otInstance *aInstance); /** * @} @@ -401,7 +467,7 @@ bool otIsDiscoverInProgress(otInstance *aInstance); * * @sa otSetChannel */ -uint8_t otGetChannel(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetChannel(otInstance *aInstance); /** * Set the IEEE 802.15.4 channel @@ -414,7 +480,7 @@ uint8_t otGetChannel(otInstance *aInstance); * * @sa otGetChannel */ -ThreadError otSetChannel(otInstance *aInstance, uint8_t aChannel); +OTAPI ThreadError OTCALL otSetChannel(otInstance *aInstance, uint8_t aChannel); /** * Get the maximum number of children currently allowed. @@ -425,7 +491,7 @@ ThreadError otSetChannel(otInstance *aInstance, uint8_t aChannel); * * @sa otSetMaxAllowedChildren */ -uint8_t otGetMaxAllowedChildren(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetMaxAllowedChildren(otInstance *aInstance); /** * Set the maximum number of children currently allowed. @@ -442,7 +508,7 @@ uint8_t otGetMaxAllowedChildren(otInstance *aInstance); * * @sa otGetMaxAllowedChildren, otThreadStop */ -ThreadError otSetMaxAllowedChildren(otInstance *aInstance, uint8_t aMaxChildren); +OTAPI ThreadError OTCALL otSetMaxAllowedChildren(otInstance *aInstance, uint8_t aMaxChildren); /** * Get the Thread Child Timeout used when operating in the Child role. @@ -453,7 +519,7 @@ ThreadError otSetMaxAllowedChildren(otInstance *aInstance, uint8_t aMaxChildren) * * @sa otSetChildTimeout */ -uint32_t otGetChildTimeout(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetChildTimeout(otInstance *aInstance); /** * Set the Thread Child Timeout used when operating in the Child role. @@ -462,7 +528,7 @@ uint32_t otGetChildTimeout(otInstance *aInstance); * * @sa otSetChildTimeout */ -void otSetChildTimeout(otInstance *aInstance, uint32_t aTimeout); +OTAPI void OTCALL otSetChildTimeout(otInstance *aInstance, uint32_t aTimeout); /** * Get the IEEE 802.15.4 Extended Address. @@ -471,7 +537,7 @@ void otSetChildTimeout(otInstance *aInstance, uint32_t aTimeout); * * @returns A pointer to the IEEE 802.15.4 Extended Address. */ -const uint8_t *otGetExtendedAddress(otInstance *aInstance); +OTAPI const uint8_t *OTCALL otGetExtendedAddress(otInstance *aInstance); /** * This function sets the IEEE 802.15.4 Extended Address. @@ -483,7 +549,7 @@ const uint8_t *otGetExtendedAddress(otInstance *aInstance); * @retval kThreadError_InvalidArgs @p aExtendedAddress was NULL. * */ -ThreadError otSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtendedAddress); +OTAPI ThreadError OTCALL otSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtendedAddress); /** * Get the IEEE 802.15.4 Extended PAN ID. @@ -494,7 +560,7 @@ ThreadError otSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExt * * @sa otSetExtendedPanId */ -const uint8_t *otGetExtendedPanId(otInstance *aInstance); +OTAPI const uint8_t *OTCALL otGetExtendedPanId(otInstance *aInstance); /** * Set the IEEE 802.15.4 Extended PAN ID. @@ -504,7 +570,7 @@ const uint8_t *otGetExtendedPanId(otInstance *aInstance); * * @sa otGetExtendedPanId */ -void otSetExtendedPanId(otInstance *aInstance, const uint8_t *aExtendedPanId); +OTAPI void OTCALL otSetExtendedPanId(otInstance *aInstance, const uint8_t *aExtendedPanId); /** * Get the factory-assigned IEEE EUI-64. @@ -513,7 +579,7 @@ void otSetExtendedPanId(otInstance *aInstance, const uint8_t *aExtendedPanId); * @param[out] aEui64 A pointer to where the factory-assigned IEEE EUI-64 is placed. * */ -void otGetFactoryAssignedIeeeEui64(otInstance *aInstance, otExtAddress *aEui64); +OTAPI void OTCALL otGetFactoryAssignedIeeeEui64(otInstance *aInstance, otExtAddress *aEui64); /** * Get the Hash Mac Address. @@ -525,7 +591,7 @@ void otGetFactoryAssignedIeeeEui64(otInstance *aInstance, otExtAddress *aEui64); * @param[out] aHashMacAddress A pointer to where the Hash Mac Address is placed. * */ -void otGetHashMacAddress(otInstance *aInstance, otExtAddress *aHashMacAddress); +OTAPI void OTCALL otGetHashMacAddress(otInstance *aInstance, otExtAddress *aHashMacAddress); /** * This function returns a pointer to the Leader's RLOC. @@ -538,7 +604,7 @@ void otGetHashMacAddress(otInstance *aInstance, otExtAddress *aHashMacAddress); * @retval kThreadError_Detached Not currently attached to a Thread Partition. * */ -ThreadError otGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc); +OTAPI ThreadError OTCALL otGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc); /** * Get the MLE Link Mode configuration. @@ -549,7 +615,7 @@ ThreadError otGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc); * * @sa otSetLinkMode */ -otLinkModeConfig otGetLinkMode(otInstance *aInstance); +OTAPI otLinkModeConfig OTCALL otGetLinkMode(otInstance *aInstance); /** * Set the MLE Link Mode configuration. @@ -561,7 +627,7 @@ otLinkModeConfig otGetLinkMode(otInstance *aInstance); * * @sa otGetLinkMode */ -ThreadError otSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig); +OTAPI ThreadError OTCALL otSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig); /** * Get the thrMasterKey. @@ -574,7 +640,7 @@ ThreadError otSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig); * * @sa otSetMasterKey */ -const uint8_t *otGetMasterKey(otInstance *aInstance, uint8_t *aKeyLength); +OTAPI const uint8_t *OTCALL otGetMasterKey(otInstance *aInstance, uint8_t *aKeyLength); /** * Set the thrMasterKey. @@ -588,7 +654,7 @@ const uint8_t *otGetMasterKey(otInstance *aInstance, uint8_t *aKeyLength); * * @sa otGetMasterKey */ -ThreadError otSetMasterKey(otInstance *aInstance, const uint8_t *aKey, uint8_t aKeyLength); +OTAPI ThreadError OTCALL otSetMasterKey(otInstance *aInstance, const uint8_t *aKey, uint8_t aKeyLength); /** * This function returns the maximum transmit power setting in dBm. @@ -598,7 +664,7 @@ ThreadError otSetMasterKey(otInstance *aInstance, const uint8_t *aKey, uint8_t a * @returns The maximum transmit power setting. * */ -int8_t otGetMaxTransmitPower(otInstance *aInstance); +OTAPI int8_t OTCALL otGetMaxTransmitPower(otInstance *aInstance); /** * This function sets the maximum transmit power in dBm. @@ -607,7 +673,7 @@ int8_t otGetMaxTransmitPower(otInstance *aInstance); * @param[in] aPower The maximum transmit power in dBm. * */ -void otSetMaxTransmitPower(otInstance *aInstance, int8_t aPower); +OTAPI void OTCALL otSetMaxTransmitPower(otInstance *aInstance, int8_t aPower); /** * This function returns a pointer to the Mesh Local EID. @@ -617,7 +683,7 @@ void otSetMaxTransmitPower(otInstance *aInstance, int8_t aPower); * @returns A pointer to the Mesh Local EID. * */ -const otIp6Address *otGetMeshLocalEid(otInstance *aInstance); +OTAPI const otIp6Address *OTCALL otGetMeshLocalEid(otInstance *aInstance); /** * This function returns a pointer to the Mesh Local Prefix. @@ -627,7 +693,7 @@ const otIp6Address *otGetMeshLocalEid(otInstance *aInstance); * @returns A pointer to the Mesh Local Prefix. * */ -const uint8_t *otGetMeshLocalPrefix(otInstance *aInstance); +OTAPI const uint8_t *OTCALL otGetMeshLocalPrefix(otInstance *aInstance); /** * This function sets the Mesh Local Prefix. @@ -638,7 +704,7 @@ const uint8_t *otGetMeshLocalPrefix(otInstance *aInstance); * @retval kThreadError_None Successfully set the Mesh Local Prefix. * */ -ThreadError otSetMeshLocalPrefix(otInstance *aInstance, const uint8_t *aMeshLocalPrefix); +OTAPI ThreadError OTCALL otSetMeshLocalPrefix(otInstance *aInstance, const uint8_t *aMeshLocalPrefix); /** * This method provides a full or stable copy of the Leader's Thread Network Data. @@ -649,7 +715,8 @@ ThreadError otSetMeshLocalPrefix(otInstance *aInstance, const uint8_t *aMeshLoca * @param[inout] aDataLength On entry, size of the data buffer pointed to by @p aData. * On exit, number of copied bytes. */ -ThreadError otGetNetworkDataLeader(otInstance *aInstance, bool aStable, uint8_t *aData, uint8_t *aDataLength); +OTAPI ThreadError OTCALL otGetNetworkDataLeader(otInstance *aInstance, bool aStable, uint8_t *aData, + uint8_t *aDataLength); /** * This method provides a full or stable copy of the local Thread Network Data. @@ -660,7 +727,8 @@ ThreadError otGetNetworkDataLeader(otInstance *aInstance, bool aStable, uint8_t * @param[inout] aDataLength On entry, size of the data buffer pointed to by @p aData. * On exit, number of copied bytes. */ -ThreadError otGetNetworkDataLocal(otInstance *aInstance, bool aStable, uint8_t *aData, uint8_t *aDataLength); +OTAPI ThreadError OTCALL otGetNetworkDataLocal(otInstance *aInstance, bool aStable, uint8_t *aData, + uint8_t *aDataLength); /** * Get the Thread Network Name. @@ -671,7 +739,7 @@ ThreadError otGetNetworkDataLocal(otInstance *aInstance, bool aStable, uint8_t * * * @sa otSetNetworkName */ -const char *otGetNetworkName(otInstance *aInstance); +OTAPI const char *OTCALL otGetNetworkName(otInstance *aInstance); /** * Set the Thread Network Name. @@ -683,7 +751,7 @@ const char *otGetNetworkName(otInstance *aInstance); * * @sa otGetNetworkName */ -ThreadError otSetNetworkName(otInstance *aInstance, const char *aNetworkName); +OTAPI ThreadError OTCALL otSetNetworkName(otInstance *aInstance, const char *aNetworkName); /** * This function gets the next On Mesh Prefix in the Network Data. @@ -698,8 +766,8 @@ ThreadError otSetNetworkName(otInstance *aInstance, const char *aNetworkName); * @retval kThreadError_NotFound No subsequent On Mesh prefix exists in the Thread Network Data. * */ -ThreadError otGetNextOnMeshPrefix(otInstance *aInstance, bool aLocal, otNetworkDataIterator *aIterator, - otBorderRouterConfig *aConfig); +OTAPI ThreadError OTCALL otGetNextOnMeshPrefix(otInstance *aInstance, bool aLocal, otNetworkDataIterator *aIterator, + otBorderRouterConfig *aConfig); /** * Get the IEEE 802.15.4 PAN ID. @@ -710,7 +778,7 @@ ThreadError otGetNextOnMeshPrefix(otInstance *aInstance, bool aLocal, otNetworkD * * @sa otSetPanId */ -otPanId otGetPanId(otInstance *aInstance); +OTAPI otPanId OTCALL otGetPanId(otInstance *aInstance); /** * Set the IEEE 802.15.4 PAN ID. @@ -723,7 +791,7 @@ otPanId otGetPanId(otInstance *aInstance); * * @sa otGetPanId */ -ThreadError otSetPanId(otInstance *aInstance, otPanId aPanId); +OTAPI ThreadError OTCALL otSetPanId(otInstance *aInstance, otPanId aPanId); /** * This function indicates whether or not the Router Role is enabled. @@ -734,7 +802,7 @@ ThreadError otSetPanId(otInstance *aInstance, otPanId aPanId); * @retval FALSE If the Router Role is not enabled. * */ -bool otIsRouterRoleEnabled(otInstance *aInstance); +OTAPI bool OTCALL otIsRouterRoleEnabled(otInstance *aInstance); /** * This function sets whether or not the Router Role is enabled. @@ -743,7 +811,7 @@ bool otIsRouterRoleEnabled(otInstance *aInstance); * @param[in] aEnabled TRUE if the Router Role is enabled, FALSE otherwise. * */ -void otSetRouterRoleEnabled(otInstance *aInstance, bool aEnabled); +OTAPI void OTCALL otSetRouterRoleEnabled(otInstance *aInstance, bool aEnabled); /** * Get the IEEE 802.15.4 Short Address. @@ -752,7 +820,7 @@ void otSetRouterRoleEnabled(otInstance *aInstance, bool aEnabled); * * @returns A pointer to the IEEE 802.15.4 Short Address. */ -otShortAddress otGetShortAddress(otInstance *aInstance); +OTAPI otShortAddress OTCALL otGetShortAddress(otInstance *aInstance); /** * Get the list of IPv6 addresses assigned to the Thread interface. @@ -761,7 +829,7 @@ otShortAddress otGetShortAddress(otInstance *aInstance); * * @returns A pointer to the first Network Interface Address. */ -const otNetifAddress *otGetUnicastAddresses(otInstance *aInstance); +OTAPI const otNetifAddress *OTCALL otGetUnicastAddresses(otInstance *aInstance); /** * Add a Network Interface Address to the Thread interface. @@ -776,7 +844,7 @@ const otNetifAddress *otGetUnicastAddresses(otInstance *aInstance); * @retval kThreadError_InvalidArgs The IP Address indicated by @p aAddress is an internal address. * @retval kThreadError_NoBufs The Network Interface is already storing the maximum allowed external addresses. */ -ThreadError otAddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAddress); +OTAPI ThreadError OTCALL otAddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAddress); /** * Remove a Network Interface Address from the Thread interface. @@ -788,7 +856,7 @@ ThreadError otAddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAd * @retval kThreadError_InvalidArgs The IP Address indicated by @p aAddress is an internal address. * @retval kThreadError_NotFound The IP Address indicated by @p aAddress was not found. */ -ThreadError otRemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress); +OTAPI ThreadError OTCALL otRemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress); /** * Get the list of IPv6 multicast addresses subscribed to the Thread interface. @@ -926,7 +994,7 @@ ThreadError otCreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress * @param[in] aContext A pointer to application-specific context. * */ -typedef void (*otStateChangedCallback)(uint32_t aFlags, void *aContext); +typedef void (OTCALL *otStateChangedCallback)(uint32_t aFlags, void *aContext); /** * This function registers a callback to indicate when certain configuration or state changes within OpenThread. @@ -939,7 +1007,8 @@ typedef void (*otStateChangedCallback)(uint32_t aFlags, void *aContext); * @retval kThreadError_NoBufs Could not add the callback due to resource constraints. * */ -ThreadError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aContext); +OTAPI ThreadError OTCALL otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, + void *aContext); /** * This function removes a callback to indicate when certain configuration or state changes within OpenThread. @@ -949,7 +1018,8 @@ ThreadError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallb * @param[in] aContext A pointer to application-specific context. * */ -void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext); +OTAPI void OTCALL otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback aCallback, + void *aCallbackContext); /** * This function gets the Active Operational Dataset. @@ -961,7 +1031,7 @@ void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback a * @retval kThreadError_InvalidArgs @p aDataset was NULL. * */ -ThreadError otGetActiveDataset(otInstance *aInstance, otOperationalDataset *aDataset); +OTAPI ThreadError OTCALL otGetActiveDataset(otInstance *aInstance, otOperationalDataset *aDataset); /** * This function sets the Active Operational Dataset. @@ -974,7 +1044,7 @@ ThreadError otGetActiveDataset(otInstance *aInstance, otOperationalDataset *aDat * @retval kThreadError_InvalidArgs @p aDataset was NULL. * */ -ThreadError otSetActiveDataset(otInstance *aInstance, const otOperationalDataset *aDataset); +OTAPI ThreadError OTCALL otSetActiveDataset(otInstance *aInstance, const otOperationalDataset *aDataset); /** * This function gets the Pending Operational Dataset. @@ -986,7 +1056,7 @@ ThreadError otSetActiveDataset(otInstance *aInstance, const otOperationalDataset * @retval kThreadError_InvalidArgs @p aDataset was NULL. * */ -ThreadError otGetPendingDataset(otInstance *aInstance, otOperationalDataset *aDataset); +OTAPI ThreadError OTCALL otGetPendingDataset(otInstance *aInstance, otOperationalDataset *aDataset); /** * This function sets the Pending Operational Dataset. @@ -999,7 +1069,7 @@ ThreadError otGetPendingDataset(otInstance *aInstance, otOperationalDataset *aDa * @retval kThreadError_InvalidArgs @p aDataset was NULL. * */ -ThreadError otSetPendingDataset(otInstance *aInstance, const otOperationalDataset *aDataset); +OTAPI ThreadError OTCALL otSetPendingDataset(otInstance *aInstance, const otOperationalDataset *aDataset); /** * This function sends MGMT_ACTIVE_GET. @@ -1013,8 +1083,8 @@ ThreadError otSetPendingDataset(otInstance *aInstance, const otOperationalDatase * @retval kThreadError_NoBufs Insufficient buffer space to send. * */ -ThreadError otSendActiveGet(otInstance *aInstance, const uint8_t *aTlvTypes, uint8_t aLength, - const otIp6Address *aAddress); +OTAPI ThreadError OTCALL otSendActiveGet(otInstance *aInstance, const uint8_t *aTlvTypes, uint8_t aLength, + const otIp6Address *aAddress); /** * This function sends MGMT_ACTIVE_SET. @@ -1028,8 +1098,8 @@ ThreadError otSendActiveGet(otInstance *aInstance, const uint8_t *aTlvTypes, uin * @retval kThreadError_NoBufs Insufficient buffer space to send. * */ -ThreadError otSendActiveSet(otInstance *aInstance, const otOperationalDataset *aDataset, const uint8_t *aTlvs, - uint8_t aLength); +OTAPI ThreadError OTCALL otSendActiveSet(otInstance *aInstance, const otOperationalDataset *aDataset, + const uint8_t *aTlvs, uint8_t aLength); /** * This function sends MGMT_PENDING_GET. @@ -1043,8 +1113,8 @@ ThreadError otSendActiveSet(otInstance *aInstance, const otOperationalDataset *a * @retval kThreadError_NoBufs Insufficient buffer space to send. * */ -ThreadError otSendPendingGet(otInstance *aInstance, const uint8_t *aTlvTypes, uint8_t aLength, - const otIp6Address *aAddress); +OTAPI ThreadError OTCALL otSendPendingGet(otInstance *aInstance, const uint8_t *aTlvTypes, uint8_t aLength, + const otIp6Address *aAddress); /** * This function sends MGMT_PENDING_SET. @@ -1058,8 +1128,8 @@ ThreadError otSendPendingGet(otInstance *aInstance, const uint8_t *aTlvTypes, ui * @retval kThreadError_NoBufs Insufficient buffer space to send. * */ -ThreadError otSendPendingSet(otInstance *aInstance, const otOperationalDataset *aDataset, const uint8_t *aTlvs, - uint8_t aLength); +OTAPI ThreadError OTCALL otSendPendingSet(otInstance *aInstance, const otOperationalDataset *aDataset, + const uint8_t *aTlvs, uint8_t aLength); /** * Get the data poll period of sleepy end device. @@ -1070,7 +1140,7 @@ ThreadError otSendPendingSet(otInstance *aInstance, const otOperationalDataset * * * @sa otSetPollPeriod */ -uint32_t otGetPollPeriod(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetPollPeriod(otInstance *aInstance); /** * Set the data poll period for sleepy end device. @@ -1080,7 +1150,7 @@ uint32_t otGetPollPeriod(otInstance *aInstance); * * @sa otGetPollPeriod */ -void otSetPollPeriod(otInstance *aInstance, uint32_t aPollPeriod); +OTAPI void OTCALL otSetPollPeriod(otInstance *aInstance, uint32_t aPollPeriod); /** * Set the preferred Router Id. @@ -1122,7 +1192,7 @@ ThreadError otSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId); * * @sa otSetLeaderWeight */ -uint8_t otGetLocalLeaderWeight(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetLocalLeaderWeight(otInstance *aInstance); /** * Set the Thread Leader Weight used when operating in the Leader role. @@ -1132,7 +1202,7 @@ uint8_t otGetLocalLeaderWeight(otInstance *aInstance); * * @sa otGetLeaderWeight */ -void otSetLocalLeaderWeight(otInstance *aInstance, uint8_t aWeight); +OTAPI void OTCALL otSetLocalLeaderWeight(otInstance *aInstance, uint8_t aWeight); /** * Get the Thread Leader Partition Id used when operating in the Leader role. @@ -1142,7 +1212,7 @@ void otSetLocalLeaderWeight(otInstance *aInstance, uint8_t aWeight); * @returns The Thread Leader Partition Id value. * */ -uint32_t otGetLocalLeaderPartitionId(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetLocalLeaderPartitionId(otInstance *aInstance); /** * Set the Thread Leader Partition Id used when operating in the Leader role. @@ -1151,7 +1221,7 @@ uint32_t otGetLocalLeaderPartitionId(otInstance *aInstance); * @param[in] aPartitionId The Thread Leader Partition Id value. * */ -void otSetLocalLeaderPartitionId(otInstance *aInstance, uint32_t aPartitionId); +OTAPI void OTCALL otSetLocalLeaderPartitionId(otInstance *aInstance, uint32_t aPartitionId); /** * Get the Joiner UDP Port. @@ -1162,7 +1232,7 @@ void otSetLocalLeaderPartitionId(otInstance *aInstance, uint32_t aPartitionId); * * @sa otSetJoinerUdpPort */ -uint16_t otGetJoinerUdpPort(otInstance *aInstance); +OTAPI uint16_t OTCALL otGetJoinerUdpPort(otInstance *aInstance); /** * Set the Joiner UDP Port @@ -1174,7 +1244,7 @@ uint16_t otGetJoinerUdpPort(otInstance *aInstance); * * @sa otGetJoinerUdpPort */ -ThreadError otSetJoinerUdpPort(otInstance *aInstance, uint16_t aJoinerUdpPort); +OTAPI ThreadError OTCALL otSetJoinerUdpPort(otInstance *aInstance, uint16_t aJoinerUdpPort); /** * @} @@ -1203,7 +1273,7 @@ ThreadError otSetJoinerUdpPort(otInstance *aInstance, uint16_t aJoinerUdpPort); * @sa otRemoveBorderRouter * @sa otSendServerData */ -ThreadError otAddBorderRouter(otInstance *aInstance, const otBorderRouterConfig *aConfig); +OTAPI ThreadError OTCALL otAddBorderRouter(otInstance *aInstance, const otBorderRouterConfig *aConfig); /** * Remove a border router configuration from the local network data. @@ -1216,7 +1286,7 @@ ThreadError otAddBorderRouter(otInstance *aInstance, const otBorderRouterConfig * @sa otAddBorderRouter * @sa otSendServerData */ -ThreadError otRemoveBorderRouter(otInstance *aInstance, const otIp6Prefix *aPrefix); +OTAPI ThreadError OTCALL otRemoveBorderRouter(otInstance *aInstance, const otIp6Prefix *aPrefix); /** * Add an external route configuration to the local network data. @@ -1231,7 +1301,7 @@ ThreadError otRemoveBorderRouter(otInstance *aInstance, const otIp6Prefix *aPref * @sa otRemoveExternalRoute * @sa otSendServerData */ -ThreadError otAddExternalRoute(otInstance *aInstance, const otExternalRouteConfig *aConfig); +OTAPI ThreadError OTCALL otAddExternalRoute(otInstance *aInstance, const otExternalRouteConfig *aConfig); /** * Remove an external route configuration from the local network data. @@ -1244,7 +1314,7 @@ ThreadError otAddExternalRoute(otInstance *aInstance, const otExternalRouteConfi * @sa otAddExternalRoute * @sa otSendServerData */ -ThreadError otRemoveExternalRoute(otInstance *aInstance, const otIp6Prefix *aPrefix); +OTAPI ThreadError OTCALL otRemoveExternalRoute(otInstance *aInstance, const otIp6Prefix *aPrefix); /** * Immediately register the local network data with the Leader. @@ -1258,7 +1328,7 @@ ThreadError otRemoveExternalRoute(otInstance *aInstance, const otIp6Prefix *aPre * @sa otAddExternalRoute * @sa otRemoveExternalRoute */ -ThreadError otSendServerData(otInstance *aInstance); +OTAPI ThreadError OTCALL otSendServerData(otInstance *aInstance); /** * This function adds a port to the allowed unsecured port list. @@ -1321,7 +1391,7 @@ const uint16_t *otGetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries); * * @sa otSetContextIdReuseDelay */ -uint32_t otGetContextIdReuseDelay(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetContextIdReuseDelay(otInstance *aInstance); /** * Set the CONTEXT_ID_REUSE_DELAY parameter used in the Leader role. @@ -1331,7 +1401,7 @@ uint32_t otGetContextIdReuseDelay(otInstance *aInstance); * * @sa otGetContextIdReuseDelay */ -void otSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay); +OTAPI void OTCALL otSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay); /** * Get the thrKeySequenceCounter. @@ -1342,7 +1412,7 @@ void otSetContextIdReuseDelay(otInstance *aInstance, uint32_t aDelay); * * @sa otSetKeySequenceCounter */ -uint32_t otGetKeySequenceCounter(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetKeySequenceCounter(otInstance *aInstance); /** * Set the thrKeySequenceCounter. @@ -1352,7 +1422,7 @@ uint32_t otGetKeySequenceCounter(otInstance *aInstance); * * @sa otGetKeySequenceCounter */ -void otSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter); +OTAPI void OTCALL otSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter); /** * Get the thrKeySwitchGuardTime @@ -1363,7 +1433,7 @@ void otSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter * * @sa otSetKeySwitchGuardTime */ -uint32_t otGetKeySwitchGuardTime(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetKeySwitchGuardTime(otInstance *aInstance); /** * Set the thrKeySwitchGuardTime @@ -1373,7 +1443,7 @@ uint32_t otGetKeySwitchGuardTime(otInstance *aInstance); * * @sa otGetKeySwitchGuardTime */ -void otSetKeySwitchGuardTime(otInstance *aInstance, uint32_t aKeySwitchGuardTime); +OTAPI void OTCALL otSetKeySwitchGuardTime(otInstance *aInstance, uint32_t aKeySwitchGuardTime); /** @@ -1385,7 +1455,7 @@ void otSetKeySwitchGuardTime(otInstance *aInstance, uint32_t aKeySwitchGuardTime * * @sa otSetNetworkIdTimeout */ -uint8_t otGetNetworkIdTimeout(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetNetworkIdTimeout(otInstance *aInstance); /** * Set the NETWORK_ID_TIMEOUT parameter used in the Leader role. @@ -1395,7 +1465,7 @@ uint8_t otGetNetworkIdTimeout(otInstance *aInstance); * * @sa otGetNetworkIdTimeout */ -void otSetNetworkIdTimeout(otInstance *aInstance, uint8_t aTimeout); +OTAPI void OTCALL otSetNetworkIdTimeout(otInstance *aInstance, uint8_t aTimeout); /** * Get the ROUTER_UPGRADE_THRESHOLD parameter used in the REED role. @@ -1406,7 +1476,7 @@ void otSetNetworkIdTimeout(otInstance *aInstance, uint8_t aTimeout); * * @sa otSetRouterUpgradeThreshold */ -uint8_t otGetRouterUpgradeThreshold(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetRouterUpgradeThreshold(otInstance *aInstance); /** * Set the ROUTER_UPGRADE_THRESHOLD parameter used in the Leader role. @@ -1416,7 +1486,7 @@ uint8_t otGetRouterUpgradeThreshold(otInstance *aInstance); * * @sa otGetRouterUpgradeThreshold */ -void otSetRouterUpgradeThreshold(otInstance *aInstance, uint8_t aThreshold); +OTAPI void OTCALL otSetRouterUpgradeThreshold(otInstance *aInstance, uint8_t aThreshold); /** * Release a Router ID that has been allocated by the device in the Leader role. @@ -1426,7 +1496,7 @@ void otSetRouterUpgradeThreshold(otInstance *aInstance, uint8_t aThreshold); * * @retval kThreadErrorNone Successfully released the Router ID specified by aRouterId. */ -ThreadError otReleaseRouterId(otInstance *aInstance, uint8_t aRouterId); +OTAPI ThreadError OTCALL otReleaseRouterId(otInstance *aInstance, uint8_t aRouterId); /** * Add an IEEE 802.15.4 Extended Address to the MAC whitelist. @@ -1444,7 +1514,7 @@ ThreadError otReleaseRouterId(otInstance *aInstance, uint8_t aRouterId); * @sa otDisableMacWhitelist * @sa otEnableMacWhitelist */ -ThreadError otAddMacWhitelist(otInstance *aInstance, const uint8_t *aExtAddr); +OTAPI ThreadError OTCALL otAddMacWhitelist(otInstance *aInstance, const uint8_t *aExtAddr); /** * Add an IEEE 802.15.4 Extended Address to the MAC whitelist and fix the RSSI value. @@ -1463,7 +1533,7 @@ ThreadError otAddMacWhitelist(otInstance *aInstance, const uint8_t *aExtAddr); * @sa otDisableMacWhitelist * @sa otEnableMacWhitelist */ -ThreadError otAddMacWhitelistRssi(otInstance *aInstance, const uint8_t *aExtAddr, int8_t aRssi); +OTAPI ThreadError OTCALL otAddMacWhitelistRssi(otInstance *aInstance, const uint8_t *aExtAddr, int8_t aRssi); /** * Remove an IEEE 802.15.4 Extended Address from the MAC whitelist. @@ -1478,7 +1548,7 @@ ThreadError otAddMacWhitelistRssi(otInstance *aInstance, const uint8_t *aExtAddr * @sa otDisableMacWhitelist * @sa otEnableMacWhitelist */ -void otRemoveMacWhitelist(otInstance *aInstance, const uint8_t *aExtAddr); +OTAPI void OTCALL otRemoveMacWhitelist(otInstance *aInstance, const uint8_t *aExtAddr); /** * This function gets a MAC whitelist entry. @@ -1491,7 +1561,7 @@ void otRemoveMacWhitelist(otInstance *aInstance, const uint8_t *aExtAddr); * @retval kThreadError_InvalidArgs @p aIndex is out of bounds or @p aEntry is NULL. * */ -ThreadError otGetMacWhitelistEntry(otInstance *aInstance, uint8_t aIndex, otMacWhitelistEntry *aEntry); +OTAPI ThreadError OTCALL otGetMacWhitelistEntry(otInstance *aInstance, uint8_t aIndex, otMacWhitelistEntry *aEntry); /** * Remove all entries from the MAC whitelist. @@ -1505,7 +1575,7 @@ ThreadError otGetMacWhitelistEntry(otInstance *aInstance, uint8_t aIndex, otMacW * @sa otDisableMacWhitelist * @sa otEnableMacWhitelist */ -void otClearMacWhitelist(otInstance *aInstance); +OTAPI void OTCALL otClearMacWhitelist(otInstance *aInstance); /** * Disable MAC whitelist filtering. @@ -1519,7 +1589,7 @@ void otClearMacWhitelist(otInstance *aInstance); * @sa otGetMacWhitelistEntry * @sa otEnableMacWhitelist */ -void otDisableMacWhitelist(otInstance *aInstance); +OTAPI void OTCALL otDisableMacWhitelist(otInstance *aInstance); /** * Enable MAC whitelist filtering. @@ -1533,7 +1603,7 @@ void otDisableMacWhitelist(otInstance *aInstance); * @sa otGetMacWhitelistEntry * @sa otDisableMacWhitelist */ -void otEnableMacWhitelist(otInstance *aInstance); +OTAPI void OTCALL otEnableMacWhitelist(otInstance *aInstance); /** * This function indicates whether or not the MAC whitelist is enabled. @@ -1551,7 +1621,7 @@ void otEnableMacWhitelist(otInstance *aInstance); * @sa otEnableMacWhitelist * */ -bool otIsMacWhitelistEnabled(otInstance *aInstance); +OTAPI bool OTCALL otIsMacWhitelistEnabled(otInstance *aInstance); /** * Detach from the Thread network. @@ -1561,7 +1631,7 @@ bool otIsMacWhitelistEnabled(otInstance *aInstance); * @retval kThreadErrorNone Successfully detached from the Thread network. * @retval kThreadErrorInvalidState Thread is disabled. */ -ThreadError otBecomeDetached(otInstance *aInstance); +OTAPI ThreadError OTCALL otBecomeDetached(otInstance *aInstance); /** * Attempt to reattach as a child. @@ -1572,7 +1642,7 @@ ThreadError otBecomeDetached(otInstance *aInstance); * @retval kThreadErrorNone Successfully begin attempt to become a child. * @retval kThreadErrorInvalidState Thread is disabled. */ -ThreadError otBecomeChild(otInstance *aInstance, otMleAttachFilter aFilter); +OTAPI ThreadError OTCALL otBecomeChild(otInstance *aInstance, otMleAttachFilter aFilter); /** * Attempt to become a router. @@ -1582,7 +1652,7 @@ ThreadError otBecomeChild(otInstance *aInstance, otMleAttachFilter aFilter); * @retval kThreadErrorNone Successfully begin attempt to become a router. * @retval kThreadErrorInvalidState Thread is disabled. */ -ThreadError otBecomeRouter(otInstance *aInstance); +OTAPI ThreadError OTCALL otBecomeRouter(otInstance *aInstance); /** * Become a leader and start a new partition. @@ -1592,7 +1662,7 @@ ThreadError otBecomeRouter(otInstance *aInstance); * @retval kThreadErrorNone Successfully became a leader and started a new partition. * @retval kThreadErrorInvalidState Thread is disabled. */ -ThreadError otBecomeLeader(otInstance *aInstance); +OTAPI ThreadError OTCALL otBecomeLeader(otInstance *aInstance); /** * Add an IEEE 802.15.4 Extended Address to the MAC blacklist. @@ -1609,7 +1679,7 @@ ThreadError otBecomeLeader(otInstance *aInstance); * @sa otDisableMacBlacklist * @sa otEnableMacBlacklist */ -ThreadError otAddMacBlacklist(otInstance *aInstance, const uint8_t *aExtAddr); +OTAPI ThreadError OTCALL otAddMacBlacklist(otInstance *aInstance, const uint8_t *aExtAddr); /** * Remove an IEEE 802.15.4 Extended Address from the MAC blacklist. @@ -1623,7 +1693,7 @@ ThreadError otAddMacBlacklist(otInstance *aInstance, const uint8_t *aExtAddr); * @sa otDisableMacBlacklist * @sa otEnableMacBlacklist */ -void otRemoveMacBlacklist(otInstance *aInstance, const uint8_t *aExtAddr); +OTAPI void OTCALL otRemoveMacBlacklist(otInstance *aInstance, const uint8_t *aExtAddr); /** * This function gets a MAC Blacklist entry. @@ -1636,7 +1706,7 @@ void otRemoveMacBlacklist(otInstance *aInstance, const uint8_t *aExtAddr); * @retval kThreadError_InvalidArgs @p aIndex is out of bounds or @p aEntry is NULL. * */ -ThreadError otGetMacBlacklistEntry(otInstance *aInstance, uint8_t aIndex, otMacBlacklistEntry *aEntry); +OTAPI ThreadError OTCALL otGetMacBlacklistEntry(otInstance *aInstance, uint8_t aIndex, otMacBlacklistEntry *aEntry); /** * Remove all entries from the MAC Blacklist. @@ -1649,7 +1719,7 @@ ThreadError otGetMacBlacklistEntry(otInstance *aInstance, uint8_t aIndex, otMacB * @sa otDisableMacBlacklist * @sa otEnableMacBlacklist */ -void otClearMacBlacklist(otInstance *aInstance); +OTAPI void OTCALL otClearMacBlacklist(otInstance *aInstance); /** * Disable MAC blacklist filtering. @@ -1663,7 +1733,7 @@ void otClearMacBlacklist(otInstance *aInstance); * @sa otGetMacBlacklistEntry * @sa otEnableMacBlacklist */ -void otDisableMacBlacklist(otInstance *aInstance); +OTAPI void OTCALL otDisableMacBlacklist(otInstance *aInstance); /** * Enable MAC Blacklist filtering. @@ -1676,7 +1746,7 @@ void otDisableMacBlacklist(otInstance *aInstance); * @sa otGetMacBlacklistEntry * @sa otDisableMacBlacklist */ -void otEnableMacBlacklist(otInstance *aInstance); +OTAPI void OTCALL otEnableMacBlacklist(otInstance *aInstance); /** * This function indicates whether or not the MAC Blacklist is enabled. @@ -1693,7 +1763,7 @@ void otEnableMacBlacklist(otInstance *aInstance); * @sa otEnableMacBlacklist * */ -bool otIsMacBlacklistEnabled(otInstance *aInstance); +OTAPI bool OTCALL otIsMacBlacklistEnabled(otInstance *aInstance); /** * Get the assigned link quality which is on the link to a given extended address. @@ -1707,7 +1777,7 @@ bool otIsMacBlacklistEnabled(otInstance *aInstance); * * @sa otSetAssignLinkQuality */ -ThreadError otGetAssignLinkQuality(otInstance *aInstance, const uint8_t *aExtAddr, uint8_t *aLinkQuality); +OTAPI ThreadError OTCALL otGetAssignLinkQuality(otInstance *aInstance, const uint8_t *aExtAddr, uint8_t *aLinkQuality); /** * Set the link quality which is on the link to a given extended address. @@ -1718,14 +1788,14 @@ ThreadError otGetAssignLinkQuality(otInstance *aInstance, const uint8_t *aExtAdd * * @sa otGetAssignLinkQuality */ -void otSetAssignLinkQuality(otInstance *aInstance, const uint8_t *aExtAddr, uint8_t aLinkQuality); +OTAPI void OTCALL otSetAssignLinkQuality(otInstance *aInstance, const uint8_t *aExtAddr, uint8_t aLinkQuality); /** * This method triggers platform reset. * * @param[in] aInstance A pointer to an OpenThread instance. */ -void otPlatformReset(otInstance *aInstance); +OTAPI void OTCALL otPlatformReset(otInstance *aInstance); /** * This method deletes all the settings stored on non-volatile memory, and then triggers platform reset. @@ -1743,7 +1813,7 @@ void otFactoryReset(otInstance *aInstance); * * @sa otSetRouterDowngradeThreshold */ -uint8_t otGetRouterDowngradeThreshold(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetRouterDowngradeThreshold(otInstance *aInstance); /** * Set the ROUTER_DOWNGRADE_THRESHOLD parameter used in the Leader role. @@ -1753,25 +1823,28 @@ uint8_t otGetRouterDowngradeThreshold(otInstance *aInstance); * * @sa otGetRouterDowngradeThreshold */ -void otSetRouterDowngradeThreshold(otInstance *aInstance, uint8_t aThreshold); +OTAPI void OTCALL otSetRouterDowngradeThreshold(otInstance *aInstance, uint8_t aThreshold); /** * Get the ROUTER_SELECTION_JITTER parameter used in the REED/Router role. * + * @param[in] aInstance A pointer to an OpenThread instance. + * * @returns The ROUTER_SELECTION_JITTER value. * * @sa otSetRouterSelectionJitter */ -uint8_t otGetRouterSelectionJitter(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetRouterSelectionJitter(otInstance *aInstance); /** * Set the ROUTER_SELECTION_JITTER parameter used in the REED/Router role. * + * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aRouterJitter The ROUTER_SELECTION_JITTER value. * * @sa otGetRouterSelectionJitter */ -void otSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter); +OTAPI void OTCALL otSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter); /** * @} @@ -1801,7 +1874,7 @@ void otSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter); * @param[out] aChildInfo A pointer to where the child information is placed. * */ -ThreadError otGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChildInfo *aChildInfo); +OTAPI ThreadError OTCALL otGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChildInfo *aChildInfo); /** * The function retains diagnostic information for an attached Child by the internal table index. @@ -1811,7 +1884,7 @@ ThreadError otGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChild * @param[out] aChildInfo A pointer to where the child information is placed. * */ -ThreadError otGetChildInfoByIndex(otInstance *aInstance, uint8_t aChildIndex, otChildInfo *aChildInfo); +OTAPI ThreadError OTCALL otGetChildInfoByIndex(otInstance *aInstance, uint8_t aChildIndex, otChildInfo *aChildInfo); /** * This function gets the next neighbor information. It is used to go through the entries of @@ -1840,7 +1913,7 @@ ThreadError otGetNextNeighborInfo(otInstance *aInstance, otNeighborInfoIterator * @retval ::kDeviceRoleRouter The device is currently operating as a Thread Router. * @retval ::kDeviceRoleLeader The device is currently operating as a Thread Leader. */ -otDeviceRole otGetDeviceRole(otInstance *aInstance); +OTAPI otDeviceRole OTCALL otGetDeviceRole(otInstance *aInstance); /** * This function gets an EID cache entry. @@ -1853,7 +1926,7 @@ otDeviceRole otGetDeviceRole(otInstance *aInstance); * @retval kThreadError_InvalidArgs @p aIndex was out of bounds or @p aEntry was NULL. * */ -ThreadError otGetEidCacheEntry(otInstance *aInstance, uint8_t aIndex, otEidCacheEntry *aEntry); +OTAPI ThreadError OTCALL otGetEidCacheEntry(otInstance *aInstance, uint8_t aIndex, otEidCacheEntry *aEntry); /** * This function get the Thread Leader Data. @@ -1866,7 +1939,7 @@ ThreadError otGetEidCacheEntry(otInstance *aInstance, uint8_t aIndex, otEidCache * @retval kThreadError_InvalidArgs @p aLeaderData is NULL. * */ -ThreadError otGetLeaderData(otInstance *aInstance, otLeaderData *aLeaderData); +OTAPI ThreadError OTCALL otGetLeaderData(otInstance *aInstance, otLeaderData *aLeaderData); /** * Get the Leader's Router ID. @@ -1875,7 +1948,7 @@ ThreadError otGetLeaderData(otInstance *aInstance, otLeaderData *aLeaderData); * * @returns The Leader's Router ID. */ -uint8_t otGetLeaderRouterId(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetLeaderRouterId(otInstance *aInstance); /** * Get the Leader's Weight. @@ -1884,7 +1957,7 @@ uint8_t otGetLeaderRouterId(otInstance *aInstance); * * @returns The Leader's Weight. */ -uint8_t otGetLeaderWeight(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetLeaderWeight(otInstance *aInstance); /** * Get the Network Data Version. @@ -1893,7 +1966,7 @@ uint8_t otGetLeaderWeight(otInstance *aInstance); * * @returns The Network Data Version. */ -uint8_t otGetNetworkDataVersion(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetNetworkDataVersion(otInstance *aInstance); /** * Get the Partition ID. @@ -1902,7 +1975,7 @@ uint8_t otGetNetworkDataVersion(otInstance *aInstance); * * @returns The Partition ID. */ -uint32_t otGetPartitionId(otInstance *aInstance); +OTAPI uint32_t OTCALL otGetPartitionId(otInstance *aInstance); /** * Get the RLOC16. @@ -1911,7 +1984,7 @@ uint32_t otGetPartitionId(otInstance *aInstance); * * @returns The RLOC16. */ -uint16_t otGetRloc16(otInstance *aInstance); +OTAPI uint16_t OTCALL otGetRloc16(otInstance *aInstance); /** * Get the current Router ID Sequence. @@ -1920,7 +1993,7 @@ uint16_t otGetRloc16(otInstance *aInstance); * * @returns The Router ID Sequence. */ -uint8_t otGetRouterIdSequence(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetRouterIdSequence(otInstance *aInstance); /** * The function retains diagnostic information for a given Thread Router. @@ -1930,7 +2003,7 @@ uint8_t otGetRouterIdSequence(otInstance *aInstance); * @param[out] aRouterInfo A pointer to where the router information is placed. * */ -ThreadError otGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo); +OTAPI ThreadError OTCALL otGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo); /** * The function retains diagnostic information for a Thread Router as parent. @@ -1939,7 +2012,7 @@ ThreadError otGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterI * @param[out] aParentInfo A pointer to where the parent router information is placed. * */ -ThreadError otGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo); +OTAPI ThreadError OTCALL otGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo); /** * Get the Stable Network Data Version. @@ -1948,58 +2021,28 @@ ThreadError otGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo); * * @returns The Stable Network Data Version. */ -uint8_t otGetStableNetworkDataVersion(otInstance *aInstance); +OTAPI uint8_t OTCALL otGetStableNetworkDataVersion(otInstance *aInstance); /** - * This function pointer is called when an IEEE 802.15.4 frame is received. - * - * @note This callback is called after FCS processing and @p aFrame may not contain the actual FCS that was received. - * - * @note This callback is called before IEEE 802.15.4 security processing and mSecurityValid in @p aFrame will - * always be false. - * - * @param[in] aFrame A pointer to the received IEEE 802.15.4 frame. - * @param[in] aContext A pointer to application-specific context. + * Send a Network Diagnostic Get request * + * @param[in] aDestination A pointer to destination address. + * @param[in] aTlvTypes An array of Network Diagnostic TLV types. + * @param[in] aCount Number of types in aTlvTypes */ -typedef void (*otLinkPcapCallback)(const RadioPacket *aFrame, void *aContext); +OTAPI ThreadError OTCALL otSendDiagnosticGet(otInstance *aInstance, const otIp6Address *aDestination, + const uint8_t aTlvTypes[], uint8_t aCount); /** - * This function registers a callback to provide received raw IEEE 802.15.4 frames. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aPcapCallback A pointer to a function that is called when receiving an IEEE 802.15.4 link frame or - * NULL to disable the callback. - * @param[in] aCallbackContext A pointer to application-specific context. + * Send a Network Diagnostic Reset request * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aDestination A pointer to destination address. + * @param[in] aTlvTypes An array of Network Diagnostic TLV types. Currently only Type 9 is allowed. + * @param[in] aCount Number of types in aTlvTypes */ -void otSetLinkPcapCallback(otInstance *aInstance, otLinkPcapCallback aPcapCallback, void *aCallbackContext); - -/** - * This function indicates whether or not promiscuous mode is enabled at the link layer. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @retval true Promiscuous mode is enabled. - * @retval false Promiscuous mode is not enabled. - * - */ -bool otIsLinkPromiscuous(otInstance *aInstance); - -/** - * This function enables or disables the link layer promiscuous mode. - * - * @note Promiscuous mode may only be enabled when the Thread interface is disabled. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aPromiscuous true to enable promiscuous mode, or false otherwise. - * - * @retval kThreadError_None Successfully enabled promiscuous mode. - * @retval kThreadError_InvalidState Could not enable promiscuous mode because - * the Thread interface is enabled. - * - */ -ThreadError otSetLinkPromiscuous(otInstance *aInstance, bool aPromiscuous); +OTAPI ThreadError OTCALL otSendDiagnosticReset(otInstance *aInstance, const otIp6Address *aDestination, + const uint8_t aTlvTypes[], uint8_t aCount); /** * Get the MAC layer counters. @@ -2008,7 +2051,7 @@ ThreadError otSetLinkPromiscuous(otInstance *aInstance, bool aPromiscuous); * * @returns A pointer to the MAC layer counters. */ -const otMacCounters *otGetMacCounters(otInstance *aInstance); +OTAPI const otMacCounters *OTCALL otGetMacCounters(otInstance *aInstance); /** * @} @@ -2024,7 +2067,7 @@ const otMacCounters *otGetMacCounters(otInstance *aInstance); * @retval TRUE The two IPv6 addresses are the same. * @retval FALSE The two IPv6 addresses are not the same. */ -bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b); +OTAPI bool OTCALL otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b); /** * Convert a human-readable IPv6 address string into a binary representation. @@ -2035,285 +2078,7 @@ bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b); * @retval kThreadErrorNone Successfully parsed the string. * @retval kThreadErrorInvalidArg Failed to parse the string. */ -ThreadError otIp6AddressFromString(const char *aString, otIp6Address *aAddress); - -/** - * @addtogroup messages Message Buffers - * - * @brief - * This module includes functions that manipulate OpenThread message buffers - * - * @{ - * - */ - -/** - * Free an allocated message buffer. - * - * @param[in] aMessage A pointer to a message buffer. - * - * @retval kThreadErrorNone Successfully freed the message buffer. - * - * @sa otNewUdpMessage - * @sa otAppendMessage - * @sa otGetMessageLength - * @sa otSetMessageLength - * @sa otGetMessageOffset - * @sa otSetMessageOffset - * @sa otReadMessage - * @sa otWriteMessage - */ -ThreadError otFreeMessage(otMessage aMessage); - -/** - * Get the message length in bytes. - * - * @param[in] aMessage A pointer to a message buffer. - * - * @returns The message length in bytes. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otAppendMessage - * @sa otSetMessageLength - * @sa otGetMessageOffset - * @sa otSetMessageOffset - * @sa otReadMessage - * @sa otWriteMessage - * @sa otSetMessageLength - */ -uint16_t otGetMessageLength(otMessage aMessage); - -/** - * Set the message length in bytes. - * - * @param[in] aMessage A pointer to a message buffer. - * @param[in] aLength A length in bytes. - * - * @retval kThreadErrorNone Successfully set the message length. - * @retval kThreadErrorNoBufs No available buffers to grow the message. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otAppendMessage - * @sa otGetMessageLength - * @sa otGetMessageOffset - * @sa otSetMessageOffset - * @sa otReadMessage - * @sa otWriteMessage - */ -ThreadError otSetMessageLength(otMessage aMessage, uint16_t aLength); - -/** - * Get the message offset in bytes. - * - * @param[in] aMessage A pointer to a message buffer. - * - * @returns The message offset value. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otAppendMessage - * @sa otGetMessageLength - * @sa otSetMessageLength - * @sa otSetMessageOffset - * @sa otReadMessage - * @sa otWriteMessage - */ -uint16_t otGetMessageOffset(otMessage aMessage); - -/** - * Set the message offset in bytes. - * - * @param[in] aMessage A pointer to a message buffer. - * @param[in] aOffset An offset in bytes. - * - * @retval kThreadErrorNone Successfully set the message offset. - * @retval kThreadErrorInvalidArg The offset is beyond the message length. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otAppendMessage - * @sa otGetMessageLength - * @sa otSetMessageLength - * @sa otGetMessageOffset - * @sa otReadMessage - * @sa otWriteMessage - */ -ThreadError otSetMessageOffset(otMessage aMessage, uint16_t aOffset); - -/** - * Append bytes to a message. - * - * @param[in] aMessage A pointer to a message buffer. - * @param[in] aBuf A pointer to the data to append. - * @param[in] aLength Number of bytes to append. - * - * @retval kThreadErrorNone Successfully appended to the message - * @retval kThreadErrorNoBufs No available buffers to grow the message. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otGetMessageLength - * @sa otSetMessageLength - * @sa otGetMessageOffset - * @sa otSetMessageOffset - * @sa otReadMessage - * @sa otWriteMessage - */ -ThreadError otAppendMessage(otMessage aMessage, const void *aBuf, uint16_t aLength); - -/** - * Read bytes from a message. - * - * @param[in] aMessage A pointer to a message buffer. - * @param[in] aOffset An offset in bytes. - * @param[in] aBuf A pointer to a buffer that message bytes are read to. - * @param[in] aLength Number of bytes to read. - * - * @returns The number of bytes read. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otAppendMessage - * @sa otGetMessageLength - * @sa otSetMessageLength - * @sa otGetMessageOffset - * @sa otSetMessageOffset - * @sa otWriteMessage - */ -int otReadMessage(otMessage aMessage, uint16_t aOffset, void *aBuf, uint16_t aLength); - -/** - * Write bytes to a message. - * - * @param[in] aMessage A pointer to a message buffer. - * @param[in] aOffset An offset in bytes. - * @param[in] aBuf A pointer to a buffer that message bytes are written from. - * @param[in] aLength Number of bytes to write. - * - * @returns The number of bytes written. - * - * @sa otNewUdpMessage - * @sa otFreeMessage - * @sa otAppendMessage - * @sa otGetMessageLength - * @sa otSetMessageLength - * @sa otGetMessageOffset - * @sa otSetMessageOffset - * @sa otReadMessage - */ -int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint16_t aLength); - -/** - * @} - * - */ - -/** - * @addtogroup ip6 IPv6 - * - * @brief - * This module includes functions that control IPv6 communication. - * - * @{ - * - */ - -/** - * Allocate a new message buffer for sending an IPv6 message. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aLinkSecurityEnabled TRUE if the message should be secured at Layer 2 - * - * @returns A pointer to the message buffer or NULL if no message buffers are available. - * - * @sa otFreeMessage - */ -otMessage otNewIp6Message(otInstance *aInstance, bool aLinkSecurityEnabled); - -/** - * This function pointer is called when an IPv6 datagram is received. - * - * @param[in] aMessage A pointer to the message buffer containing the received IPv6 datagram. - * @param[in] aContext A pointer to application-specific context. - * - */ -typedef void (*otReceiveIp6DatagramCallback)(otMessage aMessage, void *aContext); - -/** - * This function registers a callback to provide received IPv6 datagrams. - * - * By default, this callback does not pass Thread control traffic. See otSetReceiveIp6DatagramFilterEnabled() to - * change the Thread control traffic filter setting. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aCallback A pointer to a function that is called when an IPv6 datagram is received or - * NULL to disable the callback. - * @param[in] aCallbackContext A pointer to application-specific context. - * - * @sa otIsReceiveIp6DatagramFilterEnabled - * @sa otSetReceiveIp6DatagramFilterEnabled - * - */ -void otSetReceiveIp6DatagramCallback(otInstance *aInstance, otReceiveIp6DatagramCallback aCallback, - void *aCallbackContext); - -/** - * This function indicates whether or not Thread control traffic is filtered out when delivering IPv6 datagrams - * via the callback specified in otSetReceiveIp6DatagramCallback(). - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @returns TRUE if Thread control traffic is filtered out, FALSE otherwise. - * - * @sa otSetReceiveIp6DatagramCallback - * @sa otSetReceiveIp6DatagramFilterEnabled - * - */ -bool otIsReceiveIp6DatagramFilterEnabled(otInstance *aInstance); - -/** - * This function sets whether or not Thread control traffic is filtered out when delivering IPv6 datagrams - * via the callback specified in otSetReceiveIp6DatagramCallback(). - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aEnabled TRUE if Thread control traffic is filtered out, FALSE otherwise. - * - * @sa otSetReceiveIp6DatagramCallback - * @sa otIsReceiveIp6DatagramFilterEnabled - * - */ -void otSetReceiveIp6DatagramFilterEnabled(otInstance *aInstance, bool aEnabled); - -/** - * This function sends an IPv6 datagram via the Thread interface. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aMessage A pointer to the message buffer containing the IPv6 datagram. - * - */ -ThreadError otSendIp6Datagram(otInstance *aInstance, otMessage aMessage); - -/** - * This function indicates whether or not ICMPv6 Echo processing is enabled. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @retval TRUE ICMPv6 Echo processing is enabled. - * @retval FALSE ICMPv6 Echo processing is disabled. - * - */ -bool otIsIcmpEchoEnabled(otInstance *aInstance); - -/** - * This function sets whether or not ICMPv6 Echo processing is enabled. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aEnabled TRUE to enable ICMPv6 Echo processing, FALSE otherwise. - * - */ -void otSetIcmpEchoEnabled(otInstance *aInstance, bool aEnabled); +OTAPI ThreadError OTCALL otIp6AddressFromString(const char *aString, otIp6Address *aAddress); /** * This function returns the prefix match length (bits) for two IPv6 addresses. @@ -2324,122 +2089,7 @@ void otSetIcmpEchoEnabled(otInstance *aInstance, bool aEnabled); * @returns The prefix match length in bits. * */ -uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond); - -/** - * @} - * - */ - -/** - * @addtogroup udp UDP - * - * @brief - * This module includes functions that control UDP communication. - * - * @{ - * - */ - -/** - * Allocate a new message buffer for sending a UDP message. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aLinkSecurityEnabled TRUE if the message should be secured at Layer 2. - * - * @returns A pointer to the message buffer or NULL if no message buffers are available. - * - * @sa otFreeMessage - */ -otMessage otNewUdpMessage(otInstance *aInstance, bool aLinkSecurityEnabled); - -/** - * Open a UDP/IPv6 socket. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aSocket A pointer to a UDP socket structure. - * @param[in] aCallback A pointer to the application callback function. - * @param[in] aContext A pointer to application-specific context. - * - * @retval kThreadErrorNone Successfully opened the socket. - * @retval kThreadErrorInvalidArgs Given socket structure was already opened. - * - * @sa otNewUdpMessage - * @sa otCloseUdpSocket - * @sa otBindUdpSocket - * @sa otSendUdp - */ -ThreadError otOpenUdpSocket(otInstance *aInstance, otUdpSocket *aSocket, otUdpReceive aCallback, void *aContext); - -/** - * Close a UDP/IPv6 socket. - * - * @param[in] aSocket A pointer to a UDP socket structure. - * - * @retval kThreadErrorNone Successfully closed the socket. - * - * @sa otNewUdpMessage - * @sa otOpenUdpSocket - * @sa otBindUdpSocket - * @sa otSendUdp - */ -ThreadError otCloseUdpSocket(otUdpSocket *aSocket); - -/** - * Bind a UDP/IPv6 socket. - * - * @param[in] aSocket A pointer to a UDP socket structure. - * @param[in] aSockName A pointer to an IPv6 socket address structure. - * - * @retval kThreadErrorNone Bind operation was successful. - * - * @sa otNewUdpMessage - * @sa otOpenUdpSocket - * @sa otCloseUdpSocket - * @sa otSendUdp - */ -ThreadError otBindUdpSocket(otUdpSocket *aSocket, otSockAddr *aSockName); - -/** - * Send a UDP/IPv6 message. - * - * @param[in] aSocket A pointer to a UDP socket structure. - * @param[in] aMessage A pointer to a message buffer. - * @param[in] aMessageInfo A pointer to a message info structure. - * - * @sa otNewUdpMessage - * @sa otOpenUdpSocket - * @sa otCloseUdpSocket - * @sa otBindUdpSocket - * @sa otSendUdp - */ -ThreadError otSendUdp(otUdpSocket *aSocket, otMessage aMessage, const otMessageInfo *aMessageInfo); - -/** - * Send a Network Diagnostic Get request - * - * @param[in] aDestination A pointer to destination address. - * @param[in] aTlvTypes An array of Network Diagnostic TLV types. - * @param[in] aCount Number of types in aTlvTypes - */ -ThreadError otSendDiagnosticGet(otInstance *aInstance, const otIp6Address *aDestination, const uint8_t aTlvTypes[], - uint8_t aCount); - -/** - * Send a Network Diagnostic Reset request - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aDestination A pointer to destination address. - * @param[in] aTlvTypes An array of Network Diagnostic TLV types. Currently only Type 9 is allowed. - * @param[in] aCount Number of types in aTlvTypes - */ -ThreadError otSendDiagnosticReset(otInstance *aInstance, const otIp6Address *aDestination, const uint8_t aTlvTypes[], - uint8_t aCount); - -/** - * @} - * - */ +OTAPI uint8_t OTCALL otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond); #ifdef __cplusplus } // extern "C" diff --git a/include/platform/toolchain.h b/include/platform/toolchain.h index 9b9d39d8d..bf684687d 100644 --- a/include/platform/toolchain.h +++ b/include/platform/toolchain.h @@ -96,6 +96,8 @@ extern "C" { #define OT_TOOL_PACKED_FIELD __attribute__((packed)) #define OT_TOOL_PACKED_END __attribute__((packed)) +#define OT_TOOL_ALIGN(X) + #elif defined(__ICCARM__) || defined(__ICC8051__) // http://supp.iar.com/FilesPublic/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf @@ -106,12 +108,16 @@ extern "C" { #define OT_TOOL_PACKED_FIELD #define OT_TOOL_PACKED_END +#define OT_TOOL_ALIGN(X) + #elif defined(_MSC_VER) #define OT_TOOL_PACKED_BEGIN __pragma(pack(push,1)) #define OT_TOOL_PACKED_FIELD #define OT_TOOL_PACKED_END __pragma(pack(pop)) +#define OT_TOOL_ALIGN(X) __declspec(align(4)) + #elif defined(__SDCC) // Structures are packed by default in sdcc, as it primarily targets 8-bit MCUs. @@ -120,6 +126,8 @@ extern "C" { #define OT_TOOL_PACKED_FIELD #define OT_TOOL_PACKED_END +#define OT_TOOL_ALIGN(X) + #else #error "Error: No valid Toolchain specified" @@ -130,6 +138,8 @@ extern "C" { #define OT_TOOL_PACKED_FIELD #define OT_TOOL_PACKED_END +#define OT_TOOL_ALIGN(X) + #endif // =========== TOOLCHAIN SELECTION : END =========== @@ -137,10 +147,8 @@ extern "C" { #ifdef _MSC_VER #ifdef _WIN64 -#define OT_CALL #define OT_CDECL #else -#define OT_CALL __stdcall #define OT_CDECL __cdecl #endif @@ -151,6 +159,16 @@ extern "C" { #endif +#ifdef OTDLL +#ifndef OTAPI +#define OTAPI __declspec(dllimport) +#endif +#define OTCALL WINAPI +#else +#define OTAPI +#define OTCALL +#endif + /** * @} * diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index f3dce9c1a..fd0185161 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -2033,6 +2033,10 @@ void Interpreter::ProcessState(int argc, char *argv[]) { switch (otGetDeviceRole(mInstance)) { + case kDeviceRoleOffline: + sServer->OutputFormat("offline\r\n"); + break; + case kDeviceRoleDisabled: sServer->OutputFormat("disabled\r\n"); break; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index ad4657d06..364633e81 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -42,6 +42,8 @@ #include +#include +#include #include #include #include diff --git a/src/core/common/tasklet.hpp b/src/core/common/tasklet.hpp index e6c83c29c..497bdb489 100644 --- a/src/core/common/tasklet.hpp +++ b/src/core/common/tasklet.hpp @@ -35,6 +35,7 @@ #define TASKLET_HPP_ #include +#include namespace Thread { diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 6a96c3299..d973ecb6e 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -36,7 +36,8 @@ #include -#include +#include +#include #include #include #include diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 862f5bb0c..26e3a436d 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -1728,6 +1728,7 @@ ThreadError NcpBase::GetPropertyHandler_NET_ROLE(uint8_t header, spinel_prop_key switch (otGetDeviceRole(mInstance)) { + case kDeviceRoleOffline: case kDeviceRoleDisabled: case kDeviceRoleDetached: role = SPINEL_NET_ROLE_DETACHED;