diff --git a/etc/visual-studio/openthread.sln b/etc/visual-studio/openthread.sln
index 8313dcd5d..6ddf448f0 100644
--- a/etc/visual-studio/openthread.sln
+++ b/etc/visual-studio/openthread.sln
@@ -57,6 +57,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenThread", "OpenThread.vc
{ED0EA262-C222-42C7-98D3-E70C72978ED2} = {ED0EA262-C222-42C7-98D3-E70C72978ED2}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spinel_k", "spinel_k.vcxproj", "{A55766B5-58B6-4519-835E-5A4B7C164B5A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
@@ -291,6 +293,24 @@ Global
{F8C22844-9B93-4978-80DF-8AF2B37A7ABB}.Release|x86.ActiveCfg = Release|Win32
{F8C22844-9B93-4978-80DF-8AF2B37A7ABB}.Release|x86.Build.0 = Release|Win32
{F8C22844-9B93-4978-80DF-8AF2B37A7ABB}.Release|x86.Deploy.0 = Release|Win32
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|ARM.Build.0 = Debug|ARM
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|ARM.Deploy.0 = Debug|ARM
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|x64.ActiveCfg = Debug|x64
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|x64.Build.0 = Debug|x64
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|x64.Deploy.0 = Debug|x64
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|x86.ActiveCfg = Debug|Win32
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|x86.Build.0 = Debug|Win32
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Debug|x86.Deploy.0 = Debug|Win32
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|ARM.ActiveCfg = Release|ARM
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|ARM.Build.0 = Release|ARM
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|ARM.Deploy.0 = Release|ARM
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|x64.ActiveCfg = Release|x64
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|x64.Build.0 = Release|x64
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|x64.Deploy.0 = Release|x64
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|x86.ActiveCfg = Release|Win32
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|x86.Build.0 = Release|Win32
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}.Release|x86.Deploy.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -313,5 +333,6 @@ Global
{B7C6F344-7287-4930-AF38-223622BD8CBB} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133}
{D5577E51-FA31-4802-8669-1DB32805935E} = {35F6AB71-5BD2-4D53-8A51-D75CCD4CCC3D}
{F8C22844-9B93-4978-80DF-8AF2B37A7ABB} = {76EA541E-CAB1-4DB5-A39F-E3DB2A78CDDD}
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A} = {95BD0669-04C8-4EEB-B3CC-0535B03F4468}
EndGlobalSection
EndGlobal
diff --git a/etc/visual-studio/otLwf.vcxproj b/etc/visual-studio/otLwf.vcxproj
index 116e7ef95..fea7869b4 100644
--- a/etc/visual-studio/otLwf.vcxproj
+++ b/etc/visual-studio/otLwf.vcxproj
@@ -49,6 +49,7 @@
..\..\include;
..\..\examples\drivers\windows\include;
..\..\examples\drivers\windows\otLwf;
+ ..\..\src;
..\..\src\core;
..\..\src\missing\stdint;
..\..\src\missing\stdbool;
@@ -78,6 +79,9 @@
cng.lib;
+
+ inf2cat /driver:$(TargetDir) /os:8_ARM
+
@@ -87,6 +91,8 @@
+
+
..;.;%(AdditionalIncludeDirectories)
@@ -103,6 +109,8 @@
+
+
@@ -118,6 +126,9 @@
{69be8e8c-cf1e-46d6-932b-db435f47059b}
+
+ {a55766b5-58b6-4519-835e-5a4b7c164b5a}
+
diff --git a/etc/visual-studio/otLwf.vcxproj.filters b/etc/visual-studio/otLwf.vcxproj.filters
index f38de36b2..bb43d0104 100644
--- a/etc/visual-studio/otLwf.vcxproj.filters
+++ b/etc/visual-studio/otLwf.vcxproj.filters
@@ -48,6 +48,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
@@ -83,6 +89,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
Source Files
diff --git a/etc/visual-studio/spinel_k.vcxproj b/etc/visual-studio/spinel_k.vcxproj
new file mode 100644
index 000000000..b9d207a63
--- /dev/null
+++ b/etc/visual-studio/spinel_k.vcxproj
@@ -0,0 +1,67 @@
+
+
+
+
+ {A55766B5-58B6-4519-835E-5A4B7C164B5A}
+ {8c0e3d8b-df43-455b-815a-4a0e72973bc6}
+ v4.5
+ 12.0
+ Debug
+ Win32
+ Thread
+ KMDF
+ Universal
+
+
+ WindowsKernelModeDriver10.0
+ StaticLibrary
+
+
+
+ Windows10
+ true
+
+
+ Windows10
+ false
+
+
+
+
+
+
+
+ ..\..\build\bin\$(Platform)\$(Configuration)\lib\
+ ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
+
+
+
+
+ %(PreprocessorDefinitions);
+ HAVE_STRNLEN=1;
+ SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR=1;
+
+
+ %(AdditionalIncludeDirectories);
+ ..\..\include;
+ ..\..\src\missing\stdint;
+ ..\..\src\missing\stdbool;
+
+ 4100;4706;4748;%(DisableSpecificWarnings)
+ true
+ true
+ ..\..\include\platform\logging-windows.h
+ -km %(WppAdditionalOptions)
+ otCore
+ WPP_INIT_TRACING
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/etc/visual-studio/spinel_k.vcxproj.filters b/etc/visual-studio/spinel_k.vcxproj.filters
new file mode 100644
index 000000000..24312b902
--- /dev/null
+++ b/etc/visual-studio/spinel_k.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {C034F7F4-3CBD-4B9A-A033-0D76A195B581}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {7A95885E-AD23-439A-B283-9BDE0E39D84E}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {1E1DF93E-9746-4688-A1F0-7B59378CF28F}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/examples/apps/windows/MainPage.xaml b/examples/apps/windows/MainPage.xaml
index 4bfb3503e..05aaec872 100644
--- a/examples/apps/windows/MainPage.xaml
+++ b/examples/apps/windows/MainPage.xaml
@@ -36,6 +36,11 @@
mc:Ignorable="d">
+
+
+
+
+
-
+
OpenThread
diff --git a/examples/drivers/windows/include/otLwfIoctl.h b/examples/drivers/windows/include/otLwfIoctl.h
index c362d2ca5..a9675807b 100644
--- a/examples/drivers/windows/include/otLwfIoctl.h
+++ b/examples/drivers/windows/include/otLwfIoctl.h
@@ -256,10 +256,12 @@ typedef enum _OTLWF_NOTIF_TYPE
// GUID - InterfaceGuid
// otShortAddress - aShortAddress
+/* NOT USED
#define IOCTL_OTLWF_OT_UNICAST_ADDRESSES \
OTLWF_CTL_CODE(120, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otNetifAddress[] - aAddresses
+*/
#define IOCTL_OTLWF_OT_ACTIVE_DATASET \
OTLWF_CTL_CODE(121, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
@@ -616,6 +618,7 @@ typedef struct otCommissionConfig
// GUID - InterfaceGuid
// uint8_t - aLength
// uint8_t[aLength] - aTlvTypes
+ // otIp6Address - aAddress (optional)
#define IOCTL_OTLWF_OT_SEND_ACTIVE_SET \
OTLWF_CTL_CODE(186, METHOD_BUFFERED, FILE_WRITE_DATA)
@@ -629,6 +632,7 @@ typedef struct otCommissionConfig
// GUID - InterfaceGuid
// uint8_t - aLength
// uint8_t[aLength] - aTlvTypes
+ // otIp6Address - aAddress (optional)
#define IOCTL_OTLWF_OT_SEND_PENDING_SET \
OTLWF_CTL_CODE(188, METHOD_BUFFERED, FILE_WRITE_DATA)
@@ -654,9 +658,13 @@ typedef struct otCommissionConfig
OTLWF_CTL_CODE(191, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aKeySwitchGuardTime
+
+#define IOCTL_OTLWF_OT_FACTORY_RESET \
+ OTLWF_CTL_CODE(192, METHOD_BUFFERED, FILE_WRITE_DATA)
+ // GUID - InterfaceGuid
// OpenThread function IOCTL codes
#define MIN_OTLWF_IOCTL_FUNC_CODE 100
-#define MAX_OTLWF_IOCTL_FUNC_CODE 191
+#define MAX_OTLWF_IOCTL_FUNC_CODE 192
#endif //__OTLWFIOCTL_H__
diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp
index 015b905c3..be469e33c 100644
--- a/examples/drivers/windows/otApi/otApi.cpp
+++ b/examples/drivers/windows/otApi/otApi.cpp
@@ -35,7 +35,7 @@ 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;
+const DWORD c_MaxOverlappedWaitTimeMS = 5 * 1000;
// Version string returned by the API
const char c_Version[] = "Windows"; // TODO - What should we really put here?
@@ -2144,6 +2144,7 @@ otSendActiveGet(
if (aTlvTypes == nullptr && aLength != 0) return kThreadError_InvalidArgs;
DWORD BufferSize = sizeof(GUID) + sizeof(uint8_t) + aLength;
+ if (aAddress) BufferSize += sizeof(otIp6Address);
PBYTE Buffer = (PBYTE)malloc(BufferSize);
if (Buffer == nullptr) return kThreadError_NoBufs;
@@ -2151,9 +2152,8 @@ otSendActiveGet(
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);
+ if (aAddress)
+ memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t) + aLength, BufferSize - sizeof(GUID) - sizeof(uint8_t) - aLength, aAddress, sizeof(otIp6Address));
ThreadError result =
DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_ACTIVE_GET, Buffer, BufferSize, nullptr, 0));
@@ -2206,6 +2206,7 @@ otSendPendingGet(
if (aTlvTypes == nullptr && aLength != 0) return kThreadError_InvalidArgs;
DWORD BufferSize = sizeof(GUID) + sizeof(uint8_t) + aLength;
+ if (aAddress) BufferSize += sizeof(otIp6Address);
PBYTE Buffer = (PBYTE)malloc(BufferSize);
if (Buffer == nullptr) return kThreadError_NoBufs;
@@ -2213,9 +2214,8 @@ otSendPendingGet(
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);
+ if (aAddress)
+ memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t) + aLength, BufferSize - sizeof(GUID) - sizeof(uint8_t) - aLength, aAddress, sizeof(otIp6Address));
ThreadError result =
DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_SEND_PENDING_GET, Buffer, BufferSize, nullptr, 0));
@@ -2844,8 +2844,7 @@ otFactoryReset(
_In_ otInstance *aInstance
)
{
- UNREFERENCED_PARAMETER(aInstance);
- // TODO ...
+ if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_FACTORY_RESET);
}
OTAPI
@@ -3042,6 +3041,18 @@ otGetMacCounters(
return aCounters;
}
+OTAPI
+void
+OTCALL
+otGetMessageBufferInfo(
+ _In_ otInstance *,
+ _Out_ otBufferInfo *aBufferInfo
+ )
+{
+ // Not supported on Windows
+ ZeroMemory(aBufferInfo, sizeof(otBufferInfo));
+}
+
OTAPI
bool
OTCALL
diff --git a/examples/drivers/windows/otLwf/address.c b/examples/drivers/windows/otLwf/address.c
index ae0d50270..594ec8a81 100644
--- a/examples/drivers/windows/otLwf/address.c
+++ b/examples/drivers/windows/otLwf/address.c
@@ -373,7 +373,7 @@ otLwfEventProcessingAddressChanged(
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID
-otLwfAddressesUpdated(
+otLwfRadioAddressesUpdated(
_In_ PMS_FILTER pFilter
)
{
@@ -382,6 +382,8 @@ otLwfAddressesUpdated(
ULONG FoundInOpenThread = 0; // Bit field
ULONG OriginalCacheLength = pFilter->otCachedAddrCount;
+ NT_ASSERT(pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO);
+
const otNetifAddress* addr = otGetUnicastAddresses(pFilter->otCtx);
// Process the addresses
@@ -411,3 +413,76 @@ otLwfAddressesUpdated(
LogFuncExit(DRIVER_DEFAULT);
}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfTunAddressesUpdated(
+ _In_ PMS_FILTER pFilter,
+ _In_reads_bytes_(value_data_len) const uint8_t* value_data_ptr,
+ _In_ spinel_size_t value_data_len,
+ _Out_ uint32_t *aNotifFlags
+ )
+{
+ ULONG FoundInOpenThread = 0; // Bit field
+ ULONG OriginalCacheLength = pFilter->otCachedAddrCount;
+
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ NT_ASSERT (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD);
+
+ *aNotifFlags = 0;
+
+ while (value_data_len > 0)
+ {
+ const uint8_t *entry_ptr = NULL;
+ spinel_size_t entry_len = 0;
+
+ spinel_ssize_t len = spinel_datatype_unpack(value_data_ptr, value_data_len, "D.", &entry_ptr, &entry_len);
+ if (len < 1) break;
+
+ {
+ PIN6_ADDR pAddr = NULL;
+ otNetifAddress addr = { { 0 }, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0, NULL };
+
+ spinel_datatype_unpack(
+ entry_ptr,
+ entry_len,
+ "6CLL",
+ &pAddr,
+ &addr.mPrefixLength,
+ &addr.mValidLifetime,
+ &addr.mPreferredLifetime);
+
+ if (pAddr)
+ {
+ int index = otLwfFindCachedAddrIndex(pFilter, pAddr);
+ if (index == -1)
+ {
+ memcpy_s(&addr.mAddress, sizeof(addr.mAddress), pAddr, sizeof(IN6_ADDR));
+ otLwfOnAddressAdded(pFilter, &addr, TRUE);
+ *aNotifFlags |= OT_IP6_ADDRESS_ADDED;
+ }
+ else
+ {
+ NT_ASSERT(index < 8 * sizeof(FoundInOpenThread));
+ FoundInOpenThread |= 1 << index;
+ }
+ }
+ }
+
+ value_data_len -= len;
+ value_data_ptr += len;
+ }
+
+ // Look for missing addresses and mark them as removed
+ for (int i = OriginalCacheLength - 1; i >= 0; i--)
+ {
+ if ((FoundInOpenThread & (1 << i)) == 0)
+ {
+ otLwfOnAddressRemoved(pFilter, (ULONG)i, TRUE);
+ *aNotifFlags |= OT_IP6_ADDRESS_REMOVED;
+ }
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
diff --git a/examples/drivers/windows/otLwf/datapath.c b/examples/drivers/windows/otLwf/datapath.c
index f3377226c..4188d3d68 100644
--- a/examples/drivers/windows/otLwf/datapath.c
+++ b/examples/drivers/windows/otLwf/datapath.c
@@ -148,14 +148,34 @@ Arguments:
--*/
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
-
- UNREFERENCED_PARAMETER(SendCompleteFlags);
- LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, NBL: %p", FilterModuleContext, NetBufferLists);
+ LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, NBL: %p %!STATUS!", FilterModuleContext, NetBufferLists, NetBufferLists->Status);
- NT_ASSERT(NetBufferLists == pFilter->SendNetBufferList);
- NT_ASSERT(kStateTransmit == pFilter->otPhyState);
- KeSetEvent(&pFilter->SendNetBufferListComplete, 0, FALSE);
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ NT_ASSERT(NetBufferLists == pFilter->SendNetBufferList);
+ NT_ASSERT(kStateTransmit == pFilter->otPhyState);
+ KeSetEvent(&pFilter->SendNetBufferListComplete, 0, FALSE);
+ }
+ else
+ {
+ NT_ASSERT(NET_BUFFER_LIST_NEXT_NBL(NetBufferLists) == NULL);
+ PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferLists);
+
+ // Cancel command if we failed to send the NBL
+ if (!NT_SUCCESS(NetBufferLists->Status))
+ {
+ spinel_tid_t tid = (spinel_tid_t)(ULONG_PTR)NetBuffer->ProtocolReserved[1];
+ if (tid != 0)
+ {
+ otLwfCancelCommandHandler(pFilter, NDIS_TEST_SEND_COMPLETE_AT_DISPATCH_LEVEL(SendCompleteFlags), tid);
+ }
+ }
+
+ NetBuffer->DataLength = (ULONG)(ULONG_PTR)NetBuffer->ProtocolReserved[0];
+ NdisAdvanceNetBufferDataStart(NetBuffer, NetBuffer->DataLength, TRUE, NULL);
+ NdisFreeNetBufferList(NetBufferLists);
+ }
LogFuncExit(DRIVER_DATA_PATH);
}
@@ -214,14 +234,39 @@ Arguments:
}
else
{
- // Indicate a new NBL to process on our worker thread
- otLwfEventProcessingIndicateNewNetBufferLists(
- pFilter,
- DispatchLevel,
- FALSE,
- PortNumber,
- NetBufferLists
- );
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ // Indicate a new NBL to process on our worker thread
+ otLwfEventProcessingIndicateNewNetBufferLists(
+ pFilter,
+ DispatchLevel,
+ FALSE,
+ PortNumber,
+ NetBufferLists
+ );
+ }
+ else
+ {
+ PNET_BUFFER_LIST CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl);
+ while (CurrNb)
+ {
+ otLwfSendTunnelPacket(pFilter, DispatchLevel, CurrNb, TRUE);
+ CurrNb = NET_BUFFER_NEXT_NB(CurrNb);
+ }
+
+ NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_SUCCESS;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+
+ NdisFSendNetBufferListsComplete(
+ pFilter->FilterHandle,
+ NetBufferLists,
+ DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0
+ );
+ }
// Release the data path ref now
ExReleaseRundownProtection(&pFilter->DataPathRundown);
@@ -273,15 +318,19 @@ Arguments:
{
LogVerbose(DRIVER_DATA_PATH, "NBL failed on return: %!STATUS!", CurrNbl->Status);
}
+
+ //if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO ||
+ // pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD)
+ {
+ PNET_BUFFER_LIST NblToFree = CurrNbl;
+ PNET_BUFFER NbToFree = NET_BUFFER_LIST_FIRST_NB(NblToFree);
- PNET_BUFFER_LIST NblToFree = CurrNbl;
- PNET_BUFFER NbToFree = NET_BUFFER_LIST_FIRST_NB(NblToFree);
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ NET_BUFFER_LIST_NEXT_NBL(NblToFree) = NULL;
- CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
- NET_BUFFER_LIST_NEXT_NBL(NblToFree) = NULL;
-
- NdisAdvanceNetBufferDataStart(NbToFree, NET_BUFFER_DATA_LENGTH(NbToFree), TRUE, NULL);
- NdisFreeNetBufferList(NblToFree);
+ NdisAdvanceNetBufferDataStart(NbToFree, NET_BUFFER_DATA_LENGTH(NbToFree), TRUE, NULL);
+ NdisFreeNetBufferList(NblToFree);
+ }
}
LogFuncExit(DRIVER_DATA_PATH);
@@ -343,8 +392,46 @@ N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
}
+ else if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD)
+ {
+ PNET_BUFFER_LIST CurrNbl = NetBufferLists;
+ while (CurrNbl)
+ {
+ PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl);
+ while (CurrNb)
+ {
+ PUCHAR Buffer = (PUCHAR)NdisGetDataBuffer(CurrNb, CurrNb->DataLength, NULL, 1, 0);
+ if (Buffer == NULL)
+ {
+ Buffer = (PUCHAR)FILTER_ALLOC_MEM(pFilter->FilterHandle, CurrNb->DataLength);
+ if (Buffer != NULL)
+ {
+ PUCHAR _Buffer = (PUCHAR)NdisGetDataBuffer(CurrNb, CurrNb->DataLength, Buffer, 1, 0);
+ NT_ASSERT(_Buffer == Buffer);
+ UNREFERENCED_PARAMETER(_Buffer);
+ otLwfReceiveTunnelPacket(pFilter, DispatchLevel, Buffer, CurrNb->DataLength);
+ FILTER_FREE_MEM(Buffer);
+ }
+ }
+ else
+ {
+ otLwfReceiveTunnelPacket(pFilter, DispatchLevel, Buffer, CurrNb->DataLength);
+ }
+ CurrNb = NET_BUFFER_NEXT_NB(CurrNb);
+ }
+
+ NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_SUCCESS;
+ CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
+ }
+
+ NdisFReturnNetBufferLists(
+ pFilter->FilterHandle,
+ NetBufferLists,
+ DispatchLevel ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0
+ );
+ }
// Try to grab a ref on the data path first, to make sure we are allowed
- else if(pFilter->otPhyState == kStateDisabled || !ExAcquireRundownProtection(&pFilter->DataPathRundown))
+ else if (pFilter->otPhyState == kStateDisabled || !ExAcquireRundownProtection(&pFilter->DataPathRundown))
{
LogVerbose(DRIVER_DATA_PATH, "Failing ReceiveNetBufferLists because data path isn't active.");
@@ -415,26 +502,19 @@ Arguments:
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, CancelId: %p", FilterModuleContext, CancelId);
-
- otLwfEventProcessingIndicateNetBufferListsCancelled(pFilter, CancelId);
+
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ otLwfEventProcessingIndicateNetBufferListsCancelled(pFilter, CancelId);
+ }
+ else
+ {
+ NT_ASSERT(FALSE); // TODO
+ }
LogFuncExit(DRIVER_DATA_PATH);
}
-#pragma pack(push)
-#pragma pack(1)
-
-typedef struct UDPHeader
-{
- USHORT SourcePort;
- USHORT DestinationPort;
- USHORT TotalLength;
- USHORT Checksum;
-
-} UDPHeader;
-
-#pragma pack(pop)
-
// Callback received from OpenThread when it has an IPv6 packet ready for
// delivery to TCPIP.
void
diff --git a/examples/drivers/windows/otLwf/device.c b/examples/drivers/windows/otLwf/device.c
index 6bd72870f..57ff80aa5 100644
--- a/examples/drivers/windows/otLwf/device.c
+++ b/examples/drivers/windows/otLwf/device.c
@@ -532,7 +532,7 @@ otLwfIndicateNotification(
{
LogWarning(DRIVER_IOCTL, "Dropping old notification!");
otLwfReleaseNotification(DeviceClient->PendingNotifications[DeviceClient->NotificationOffset]);
- DeviceClient->NotificationOffset++;
+ DeviceClient->NotificationOffset = (DeviceClient->NotificationOffset + 1) % OTLWF_MAX_PENDING_NOTIFICATIONS_PER_CLIENT;
}
else
{
diff --git a/examples/drivers/windows/otLwf/eventprocessing.c b/examples/drivers/windows/otLwf/eventprocessing.c
index 8f6f9339c..8111a5692 100644
--- a/examples/drivers/windows/otLwf/eventprocessing.c
+++ b/examples/drivers/windows/otLwf/eventprocessing.c
@@ -142,6 +142,8 @@ otLwfEventProcessingStop(
_In_ PMS_FILTER pFilter
)
{
+ PLIST_ENTRY Link = NULL;
+
LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", pFilter);
// By this point, we have disabled the Data Path, so no more
@@ -172,57 +174,66 @@ otLwfEventProcessingStop(
}
// Clean up any left over events
- PLIST_ENTRY Link = pFilter->AddressChangesHead.Flink;
- while (Link != &pFilter->AddressChangesHead)
+ if (pFilter->AddressChangesHead.Flink)
{
- POTLWF_ADDR_EVENT Event = CONTAINING_RECORD(Link, OTLWF_ADDR_EVENT, Link);
- Link = Link->Flink;
+ Link = pFilter->AddressChangesHead.Flink;
+ while (Link != &pFilter->AddressChangesHead)
+ {
+ POTLWF_ADDR_EVENT Event = CONTAINING_RECORD(Link, OTLWF_ADDR_EVENT, Link);
+ Link = Link->Flink;
- // Delete the event
- NdisFreeMemory(Event, 0, 0);
+ // Delete the event
+ NdisFreeMemory(Event, 0, 0);
+ }
}
// Clean up any left over events
- Link = pFilter->NBLsHead.Flink;
- while (Link != &pFilter->NBLsHead)
+ if (pFilter->NBLsHead.Flink)
{
- POTLWF_NBL_EVENT Event = CONTAINING_RECORD(Link, OTLWF_NBL_EVENT, Link);
- Link = Link->Flink;
+ Link = pFilter->NBLsHead.Flink;
+ while (Link != &pFilter->NBLsHead)
+ {
+ POTLWF_NBL_EVENT Event = CONTAINING_RECORD(Link, OTLWF_NBL_EVENT, Link);
+ Link = Link->Flink;
- otLwfCompleteNBLs(pFilter, FALSE, Event->Received, Event->NetBufferLists, STATUS_CANCELLED);
+ otLwfCompleteNBLs(pFilter, FALSE, Event->Received, Event->NetBufferLists, STATUS_CANCELLED);
- // Delete the event
- NdisFreeMemory(Event, 0, 0);
+ // Delete the event
+ NdisFreeMemory(Event, 0, 0);
+ }
}
// Reinitialize the list head
InitializeListHead(&pFilter->AddressChangesHead);
InitializeListHead(&pFilter->NBLsHead);
- FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, FALSE);
-
- // Clean up any left over IRPs
- Link = pFilter->EventIrpListHead.Flink;
- while (Link != &pFilter->EventIrpListHead)
+ if (pFilter->EventIrpListHead.Flink)
{
- PIRP Irp = CONTAINING_RECORD(Link, IRP, Tail.Overlay.ListEntry);
- Link = Link->Flink;
-
- // Before we are allowed to complete the pending IRP, we must remove the cancel routine
- KIRQL irql;
- IoAcquireCancelSpinLock(&irql);
- IoSetCancelRoutine(Irp, NULL);
- IoReleaseCancelSpinLock(irql);
+ FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, FALSE);
- Irp->IoStatus.Status = STATUS_CANCELLED;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ // Clean up any left over IRPs
+ Link = pFilter->EventIrpListHead.Flink;
+ while (Link != &pFilter->EventIrpListHead)
+ {
+ PIRP Irp = CONTAINING_RECORD(Link, IRP, Tail.Overlay.ListEntry);
+ Link = Link->Flink;
+
+ // Before we are allowed to complete the pending IRP, we must remove the cancel routine
+ KIRQL irql;
+ IoAcquireCancelSpinLock(&irql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(irql);
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ // Reinitialize the list head
+ InitializeListHead(&pFilter->EventIrpListHead);
+
+ FILTER_RELEASE_LOCK(&pFilter->EventsLock, FALSE);
}
-
- // Reinitialize the list head
- InitializeListHead(&pFilter->EventIrpListHead);
-
- FILTER_RELEASE_LOCK(&pFilter->EventsLock, FALSE);
LogFuncExit(DRIVER_DEFAULT);
}
@@ -307,23 +318,31 @@ otLwfEventProcessingIndicateAddressChange(
_In_ PIN6_ADDR pAddr
)
{
- POTLWF_ADDR_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(OTLWF_ADDR_EVENT));
- if (Event == NULL)
+ if (pFilter->InternalStateInitialized == FALSE)
{
- LogWarning(DRIVER_DATA_PATH, "Failed to alloc new OTLWF_ADDR_EVENT");
return;
}
-
- Event->NotificationType = NotificationType;
- Event->Address = *pAddr;
- // Add the event to the queue
- NdisAcquireSpinLock(&pFilter->EventsLock);
- InsertTailList(&pFilter->AddressChangesHead, &Event->Link);
- NdisReleaseSpinLock(&pFilter->EventsLock);
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ POTLWF_ADDR_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(OTLWF_ADDR_EVENT));
+ if (Event == NULL)
+ {
+ LogWarning(DRIVER_DATA_PATH, "Failed to alloc new OTLWF_ADDR_EVENT");
+ return;
+ }
- // Set the event to indicate we have a new address to process
- KeSetEvent(&pFilter->EventWorkerThreadProcessAddressChanges, 0, FALSE);
+ Event->NotificationType = NotificationType;
+ Event->Address = *pAddr;
+
+ // Add the event to the queue
+ NdisAcquireSpinLock(&pFilter->EventsLock);
+ InsertTailList(&pFilter->AddressChangesHead, &Event->Link);
+ NdisReleaseSpinLock(&pFilter->EventsLock);
+
+ // Set the event to indicate we have a new address to process
+ KeSetEvent(&pFilter->EventWorkerThreadProcessAddressChanges, 0, FALSE);
+ }
}
// Called to indicate that we have a NetBufferLists to process
@@ -689,7 +708,7 @@ otLwfEventWorkerThread(
return;
}
-#if DBG
+#if DEBUG_ALLOC
// Initialize the list head for allocations
InitializeListHead(&pFilter->otOutStandingAllocations);
@@ -1017,7 +1036,7 @@ exit:
otInstanceFinalize(pFilter->otCtx);
pFilter->otCtx = NULL;
-#if DBG
+#if DEBUG_ALLOC
{
NT_ASSERT(pFilter->otOutstandingAllocationCount == 0);
NT_ASSERT(pFilter->otOutstandingMemoryAllocated == 0);
diff --git a/examples/drivers/windows/otLwf/filter.c b/examples/drivers/windows/otLwf/filter.c
index 4fb65702f..61f3ed36c 100644
--- a/examples/drivers/windows/otLwf/filter.c
+++ b/examples/drivers/windows/otLwf/filter.c
@@ -93,7 +93,6 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
NTSTATUS NtStatus;
NDIS_FILTER_ATTRIBUTES FilterAttributes;
ULONG Size;
- PNET_BUFFER SendNetBuffer;
ULONG bytesProcessed = 0;
COMPARTMENT_ID OriginalCompartmentID;
@@ -119,8 +118,7 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
break;
}
- Size = sizeof(MS_FILTER) +
- AttachParameters->BaseMiniportInstanceName->Length;
+ Size = sizeof(MS_FILTER) + AttachParameters->BaseMiniportInstanceName->Length;
pFilter = (PMS_FILTER)FILTER_ALLOC_MEM(NdisFilterHandle, Size);
if (pFilter == NULL)
@@ -135,8 +133,7 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
// Format of "\DEVICE\{5BA90C49-0D7E-455B-8D3B-614F6714A212}"
AttachParameters->BaseMiniportName->Buffer += 8;
AttachParameters->BaseMiniportName->Length -= 8 * sizeof(WCHAR);
- NtStatus = RtlGUIDFromString(AttachParameters->BaseMiniportName,
- &pFilter->InterfaceGuid);
+ NtStatus = RtlGUIDFromString(AttachParameters->BaseMiniportName, &pFilter->InterfaceGuid);
AttachParameters->BaseMiniportName->Buffer -= 8;
AttachParameters->BaseMiniportName->Length += 8 * sizeof(WCHAR);
if (!NT_SUCCESS(NtStatus))
@@ -164,15 +161,27 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
FilterAttributes.Flags = 0;
NDIS_DECLARE_FILTER_MODULE_CONTEXT(MS_FILTER);
- Status = NdisFSetAttributes(NdisFilterHandle,
- pFilter,
- &FilterAttributes);
+ Status = NdisFSetAttributes(NdisFilterHandle, pFilter, &FilterAttributes);
if (Status != NDIS_STATUS_SUCCESS)
{
- LogWarning(DRIVER_DEFAULT, "Failed to set attributes, %!NDIS_STATUS!", Status);
+ LogError(DRIVER_DEFAULT, "Failed to set attributes, %!NDIS_STATUS!", Status);
break;
}
+ // Filter initially in Paused state
+ pFilter->State = FilterPaused;
+ NdisInitializeEvent(&pFilter->FilterPauseComplete);
+
+ // Initialize initial ref count on IoControl to 1, which we release on shutdown
+ RtlInitializeReferenceCount(&pFilter->IoControlReferences);
+ NdisInitializeEvent(&pFilter->IoControlShutdownComplete);
+
+ // Initialize PendingOidRequest lock
+ NdisAllocateSpinLock(&pFilter->PendingOidRequestLock);
+
+ // Initialize datapath to disabled with no active references
+ pFilter->DataPathRundown.Count = EX_RUNDOWN_ACTIVE;
+
// Create the NDIS pool for creating the SendNetBufferList
NET_BUFFER_LIST_POOL_PARAMETERS PoolParams =
{
@@ -191,111 +200,30 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
break;
}
- // Create the SendNetBufferList
- pFilter->SendNetBufferList =
- NdisAllocateNetBufferAndNetBufferList(
- pFilter->NetBufferListPool, // PoolHandle
- 0, // ContextSize
- 0, // ContextBackFill
- NULL, // MdlChain
- 0, // DataOffset
- 0 // DataLength
+ // Query the compartment ID for this interface to use for the IP stack
+ pFilter->InterfaceCompartmentID = GetInterfaceCompartmentID(&pFilter->InterfaceLuid);
+ LogVerbose(DRIVER_DEFAULT, "Interface %!GUID! is in Compartment %u", &pFilter->InterfaceGuid, (ULONG)pFilter->InterfaceCompartmentID);
+
+ // Make sure we are in the right compartment
+ (VOID)otLwfSetCompartment(pFilter, &OriginalCompartmentID);
+
+ // Register for address changed notifications
+ NtStatus =
+ NotifyUnicastIpAddressChange(
+ AF_INET6,
+ otLwfAddressChangeCallback,
+ pFilter,
+ FALSE,
+ &pFilter->AddressChangeHandle
);
- if (pFilter->SendNetBufferList == NULL)
+
+ // Revert the compartment, now that we have the table
+ otLwfRevertCompartment(OriginalCompartmentID);
+
+ if (!NT_SUCCESS(NtStatus))
{
- NdisFreeNetBufferListPool(pFilter->NetBufferListPool);
- Status = NDIS_STATUS_RESOURCES;
- LogWarning(DRIVER_DEFAULT, "Failed to create Send NetBufferList");
- break;
- }
-
- // Initialize NetBuffer fields
- SendNetBuffer = NET_BUFFER_LIST_FIRST_NB(pFilter->SendNetBufferList);
- NET_BUFFER_CURRENT_MDL(SendNetBuffer) = NULL;
- NET_BUFFER_CURRENT_MDL_OFFSET(SendNetBuffer) = 0;
- NET_BUFFER_DATA_LENGTH(SendNetBuffer) = 0;
- NET_BUFFER_DATA_OFFSET(SendNetBuffer) = 0;
- NET_BUFFER_FIRST_MDL(SendNetBuffer) = NULL;
-
- // Allocate the NetBuffer for SendNetBufferList
- Status = NdisRetreatNetBufferDataStart(SendNetBuffer, kMaxPHYPacketSize, 0, NULL);
- if (Status != NDIS_STATUS_SUCCESS)
- {
- NdisFreeNetBufferList(pFilter->SendNetBufferList);
- NdisFreeNetBufferListPool(pFilter->NetBufferListPool);
- LogError(DRIVER_DEFAULT, "Failed to allocate NB for Send NetBufferList, %!NDIS_STATUS!", Status);
- break;
- }
-
- // Filter initially in Paused state
- pFilter->State = FilterPaused;
- NdisInitializeEvent(&pFilter->FilterPauseComplete);
-
- // Initialize initial ref count on IoControl to 1, which we release on shutdown
- RtlInitializeReferenceCount(&pFilter->IoControlReferences);
- NdisInitializeEvent(&pFilter->IoControlShutdownComplete);
-
- // Initialize PendingOidRequest lock
- NdisAllocateSpinLock(&pFilter->PendingOidRequestLock);
-
- // Initialize datapath to disabled with no active references
- pFilter->DataPathRundown.Count = EX_RUNDOWN_ACTIVE;
- KeInitializeEvent(
- &pFilter->SendNetBufferListComplete,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
-
- // Initialize the event processing
- pFilter->EventWorkerThread = NULL;
- NdisAllocateSpinLock(&pFilter->EventsLock);
- InitializeListHead(&pFilter->AddressChangesHead);
- InitializeListHead(&pFilter->NBLsHead);
- InitializeListHead(&pFilter->EventIrpListHead);
- KeInitializeEvent(
- &pFilter->EventWorkerThreadStopEvent,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- KeInitializeEvent(
- &pFilter->EventWorkerThreadWaitTimeUpdated,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- KeInitializeEvent(
- &pFilter->EventWorkerThreadProcessTasklets,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- KeInitializeEvent(
- &pFilter->EventWorkerThreadProcessAddressChanges,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- KeInitializeEvent(
- &pFilter->EventWorkerThreadProcessNBLs,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- KeInitializeEvent(
- &pFilter->EventWorkerThreadProcessIrp,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- KeInitializeEvent(
- &pFilter->EventWorkerThreadEnergyScanComplete,
- SynchronizationEvent, // auto-clearing event
- FALSE // event initially non-signalled
- );
- pFilter->EventHighPrecisionTimer =
- ExAllocateTimer(
- otLwfEventProcessingTimer,
- pFilter,
- EX_TIMER_HIGH_RESOLUTION
- );
- if (pFilter->EventHighPrecisionTimer == NULL)
- {
- LogError(DRIVER_DEFAULT, "Failed to allocate timer!");
+ LogError(DRIVER_DEFAULT, "NotifyUnicastIpAddressChange failed, %!STATUS!", NtStatus);
+ Status = NDIS_STATUS_FAILURE;
break;
}
@@ -330,37 +258,11 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
}
// Make sure we are in RADIO mode
- if (pFilter->MiniportCapabilities.MiniportMode != OT_MP_MODE_RADIO)
+ if (pFilter->MiniportCapabilities.MiniportMode != OT_MP_MODE_RADIO &&
+ pFilter->MiniportCapabilities.MiniportMode != OT_MP_MODE_THREAD)
{
Status = NDIS_STATUS_NOT_SUPPORTED;
- LogError(DRIVER_DEFAULT, "Miniport indicated it isn't running in RADIO mode!");
- break;
- }
-
- // Query the compartment ID for this interface to use for the IP stack
- pFilter->InterfaceCompartmentID = GetInterfaceCompartmentID(&pFilter->InterfaceLuid);
- LogVerbose(DRIVER_DEFAULT, "Interface %!GUID! is in Compartment %u", &pFilter->InterfaceGuid, (ULONG)pFilter->InterfaceCompartmentID);
-
- // Make sure we are in the right compartment
- (VOID)otLwfSetCompartment(pFilter, &OriginalCompartmentID);
-
- // Register for address changed notifications
- NtStatus =
- NotifyUnicastIpAddressChange(
- AF_INET6,
- otLwfAddressChangeCallback,
- pFilter,
- FALSE,
- &pFilter->AddressChangeHandle
- );
-
- // Revert the compartment, now that we have the table
- otLwfRevertCompartment(OriginalCompartmentID);
-
- if (!NT_SUCCESS(NtStatus))
- {
- LogError(DRIVER_DEFAULT, "NotifyUnicastIpAddressChange failed, %!STATUS!", NtStatus);
- Status = NDIS_STATUS_FAILURE;
+ LogError(DRIVER_DEFAULT, "Miniport indicated it isn't running in RADIO or THREAD mode!");
break;
}
@@ -369,16 +271,6 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
InsertTailList(&FilterModuleList, &pFilter->FilterModuleLink);
NdisReleaseSpinLock(&FilterListLock);
- // Initialize the event processing thread
- if (!NT_SUCCESS(otLwfEventProcessingStart(pFilter)))
- {
- NdisAcquireSpinLock(&FilterListLock);
- RemoveEntryList(&pFilter->FilterModuleLink);
- NdisReleaseSpinLock(&FilterListLock);
- Status = NDIS_STATUS_RESOURCES;
- break;
- }
-
LogVerbose(DRIVER_DEFAULT, "Created Filter: %p", pFilter);
} while (FALSE);
@@ -392,11 +284,13 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper
CancelMibChangeNotify2(pFilter->AddressChangeHandle);
pFilter->AddressChangeHandle = NULL;
}
-
- // Stop event processing thread
- otLwfEventProcessingStop(pFilter);
- if (pFilter->EventHighPrecisionTimer) ExDeleteTimer(pFilter->EventHighPrecisionTimer, TRUE, FALSE, NULL);
+ // Free NBL Pool
+ if (pFilter->NetBufferListPool)
+ {
+ NdisFreeNetBufferPool(pFilter->NetBufferListPool);
+ }
+
NdisFreeMemory(pFilter, 0, 0);
}
}
@@ -456,21 +350,29 @@ NOTE: Called at PASSIVE_LEVEL and the filter is in paused state
CancelMibChangeNotify2(pFilter->AddressChangeHandle);
pFilter->AddressChangeHandle = NULL;
- // Stop event processing thread
- otLwfEventProcessingStop(pFilter);
+ if (pFilter->InternalStateInitialized)
+ {
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ otLwfUninitializeThreadMode(pFilter);
+ }
+ else if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD)
+ {
+ otLwfUninitializeTunnelMode(pFilter);
+ }
+ else
+ {
+ NT_ASSERT(FALSE);
+ }
+ }
// Remove this Filter from the global list
NdisAcquireSpinLock(&FilterListLock);
RemoveEntryList(&pFilter->FilterModuleLink);
NdisReleaseSpinLock(&FilterListLock);
- // Free NBL & Pools
- NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pFilter->SendNetBufferList), kMaxPHYPacketSize, TRUE, NULL);
- NdisFreeNetBufferList(pFilter->SendNetBufferList);
+ // Free NBL Pool
NdisFreeNetBufferPool(pFilter->NetBufferListPool);
-
- // Free timer
- ExDeleteTimer(pFilter->EventHighPrecisionTimer, TRUE, FALSE, NULL);
// Free the memory allocated
NdisFreeMemory(pFilter, 0, 0);
@@ -557,6 +459,37 @@ Return Value:
//
NdisGeneralAttributes->LookaheadSize = 128;
}
+
+
+ // Initialize the processing logic
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ NtStatus = otLwfInitializeThreadMode(pFilter);
+ if (!NT_SUCCESS(NtStatus))
+ {
+ LogError(DRIVER_DEFAULT, "otLwfInitializeThreadMode failed, %!STATUS!", NtStatus);
+ NdisStatus = NDIS_STATUS_FAILURE;
+ goto exit;
+ }
+ pFilter->InternalStateInitialized = TRUE;
+ }
+ else if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD)
+ {
+ NtStatus = otLwfInitializeTunnelMode(pFilter);
+ if (!NT_SUCCESS(NtStatus))
+ {
+ LogError(DRIVER_DEFAULT, "otLwfInitializeTunnelMode failed, %!STATUS!", NtStatus);
+ NdisStatus = NDIS_STATUS_FAILURE;
+ goto exit;
+ }
+ pFilter->InternalStateInitialized = TRUE;
+ }
+ else
+ {
+ NT_ASSERT(FALSE);
+ NdisStatus = NDIS_STATUS_FAILURE;
+ goto exit;
+ }
key.Luid = pFilter->InterfaceLuid;
NlInitializeInterfaceRw(&interfaceRw);
@@ -600,6 +533,19 @@ exit:
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
pFilter->State = FilterPaused;
+
+ if (pFilter->InternalStateInitialized)
+ {
+ pFilter->InternalStateInitialized = FALSE;
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ otLwfUninitializeThreadMode(pFilter);
+ }
+ else
+ {
+ otLwfUninitializeTunnelMode(pFilter);
+ }
+ }
}
LogFuncExitNDIS(DRIVER_DEFAULT, NdisStatus);
@@ -654,13 +600,6 @@ N.B.: When the filter is in Pausing state, it can still process OID requests,
//
NT_ASSERT(pFilter->State == FilterRunning);
pFilter->State = FilterPausing;
-
- //
- // Make sure we are disconnected from the network
- //
- // TODO ...
- //otBecomeDetached(pFilter->otCtx); // TODO - This should block or we wait for it to complete
- //otDisable(pFilter->otCtx);
otLwfNotifyDeviceAvailabilityChange(pFilter, FALSE);
LogInfo(DRIVER_DEFAULT, "Interface %!GUID! removal.", &pFilter->InterfaceGuid);
@@ -724,6 +663,7 @@ NOTE: called at <= DISPATCH_LEVEL
LogInfo(DRIVER_DEFAULT, "Filter: %p, completed energy scan: Rssi:%d, Status:%!NDIS_STATUS!", FilterModuleContext, ScanResult->MaxRssi, ScanResult->Status);
// Marshal to OpenThread worker to indicate back
+ NT_ASSERT(pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO);
otLwfEventProcessingIndicateEnergyScanResult(pFilter, ScanResult->MaxRssi);
}
@@ -872,6 +812,13 @@ otLwfSetCompartment(
_In_ PMS_FILTER pFilter,
_Out_ COMPARTMENT_ID* pOriginalCompartment
)
+/*++
+
+Routine Description:
+
+ Sets the current thread's compartment ID to match the filter instance.
+
+--*/
{
NTSTATUS status = STATUS_SUCCESS;
@@ -899,6 +846,13 @@ VOID
otLwfRevertCompartment(
_In_ COMPARTMENT_ID OriginalCompartment
)
+/*++
+
+Routine Description:
+
+ Resets the current thread's compartment ID.
+
+--*/
{
// Revert the compartment if it is set
if (OriginalCompartment != 0)
@@ -906,337 +860,3 @@ otLwfRevertCompartment(
(VOID)NdisSetCurrentThreadCompartmentId(OriginalCompartment);
}
}
-
-#if DBG
-PMS_FILTER
-otLwfFindFromCurrentThread()
-{
- PMS_FILTER pOutput = NULL;
- HANDLE CurThreadId = PsGetCurrentThreadId();
-
- NdisAcquireSpinLock(&FilterListLock);
-
- for (PLIST_ENTRY Link = FilterModuleList.Flink; Link != &FilterModuleList; Link = Link->Flink)
- {
- PMS_FILTER pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
-
- if (pFilter->otThreadId == CurThreadId)
- {
- pOutput = pFilter;
- break;
- }
- }
-
- NdisReleaseSpinLock(&FilterListLock);
-
- NT_ASSERT(pOutput);
- return pOutput;
-}
-#endif
-
-void *otPlatCAlloc(size_t aNum, size_t aSize)
-{
- size_t totalSize = aNum * aSize;
-#if DBG
- totalSize += sizeof(OT_ALLOC);
-#endif
- PVOID mem = ExAllocatePoolWithTag(NonPagedPoolNx, totalSize, 'OTDM');
- if (mem)
- {
- RtlZeroMemory(mem, totalSize);
-#if DBG
- PMS_FILTER pFilter = otLwfFindFromCurrentThread();
- //LogVerbose(DRIVER_DEFAULT, "otPlatAlloc(%u) = ID:%u %p", (ULONG)totalSize, pFilter->otAllocationID, mem);
-
- OT_ALLOC* AllocHeader = (OT_ALLOC*)mem;
- AllocHeader->Length = (LONG)totalSize;
- AllocHeader->ID = pFilter->otAllocationID++;
- InsertTailList(&pFilter->otOutStandingAllocations, &AllocHeader->Link);
-
- InterlockedIncrement(&pFilter->otOutstandingAllocationCount);
- InterlockedAdd(&pFilter->otOutstandingMemoryAllocated, AllocHeader->Length);
-
- mem = (PUCHAR)(mem) + sizeof(OT_ALLOC);
-#endif
- }
- return mem;
-}
-
-void otPlatFree(void *aPtr)
-{
- if (aPtr == NULL) return;
-#if DBG
- aPtr = (PUCHAR)(aPtr) - sizeof(OT_ALLOC);
- //LogVerbose(DRIVER_DEFAULT, "otPlatFree(%p)", aPtr);
- OT_ALLOC* AllocHeader = (OT_ALLOC*)aPtr;
-
- PMS_FILTER pFilter = otLwfFindFromCurrentThread();
- InterlockedDecrement(&pFilter->otOutstandingAllocationCount);
- InterlockedAdd(&pFilter->otOutstandingMemoryAllocated, -AllocHeader->Length);
- RemoveEntryList(&AllocHeader->Link);
-#endif
- ExFreePoolWithTag(aPtr, 'OTDM');
-}
-
-uint32_t otPlatRandomGet()
-{
- LARGE_INTEGER Counter = KeQueryPerformanceCounter(NULL);
- return (uint32_t)RtlRandomEx(&Counter.LowPart);
-}
-
-ThreadError otPlatRandomSecureGet(uint16_t aInputLength, uint8_t *aOutput, uint16_t *aOutputLength)
-{
- // Just use the system-preferred random number generator algorithm
- NTSTATUS status =
- BCryptGenRandom(
- NULL,
- aOutput,
- (ULONG)aInputLength,
- BCRYPT_USE_SYSTEM_PREFERRED_RNG
- );
- NT_ASSERT(NT_SUCCESS(status));
- if (!NT_SUCCESS(status))
- {
- LogError(DRIVER_DEFAULT, "BCryptGenRandom failed, %!STATUS!", status);
- return kThreadError_Failed;
- }
-
- *aOutputLength = aInputLength;
-
- return kThreadError_None;
-}
-
-void otSignalTaskletPending(_In_ otInstance *otCtx)
-{
- LogVerbose(DRIVER_DEFAULT, "otSignalTaskletPending");
- PMS_FILTER pFilter = otCtxToFilter(otCtx);
- otLwfEventProcessingIndicateNewTasklet(pFilter);
-}
-
-// Process a role state change
-_IRQL_requires_max_(DISPATCH_LEVEL)
-VOID
-otLwfProcessRoleStateChange(
- _In_ PMS_FILTER pFilter
- )
-{
- otDeviceRole prevRole = pFilter->otCachedRole;
- pFilter->otCachedRole = otGetDeviceRole(pFilter->otCtx);
- if (prevRole == pFilter->otCachedRole) return;
-
- LogInfo(DRIVER_DEFAULT, "Interface %!GUID! new role: %!otDeviceRole!", &pFilter->InterfaceGuid, pFilter->otCachedRole);
-
- // Make sure we are in the correct media connect state
- otLwfIndicateLinkState(
- pFilter,
- IsAttached(pFilter->otCachedRole) ?
- MediaConnectStateConnected :
- MediaConnectStateDisconnected);
-}
-
-void otLwfStateChangedCallback(uint32_t aFlags, _In_ void *aContext)
-{
- LogFuncEntry(DRIVER_DEFAULT);
-
- PMS_FILTER pFilter = (PMS_FILTER)aContext;
- PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
-
- //
- // Process the notification internally
- //
-
- if ((aFlags & OT_IP6_ADDRESS_ADDED) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_IP6_ADDRESS_ADDED", pFilter);
- otLwfAddressesUpdated(pFilter);
- }
-
- if ((aFlags & OT_IP6_ADDRESS_REMOVED) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_IP6_ADDRESS_REMOVED", pFilter);
- otLwfAddressesUpdated(pFilter);
- }
-
- if ((aFlags & OT_NET_ROLE) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_NET_ROLE", pFilter);
- otLwfProcessRoleStateChange(pFilter);
- }
-
- if ((aFlags & OT_NET_PARTITION_ID) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_NET_PARTITION_ID", pFilter);
- }
-
- if ((aFlags & OT_NET_KEY_SEQUENCE_COUNTER) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_NET_KEY_SEQUENCE_COUNTER", pFilter);
- }
-
- if ((aFlags & OT_THREAD_CHILD_ADDED) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_CHILD_ADDED", pFilter);
- }
-
- if ((aFlags & OT_THREAD_CHILD_REMOVED) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_CHILD_REMOVED", pFilter);
- }
-
- if ((aFlags & OT_THREAD_NETDATA_UPDATED) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_NETDATA_UPDATED", pFilter);
- otSlaacUpdate(pFilter->otCtx, pFilter->otAutoAddresses, ARRAYSIZE(pFilter->otAutoAddresses), otCreateRandomIid, NULL);
- }
-
- if ((aFlags & OT_IP6_ML_ADDR_CHANGED) != 0)
- {
- LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_IP6_ML_ADDR_CHANGED", pFilter);
- }
-
- //
- // Queue the notification for clients
- //
-
- if (NotifEntry)
- {
- RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
- NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
- NotifEntry->Notif.NotifType = OTLWF_NOTIF_STATE_CHANGE;
- NotifEntry->Notif.StateChangePayload.Flags = aFlags;
-
- otLwfIndicateNotification(NotifEntry);
- }
-
- LogFuncExit(DRIVER_DEFAULT);
-}
-
-void otLwfActiveScanCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext)
-{
- LogFuncEntry(DRIVER_DEFAULT);
-
- PMS_FILTER pFilter = (PMS_FILTER)aContext;
- PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
- if (NotifEntry)
- {
- RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
- NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
- NotifEntry->Notif.NotifType = OTLWF_NOTIF_ACTIVE_SCAN;
-
- if (aResult)
- {
- NotifEntry->Notif.ActiveScanPayload.Valid = TRUE;
- NotifEntry->Notif.ActiveScanPayload.Results = *aResult;
- }
- else
- {
- NotifEntry->Notif.ActiveScanPayload.Valid = FALSE;
- }
-
- otLwfIndicateNotification(NotifEntry);
- }
-
- LogFuncExit(DRIVER_DEFAULT);
-}
-
-void otLwfEnergyScanCallback(_In_ otEnergyScanResult *aResult, _In_ void *aContext)
-{
- LogFuncEntry(DRIVER_DEFAULT);
-
- PMS_FILTER pFilter = (PMS_FILTER)aContext;
- PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
- if (NotifEntry)
- {
- RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
- NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
- NotifEntry->Notif.NotifType = OTLWF_NOTIF_ENERGY_SCAN;
-
- if (aResult)
- {
- NotifEntry->Notif.EnergyScanPayload.Valid = TRUE;
- NotifEntry->Notif.EnergyScanPayload.Results = *aResult;
- }
- else
- {
- NotifEntry->Notif.EnergyScanPayload.Valid = FALSE;
- }
-
- otLwfIndicateNotification(NotifEntry);
- }
-
- LogFuncExit(DRIVER_DEFAULT);
-}
-
-void otLwfDiscoverCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext)
-{
- LogFuncEntry(DRIVER_DEFAULT);
-
- PMS_FILTER pFilter = (PMS_FILTER)aContext;
- PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
- if (NotifEntry)
- {
- RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
- NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
- NotifEntry->Notif.NotifType = OTLWF_NOTIF_DISCOVER;
-
- if (aResult)
- {
- NotifEntry->Notif.DiscoverPayload.Valid = TRUE;
- NotifEntry->Notif.DiscoverPayload.Results = *aResult;
- }
- else
- {
- NotifEntry->Notif.DiscoverPayload.Valid = FALSE;
- }
-
- otLwfIndicateNotification(NotifEntry);
- }
-
- LogFuncExit(DRIVER_DEFAULT);
-}
-
-void otLwfCommissionerEnergyReportCallback(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength, void *aContext)
-{
- LogFuncEntry(DRIVER_DEFAULT);
-
- PMS_FILTER pFilter = (PMS_FILTER)aContext;
- PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
- if (NotifEntry)
- {
- RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
- NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
- NotifEntry->Notif.NotifType = OTLWF_NOTIF_COMMISSIONER_ENERGY_REPORT;
-
- // Limit the number of reports if necessary
- if (aEnergyListLength > MAX_ENERGY_REPORT_LENGTH) aEnergyListLength = MAX_ENERGY_REPORT_LENGTH;
-
- NotifEntry->Notif.CommissionerEnergyReportPayload.ChannelMask = aChannelMask;
- NotifEntry->Notif.CommissionerEnergyReportPayload.EnergyListLength = aEnergyListLength;
- memcpy(NotifEntry->Notif.CommissionerEnergyReportPayload.EnergyList, aEnergyList, aEnergyListLength);
-
- otLwfIndicateNotification(NotifEntry);
- }
-
- LogFuncExit(DRIVER_DEFAULT);
-}
-
-void otLwfCommissionerPanIdConflictCallback(uint16_t aPanId, uint32_t aChannelMask, _In_ void *aContext)
-{
- LogFuncEntry(DRIVER_DEFAULT);
-
- PMS_FILTER pFilter = (PMS_FILTER)aContext;
- PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
- if (NotifEntry)
- {
- RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
- NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
- NotifEntry->Notif.NotifType = OTLWF_NOTIF_COMMISSIONER_PANID_QUERY;
-
- NotifEntry->Notif.CommissionerPanIdQueryPayload.PanId = aPanId;
- NotifEntry->Notif.CommissionerPanIdQueryPayload.ChannelMask = aChannelMask;
-
- otLwfIndicateNotification(NotifEntry);
- }
-
- LogFuncExit(DRIVER_DEFAULT);
-}
diff --git a/examples/drivers/windows/otLwf/filter.h b/examples/drivers/windows/otLwf/filter.h
index 7f42eeb77..5c42ababa 100644
--- a/examples/drivers/windows/otLwf/filter.h
+++ b/examples/drivers/windows/otLwf/filter.h
@@ -124,102 +124,113 @@ typedef struct _MS_FILTER
NDIS_EVENT IoControlShutdownComplete;
//
- // Event processing
- //
- PVOID EventWorkerThread;
- KEVENT EventWorkerThreadStopEvent;
- KEVENT EventWorkerThreadProcessAddressChanges;
- KEVENT EventWorkerThreadProcessNBLs;
- NDIS_SPIN_LOCK EventsLock;
- LIST_ENTRY AddressChangesHead;
- LIST_ENTRY NBLsHead;
- ULONG CountPendingRecvNBLs;
- LARGE_INTEGER NextAlarmTickCount;
- KEVENT EventWorkerThreadWaitTimeUpdated;
- KEVENT EventWorkerThreadProcessTasklets;
- PEX_TIMER EventHighPrecisionTimer;
- UCHAR EventTimerState;
- LIST_ENTRY EventIrpListHead;
- KEVENT EventWorkerThreadProcessIrp;
- KEVENT EventWorkerThreadEnergyScanComplete;
-
- //
- // Data Path Synchronization
+ // Data Path
//
EX_RUNDOWN_REF DataPathRundown;
NDIS_HANDLE NetBufferListPool;
- BOOLEAN SendPending;
- PNET_BUFFER_LIST SendNetBufferList;
- KEVENT SendNetBufferListComplete;
- //
- // OpenThread state management
- //
- otDeviceRole otCachedRole;
+ BOOLEAN InternalStateInitialized;
//
// OpenThread addresses
//
- IN6_ADDR otCachedAddr[OT_MAX_ADDRESSES];
- ULONG otCachedAddrCount;
- IN6_ADDR otLinkLocalAddr;
- otNetifAddress otAutoAddresses[OT_MAX_AUTO_ADDRESSES];
+ IN6_ADDR otCachedAddr[OT_MAX_ADDRESSES];
+ ULONG otCachedAddrCount;
+ IN6_ADDR otLinkLocalAddr;
+ otNetifAddress otAutoAddresses[OT_MAX_AUTO_ADDRESSES];
+
+ union
+ {
+ struct // Thread Mode Variables
+ {
+ //
+ // OpenThread Event processing
+ //
+ PVOID EventWorkerThread;
+ KEVENT EventWorkerThreadStopEvent;
+ KEVENT EventWorkerThreadProcessAddressChanges;
+ KEVENT EventWorkerThreadProcessNBLs;
+ NDIS_SPIN_LOCK EventsLock;
+ LIST_ENTRY AddressChangesHead;
+ LIST_ENTRY NBLsHead;
+ ULONG CountPendingRecvNBLs;
+ LARGE_INTEGER NextAlarmTickCount;
+ KEVENT EventWorkerThreadWaitTimeUpdated;
+ KEVENT EventWorkerThreadProcessTasklets;
+ PEX_TIMER EventHighPrecisionTimer;
+ UCHAR EventTimerState;
+ LIST_ENTRY EventIrpListHead;
+ KEVENT EventWorkerThreadProcessIrp;
+ KEVENT EventWorkerThreadEnergyScanComplete;
+
+ //
+ // OpenThread state management
+ //
+ otDeviceRole otCachedRole;
+
+ //
+ // OpenThread data path state
+ //
+ BOOLEAN SendPending;
+ PNET_BUFFER_LIST SendNetBufferList;
+ KEVENT SendNetBufferListComplete;
- //
- // OpenThread radio variables
- //
- otRadioCaps otRadioCapabilities;
- PhyState otPhyState;
- uint8_t otCurrentListenChannel;
- uint8_t otReceiveMessage[kMaxPHYPacketSize];
- uint8_t otTransmitMessage[kMaxPHYPacketSize];
- RadioPacket otReceiveFrame;
- RadioPacket otTransmitFrame;
- CHAR otLastEnergyScanMaxRssi;
+ //
+ // OpenThread radio variables
+ //
+ otRadioCaps otRadioCapabilities;
+ PhyState otPhyState;
+ uint8_t otCurrentListenChannel;
+ uint8_t otReceiveMessage[kMaxPHYPacketSize];
+ uint8_t otTransmitMessage[kMaxPHYPacketSize];
+ RadioPacket otReceiveFrame;
+ RadioPacket otTransmitFrame;
+ CHAR otLastEnergyScanMaxRssi;
- BOOLEAN otPromiscuous;
- uint16_t otPanID;
- uint64_t otFactoryAddress;
- uint64_t otExtendedAddress;
- uint16_t otShortAddress;
+ BOOLEAN otPromiscuous;
+ uint16_t otPanID;
+ uint64_t otFactoryAddress;
+ uint64_t otExtendedAddress;
+ uint16_t otShortAddress;
- BOOLEAN otPendingMacOffloadEnabled;
- uint8_t otPendingShortAddressCount;
- uint16_t otPendingShortAddresses[MAX_PENDING_MAC_SIZE];
- uint8_t otPendingExtendedAddressCount;
- uint64_t otPendingExtendedAddresses[MAX_PENDING_MAC_SIZE];
+ BOOLEAN otPendingMacOffloadEnabled;
+ uint8_t otPendingShortAddressCount;
+ uint16_t otPendingShortAddresses[MAX_PENDING_MAC_SIZE];
+ uint8_t otPendingExtendedAddressCount;
+ uint64_t otPendingExtendedAddresses[MAX_PENDING_MAC_SIZE];
-#if DBG
- // Used for tracking memory allocations
- HANDLE otThreadId;
- volatile LONG otOutstandingAllocationCount;
- volatile LONG otOutstandingMemoryAllocated;
- LIST_ENTRY otOutStandingAllocations;
- ULONG otAllocationID;
+#if DEBUG_ALLOC
+ // Used for tracking memory allocations
+ HANDLE otThreadId;
+ volatile LONG otOutstandingAllocationCount;
+ volatile LONG otOutstandingMemoryAllocated;
+ LIST_ENTRY otOutStandingAllocations;
+ ULONG otAllocationID;
#endif
- //
- // OpenThread context buffer
- //
- otInstance* otCtx;
- PUCHAR otInstanceBuffer;
+ //
+ // OpenThread context buffer
+ //
+ otInstance* otCtx;
+ PUCHAR otInstanceBuffer;
+ };
+ struct // Tunnel Mode Variables
+ {
+ NDIS_SPIN_LOCK tunCommandLock;
+ LIST_ENTRY tunCommandHandlers;
+ USHORT tunTIDsInUse;
+ spinel_tid_t tunNextTID;
+
+ PVOID TunWorkerThread;
+ KEVENT TunWorkerThreadStopEvent;
+ KEVENT TunWorkerThreadAddressChangedEvent;
+ };
+ };
} MS_FILTER, * PMS_FILTER;
-// Helper function that converts an otInstance pointer to a MS_FILTER pointer
-__inline PMS_FILTER otCtxToFilter(_In_ otInstance* otCtx)
-{
- return *(PMS_FILTER*)((PUCHAR)otCtx - sizeof(PMS_FILTER));
-}
-
-// Helper function to indicate if a role means it is attached or not
-_inline BOOLEAN IsAttached(_In_ otDeviceRole role)
-{
- return role > kDeviceRoleDetached;
-}
-
//
-// function prototypes
+// NDIS Filter Functions
//
FILTER_ATTACH FilterAttach;
@@ -235,6 +246,10 @@ FILTER_SEND_NET_BUFFER_LISTS_COMPLETE FilterSendNetBufferListsComplete;
FILTER_RECEIVE_NET_BUFFER_LISTS FilterReceiveNetBufferLists;
FILTER_CANCEL_SEND_NET_BUFFER_LISTS FilterCancelSendNetBufferLists;
+//
+// Link State Functions
+//
+
_IRQL_requires_max_(DISPATCH_LEVEL)
VOID
otLwfIndicateLinkState(
@@ -259,76 +274,6 @@ otLwfRevertCompartment(
_In_ COMPARTMENT_ID OriginalCompartment
);
-//
-// Event Processing Functions
-//
-
-EXT_CALLBACK otLwfEventProcessingTimer;
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-NTSTATUS
-otLwfEventProcessingStart(
- _In_ PMS_FILTER pFilter
- );
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-VOID
-otLwfEventProcessingStop(
- _In_ PMS_FILTER pFilter
- );
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-VOID
-otLwfEventProcessingIndicateNewWaitTime(
- _In_ PMS_FILTER pFilter,
- _In_ ULONG waitTime
- );
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-VOID
-otLwfEventProcessingIndicateNewTasklet(
- _In_ PMS_FILTER pFilter
- );
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-VOID
-otLwfEventProcessingIndicateAddressChange(
- _In_ PMS_FILTER pFilter,
- _In_ MIB_NOTIFICATION_TYPE NotificationType,
- _In_ PIN6_ADDR pAddr
- );
-
-_IRQL_requires_max_(DISPATCH_LEVEL)
-VOID
-otLwfEventProcessingIndicateNewNetBufferLists(
- _In_ PMS_FILTER pFilter,
- _In_ BOOLEAN DispatchLevel,
- _In_ BOOLEAN Received,
- _In_ NDIS_PORT_NUMBER PortNumber,
- _In_ PNET_BUFFER_LIST NetBufferLists
- );
-
-_IRQL_requires_max_(DISPATCH_LEVEL)
-VOID
-otLwfEventProcessingIndicateNetBufferListsCancelled(
- _In_ PMS_FILTER pFilter,
- _In_ PVOID CancelId
- );
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-VOID
-otLwfEventProcessingIndicateIrp(
- _In_ PMS_FILTER pFilter,
- _In_ PIRP Irp
- );
-
-_IRQL_requires_max_(DISPATCH_LEVEL)
-VOID
-otLwfEventProcessingIndicateEnergyScanResult(
- _In_ PMS_FILTER pFilter,
- _In_ CHAR MaxRssi
- );
-
//
// Data Path functions
//
@@ -345,18 +290,6 @@ otLwfDisableDataPath(
_In_ PMS_FILTER pFilter
);
-//
-// OpenThread callbacks
-//
-
-void otLwfStateChangedCallback(uint32_t aFlags, _In_ void *aContext);
-void otLwfReceiveIp6DatagramCallback(_In_ otMessage aMessage, _In_ void *aContext);
-void otLwfActiveScanCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext);
-void otLwfEnergyScanCallback(_In_ otEnergyScanResult *aResult, _In_ void *aContext);
-void otLwfDiscoverCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext);
-void otLwfCommissionerEnergyReportCallback(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength, void *aContext);
-void otLwfCommissionerPanIdConflictCallback(uint16_t aPanId, uint32_t aChannelMask, _In_ void *aContext);
-
//
// Address Functions
//
@@ -386,16 +319,41 @@ otLwfInitializeAddresses(
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID
-otLwfAddressesUpdated(
+otLwfRadioAddressesUpdated(
_In_ PMS_FILTER pFilter
);
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfTunAddressesUpdated(
+ _In_ PMS_FILTER pFilter,
+ _In_reads_bytes_(value_data_len) const uint8_t* value_data_ptr,
+ _In_ spinel_size_t value_data_len,
+ _Out_ uint32_t *aNotifFlags
+ );
+
int
otLwfFindCachedAddrIndex(
_In_ PMS_FILTER pFilter,
_In_ PIN6_ADDR addr
);
+//
+// Tunnel Logic Functions
+//
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+otLwfInitializeTunnelMode(
+ _In_ PMS_FILTER pFilter
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+otLwfUninitializeTunnelMode(
+ _In_ PMS_FILTER pFilter
+ );
+
//
// Logging Helper
//
@@ -412,7 +370,7 @@ otLogBuffer(
// Debug Helpers
//
-#if DBG
+#if DEBUG_ALLOC
typedef struct _OT_ALLOC
{
diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c
index 026f57121..260280e75 100644
--- a/examples/drivers/windows/otLwf/iocontrol.c
+++ b/examples/drivers/windows/otLwf/iocontrol.c
@@ -29,6 +29,145 @@
#include "precomp.h"
#include "iocontrol.tmh"
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP Irp
+ );
+
+typedef struct _OTLWF_IOCTL_HANDLER
+{
+ const char* Name;
+ OTLWF_OT_IOCTL_FUNC* otFunc;
+ OTLWF_TUN_IOCTL_FUNC* tunFunc;
+} OTLWF_IOCTL_HANDLER;
+
+OTLWF_IOCTL_HANDLER IoCtls[] =
+{
+ { "IOCTL_OTLWF_OT_ENABLED", NULL },
+ { "IOCTL_OTLWF_OT_INTERFACE", REF_IOCTL_FUNC_WITH_TUN(otInterface) },
+ { "IOCTL_OTLWF_OT_THREAD", REF_IOCTL_FUNC_WITH_TUN(otThread) },
+ { "IOCTL_OTLWF_OT_ACTIVE_SCAN", REF_IOCTL_FUNC_WITH_TUN(otActiveScan) },
+ { "IOCTL_OTLWF_OT_DISCOVER", REF_IOCTL_FUNC(otDiscover) },
+ { "IOCTL_OTLWF_OT_CHANNEL", REF_IOCTL_FUNC_WITH_TUN(otChannel) },
+ { "IOCTL_OTLWF_OT_CHILD_TIMEOUT", REF_IOCTL_FUNC_WITH_TUN(otChildTimeout) },
+ { "IOCTL_OTLWF_OT_EXTENDED_ADDRESS", REF_IOCTL_FUNC_WITH_TUN(otExtendedAddress) },
+ { "IOCTL_OTLWF_OT_EXTENDED_PANID", REF_IOCTL_FUNC_WITH_TUN(otExtendedPanId) },
+ { "IOCTL_OTLWF_OT_LEADER_RLOC", REF_IOCTL_FUNC_WITH_TUN(otLeaderRloc) },
+ { "IOCTL_OTLWF_OT_LINK_MODE", REF_IOCTL_FUNC_WITH_TUN(otLinkMode) },
+ { "IOCTL_OTLWF_OT_MASTER_KEY", REF_IOCTL_FUNC_WITH_TUN(otMasterKey) },
+ { "IOCTL_OTLWF_OT_MESH_LOCAL_EID", REF_IOCTL_FUNC_WITH_TUN(otMeshLocalEid) },
+ { "IOCTL_OTLWF_OT_MESH_LOCAL_PREFIX", REF_IOCTL_FUNC_WITH_TUN(otMeshLocalPrefix) },
+ { "IOCTL_OTLWF_OT_NETWORK_DATA_LEADER", NULL },
+ { "IOCTL_OTLWF_OT_NETWORK_DATA_LOCAL", NULL },
+ { "IOCTL_OTLWF_OT_NETWORK_NAME", REF_IOCTL_FUNC_WITH_TUN(otNetworkName) },
+ { "IOCTL_OTLWF_OT_PAN_ID", REF_IOCTL_FUNC_WITH_TUN(otPanId) },
+ { "IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED", REF_IOCTL_FUNC_WITH_TUN(otRouterRollEnabled) },
+ { "IOCTL_OTLWF_OT_SHORT_ADDRESS", REF_IOCTL_FUNC_WITH_TUN(otShortAddress) },
+ { "IOCTL_OTLWF_OT_UNICAST_ADDRESSES", NULL },
+ { "IOCTL_OTLWF_OT_ACTIVE_DATASET", REF_IOCTL_FUNC(otActiveDataset) },
+ { "IOCTL_OTLWF_OT_PENDING_DATASET", REF_IOCTL_FUNC(otPendingDataset) },
+ { "IOCTL_OTLWF_OT_LOCAL_LEADER_WEIGHT", REF_IOCTL_FUNC_WITH_TUN(otLocalLeaderWeight) },
+ { "IOCTL_OTLWF_OT_ADD_BORDER_ROUTER", REF_IOCTL_FUNC_WITH_TUN(otAddBorderRouter) },
+ { "IOCTL_OTLWF_OT_REMOVE_BORDER_ROUTER", REF_IOCTL_FUNC_WITH_TUN(otRemoveBorderRouter) },
+ { "IOCTL_OTLWF_OT_ADD_EXTERNAL_ROUTE", REF_IOCTL_FUNC_WITH_TUN(otAddExternalRoute) },
+ { "IOCTL_OTLWF_OT_REMOVE_EXTERNAL_ROUTE", REF_IOCTL_FUNC_WITH_TUN(otRemoveExternalRoute) },
+ { "IOCTL_OTLWF_OT_SEND_SERVER_DATA", REF_IOCTL_FUNC(otSendServerData) },
+ { "IOCTL_OTLWF_OT_CONTEXT_ID_REUSE_DELAY", REF_IOCTL_FUNC_WITH_TUN(otContextIdReuseDelay) },
+ { "IOCTL_OTLWF_OT_KEY_SEQUENCE_COUNTER", REF_IOCTL_FUNC_WITH_TUN(otKeySequenceCounter) },
+ { "IOCTL_OTLWF_OT_NETWORK_ID_TIMEOUT", REF_IOCTL_FUNC_WITH_TUN(otNetworkIdTimeout) },
+ { "IOCTL_OTLWF_OT_ROUTER_UPGRADE_THRESHOLD", REF_IOCTL_FUNC_WITH_TUN(otRouterUpgradeThreshold) },
+ { "IOCTL_OTLWF_OT_RELEASE_ROUTER_ID", REF_IOCTL_FUNC_WITH_TUN(otReleaseRouterId) },
+ { "IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED", REF_IOCTL_FUNC_WITH_TUN(otMacWhitelistEnabled) },
+ { "IOCTL_OTLWF_OT_ADD_MAC_WHITELIST", REF_IOCTL_FUNC_WITH_TUN(otAddMacWhitelist) },
+ { "IOCTL_OTLWF_OT_REMOVE_MAC_WHITELIST", REF_IOCTL_FUNC_WITH_TUN(otRemoveMacWhitelist) },
+ { "IOCTL_OTLWF_OT_MAC_WHITELIST_ENTRY", REF_IOCTL_FUNC(otMacWhitelistEntry) },
+ { "IOCTL_OTLWF_OT_CLEAR_MAC_WHITELIST", REF_IOCTL_FUNC_WITH_TUN(otClearMacWhitelist) },
+ { "IOCTL_OTLWF_OT_DEVICE_ROLE", REF_IOCTL_FUNC_WITH_TUN(otDeviceRole) },
+ { "IOCTL_OTLWF_OT_CHILD_INFO_BY_ID", REF_IOCTL_FUNC(otChildInfoById) },
+ { "IOCTL_OTLWF_OT_CHILD_INFO_BY_INDEX", REF_IOCTL_FUNC(otChildInfoByIndex) },
+ { "IOCTL_OTLWF_OT_EID_CACHE_ENTRY", REF_IOCTL_FUNC(otEidCacheEntry) },
+ { "IOCTL_OTLWF_OT_LEADER_DATA", REF_IOCTL_FUNC(otLeaderData) },
+ { "IOCTL_OTLWF_OT_LEADER_ROUTER_ID", REF_IOCTL_FUNC_WITH_TUN(otLeaderRouterId) },
+ { "IOCTL_OTLWF_OT_LEADER_WEIGHT", REF_IOCTL_FUNC_WITH_TUN(otLeaderWeight) },
+ { "IOCTL_OTLWF_OT_NETWORK_DATA_VERSION", REF_IOCTL_FUNC_WITH_TUN(otNetworkDataVersion) },
+ { "IOCTL_OTLWF_OT_PARTITION_ID", REF_IOCTL_FUNC_WITH_TUN(otPartitionId) },
+ { "IOCTL_OTLWF_OT_RLOC16", REF_IOCTL_FUNC_WITH_TUN(otRloc16) },
+ { "IOCTL_OTLWF_OT_ROUTER_ID_SEQUENCE", REF_IOCTL_FUNC(otRouterIdSequence) },
+ { "IOCTL_OTLWF_OT_ROUTER_INFO", REF_IOCTL_FUNC(otRouterInfo) },
+ { "IOCTL_OTLWF_OT_STABLE_NETWORK_DATA_VERSION", REF_IOCTL_FUNC_WITH_TUN(otStableNetworkDataVersion) },
+ { "IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED", REF_IOCTL_FUNC(otMacBlacklistEnabled) },
+ { "IOCTL_OTLWF_OT_ADD_MAC_BLACKLIST", REF_IOCTL_FUNC(otAddMacBlacklist) },
+ { "IOCTL_OTLWF_OT_REMOVE_MAC_BLACKLIST", REF_IOCTL_FUNC(otRemoveMacBlacklist) },
+ { "IOCTL_OTLWF_OT_MAC_BLACKLIST_ENTRY", REF_IOCTL_FUNC(otMacBlacklistEntry) },
+ { "IOCTL_OTLWF_OT_CLEAR_MAC_BLACKLIST", REF_IOCTL_FUNC(otClearMacBlacklist) },
+ { "IOCTL_OTLWF_OT_MAX_TRANSMIT_POWER", REF_IOCTL_FUNC(otMaxTransmitPower) },
+ { "IOCTL_OTLWF_OT_NEXT_ON_MESH_PREFIX", REF_IOCTL_FUNC(otNextOnMeshPrefix) },
+ { "IOCTL_OTLWF_OT_POLL_PERIOD", REF_IOCTL_FUNC(otPollPeriod) },
+ { "IOCTL_OTLWF_OT_LOCAL_LEADER_PARTITION_ID", REF_IOCTL_FUNC(otLocalLeaderPartitionId) },
+ { "IOCTL_OTLWF_OT_ASSIGN_LINK_QUALITY", REF_IOCTL_FUNC(otAssignLinkQuality) },
+ { "IOCTL_OTLWF_OT_PLATFORM_RESET", REF_IOCTL_FUNC_WITH_TUN(otPlatformReset) },
+ { "IOCTL_OTLWF_OT_PARENT_INFO", REF_IOCTL_FUNC_WITH_TUN(otParentInfo) },
+ { "IOCTL_OTLWF_OT_SINGLETON", REF_IOCTL_FUNC(otSingleton) },
+ { "IOCTL_OTLWF_OT_MAC_COUNTERS", REF_IOCTL_FUNC(otMacCounters) },
+ { "IOCTL_OTLWF_OT_MAX_CHILDREN", REF_IOCTL_FUNC_WITH_TUN(otMaxChildren) },
+ { "IOCTL_OTLWF_OT_COMMISIONER_START", REF_IOCTL_FUNC(otCommissionerStart) },
+ { "IOCTL_OTLWF_OT_COMMISIONER_STOP", REF_IOCTL_FUNC(otCommissionerStop) },
+ { "IOCTL_OTLWF_OT_JOINER_START", REF_IOCTL_FUNC(otJoinerStart) },
+ { "IOCTL_OTLWF_OT_JOINER_STOP", REF_IOCTL_FUNC(otJoinerStop) },
+ { "IOCTL_OTLWF_OT_FACTORY_EUI64", REF_IOCTL_FUNC(otFactoryAssignedIeeeEui64) },
+ { "IOCTL_OTLWF_OT_HASH_MAC_ADDRESS", REF_IOCTL_FUNC(otHashMacAddress) },
+ { "IOCTL_OTLWF_OT_ROUTER_DOWNGRADE_THRESHOLD", REF_IOCTL_FUNC_WITH_TUN(otRouterDowngradeThreshold) },
+ { "IOCTL_OTLWF_OT_COMMISSIONER_PANID_QUERY", REF_IOCTL_FUNC(otCommissionerPanIdQuery) },
+ { "IOCTL_OTLWF_OT_COMMISSIONER_ENERGY_SCAN", REF_IOCTL_FUNC(otCommissionerEnergyScan) },
+ { "IOCTL_OTLWF_OT_ROUTER_SELECTION_JITTER", REF_IOCTL_FUNC_WITH_TUN(otRouterSelectionJitter) },
+ { "IOCTL_OTLWF_OT_JOINER_UDP_PORT", REF_IOCTL_FUNC(otJoinerUdpPort) },
+ { "IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_GET", REF_IOCTL_FUNC(otSendDiagnosticGet) },
+ { "IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_RESET", REF_IOCTL_FUNC(otSendDiagnosticReset) },
+ { "IOCTL_OTLWF_OT_COMMISIONER_ADD_JOINER", REF_IOCTL_FUNC(otCommissionerAddJoiner) },
+ { "IOCTL_OTLWF_OT_COMMISIONER_REMOVE_JOINER", REF_IOCTL_FUNC(otCommissionerRemoveJoiner) },
+ { "IOCTL_OTLWF_OT_COMMISIONER_PROVISIONING_URL", REF_IOCTL_FUNC(otCommissionerProvisioningUrl) },
+ { "IOCTL_OTLWF_OT_COMMISIONER_ANNOUNCE_BEGIN", REF_IOCTL_FUNC(otCommissionerAnnounceBegin) },
+ { "IOCTL_OTLWF_OT_ENERGY_SCAN", REF_IOCTL_FUNC_WITH_TUN(otEnergyScan) },
+ { "IOCTL_OTLWF_OT_SEND_ACTIVE_GET", REF_IOCTL_FUNC(otSendActiveGet) },
+ { "IOCTL_OTLWF_OT_SEND_ACTIVE_SET", REF_IOCTL_FUNC(otSendActiveSet) },
+ { "IOCTL_OTLWF_OT_SEND_PENDING_GET", REF_IOCTL_FUNC(otSendPendingGet) },
+ { "IOCTL_OTLWF_OT_SEND_PENDING_SET", REF_IOCTL_FUNC(otSendPendingSet) },
+ { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET", REF_IOCTL_FUNC(otSendMgmtCommissionerGet) },
+ { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET", REF_IOCTL_FUNC(otSendMgmtCommissionerSet) },
+ { "IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME", REF_IOCTL_FUNC_WITH_TUN(otKeySwitchGuardtime) },
+ { "IOCTL_OTLWF_OT_FACTORY_RESET", REF_IOCTL_FUNC(otFactoryReset) }
+};
+
+static_assert(ARRAYSIZE(IoCtls) == (MAX_OTLWF_IOCTL_FUNC_CODE - MIN_OTLWF_IOCTL_FUNC_CODE) + 1,
+ "The IoCtl strings should be up to date with the actual IoCtl list.");
+
+const char*
+IoCtlString(
+ ULONG IoControlCode
+)
+{
+ ULONG FuncCode = ((IoControlCode >> 2) & 0xFFF) - 100;
+ return FuncCode < ARRAYSIZE(IoCtls) ? IoCtls[FuncCode].Name : "UNKNOWN IOCTL";
+}
+
+BOOLEAN
+try_spinel_datatype_unpack(
+ const uint8_t *data_in,
+ spinel_size_t data_len,
+ const char *pack_format,
+ ...
+ )
+{
+ va_list args;
+ va_start(args, pack_format);
+ spinel_ssize_t packed_len = spinel_datatype_vunpack(data_in, data_len, pack_format, args);
+ va_end(args);
+
+ return !(packed_len < 0 || (spinel_size_t)packed_len > data_len);
+}
+
// Handles queries for the current list of Thread interfaces
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
@@ -178,9 +317,16 @@ otLwfIoCtlOpenThreadControl(
status = STATUS_DEVICE_DOES_NOT_EXIST;
goto error;
}
-
- // Pend the Irp for processing on the OpenThread event processing thread
- otLwfEventProcessingIndicateIrp(pFilter, Irp);
+
+ if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO)
+ {
+ // Pend the Irp for processing on the OpenThread event processing thread
+ otLwfEventProcessingIndicateIrp(pFilter, Irp);
+ }
+ else
+ {
+ status = otLwfTunIoCtl(pFilter, Irp);
+ }
// Release our ref on the filter
otLwfReleaseInterface(pFilter);
@@ -201,114 +347,6 @@ error:
return status;
}
-const char* IoCtlStrings[] =
-{
- "IOCTL_OTLWF_OT_ENABLED",
- "IOCTL_OTLWF_OT_INTERFACE",
- "IOCTL_OTLWF_OT_THREAD",
- "IOCTL_OTLWF_OT_ACTIVE_SCAN",
- "IOCTL_OTLWF_OT_DISCOVER",
- "IOCTL_OTLWF_OT_CHANNEL",
- "IOCTL_OTLWF_OT_CHILD_TIMEOUT",
- "IOCTL_OTLWF_OT_EXTENDED_ADDRESS",
- "IOCTL_OTLWF_OT_EXTENDED_PANID",
- "IOCTL_OTLWF_OT_LEADER_RLOC",
- "IOCTL_OTLWF_OT_LINK_MODE",
- "IOCTL_OTLWF_OT_MASTER_KEY",
- "IOCTL_OTLWF_OT_MESH_LOCAL_EID",
- "IOCTL_OTLWF_OT_MESH_LOCAL_PREFIX",
- "IOCTL_OTLWF_OT_NETWORK_DATA_LEADER",
- "IOCTL_OTLWF_OT_NETWORK_DATA_LOCAL",
- "IOCTL_OTLWF_OT_NETWORK_NAME",
- "IOCTL_OTLWF_OT_PAN_ID",
- "IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED",
- "IOCTL_OTLWF_OT_SHORT_ADDRESS",
- "IOCTL_OTLWF_OT_UNICAST_ADDRESSES",
- "IOCTL_OTLWF_OT_ACTIVE_DATASET",
- "IOCTL_OTLWF_OT_PENDING_DATASET",
- "IOCTL_OTLWF_OT_LOCAL_LEADER_WEIGHT",
- "IOCTL_OTLWF_OT_ADD_BORDER_ROUTER",
- "IOCTL_OTLWF_OT_REMOVE_BORDER_ROUTER",
- "IOCTL_OTLWF_OT_ADD_EXTERNAL_ROUTE",
- "IOCTL_OTLWF_OT_REMOVE_EXTERNAL_ROUTE",
- "IOCTL_OTLWF_OT_SEND_SERVER_DATA",
- "IOCTL_OTLWF_OT_CONTEXT_ID_REUSE_DELAY",
- "IOCTL_OTLWF_OT_KEY_SEQUENCE_COUNTER",
- "IOCTL_OTLWF_OT_NETWORK_ID_TIMEOUT",
- "IOCTL_OTLWF_OT_ROUTER_UPGRADE_THRESHOLD",
- "IOCTL_OTLWF_OT_RELEASE_ROUTER_ID",
- "IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED",
- "IOCTL_OTLWF_OT_ADD_MAC_WHITELIST",
- "IOCTL_OTLWF_OT_REMOVE_MAC_WHITELIST",
- "IOCTL_OTLWF_OT_MAC_WHITELIST_ENTRY",
- "IOCTL_OTLWF_OT_CLEAR_MAC_WHITELIST",
- "IOCTL_OTLWF_OT_DEVICE_ROLE",
- "IOCTL_OTLWF_OT_CHILD_INFO_BY_ID",
- "IOCTL_OTLWF_OT_CHILD_INFO_BY_INDEX",
- "IOCTL_OTLWF_OT_EID_CACHE_ENTRY",
- "IOCTL_OTLWF_OT_LEADER_DATA",
- "IOCTL_OTLWF_OT_LEADER_ROUTER_ID",
- "IOCTL_OTLWF_OT_LEADER_WEIGHT",
- "IOCTL_OTLWF_OT_NETWORK_DATA_VERSION",
- "IOCTL_OTLWF_OT_PARTITION_ID",
- "IOCTL_OTLWF_OT_RLOC16",
- "IOCTL_OTLWF_OT_ROUTER_ID_SEQUENCE",
- "IOCTL_OTLWF_OT_ROUTER_INFO",
- "IOCTL_OTLWF_OT_STABLE_NETWORK_DATA_VERSION",
- "IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED",
- "IOCTL_OTLWF_OT_ADD_MAC_BLACKLIST",
- "IOCTL_OTLWF_OT_REMOVE_MAC_BLACKLIST",
- "IOCTL_OTLWF_OT_MAC_BLACKLIST_ENTRY",
- "IOCTL_OTLWF_OT_CLEAR_MAC_BLACKLIST",
- "IOCTL_OTLWF_OT_MAX_TRANSMIT_POWER",
- "IOCTL_OTLWF_OT_NEXT_ON_MESH_PREFIX",
- "IOCTL_OTLWF_OT_POLL_PERIOD",
- "IOCTL_OTLWF_OT_LOCAL_LEADER_PARTITION_ID",
- "IOCTL_OTLWF_OT_ASSIGN_LINK_QUALITY",
- "IOCTL_OTLWF_OT_PLATFORM_RESET",
- "IOCTL_OTLWF_OT_PARENT_INFO",
- "IOCTL_OTLWF_OT_SINGLETON"
- "IOCTL_OTLWF_OT_MAC_COUNTERS",
- "IOCTL_OTLWF_OT_MAX_CHILDREN",
- "IOCTL_OTLWF_OT_COMMISIONER_START",
- "IOCTL_OTLWF_OT_COMMISIONER_STOP",
- "IOCTL_OTLWF_OT_JOINER_START",
- "IOCTL_OTLWF_OT_JOINER_STOP",
- "IOCTL_OTLWF_OT_FACTORY_EUI64",
- "IOCTL_OTLWF_OT_HASH_MAC_ADDRESS",
- "IOCTL_OTLWF_OT_ROUTER_DOWNGRADE_THRESHOLD",
- "IOCTL_OTLWF_OT_COMMISSIONER_PANID_QUERY",
- "IOCTL_OTLWF_OT_COMMISSIONER_ENERGY_SCAN",
- "IOCTL_OTLWF_OT_ROUTER_SELECTION_JITTER",
- "IOCTL_OTLWF_OT_JOINER_UDP_PORT",
- "IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_GET",
- "IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_RESET",
- "IOCTL_OTLWF_OT_COMMISIONER_ADD_JOINER",
- "IOCTL_OTLWF_OT_COMMISIONER_REMOVE_JOINER",
- "IOCTL_OTLWF_OT_COMMISIONER_PROVISIONING_URL",
- "IOCTL_OTLWF_OT_COMMISIONER_ANNOUNCE_BEGIN",
- "IOCTL_OTLWF_OT_ENERGY_SCAN",
- "IOCTL_OTLWF_OT_SEND_ACTIVE_GET",
- "IOCTL_OTLWF_OT_SEND_ACTIVE_SET",
- "IOCTL_OTLWF_OT_SEND_PENDING_GET",
- "IOCTL_OTLWF_OT_SEND_PENDING_SET",
- "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET",
- "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET",
- "IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME",
-};
-
-static_assert(ARRAYSIZE(IoCtlStrings) == (MAX_OTLWF_IOCTL_FUNC_CODE - MIN_OTLWF_IOCTL_FUNC_CODE),
- "The IoCtl strings should be up to date with the actual IoCtl list.");
-
-const char*
-IoCtlString(
- ULONG IoControlCode
-)
-{
- ULONG FuncCode = ((IoControlCode >> 2) & 0xFFF) - 100;
- return FuncCode < ARRAYSIZE(IoCtlStrings) ? IoCtlStrings[FuncCode] : "UNKNOWN IOCTL";
-}
-
// Handles Irp for IOTCLs for OpenThread control on the OpenThread thread
_IRQL_requires_max_(PASSIVE_LEVEL)
VOID
@@ -328,288 +366,28 @@ otLwfCompleteOpenThreadIrp(
ULONG OrigOutBufferLength = OutBufferLength;
- NTSTATUS status = STATUS_SUCCESS;
-
- LogVerbose(DRIVER_IOCTL, "Processing Irp=%p, for %s (In:%u,Out:%u)",
- Irp, IoCtlString(IoControlCode), InBufferLength, OutBufferLength);
+ NTSTATUS status = STATUS_NOT_IMPLEMENTED;
+
+ ULONG FuncCode = ((IoControlCode >> 2) & 0xFFF) - 100;
+ if (FuncCode < ARRAYSIZE(IoCtls))
+ {
+ LogVerbose(DRIVER_IOCTL, "Processing Irp=%p, for %s (In:%u,Out:%u)",
+ Irp, IoCtls[FuncCode].Name, InBufferLength, OutBufferLength);
- switch (IoControlCode)
+ if (IoCtls[FuncCode].otFunc)
+ {
+ status = IoCtls[FuncCode].otFunc(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
+ }
+ else
+ {
+ OutBufferLength = 0;
+ }
+
+ LogVerbose(DRIVER_IOCTL, "Completing Irp=%p, with %!STATUS! for %s (Out:%u)",
+ Irp, status, IoCtls[FuncCode].Name, OutBufferLength);
+ }
+ else
{
- case IOCTL_OTLWF_OT_INTERFACE:
- status = otLwfIoCtl_otInterface(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_THREAD:
- status = otLwfIoCtl_otThread(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ACTIVE_SCAN:
- status = otLwfIoCtl_otActiveScan(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_DISCOVER:
- status = otLwfIoCtl_otDiscover(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CHANNEL:
- status = otLwfIoCtl_otChannel(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CHILD_TIMEOUT:
- status = otLwfIoCtl_otChildTimeout(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_EXTENDED_ADDRESS:
- status = otLwfIoCtl_otExtendedAddress(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_EXTENDED_PANID:
- status = otLwfIoCtl_otExtendedPanId(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LEADER_RLOC:
- status = otLwfIoCtl_otLeaderRloc(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LINK_MODE:
- status = otLwfIoCtl_otLinkMode(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MASTER_KEY:
- status = otLwfIoCtl_otMasterKey(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MESH_LOCAL_EID:
- status = otLwfIoCtl_otMeshLocalEid(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MESH_LOCAL_PREFIX:
- status = otLwfIoCtl_otMeshLocalPrefix(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_NETWORK_DATA_LEADER:
- status = STATUS_NOT_IMPLEMENTED;
- break;
- case IOCTL_OTLWF_OT_NETWORK_DATA_LOCAL:
- status = STATUS_NOT_IMPLEMENTED;
- break;
- case IOCTL_OTLWF_OT_NETWORK_NAME:
- status = otLwfIoCtl_otNetworkName(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_PAN_ID:
- status = otLwfIoCtl_otPanId(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED:
- status = otLwfIoCtl_otRouterRollEnabled(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SHORT_ADDRESS:
- status = otLwfIoCtl_otShortAddress(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_UNICAST_ADDRESSES:
- status = STATUS_NOT_IMPLEMENTED;
- break;
- case IOCTL_OTLWF_OT_ACTIVE_DATASET:
- status = otLwfIoCtl_otActiveDataset(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_PENDING_DATASET:
- status = otLwfIoCtl_otPendingDataset(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LOCAL_LEADER_WEIGHT:
- status = otLwfIoCtl_otLocalLeaderWeight(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ADD_BORDER_ROUTER:
- status = otLwfIoCtl_otAddBorderRouter(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_REMOVE_BORDER_ROUTER:
- status = otLwfIoCtl_otRemoveBorderRouter(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ADD_EXTERNAL_ROUTE:
- status = otLwfIoCtl_otAddExternalRoute(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_REMOVE_EXTERNAL_ROUTE:
- status = otLwfIoCtl_otRemoveExternalRoute(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_SERVER_DATA:
- status = otLwfIoCtl_otSendServerData(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CONTEXT_ID_REUSE_DELAY:
- status = otLwfIoCtl_otContextIdReuseDelay(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_KEY_SEQUENCE_COUNTER:
- status = otLwfIoCtl_otKeySequenceCounter(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_NETWORK_ID_TIMEOUT:
- status = otLwfIoCtl_otNetworkIdTimeout(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ROUTER_UPGRADE_THRESHOLD:
- status = otLwfIoCtl_otRouterUpgradeThreshold(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_RELEASE_ROUTER_ID:
- status = otLwfIoCtl_otReleaseRouterId(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED:
- status = otLwfIoCtl_otMacWhitelistEnabled(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ADD_MAC_WHITELIST:
- status = otLwfIoCtl_otAddMacWhitelist(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_REMOVE_MAC_WHITELIST:
- status = otLwfIoCtl_otRemoveMacWhitelist(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAC_WHITELIST_ENTRY:
- status = otLwfIoCtl_otMacWhitelistEntry(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CLEAR_MAC_WHITELIST:
- status = otLwfIoCtl_otClearMacWhitelist(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_DEVICE_ROLE:
- status = otLwfIoCtl_otDeviceRole(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CHILD_INFO_BY_ID:
- status = otLwfIoCtl_otChildInfoById(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CHILD_INFO_BY_INDEX:
- status = otLwfIoCtl_otChildInfoByIndex(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_EID_CACHE_ENTRY:
- status = otLwfIoCtl_otEidCacheEntry(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LEADER_DATA:
- status = otLwfIoCtl_otLeaderData(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LEADER_ROUTER_ID:
- status = otLwfIoCtl_otLeaderRouterId(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LEADER_WEIGHT:
- status = otLwfIoCtl_otLeaderWeight(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_NETWORK_DATA_VERSION:
- status = otLwfIoCtl_otNetworkDataVersion(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_PARTITION_ID:
- status = otLwfIoCtl_otPartitionId(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_RLOC16:
- status = otLwfIoCtl_otRloc16(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ROUTER_ID_SEQUENCE:
- status = otLwfIoCtl_otRouterIdSequence(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ROUTER_INFO:
- status = otLwfIoCtl_otRouterInfo(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_STABLE_NETWORK_DATA_VERSION:
- status = otLwfIoCtl_otStableNetworkDataVersion(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED:
- status = otLwfIoCtl_otMacBlacklistEnabled(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ADD_MAC_BLACKLIST:
- status = otLwfIoCtl_otAddMacBlacklist(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_REMOVE_MAC_BLACKLIST:
- status = otLwfIoCtl_otRemoveMacBlacklist(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAC_BLACKLIST_ENTRY:
- status = otLwfIoCtl_otMacBlacklistEntry(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_CLEAR_MAC_BLACKLIST:
- status = otLwfIoCtl_otClearMacBlacklist(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAX_TRANSMIT_POWER:
- status = otLwfIoCtl_otMaxTransmitPower(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_NEXT_ON_MESH_PREFIX:
- status = otLwfIoCtl_otNextOnMeshPrefix(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_POLL_PERIOD:
- status = otLwfIoCtl_otPollPeriod(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_LOCAL_LEADER_PARTITION_ID:
- status = otLwfIoCtl_otLocalLeaderPartitionId(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ASSIGN_LINK_QUALITY:
- status = otLwfIoCtl_otAssignLinkQuality(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_PLATFORM_RESET:
- status = otLwfIoCtl_otPlatformReset(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_PARENT_INFO:
- status = otLwfIoCtl_otParentInfo(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SINGLETON:
- status = otLwfIoCtl_otSingleton(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAC_COUNTERS:
- status = otLwfIoCtl_otMacCounters(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_MAX_CHILDREN:
- status = otLwfIoCtl_otMaxChildren(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISIONER_START:
- status = otLwfIoCtl_otCommissionerStart(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISIONER_STOP:
- status = otLwfIoCtl_otCommissionerStop(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_JOINER_START:
- status = otLwfIoCtl_otJoinerStart(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_JOINER_STOP:
- status = otLwfIoCtl_otJoinerStop(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_FACTORY_EUI64:
- status = otLwfIoCtl_otFactoryAssignedIeeeEui64(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_HASH_MAC_ADDRESS:
- status = otLwfIoCtl_otHashMacAddress(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ROUTER_DOWNGRADE_THRESHOLD:
- status = otLwfIoCtl_otRouterDowngradeThreshold(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISSIONER_PANID_QUERY:
- status = otLwfIoCtl_otCommissionerPanIdQuery(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISSIONER_ENERGY_SCAN:
- status = otLwfIoCtl_otCommissionerEnergyScan(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ROUTER_SELECTION_JITTER:
- status = otLwfIoCtl_otRouterSelectionJitter(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_JOINER_UDP_PORT:
- status = otLwfIoCtl_otJoinerUdpPort(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_GET:
- status = otLwfIoCtl_otSendDiagnosticGet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_RESET:
- status = otLwfIoCtl_otSendDiagnosticReset(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISIONER_ADD_JOINER:
- status = otLwfIoCtl_otCommissionerAddJoiner(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISIONER_REMOVE_JOINER:
- status = otLwfIoCtl_otCommissionerRemoveJoiner(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISIONER_PROVISIONING_URL:
- status = otLwfIoCtl_otCommissionerProvisioningUrl(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_COMMISIONER_ANNOUNCE_BEGIN:
- status = otLwfIoCtl_otCommissionerAnnounceBegin(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_ENERGY_SCAN:
- status = otLwfIoCtl_otEnergyScan(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_ACTIVE_GET:
- status = otLwfIoCtl_otSendActiveGet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_ACTIVE_SET:
- status = otLwfIoCtl_otSendActiveSet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_PENDING_GET:
- status = otLwfIoCtl_otSendPendingGet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_PENDING_SET:
- status = otLwfIoCtl_otSendPendingSet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET:
- status = otLwfIoCtl_otSendMgmtCommissionerGet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET:
- status = otLwfIoCtl_otSendMgmtCommissionerSet(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- case IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME:
- status = otLwfIoCtl_otKeySwitchGuardtime(pFilter, InBuffer, InBufferLength, OutBuffer, &OutBufferLength);
- break;
- default:
- status = STATUS_NOT_IMPLEMENTED;
OutBufferLength = 0;
}
@@ -619,15 +397,58 @@ otLwfCompleteOpenThreadIrp(
RtlZeroMemory((PUCHAR)OutBuffer + OutBufferLength, OrigOutBufferLength - OutBufferLength);
}
- LogVerbose(DRIVER_IOCTL, "Completing Irp=%p, with %!STATUS! for %s (Out:%u)",
- Irp, status, IoCtlString(IoControlCode), OutBufferLength);
-
// Complete the IRP
Irp->IoStatus.Information = OutBufferLength;
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
+// Handles Irp for IOTCLs for OpenThread control on the OpenThread thread
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ PUCHAR InBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer + sizeof(GUID);
+ ULONG InBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength - sizeof(GUID);
+ ULONG OutBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+
+ NTSTATUS status = STATUS_NOT_IMPLEMENTED;
+
+ ULONG FuncCode = ((IoControlCode >> 2) & 0xFFF) - 100;
+ if (FuncCode < ARRAYSIZE(IoCtls))
+ {
+ LogVerbose(DRIVER_IOCTL, "Processing Irp=%p, for %s (In:%u,Out:%u)",
+ Irp, IoCtls[FuncCode].Name, InBufferLength, OutBufferLength);
+
+ if (IoCtls[FuncCode].tunFunc)
+ {
+ status = IoCtls[FuncCode].tunFunc(pFilter, Irp, InBuffer, InBufferLength, OutBufferLength);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ LogVerbose(DRIVER_IOCTL, "Completing Irp=%p, with %!STATUS! for %s",
+ Irp, status, IoCtls[FuncCode].Name);
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ status = STATUS_PENDING;
+
+ // Mark the Irp as pending
+ IoMarkIrpPending(Irp);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otInterface(
@@ -649,7 +470,7 @@ otLwfIoCtl_otInterface(
{
// Make sure our addresses are in sync
(void)otLwfInitializeAddresses(pFilter);
- otLwfAddressesUpdated(pFilter);
+ otLwfRadioAddressesUpdated(pFilter);
status = ThreadErrorToNtstatus(otInterfaceUp(pFilter->otCtx));
}
@@ -674,6 +495,81 @@ otLwfIoCtl_otInterface(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otInterface(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(BOOLEAN))
+ {
+ BOOLEAN IsEnabled = *(BOOLEAN*)InBuffer;
+ if (IsEnabled)
+ {
+ // Make sure our addresses are in sync
+ (void)otLwfInitializeAddresses(pFilter);
+
+ // Sync the current addresses
+ KeSetEvent(&pFilter->TunWorkerThreadAddressChangedEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_IF_UP,
+ sizeof(BOOLEAN),
+ SPINEL_DATATYPE_BOOL_S,
+ IsEnabled);
+ }
+ else if (OutBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otInterface_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_IF_UP,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otInterface_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_IF_UP)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_BOOL_S, (BOOLEAN*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otThread(
@@ -687,9 +583,6 @@ otLwfIoCtl_otThread(
)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
-
- *OutBufferLength = 0;
- UNREFERENCED_PARAMETER(OutBuffer);
if (InBufferLength >= sizeof(BOOLEAN))
{
@@ -702,11 +595,88 @@ otLwfIoCtl_otThread(
{
status = ThreadErrorToNtstatus(otThreadStop(pFilter->otCtx));
}
+
+ *OutBufferLength = 0;
+ }
+ else if (*OutBufferLength >= sizeof(BOOLEAN))
+ {
+ *(BOOLEAN*)OutBuffer = (otGetDeviceRole(pFilter->otCtx) > kDeviceRoleDisabled) ? TRUE : FALSE;
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ *OutBufferLength = 0;
}
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otThread(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_STACK_UP,
+ sizeof(BOOLEAN),
+ SPINEL_DATATYPE_BOOL_S,
+ *(BOOLEAN*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otThread_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_STACK_UP,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otThread_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_STACK_UP)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_BOOL_S, (BOOLEAN*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otActiveScan(
@@ -749,6 +719,84 @@ otLwfIoCtl_otActiveScan(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otActiveScan(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint32_t) + sizeof(uint16_t))
+ {
+ uint32_t aScanChannels = *(uint32_t*)InBuffer;
+ uint16_t aScanDuration = *(uint16_t*)(InBuffer + sizeof(uint32_t));
+ uint8_t aScanState = SPINEL_SCAN_STATE_BEACON;
+
+ // TODO - Send down scan channel & duration first
+ UNREFERENCED_PARAMETER(aScanChannels);
+ status = otLwfSetTunProp(pFilter, SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_UINT16_S, aScanDuration);
+ if (!NT_SUCCESS(status)) goto error;
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ aScanState);
+ }
+ else if (OutBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otActiveScan_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ 0,
+ NULL);
+ }
+
+error:
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otActiveScan_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_MAC_SCAN_STATE)
+ {
+ uint8_t aScanState = 0;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, &aScanState))
+ {
+ *(BOOLEAN*)OutBuffer = (aScanState == SPINEL_SCAN_STATE_BEACON) ? TRUE : FALSE;
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otEnergyScan(
@@ -791,6 +839,84 @@ otLwfIoCtl_otEnergyScan(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otEnergyScan(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint32_t) + sizeof(uint16_t))
+ {
+ uint32_t aScanChannels = *(uint32_t*)InBuffer;
+ uint16_t aScanDuration = *(uint16_t*)(InBuffer + sizeof(uint32_t));
+ uint8_t aScanState = SPINEL_SCAN_STATE_ENERGY;
+
+ // TODO - Send down scan channel & duration first
+ UNREFERENCED_PARAMETER(aScanChannels);
+ status = otLwfSetTunProp(pFilter, SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_UINT16_S, aScanDuration);
+ if (!NT_SUCCESS(status)) goto error;
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ aScanState);
+ }
+ else if (OutBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otEnergyScan_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_MAC_SCAN_STATE,
+ 0,
+ NULL);
+ }
+
+error:
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otEnergyScan_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_MAC_SCAN_STATE)
+ {
+ uint8_t aScanState = 0;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, &aScanState))
+ {
+ *(BOOLEAN*)OutBuffer = (aScanState == SPINEL_SCAN_STATE_ENERGY) ? TRUE : FALSE;
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otDiscover(
@@ -850,8 +976,7 @@ otLwfIoCtl_otChannel(
if (InBufferLength >= sizeof(uint8_t))
{
- uint8_t aChannel = *(uint8_t*)InBuffer;
- status = ThreadErrorToNtstatus(otSetChannel(pFilter->otCtx, aChannel));
+ status = ThreadErrorToNtstatus(otSetChannel(pFilter->otCtx, *(uint8_t*)InBuffer));
*OutBufferLength = 0;
}
else if (*OutBufferLength >= sizeof(uint8_t))
@@ -868,6 +993,71 @@ otLwfIoCtl_otChannel(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otChannel(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_PHY_CHAN,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otChannel_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_PHY_CHAN,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otChannel_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_PHY_CHAN)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otChildTimeout(
@@ -884,8 +1074,7 @@ otLwfIoCtl_otChildTimeout(
if (InBufferLength >= sizeof(uint32_t))
{
- uint32_t aTimeout = *(uint32_t*)InBuffer;
- otSetChildTimeout(pFilter->otCtx, aTimeout);
+ otSetChildTimeout(pFilter->otCtx, *(uint32_t*)InBuffer);
status = STATUS_SUCCESS;
*OutBufferLength = 0;
}
@@ -903,6 +1092,71 @@ otLwfIoCtl_otChildTimeout(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otChildTimeout(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_CHILD_TIMEOUT,
+ sizeof(uint32_t),
+ SPINEL_DATATYPE_UINT32_S,
+ *(uint32_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otChildTimeout_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_CHILD_TIMEOUT,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otChildTimeout_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_CHILD_TIMEOUT)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT32_S, (uint32_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint32_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otExtendedAddress(
@@ -936,6 +1190,73 @@ otLwfIoCtl_otExtendedAddress(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otExtendedAddress(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otExtAddress))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_HWADDR,
+ sizeof(otExtAddress),
+ SPINEL_DATATYPE_EUI64_S,
+ (otExtAddress*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(otExtAddress))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otExtendedAddress_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_HWADDR,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otExtendedAddress_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_HWADDR)
+ {
+ spinel_eui64_t *data = NULL;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_EUI64_S, &data) && data != NULL)
+ {
+ memcpy(OutBuffer, data, sizeof(otExtAddress));
+ *OutBufferLength = sizeof(otExtAddress);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otExtendedPanId(
@@ -970,6 +1291,76 @@ otLwfIoCtl_otExtendedPanId(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otExtendedPanId(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otExtendedPanId))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_XPANID,
+ sizeof(otExtendedPanId) + sizeof(uint16_t),
+ SPINEL_DATATYPE_DATA_S,
+ (otExtendedPanId*)InBuffer,
+ sizeof(otExtendedPanId));
+ }
+ else if (OutBufferLength >= sizeof(otExtendedPanId))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otExtendedPanId_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_XPANID,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otExtendedPanId_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_XPANID)
+ {
+ uint8_t *data = NULL;
+ spinel_size_t aExtPanIdLen;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_DATA_S, &data, &aExtPanIdLen) && data != NULL &&
+ aExtPanIdLen == sizeof(otExtendedPanId))
+ {
+ memcpy(OutBuffer, data, sizeof(otExtendedPanId));
+ *OutBufferLength = sizeof(otExtendedPanId);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otFactoryAssignedIeeeEui64(
@@ -987,10 +1378,10 @@ otLwfIoCtl_otFactoryAssignedIeeeEui64(
UNREFERENCED_PARAMETER(InBuffer);
UNREFERENCED_PARAMETER(InBufferLength);
- if (*OutBufferLength >= sizeof(otExtendedPanId))
+ if (*OutBufferLength >= sizeof(otExtAddress))
{
otGetFactoryAssignedIeeeEui64(pFilter->otCtx, (otExtAddress*)OutBuffer);
- *OutBufferLength = sizeof(otExtendedPanId);
+ *OutBufferLength = sizeof(otExtAddress);
status = STATUS_SUCCESS;
}
else
@@ -1052,7 +1443,7 @@ otLwfIoCtl_otLeaderRloc(
if (*OutBufferLength >= sizeof(otIp6Address))
{
status = ThreadErrorToNtstatus(otGetLeaderRloc(pFilter->otCtx, (otIp6Address*)OutBuffer));
- *OutBufferLength = sizeof(otExtendedPanId);
+ *OutBufferLength = sizeof(otIp6Address);
}
else
{
@@ -1062,6 +1453,73 @@ otLwfIoCtl_otLeaderRloc(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLeaderRloc(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otIp6Address))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_LEADER_ADDR,
+ sizeof(otIp6Address),
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ (otIp6Address*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(otIp6Address))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otLeaderRloc_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_LEADER_ADDR,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLeaderRloc_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_LEADER_ADDR)
+ {
+ spinel_ipv6addr_t *data = NULL;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_IPv6ADDR_S, &data) && data != NULL)
+ {
+ memcpy(OutBuffer, data, sizeof(spinel_ipv6addr_t));
+ *OutBufferLength = sizeof(otIp6Address);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otLinkMode(
@@ -1096,6 +1554,95 @@ otLwfIoCtl_otLinkMode(
return status;
}
+enum
+{
+ kThreadMode_RxOnWhenIdle = (1 << 3),
+ kThreadMode_SecureDataRequest = (1 << 2),
+ kThreadMode_FullFunctionDevice = (1 << 1),
+ kThreadMode_FullNetworkData = (1 << 0),
+};
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLinkMode(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otLinkModeConfig))
+ {
+ const otLinkModeConfig* aLinkMode = (otLinkModeConfig*)InBuffer;
+ uint8_t numeric_mode = 0;
+
+ if (aLinkMode->mRxOnWhenIdle) numeric_mode |= kThreadMode_RxOnWhenIdle;
+ if (aLinkMode->mSecureDataRequests) numeric_mode |= kThreadMode_SecureDataRequest;
+ if (aLinkMode->mDeviceType) numeric_mode |= kThreadMode_FullFunctionDevice;
+ if (aLinkMode->mNetworkData) numeric_mode |= kThreadMode_FullNetworkData;
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_MODE,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ numeric_mode);
+ }
+ else if (OutBufferLength >= sizeof(otLinkModeConfig))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otLinkMode_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_MODE,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLinkMode_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_MODE)
+ {
+ uint8_t numeric_mode = 0;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, &numeric_mode))
+ {
+ otLinkModeConfig* aLinkMode = (otLinkModeConfig*)OutBuffer;
+
+ aLinkMode->mRxOnWhenIdle = ((numeric_mode & kThreadMode_RxOnWhenIdle) == kThreadMode_RxOnWhenIdle);
+ aLinkMode->mSecureDataRequests = ((numeric_mode & kThreadMode_SecureDataRequest) == kThreadMode_SecureDataRequest);
+ aLinkMode->mDeviceType = ((numeric_mode & kThreadMode_FullFunctionDevice) == kThreadMode_FullFunctionDevice);
+ aLinkMode->mNetworkData = ((numeric_mode & kThreadMode_FullNetworkData) == kThreadMode_FullNetworkData);
+
+ *OutBufferLength = sizeof(otLinkModeConfig);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otMasterKey(
@@ -1133,6 +1680,79 @@ otLwfIoCtl_otMasterKey(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMasterKey(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otMasterKey) + sizeof(uint8_t))
+ {
+ spinel_size_t aKeyLength = *(uint8_t*)(InBuffer + sizeof(otMasterKey));
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_MASTER_KEY,
+ sizeof(otMasterKey) + sizeof(uint16_t),
+ SPINEL_DATATYPE_DATA_S,
+ (otMasterKey*)InBuffer,
+ aKeyLength);
+ }
+ else if (OutBufferLength >= sizeof(otMasterKey) + sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otMasterKey_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_MASTER_KEY,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMasterKey_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_MASTER_KEY)
+ {
+ uint8_t *data = NULL;
+ spinel_size_t aKeyLength;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_DATA_S, &data, &aKeyLength) && data != NULL &&
+ aKeyLength <= sizeof(otMasterKey))
+ {
+ memcpy(OutBuffer, data, aKeyLength);
+ *(uint8_t*)((PUCHAR)OutBuffer + sizeof(otMasterKey)) = (uint8_t)aKeyLength;
+ *OutBufferLength = sizeof(otMasterKey) + sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otMeshLocalEid(
@@ -1163,6 +1783,63 @@ otLwfIoCtl_otMeshLocalEid(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMeshLocalEid(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(otIp6Address))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otMeshLocalEid_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_IPV6_ML_ADDR,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMeshLocalEid_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_IPV6_ML_ADDR)
+ {
+ spinel_ipv6addr_t *data = NULL;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_IPv6ADDR_S, &data) && data != NULL)
+ {
+ memcpy(OutBuffer, data, sizeof(spinel_ipv6addr_t));
+ *OutBufferLength = sizeof(otIp6Address);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otMeshLocalPrefix(
@@ -1196,6 +1873,75 @@ otLwfIoCtl_otMeshLocalPrefix(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMeshLocalPrefix(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otMeshLocalPrefix))
+ {
+ otIp6Address aAddress = {0};
+ memcpy(&aAddress, InBuffer, sizeof(otMeshLocalPrefix));
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_IPV6_ML_PREFIX,
+ sizeof(otIp6Address),
+ SPINEL_DATATYPE_IPv6ADDR_S,
+ &aAddress);
+ }
+ else if (OutBufferLength >= sizeof(otMeshLocalPrefix))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otMeshLocalPrefix_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_IPV6_ML_PREFIX,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMeshLocalPrefix_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_IPV6_ML_PREFIX)
+ {
+ if (DataLength >= sizeof(otMeshLocalPrefix))
+ {
+ memcpy(OutBuffer, Data, sizeof(otMeshLocalPrefix));
+ *OutBufferLength = sizeof(otMeshLocalPrefix);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
// otLwfIoCtl_otNetworkDataLeader
// otLwfIoCtl_otNetworkDataLocal
@@ -1233,6 +1979,73 @@ otLwfIoCtl_otNetworkName(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otNetworkName(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otNetworkName))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_NETWORK_NAME,
+ sizeof(otIp6Address),
+ SPINEL_DATATYPE_UTF8_S,
+ (otNetworkName*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(otNetworkName))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otNetworkName_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_NETWORK_NAME,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otNetworkName_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_NETWORK_NAME)
+ {
+ const char *data = NULL;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UTF8_S, &data) && data != NULL)
+ {
+ strcpy_s(OutBuffer, sizeof(otNetworkName), data);
+ *OutBufferLength = sizeof(otNetworkName);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otPanId(
@@ -1266,6 +2079,71 @@ otLwfIoCtl_otPanId(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otPanId(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(otPanId))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_MAC_15_4_PANID,
+ sizeof(otPanId),
+ SPINEL_DATATYPE_UINT16_S,
+ *(otPanId*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(otPanId))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otPanId_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_MAC_15_4_PANID,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otPanId_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_MAC_15_4_PANID)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT16_S, (otPanId*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(otPanId);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRouterRollEnabled(
@@ -1300,6 +2178,71 @@ otLwfIoCtl_otRouterRollEnabled(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterRollEnabled(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED,
+ sizeof(BOOLEAN),
+ SPINEL_DATATYPE_BOOL_S,
+ *(BOOLEAN*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otRouterRollEnabled_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterRollEnabled_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_ROUTER_ROLE_ENABLED)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_BOOL_S, (BOOLEAN*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otShortAddress(
@@ -1331,6 +2274,61 @@ otLwfIoCtl_otShortAddress(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otShortAddress(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(otShortAddress))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otShortAddress_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_MAC_15_4_SADDR,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otShortAddress_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_MAC_15_4_SADDR)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT16_S, (otShortAddress*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(otShortAddress);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
// otLwfIoCtl_otUnicastAddresses
_IRQL_requires_max_(PASSIVE_LEVEL)
@@ -1431,6 +2429,71 @@ otLwfIoCtl_otLocalLeaderWeight(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLocalLeaderWeight(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otLocalLeaderWeight_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLocalLeaderWeight_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otAddBorderRouter(
@@ -1456,6 +2519,62 @@ otLwfIoCtl_otAddBorderRouter(
return status;
}
+const uint8_t kPreferenceOffset = 6;
+//const uint8_t kPreferenceMask = 3 << kPreferenceOffset;
+const uint8_t kPreferredFlag = 1 << 5;
+const uint8_t kSlaacFlag = 1 << 4;
+const uint8_t kDhcpFlag = 1 << 3;
+const uint8_t kConfigureFlag = 1 << 2;
+const uint8_t kDefaultRouteFlag = 1 << 1;
+const uint8_t kOnMeshFlag = 1 << 0;
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otAddBorderRouter(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(otBorderRouterConfig))
+ {
+ const otBorderRouterConfig *aConfig = (otBorderRouterConfig*)InBuffer;
+
+ otIp6Address prefix = {0};
+ memcpy_s(&prefix, sizeof(prefix), &aConfig->mPrefix.mPrefix, aConfig->mPrefix.mLength);
+
+ uint8_t flags = (uint8_t)(aConfig->mPreference << kPreferenceOffset);
+ if (aConfig->mSlaac) flags |= kSlaacFlag;
+ if (aConfig->mDhcp) flags |= kDhcpFlag;
+ if (aConfig->mConfigure) flags |= kConfigureFlag;
+ if (aConfig->mDefaultRoute) flags |= kDefaultRouteFlag;
+ if (aConfig->mOnMesh) flags |= kOnMeshFlag;
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_INSERT,
+ SPINEL_PROP_THREAD_ON_MESH_NETS,
+ sizeof(otIp6Address) + 3 * sizeof(uint8_t),
+ "6CbC",
+ &prefix,
+ aConfig->mPrefix.mLength,
+ aConfig->mStable,
+ flags);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRemoveBorderRouter(
@@ -1481,6 +2600,44 @@ otLwfIoCtl_otRemoveBorderRouter(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRemoveBorderRouter(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(otIp6Prefix))
+ {
+ const otIp6Prefix *aPrefix = (otIp6Prefix*)InBuffer;
+
+ otIp6Address prefix = {0};
+ memcpy_s(&prefix, sizeof(prefix), &aPrefix->mPrefix, aPrefix->mLength);
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_REMOVE,
+ SPINEL_PROP_THREAD_ON_MESH_NETS,
+ sizeof(otIp6Address) + sizeof(uint8_t),
+ "6C",
+ &prefix,
+ aPrefix->mLength);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otAddExternalRoute(
@@ -1506,6 +2663,53 @@ otLwfIoCtl_otAddExternalRoute(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otAddExternalRoute(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(otBorderRouterConfig))
+ {
+ const otBorderRouterConfig *aConfig = (otBorderRouterConfig*)InBuffer;
+
+ otIp6Address prefix = {0};
+ memcpy_s(&prefix, sizeof(prefix), &aConfig->mPrefix.mPrefix, aConfig->mPrefix.mLength);
+
+ uint8_t flags = (uint8_t)(aConfig->mPreference << kPreferenceOffset);
+ if (aConfig->mSlaac) flags |= kSlaacFlag;
+ if (aConfig->mDhcp) flags |= kDhcpFlag;
+ if (aConfig->mConfigure) flags |= kConfigureFlag;
+ if (aConfig->mDefaultRoute) flags |= kDefaultRouteFlag;
+ if (aConfig->mOnMesh) flags |= kOnMeshFlag;
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_INSERT,
+ SPINEL_PROP_THREAD_LOCAL_ROUTES,
+ sizeof(otIp6Address) + 3 * sizeof(uint8_t),
+ "6CbC",
+ &prefix,
+ aConfig->mPrefix.mLength,
+ aConfig->mStable,
+ flags);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRemoveExternalRoute(
@@ -1531,6 +2735,44 @@ otLwfIoCtl_otRemoveExternalRoute(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRemoveExternalRoute(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(otIp6Prefix))
+ {
+ const otIp6Prefix *aPrefix = (otIp6Prefix*)InBuffer;
+
+ otIp6Address prefix = {0};
+ memcpy_s(&prefix, sizeof(prefix), &aPrefix->mPrefix, aPrefix->mLength);
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_REMOVE,
+ SPINEL_PROP_THREAD_LOCAL_ROUTES,
+ sizeof(otIp6Address) + sizeof(uint8_t),
+ "6C",
+ &prefix,
+ aPrefix->mLength);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otSendServerData(
@@ -1589,6 +2831,71 @@ otLwfIoCtl_otContextIdReuseDelay(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otContextIdReuseDelay(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY,
+ sizeof(uint32_t),
+ SPINEL_DATATYPE_UINT32_S,
+ *(uint32_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otContextIdReuseDelay_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otContextIdReuseDelay_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_CONTEXT_REUSE_DELAY)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT32_S, (uint32_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint32_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otKeySequenceCounter(
@@ -1623,6 +2930,71 @@ otLwfIoCtl_otKeySequenceCounter(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otKeySequenceCounter(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER,
+ sizeof(uint32_t),
+ SPINEL_DATATYPE_UINT32_S,
+ *(uint32_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otKeySequenceCounter_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otKeySequenceCounter_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT32_S, (uint32_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint32_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otNetworkIdTimeout(
@@ -1657,6 +3029,71 @@ otLwfIoCtl_otNetworkIdTimeout(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otNetworkIdTimeout(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otNetworkIdTimeout_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otNetworkIdTimeout_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_NETWORK_ID_TIMEOUT)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRouterUpgradeThreshold(
@@ -1691,6 +3128,71 @@ otLwfIoCtl_otRouterUpgradeThreshold(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterUpgradeThreshold(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otRouterUpgradeThreshold_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterUpgradeThreshold_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_ROUTER_UPGRADE_THRESHOLD)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRouterDowngradeThreshold(
@@ -1725,6 +3227,71 @@ otLwfIoCtl_otRouterDowngradeThreshold(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterDowngradeThreshold(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otRouterDowngradeThreshold_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterDowngradeThreshold_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_ROUTER_DOWNGRADE_THRESHOLD)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otReleaseRouterId(
@@ -1750,6 +3317,38 @@ otLwfIoCtl_otReleaseRouterId(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otReleaseRouterId(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_REMOVE,
+ SPINEL_PROP_THREAD_ACTIVE_ROUTER_IDS,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otMacWhitelistEnabled(
@@ -1792,6 +3391,71 @@ otLwfIoCtl_otMacWhitelistEnabled(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMacWhitelistEnabled(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_MAC_WHITELIST_ENABLED,
+ sizeof(BOOLEAN),
+ SPINEL_DATATYPE_BOOL_S,
+ *(BOOLEAN*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(BOOLEAN))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otMacWhitelistEnabled_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_MAC_WHITELIST_ENABLED,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMacWhitelistEnabled_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_MAC_WHITELIST_ENABLED)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_BOOL_S, (BOOLEAN*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(BOOLEAN);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otAddMacWhitelist(
@@ -1822,6 +3486,47 @@ otLwfIoCtl_otAddMacWhitelist(
return status;
}
+#define RSSI_OVERRIDE_DISABLED 127 // Used for PROP_MAC_WHITELIST
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otAddMacWhitelist(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(otExtAddress))
+ {
+ int8_t aRssi = RSSI_OVERRIDE_DISABLED;
+ if (InBufferLength >= sizeof(otExtAddress) + sizeof(int8_t))
+ {
+ aRssi = *(int8_t*)(InBuffer + sizeof(otExtAddress));
+ }
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_INSERT,
+ SPINEL_PROP_MAC_WHITELIST,
+ sizeof(otExtAddress) + sizeof(int8_t),
+ "Ec",
+ (otExtAddress*)InBuffer,
+ &aRssi);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRemoveMacWhitelist(
@@ -1848,6 +3553,38 @@ otLwfIoCtl_otRemoveMacWhitelist(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRemoveMacWhitelist(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ if (InBufferLength >= sizeof(otExtAddress))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_REMOVE,
+ SPINEL_PROP_MAC_WHITELIST,
+ sizeof(otExtAddress),
+ "E",
+ (otExtAddress*)InBuffer);
+ }
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otMacWhitelistEntry(
@@ -1905,6 +3642,36 @@ otLwfIoCtl_otClearMacWhitelist(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otClearMacWhitelist(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_MAC_WHITELIST,
+ 0,
+ NULL);
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otDeviceRole(
@@ -1969,6 +3736,105 @@ otLwfIoCtl_otDeviceRole(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otDeviceRole(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ otDeviceRole role = *(uint8_t*)InBuffer;
+ uint8_t spinel_role = SPINEL_NET_ROLE_DETACHED;
+
+ switch (role)
+ {
+ case kDeviceRoleChild:
+ spinel_role = SPINEL_NET_ROLE_CHILD;
+ break;
+ case kDeviceRoleRouter:
+ spinel_role = SPINEL_NET_ROLE_ROUTER;
+ break;
+ case kDeviceRoleLeader:
+ spinel_role = SPINEL_NET_ROLE_LEADER;
+ break;
+ }
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_ROLE,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ spinel_role);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otDeviceRole_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_ROLE,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otDeviceRole_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_ROLE)
+ {
+ uint8_t spinel_role = 0;
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, &spinel_role))
+ {
+ switch (spinel_role)
+ {
+ default:
+ case SPINEL_NET_ROLE_DETACHED:
+ *(uint8_t*)OutBuffer = kDeviceRoleDetached;
+ break;
+ case SPINEL_NET_ROLE_CHILD:
+ *(uint8_t*)OutBuffer = kDeviceRoleChild;
+ break;
+ case SPINEL_NET_ROLE_ROUTER:
+ *(uint8_t*)OutBuffer = kDeviceRoleRouter;
+ break;
+ case SPINEL_NET_ROLE_LEADER:
+ *(uint8_t*)OutBuffer = kDeviceRoleLeader;
+ break;
+ }
+
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otChildInfoById(
@@ -2129,6 +3995,61 @@ otLwfIoCtl_otLeaderRouterId(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLeaderRouterId(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otLeaderRouterId_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_LEADER_RID,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLeaderRouterId_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_LEADER_RID)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otLeaderWeight(
@@ -2160,6 +4081,61 @@ otLwfIoCtl_otLeaderWeight(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLeaderWeight(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otLeaderWeight_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_LEADER_WEIGHT,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otLeaderWeight_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_LEADER_WEIGHT)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otNetworkDataVersion(
@@ -2191,6 +4167,61 @@ otLwfIoCtl_otNetworkDataVersion(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otNetworkDataVersion(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otNetworkDataVersion_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_NETWORK_DATA_VERSION,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otNetworkDataVersion_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_NETWORK_DATA_VERSION)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otPartitionId(
@@ -2222,6 +4253,61 @@ otLwfIoCtl_otPartitionId(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otPartitionId(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otPartitionId_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_PARTITION_ID,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otPartitionId_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_PARTITION_ID)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT32_S, (uint32_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint32_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRloc16(
@@ -2253,6 +4339,61 @@ otLwfIoCtl_otRloc16(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRloc16(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(uint16_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otRloc16_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_RLOC16,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRloc16_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_RLOC16)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT16_S, (uint16_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint16_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otRouterIdSequence(
@@ -2348,6 +4489,61 @@ otLwfIoCtl_otStableNetworkDataVersion(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otStableNetworkDataVersion(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otStableNetworkDataVersion_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otStableNetworkDataVersion_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otMacBlacklistEnabled(
@@ -2707,6 +4903,60 @@ otLwfIoCtl_otPlatformReset(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfIoCtl_otFactoryReset(
+ _In_ PMS_FILTER pFilter,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+ UNREFERENCED_PARAMETER(OutBuffer);
+ *OutBufferLength = 0;
+
+ otFactoryReset(pFilter->otCtx);
+
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otPlatformReset(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+ UNREFERENCED_PARAMETER(OutBufferLength);
+
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_RESET,
+ 0,
+ 0,
+ NULL);
+
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otParentInfo(
@@ -2738,6 +4988,63 @@ otLwfIoCtl_otParentInfo(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otParentInfo(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferLength);
+
+ if (OutBufferLength >= sizeof(otRouterInfo))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otParentInfo_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_PARENT,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otParentInfo_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_PARENT)
+ {
+ otRouterInfo* aRouterInfo = (otRouterInfo*)OutBuffer;
+ RtlZeroMemory(aRouterInfo, sizeof(otRouterInfo));
+ if (try_spinel_datatype_unpack(Data, DataLength, "ES", &aRouterInfo->mExtAddress.m8, &aRouterInfo->mRloc16))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otSingleton(
@@ -2834,6 +5141,71 @@ otLwfIoCtl_otMaxChildren(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMaxChildren(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_CHILD_COUNT_MAX,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otMaxChildren_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_CHILD_COUNT_MAX,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otMaxChildren_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_CHILD_COUNT_MAX)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otCommissionerStart(
@@ -3041,6 +5413,71 @@ otLwfIoCtl_otRouterSelectionJitter(
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterSelectionJitter(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER,
+ sizeof(uint8_t),
+ SPINEL_DATATYPE_UINT8_S,
+ *(uint8_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otRouterSelectionJitter_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otRouterSelectionJitter_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_THREAD_ROUTER_SELECTION_JITTER)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT8_S, (uint8_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint8_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
+
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
otLwfIoCtl_otJoinerUdpPort(
@@ -3139,7 +5576,7 @@ otLwfIoCtl_otSendDiagnosticReset(
if (InBufferLength >= sizeof(otIp6Address) + sizeof(uint8_t) + aCount)
{
status = ThreadErrorToNtstatus(
- otSendDiagnosticGet(
+ otSendDiagnosticReset(
pFilter->otCtx,
aAddress,
aTlvTypes,
@@ -3315,12 +5752,16 @@ otLwfIoCtl_otSendActiveGet(
if (InBufferLength >= sizeof(uint8_t) + aLength)
{
+ otIp6Address *aAddress = NULL;
+ if (InBufferLength >= sizeof(uint8_t) + aLength + sizeof(otIp6Address))
+ aAddress = (otIp6Address*)(InBuffer + sizeof(uint8_t) + aLength);
+
status = ThreadErrorToNtstatus(
otSendActiveGet(
pFilter->otCtx,
aTlvTypes,
aLength,
- NULL)
+ aAddress)
);
}
}
@@ -3390,12 +5831,16 @@ otLwfIoCtl_otSendPendingGet(
if (InBufferLength >= sizeof(uint8_t) + aLength)
{
+ otIp6Address *aAddress = NULL;
+ if (InBufferLength >= sizeof(uint8_t) + aLength + sizeof(otIp6Address))
+ aAddress = (otIp6Address*)(InBuffer + sizeof(uint8_t) + aLength);
+
status = ThreadErrorToNtstatus(
otSendPendingGet(
pFilter->otCtx,
aTlvTypes,
aLength,
- NULL)
+ aAddress)
);
}
}
@@ -3548,3 +5993,68 @@ otLwfIoCtl_otKeySwitchGuardtime(
return status;
}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otKeySwitchGuardtime(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP pIrp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (InBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ NULL,
+ SPINEL_CMD_PROP_VALUE_SET,
+ SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME,
+ sizeof(uint32_t),
+ SPINEL_DATATYPE_UINT32_S,
+ *(uint32_t*)InBuffer);
+ }
+ else if (OutBufferLength >= sizeof(uint32_t))
+ {
+ status =
+ otLwfSendTunnelCommandForIrp(
+ pFilter,
+ pIrp,
+ otLwfTunIoCtl_otKeySwitchGuardtime_Handler,
+ SPINEL_CMD_PROP_VALUE_GET,
+ SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME,
+ 0,
+ NULL);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfTunIoCtl_otKeySwitchGuardtime_Handler(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (Key == SPINEL_PROP_NET_KEY_SWITCH_GUARDTIME)
+ {
+ if (try_spinel_datatype_unpack(Data, DataLength, SPINEL_DATATYPE_UINT32_S, (uint32_t*)OutBuffer))
+ {
+ *OutBufferLength = sizeof(uint32_t);
+ status = STATUS_SUCCESS;
+ }
+ }
+ return status;
+}
diff --git a/examples/drivers/windows/otLwf/iocontrol.h b/examples/drivers/windows/otLwf/iocontrol.h
index 87807b3c7..350ffedb2 100644
--- a/examples/drivers/windows/otLwf/iocontrol.h
+++ b/examples/drivers/windows/otLwf/iocontrol.h
@@ -32,6 +32,7 @@
//
// Function prototype for general Io Control functions
//
+
typedef
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
@@ -69,9 +70,16 @@ otLwfCompleteOpenThreadIrp(
_In_ PIRP Irp
);
+// Helper for converting IoCtl to string
+const char*
+IoCtlString(
+ ULONG IoControlCode
+ );
+
//
// Function prototype for OpenThread Io Control functions
//
+
typedef
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
@@ -85,96 +93,136 @@ OTLWF_OT_IOCTL_FUNC(
_Inout_ PULONG OutBufferLength
);
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otInterface;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otThread;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otActiveScan;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otDiscover;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otChannel;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otChildTimeout;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otExtendedAddress;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otExtendedPanId;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLeaderRloc;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLinkMode;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMasterKey;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMeshLocalEid;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMeshLocalPrefix;
-//OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otNetworkDataLeader
-//OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otNetworkDataLocal
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otNetworkName;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otPanId;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRouterRollEnabled;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otShortAddress;
-//OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otUnicastAddresses
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otActiveDataset;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otPendingDataset;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLocalLeaderWeight;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otAddBorderRouter;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRemoveBorderRouter;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otAddExternalRoute;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRemoveExternalRoute;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendServerData;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otContextIdReuseDelay;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otKeySequenceCounter;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otNetworkIdTimeout;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRouterUpgradeThreshold;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otReleaseRouterId;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMacWhitelistEnabled;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otAddMacWhitelist;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRemoveMacWhitelist;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMacWhitelistEntry;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otClearMacWhitelist;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otDeviceRole;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otChildInfoById;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otChildInfoByIndex;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otEidCacheEntry;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLeaderData;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLeaderRouterId;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLeaderWeight;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otNetworkDataVersion;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otPartitionId;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRloc16;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRouterIdSequence;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRouterInfo;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otStableNetworkDataVersion;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMacBlacklistEnabled;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otAddMacBlacklist;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRemoveMacBlacklist;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMacBlacklistEntry;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otClearMacBlacklist;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMaxTransmitPower;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otNextOnMeshPrefix;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otPollPeriod;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otLocalLeaderPartitionId;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otAssignLinkQuality;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otPlatformReset;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otParentInfo;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSingleton;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMacCounters;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otMaxChildren;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerStart;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerStop;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otJoinerStart;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otJoinerStop;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otFactoryAssignedIeeeEui64;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otHashMacAddress;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRouterDowngradeThreshold;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerPanIdQuery;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerEnergyScan;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otRouterSelectionJitter;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otJoinerUdpPort;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendDiagnosticGet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendDiagnosticReset;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerAddJoiner;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerRemoveJoiner;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerProvisioningUrl;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otCommissionerAnnounceBegin;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otEnergyScan;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendActiveGet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendActiveSet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendPendingGet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendPendingSet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendMgmtCommissionerGet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otSendMgmtCommissionerSet;
-OTLWF_OT_IOCTL_FUNC otLwfIoCtl_otKeySwitchGuardtime;
+typedef
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+OTLWF_TUN_IOCTL_FUNC(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP Irp,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _In_ ULONG OutBufferLength
+ );
+
+typedef
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+(SPINEL_IRP_CMD_HANDLER)(
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ );
+
+#define DECL_IOCTL_FUNC(X) \
+ OTLWF_OT_IOCTL_FUNC otLwfIoCtl_##X
+
+#define DECL_IOCTL_FUNC_WITH_TUN(X) \
+ OTLWF_OT_IOCTL_FUNC otLwfIoCtl_##X; \
+ OTLWF_TUN_IOCTL_FUNC otLwfTunIoCtl_##X
+
+#define DECL_IOCTL_FUNC_WITH_TUN2(X) \
+ OTLWF_OT_IOCTL_FUNC otLwfIoCtl_##X; \
+ OTLWF_TUN_IOCTL_FUNC otLwfTunIoCtl_##X; \
+ SPINEL_IRP_CMD_HANDLER otLwfTunIoCtl_##X##_Handler
+
+#define REF_IOCTL_FUNC(X) otLwfIoCtl_##X , NULL
+
+#define REF_IOCTL_FUNC_WITH_TUN(X) otLwfIoCtl_##X , otLwfTunIoCtl_##X
+
+DECL_IOCTL_FUNC_WITH_TUN2(otInterface);
+DECL_IOCTL_FUNC_WITH_TUN2(otThread);
+DECL_IOCTL_FUNC_WITH_TUN2(otActiveScan);
+DECL_IOCTL_FUNC(otDiscover);
+DECL_IOCTL_FUNC_WITH_TUN2(otChannel);
+DECL_IOCTL_FUNC_WITH_TUN2(otChildTimeout);
+DECL_IOCTL_FUNC_WITH_TUN2(otExtendedAddress);
+DECL_IOCTL_FUNC_WITH_TUN2(otExtendedPanId);
+DECL_IOCTL_FUNC_WITH_TUN2(otLeaderRloc);
+DECL_IOCTL_FUNC_WITH_TUN2(otLinkMode);
+DECL_IOCTL_FUNC_WITH_TUN2(otMasterKey);
+DECL_IOCTL_FUNC_WITH_TUN2(otMeshLocalEid);
+DECL_IOCTL_FUNC_WITH_TUN2(otMeshLocalPrefix);
+//DECL_IOCTL_FUNC(otNetworkDataLeader);
+//DECL_IOCTL_FUNC(otNetworkDataLocal);
+DECL_IOCTL_FUNC_WITH_TUN2(otNetworkName);
+DECL_IOCTL_FUNC_WITH_TUN2(otPanId);
+DECL_IOCTL_FUNC_WITH_TUN2(otRouterRollEnabled);
+DECL_IOCTL_FUNC_WITH_TUN2(otShortAddress);
+DECL_IOCTL_FUNC(otActiveDataset);
+DECL_IOCTL_FUNC(otPendingDataset);
+DECL_IOCTL_FUNC_WITH_TUN2(otLocalLeaderWeight);
+DECL_IOCTL_FUNC_WITH_TUN(otAddBorderRouter);
+DECL_IOCTL_FUNC_WITH_TUN(otRemoveBorderRouter);
+DECL_IOCTL_FUNC_WITH_TUN(otAddExternalRoute);
+DECL_IOCTL_FUNC_WITH_TUN(otRemoveExternalRoute);
+DECL_IOCTL_FUNC(otSendServerData);
+DECL_IOCTL_FUNC_WITH_TUN2(otContextIdReuseDelay);
+DECL_IOCTL_FUNC_WITH_TUN2(otKeySequenceCounter);
+DECL_IOCTL_FUNC_WITH_TUN2(otNetworkIdTimeout);
+DECL_IOCTL_FUNC_WITH_TUN2(otRouterUpgradeThreshold);
+DECL_IOCTL_FUNC_WITH_TUN(otReleaseRouterId);
+DECL_IOCTL_FUNC_WITH_TUN2(otMacWhitelistEnabled);
+DECL_IOCTL_FUNC_WITH_TUN(otAddMacWhitelist);
+DECL_IOCTL_FUNC_WITH_TUN(otRemoveMacWhitelist);
+DECL_IOCTL_FUNC(otMacWhitelistEntry);
+DECL_IOCTL_FUNC_WITH_TUN(otClearMacWhitelist);
+DECL_IOCTL_FUNC_WITH_TUN2(otDeviceRole);
+DECL_IOCTL_FUNC(otChildInfoById);
+DECL_IOCTL_FUNC(otChildInfoByIndex);
+DECL_IOCTL_FUNC(otEidCacheEntry);
+DECL_IOCTL_FUNC(otLeaderData);
+DECL_IOCTL_FUNC_WITH_TUN2(otLeaderRouterId);
+DECL_IOCTL_FUNC_WITH_TUN2(otLeaderWeight);
+DECL_IOCTL_FUNC_WITH_TUN2(otNetworkDataVersion);
+DECL_IOCTL_FUNC_WITH_TUN2(otPartitionId);
+DECL_IOCTL_FUNC_WITH_TUN2(otRloc16);
+DECL_IOCTL_FUNC(otRouterIdSequence);
+DECL_IOCTL_FUNC(otRouterInfo);
+DECL_IOCTL_FUNC_WITH_TUN2(otStableNetworkDataVersion);
+DECL_IOCTL_FUNC(otMacBlacklistEnabled);
+DECL_IOCTL_FUNC(otAddMacBlacklist);
+DECL_IOCTL_FUNC(otRemoveMacBlacklist);
+DECL_IOCTL_FUNC(otMacBlacklistEntry);
+DECL_IOCTL_FUNC(otClearMacBlacklist);
+DECL_IOCTL_FUNC(otMaxTransmitPower);
+DECL_IOCTL_FUNC(otNextOnMeshPrefix);
+DECL_IOCTL_FUNC(otPollPeriod);
+DECL_IOCTL_FUNC(otLocalLeaderPartitionId);
+DECL_IOCTL_FUNC(otAssignLinkQuality);
+DECL_IOCTL_FUNC_WITH_TUN(otPlatformReset);
+DECL_IOCTL_FUNC_WITH_TUN2(otParentInfo);
+DECL_IOCTL_FUNC(otSingleton);
+DECL_IOCTL_FUNC(otMacCounters);
+DECL_IOCTL_FUNC_WITH_TUN2(otMaxChildren);
+DECL_IOCTL_FUNC(otCommissionerStart);
+DECL_IOCTL_FUNC(otCommissionerStop);
+DECL_IOCTL_FUNC(otJoinerStart);
+DECL_IOCTL_FUNC(otJoinerStop);
+DECL_IOCTL_FUNC(otFactoryAssignedIeeeEui64);
+DECL_IOCTL_FUNC(otHashMacAddress);
+DECL_IOCTL_FUNC_WITH_TUN2(otRouterDowngradeThreshold);
+DECL_IOCTL_FUNC(otCommissionerPanIdQuery);
+DECL_IOCTL_FUNC(otCommissionerEnergyScan);
+DECL_IOCTL_FUNC_WITH_TUN2(otRouterSelectionJitter);
+DECL_IOCTL_FUNC(otJoinerUdpPort);
+DECL_IOCTL_FUNC(otSendDiagnosticGet);
+DECL_IOCTL_FUNC(otSendDiagnosticReset);
+DECL_IOCTL_FUNC(otCommissionerAddJoiner);
+DECL_IOCTL_FUNC(otCommissionerRemoveJoiner);
+DECL_IOCTL_FUNC(otCommissionerProvisioningUrl);
+DECL_IOCTL_FUNC(otCommissionerAnnounceBegin);
+DECL_IOCTL_FUNC_WITH_TUN2(otEnergyScan);
+DECL_IOCTL_FUNC(otSendActiveGet);
+DECL_IOCTL_FUNC(otSendActiveSet);
+DECL_IOCTL_FUNC(otSendPendingGet);
+DECL_IOCTL_FUNC(otSendPendingSet);
+DECL_IOCTL_FUNC(otSendMgmtCommissionerGet);
+DECL_IOCTL_FUNC(otSendMgmtCommissionerSet);
+DECL_IOCTL_FUNC_WITH_TUN2(otKeySwitchGuardtime);
+DECL_IOCTL_FUNC(otFactoryReset);
#endif // _IOCONTROL_H
diff --git a/examples/drivers/windows/otLwf/precomp.h b/examples/drivers/windows/otLwf/precomp.h
index be0dec0ff..7126b4ebe 100644
--- a/examples/drivers/windows/otLwf/precomp.h
+++ b/examples/drivers/windows/otLwf/precomp.h
@@ -72,6 +72,7 @@ RtlCopyBufferToMdl(
#include
#include
#include
+#include
#include
#include
@@ -89,7 +90,22 @@ RtlCopyBufferToMdl(
typedef struct _MS_FILTER MS_FILTER, *PMS_FILTER;
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct UDPHeader
+{
+ USHORT SourcePort;
+ USHORT DestinationPort;
+ USHORT TotalLength;
+ USHORT Checksum;
+
+} UDPHeader;
+
+#pragma pack(pop)
+
//#define DEBUG_TIMING
+//#define DEBUG_ALLOC
//#define LOG_BUFFERS
//#define FORCE_SYNCHRONOUS_RECEIVE
@@ -99,3 +115,5 @@ typedef struct _MS_FILTER MS_FILTER, *PMS_FILTER;
#include "oid.h"
#include "radio.h"
#include "filter.h"
+#include "thread.h"
+#include "tunnel.h"
diff --git a/examples/drivers/windows/otLwf/thread.c b/examples/drivers/windows/otLwf/thread.c
new file mode 100644
index 000000000..2fbb1c853
--- /dev/null
+++ b/examples/drivers/windows/otLwf/thread.c
@@ -0,0 +1,533 @@
+/*
+ * 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 implements the Thread mode (Radio Miniport) functions required for the OpenThread library.
+ */
+
+#include "precomp.h"
+#include "thread.tmh"
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+otLwfInitializeThreadMode(
+ _In_ PMS_FILTER pFilter
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PNET_BUFFER SendNetBuffer;
+
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ do
+ {
+ // Create the SendNetBufferList
+ pFilter->SendNetBufferList =
+ NdisAllocateNetBufferAndNetBufferList(
+ pFilter->NetBufferListPool, // PoolHandle
+ 0, // ContextSize
+ 0, // ContextBackFill
+ NULL, // MdlChain
+ 0, // DataOffset
+ 0 // DataLength
+ );
+ if (pFilter->SendNetBufferList == NULL)
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ LogWarning(DRIVER_DEFAULT, "Failed to create Send NetBufferList");
+ break;
+ }
+
+ // Initialize NetBuffer fields
+ SendNetBuffer = NET_BUFFER_LIST_FIRST_NB(pFilter->SendNetBufferList);
+ NET_BUFFER_CURRENT_MDL(SendNetBuffer) = NULL;
+ NET_BUFFER_CURRENT_MDL_OFFSET(SendNetBuffer) = 0;
+ NET_BUFFER_DATA_LENGTH(SendNetBuffer) = 0;
+ NET_BUFFER_DATA_OFFSET(SendNetBuffer) = 0;
+ NET_BUFFER_FIRST_MDL(SendNetBuffer) = NULL;
+
+ // Allocate the NetBuffer for SendNetBufferList
+ Status = NdisRetreatNetBufferDataStart(SendNetBuffer, kMaxPHYPacketSize, 0, NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(DRIVER_DEFAULT, "Failed to allocate NB for Send NetBufferList, %!NDIS_STATUS!", Status);
+ break;
+ }
+
+ KeInitializeEvent(
+ &pFilter->SendNetBufferListComplete,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+
+ // Initialize the event processing
+ pFilter->EventWorkerThread = NULL;
+ NdisAllocateSpinLock(&pFilter->EventsLock);
+ InitializeListHead(&pFilter->AddressChangesHead);
+ InitializeListHead(&pFilter->NBLsHead);
+ InitializeListHead(&pFilter->EventIrpListHead);
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadStopEvent,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadWaitTimeUpdated,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadProcessTasklets,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadProcessAddressChanges,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadProcessNBLs,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadProcessIrp,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->EventWorkerThreadEnergyScanComplete,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ pFilter->EventHighPrecisionTimer =
+ ExAllocateTimer(
+ otLwfEventProcessingTimer,
+ pFilter,
+ EX_TIMER_HIGH_RESOLUTION
+ );
+ if (pFilter->EventHighPrecisionTimer == NULL)
+ {
+ LogError(DRIVER_DEFAULT, "Failed to allocate timer!");
+ break;
+ }
+
+ // Initialize the event processing thread
+ if (!NT_SUCCESS(otLwfEventProcessingStart(pFilter)))
+ {
+ Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ } while (FALSE);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // Stop event processing thread
+ otLwfEventProcessingStop(pFilter);
+
+ // Stop and free the timer
+ if (pFilter->EventHighPrecisionTimer)
+ {
+ ExDeleteTimer(pFilter->EventHighPrecisionTimer, TRUE, FALSE, NULL);
+ }
+
+ // Free NBL
+ if (pFilter->SendNetBufferList)
+ {
+ NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pFilter->SendNetBufferList), kMaxPHYPacketSize, TRUE, NULL);
+ NdisFreeNetBufferList(pFilter->SendNetBufferList);
+ }
+ }
+
+ LogFuncExitNDIS(DRIVER_DEFAULT, Status);
+
+ return Status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+otLwfUninitializeThreadMode(
+ _In_ PMS_FILTER pFilter
+ )
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ // Stop event processing thread
+ otLwfEventProcessingStop(pFilter);
+
+ // Free timer
+ ExDeleteTimer(pFilter->EventHighPrecisionTimer, TRUE, FALSE, NULL);
+
+ // Free NBL & Pools
+ NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pFilter->SendNetBufferList), kMaxPHYPacketSize, TRUE, NULL);
+ NdisFreeNetBufferList(pFilter->SendNetBufferList);
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+#if DEBUG_ALLOC
+PMS_FILTER
+otLwfFindFromCurrentThread()
+{
+ PMS_FILTER pOutput = NULL;
+ HANDLE CurThreadId = PsGetCurrentThreadId();
+
+ NdisAcquireSpinLock(&FilterListLock);
+
+ for (PLIST_ENTRY Link = FilterModuleList.Flink; Link != &FilterModuleList; Link = Link->Flink)
+ {
+ PMS_FILTER pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);
+
+ if (pFilter->otThreadId == CurThreadId)
+ {
+ pOutput = pFilter;
+ break;
+ }
+ }
+
+ NdisReleaseSpinLock(&FilterListLock);
+
+ NT_ASSERT(pOutput);
+ return pOutput;
+}
+#endif
+
+//
+// OpenThread Platform functions
+//
+
+void *otPlatCAlloc(size_t aNum, size_t aSize)
+{
+ size_t totalSize = aNum * aSize;
+#if DEBUG_ALLOC
+ totalSize += sizeof(OT_ALLOC);
+#endif
+ PVOID mem = ExAllocatePoolWithTag(NonPagedPoolNx, totalSize, 'OTDM');
+ if (mem)
+ {
+ RtlZeroMemory(mem, totalSize);
+#if DEBUG_ALLOC
+ PMS_FILTER pFilter = otLwfFindFromCurrentThread();
+ //LogVerbose(DRIVER_DEFAULT, "otPlatAlloc(%u) = ID:%u %p", (ULONG)totalSize, pFilter->otAllocationID, mem);
+
+ OT_ALLOC* AllocHeader = (OT_ALLOC*)mem;
+ AllocHeader->Length = (LONG)totalSize;
+ AllocHeader->ID = pFilter->otAllocationID++;
+ InsertTailList(&pFilter->otOutStandingAllocations, &AllocHeader->Link);
+
+ InterlockedIncrement(&pFilter->otOutstandingAllocationCount);
+ InterlockedAdd(&pFilter->otOutstandingMemoryAllocated, AllocHeader->Length);
+
+ mem = (PUCHAR)(mem) + sizeof(OT_ALLOC);
+#endif
+ }
+ return mem;
+}
+
+void otPlatFree(void *aPtr)
+{
+ if (aPtr == NULL) return;
+#if DEBUG_ALLOC
+ aPtr = (PUCHAR)(aPtr) - sizeof(OT_ALLOC);
+ //LogVerbose(DRIVER_DEFAULT, "otPlatFree(%p)", aPtr);
+ OT_ALLOC* AllocHeader = (OT_ALLOC*)aPtr;
+
+ PMS_FILTER pFilter = otLwfFindFromCurrentThread();
+ InterlockedDecrement(&pFilter->otOutstandingAllocationCount);
+ InterlockedAdd(&pFilter->otOutstandingMemoryAllocated, -AllocHeader->Length);
+ RemoveEntryList(&AllocHeader->Link);
+#endif
+ ExFreePoolWithTag(aPtr, 'OTDM');
+}
+
+uint32_t otPlatRandomGet()
+{
+ LARGE_INTEGER Counter = KeQueryPerformanceCounter(NULL);
+ return (uint32_t)RtlRandomEx(&Counter.LowPart);
+}
+
+ThreadError otPlatRandomSecureGet(uint16_t aInputLength, uint8_t *aOutput, uint16_t *aOutputLength)
+{
+ // Just use the system-preferred random number generator algorithm
+ NTSTATUS status =
+ BCryptGenRandom(
+ NULL,
+ aOutput,
+ (ULONG)aInputLength,
+ BCRYPT_USE_SYSTEM_PREFERRED_RNG
+ );
+ NT_ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ LogError(DRIVER_DEFAULT, "BCryptGenRandom failed, %!STATUS!", status);
+ return kThreadError_Failed;
+ }
+
+ *aOutputLength = aInputLength;
+
+ return kThreadError_None;
+}
+
+void otSignalTaskletPending(_In_ otInstance *otCtx)
+{
+ LogVerbose(DRIVER_DEFAULT, "otSignalTaskletPending");
+ PMS_FILTER pFilter = otCtxToFilter(otCtx);
+ otLwfEventProcessingIndicateNewTasklet(pFilter);
+}
+
+// Process a role state change
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfProcessRoleStateChange(
+ _In_ PMS_FILTER pFilter
+ )
+{
+ otDeviceRole prevRole = pFilter->otCachedRole;
+ pFilter->otCachedRole = otGetDeviceRole(pFilter->otCtx);
+ if (prevRole == pFilter->otCachedRole) return;
+
+ LogInfo(DRIVER_DEFAULT, "Interface %!GUID! new role: %!otDeviceRole!", &pFilter->InterfaceGuid, pFilter->otCachedRole);
+
+ // Make sure we are in the correct media connect state
+ otLwfIndicateLinkState(
+ pFilter,
+ IsAttached(pFilter->otCachedRole) ?
+ MediaConnectStateConnected :
+ MediaConnectStateDisconnected);
+}
+
+void otLwfStateChangedCallback(uint32_t aFlags, _In_ void *aContext)
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PMS_FILTER pFilter = (PMS_FILTER)aContext;
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+
+ //
+ // Process the notification internally
+ //
+
+ if ((aFlags & OT_IP6_ADDRESS_ADDED) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_IP6_ADDRESS_ADDED", pFilter);
+ otLwfRadioAddressesUpdated(pFilter);
+ }
+
+ if ((aFlags & OT_IP6_ADDRESS_REMOVED) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_IP6_ADDRESS_REMOVED", pFilter);
+ otLwfRadioAddressesUpdated(pFilter);
+ }
+
+ if ((aFlags & OT_NET_ROLE) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_NET_ROLE", pFilter);
+ otLwfProcessRoleStateChange(pFilter);
+ }
+
+ if ((aFlags & OT_NET_PARTITION_ID) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_NET_PARTITION_ID", pFilter);
+ }
+
+ if ((aFlags & OT_NET_KEY_SEQUENCE_COUNTER) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_NET_KEY_SEQUENCE_COUNTER", pFilter);
+ }
+
+ if ((aFlags & OT_THREAD_CHILD_ADDED) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_CHILD_ADDED", pFilter);
+ }
+
+ if ((aFlags & OT_THREAD_CHILD_REMOVED) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_CHILD_REMOVED", pFilter);
+ }
+
+ if ((aFlags & OT_THREAD_NETDATA_UPDATED) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_NETDATA_UPDATED", pFilter);
+ otSlaacUpdate(pFilter->otCtx, pFilter->otAutoAddresses, ARRAYSIZE(pFilter->otAutoAddresses), otCreateRandomIid, NULL);
+ }
+
+ if ((aFlags & OT_IP6_ML_ADDR_CHANGED) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_IP6_ML_ADDR_CHANGED", pFilter);
+ }
+
+ //
+ // Queue the notification for clients
+ //
+
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_STATE_CHANGE;
+ NotifEntry->Notif.StateChangePayload.Flags = aFlags;
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+void otLwfActiveScanCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext)
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PMS_FILTER pFilter = (PMS_FILTER)aContext;
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_ACTIVE_SCAN;
+
+ if (aResult)
+ {
+ NotifEntry->Notif.ActiveScanPayload.Valid = TRUE;
+ NotifEntry->Notif.ActiveScanPayload.Results = *aResult;
+ }
+ else
+ {
+ NotifEntry->Notif.ActiveScanPayload.Valid = FALSE;
+ }
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+void otLwfEnergyScanCallback(_In_ otEnergyScanResult *aResult, _In_ void *aContext)
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PMS_FILTER pFilter = (PMS_FILTER)aContext;
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_ENERGY_SCAN;
+
+ if (aResult)
+ {
+ NotifEntry->Notif.EnergyScanPayload.Valid = TRUE;
+ NotifEntry->Notif.EnergyScanPayload.Results = *aResult;
+ }
+ else
+ {
+ NotifEntry->Notif.EnergyScanPayload.Valid = FALSE;
+ }
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+void otLwfDiscoverCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext)
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PMS_FILTER pFilter = (PMS_FILTER)aContext;
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_DISCOVER;
+
+ if (aResult)
+ {
+ NotifEntry->Notif.DiscoverPayload.Valid = TRUE;
+ NotifEntry->Notif.DiscoverPayload.Results = *aResult;
+ }
+ else
+ {
+ NotifEntry->Notif.DiscoverPayload.Valid = FALSE;
+ }
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+void otLwfCommissionerEnergyReportCallback(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength, void *aContext)
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PMS_FILTER pFilter = (PMS_FILTER)aContext;
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_COMMISSIONER_ENERGY_REPORT;
+
+ // Limit the number of reports if necessary
+ if (aEnergyListLength > MAX_ENERGY_REPORT_LENGTH) aEnergyListLength = MAX_ENERGY_REPORT_LENGTH;
+
+ NotifEntry->Notif.CommissionerEnergyReportPayload.ChannelMask = aChannelMask;
+ NotifEntry->Notif.CommissionerEnergyReportPayload.EnergyListLength = aEnergyListLength;
+ memcpy(NotifEntry->Notif.CommissionerEnergyReportPayload.EnergyList, aEnergyList, aEnergyListLength);
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+void otLwfCommissionerPanIdConflictCallback(uint16_t aPanId, uint32_t aChannelMask, _In_ void *aContext)
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PMS_FILTER pFilter = (PMS_FILTER)aContext;
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_COMMISSIONER_PANID_QUERY;
+
+ NotifEntry->Notif.CommissionerPanIdQueryPayload.PanId = aPanId;
+ NotifEntry->Notif.CommissionerPanIdQueryPayload.ChannelMask = aChannelMask;
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
diff --git a/examples/drivers/windows/otLwf/thread.h b/examples/drivers/windows/otLwf/thread.h
new file mode 100644
index 000000000..c0b77a9a0
--- /dev/null
+++ b/examples/drivers/windows/otLwf/thread.h
@@ -0,0 +1,148 @@
+/*
+ * 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 functions for the otLwf Filter Thread mode.
+ */
+
+#ifndef _THREAD_H_
+#define _THREAD_H_
+
+// Helper function that converts an otInstance pointer to a MS_FILTER pointer
+__inline PMS_FILTER otCtxToFilter(_In_ otInstance* otCtx)
+{
+ return *(PMS_FILTER*)((PUCHAR)otCtx - sizeof(PMS_FILTER));
+}
+
+// Helper function to indicate if a role means it is attached or not
+_inline BOOLEAN IsAttached(_In_ otDeviceRole role)
+{
+ return role > kDeviceRoleDetached;
+}
+
+//
+// Initialization functions
+//
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+otLwfInitializeThreadMode(
+ _In_ PMS_FILTER pFilter
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+otLwfUninitializeThreadMode(
+ _In_ PMS_FILTER pFilter
+ );
+
+//
+// Event Processing Functions
+//
+
+EXT_CALLBACK otLwfEventProcessingTimer;
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfEventProcessingStart(
+ _In_ PMS_FILTER pFilter
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfEventProcessingStop(
+ _In_ PMS_FILTER pFilter
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfEventProcessingIndicateNewWaitTime(
+ _In_ PMS_FILTER pFilter,
+ _In_ ULONG waitTime
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfEventProcessingIndicateNewTasklet(
+ _In_ PMS_FILTER pFilter
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfEventProcessingIndicateAddressChange(
+ _In_ PMS_FILTER pFilter,
+ _In_ MIB_NOTIFICATION_TYPE NotificationType,
+ _In_ PIN6_ADDR pAddr
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfEventProcessingIndicateNewNetBufferLists(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ BOOLEAN Received,
+ _In_ NDIS_PORT_NUMBER PortNumber,
+ _In_ PNET_BUFFER_LIST NetBufferLists
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfEventProcessingIndicateNetBufferListsCancelled(
+ _In_ PMS_FILTER pFilter,
+ _In_ PVOID CancelId
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+otLwfEventProcessingIndicateIrp(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP Irp
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfEventProcessingIndicateEnergyScanResult(
+ _In_ PMS_FILTER pFilter,
+ _In_ CHAR MaxRssi
+ );
+
+//
+// OpenThread callbacks
+//
+
+void otLwfStateChangedCallback(uint32_t aFlags, _In_ void *aContext);
+void otLwfReceiveIp6DatagramCallback(_In_ otMessage aMessage, _In_ void *aContext);
+void otLwfActiveScanCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext);
+void otLwfEnergyScanCallback(_In_ otEnergyScanResult *aResult, _In_ void *aContext);
+void otLwfDiscoverCallback(_In_ otActiveScanResult *aResult, _In_ void *aContext);
+void otLwfCommissionerEnergyReportCallback(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength, void *aContext);
+void otLwfCommissionerPanIdConflictCallback(uint16_t aPanId, uint32_t aChannelMask, _In_ void *aContext);
+
+#endif //_THREAD_H_
diff --git a/examples/drivers/windows/otLwf/tunnel.c b/examples/drivers/windows/otLwf/tunnel.c
new file mode 100644
index 000000000..de81d825a
--- /dev/null
+++ b/examples/drivers/windows/otLwf/tunnel.c
@@ -0,0 +1,1731 @@
+/*
+ * 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 implements the Tunnel mode (Thread Miniport) functions required for the OpenThread library.
+ */
+
+#include "precomp.h"
+#include "tunnel.tmh"
+
+KSTART_ROUTINE otLwfTunWorkerThread;
+
+ThreadError
+SpinelStatusToThreadError(
+ spinel_status_t error
+ )
+{
+ ThreadError ret;
+
+ switch (error)
+ {
+ case SPINEL_STATUS_OK:
+ ret = kThreadError_None;
+ break;
+
+ case SPINEL_STATUS_FAILURE:
+ ret = kThreadError_Failed;
+ break;
+
+ case SPINEL_STATUS_DROPPED:
+ ret = kThreadError_Drop;
+ break;
+
+ case SPINEL_STATUS_NOMEM:
+ ret = kThreadError_NoBufs;
+ break;
+
+ case SPINEL_STATUS_BUSY:
+ ret = kThreadError_Busy;
+ break;
+
+ case SPINEL_STATUS_PARSE_ERROR:
+ ret = kThreadError_Parse;
+ break;
+
+ case SPINEL_STATUS_INVALID_ARGUMENT:
+ ret = kThreadError_InvalidArgs;
+ break;
+
+ case SPINEL_STATUS_UNIMPLEMENTED:
+ ret = kThreadError_NotImplemented;
+ break;
+
+ case SPINEL_STATUS_INVALID_STATE:
+ ret = kThreadError_InvalidState;
+ break;
+
+ case SPINEL_STATUS_NO_ACK:
+ ret = kThreadError_NoAck;
+ break;
+
+ case SPINEL_STATUS_CCA_FAILURE:
+ ret = kThreadError_ChannelAccessFailure;
+ break;
+
+ case SPINEL_STATUS_ALREADY:
+ ret = kThreadError_Already;
+ break;
+
+ case SPINEL_STATUS_ITEM_NOT_FOUND:
+ ret = kThreadError_NotFound;
+ break;
+
+ default:
+ if (error >= SPINEL_STATUS_STACK_NATIVE__BEGIN && error <= SPINEL_STATUS_STACK_NATIVE__END)
+ {
+ ret = (ThreadError)(error - SPINEL_STATUS_STACK_NATIVE__BEGIN);
+ }
+ else
+ {
+ ret = kThreadError_Failed;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+otLwfInitializeTunnelMode(
+ _In_ PMS_FILTER pFilter
+ )
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ uint32_t InterfaceType = 0;
+ HANDLE threadHandle = NULL;
+
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ pFilter->tunTIDsInUse = 0;
+ pFilter->tunNextTID = 1;
+
+ NdisAllocateSpinLock(&pFilter->tunCommandLock);
+ InitializeListHead(&pFilter->tunCommandHandlers);
+
+ KeInitializeEvent(
+ &pFilter->TunWorkerThreadStopEvent,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+ KeInitializeEvent(
+ &pFilter->TunWorkerThreadAddressChangedEvent,
+ SynchronizationEvent, // auto-clearing event
+ FALSE // event initially non-signalled
+ );
+
+ // Start the worker thread
+ Status = PsCreateSystemThread(
+ &threadHandle, // ThreadHandle
+ THREAD_ALL_ACCESS, // DesiredAccess
+ NULL, // ObjectAttributes
+ NULL, // ProcessHandle
+ NULL, // ClientId
+ otLwfTunWorkerThread, // StartRoutine
+ pFilter // StartContext
+ );
+ if (!NT_SUCCESS(Status))
+ {
+ LogError(DRIVER_DEFAULT, "PsCreateSystemThread failed, %!STATUS!", Status);
+ goto error;
+ }
+
+ // Grab the object reference to the worker thread
+ Status = ObReferenceObjectByHandle(
+ threadHandle,
+ THREAD_ALL_ACCESS,
+ *PsThreadType,
+ KernelMode,
+ &pFilter->TunWorkerThread,
+ NULL
+ );
+ if (!NT_VERIFYMSG("ObReferenceObjectByHandle can't fail with a valid kernel handle", NT_SUCCESS(Status)))
+ {
+ LogError(DRIVER_DEFAULT, "ObReferenceObjectByHandle failed, %!STATUS!", Status);
+ KeSetEvent(&pFilter->TunWorkerThreadStopEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ // Query the interface type to make sure it is a Thread device
+ Status = otLwfGetTunProp(pFilter, NULL, SPINEL_PROP_INTERFACE_TYPE, SPINEL_DATATYPE_UINT_PACKED_S, &InterfaceType);
+ if (!NT_SUCCESS(Status))
+ {
+ LogError(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_INTERFACE_TYPE, %!STATUS!", Status);
+ goto error;
+ }
+ if (InterfaceType != SPINEL_PROTOCOL_TYPE_THREAD)
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ LogError(DRIVER_DEFAULT, "SPINEL_PROP_INTERFACE_TYPE is invalid, %d", InterfaceType);
+ goto error;
+ }
+
+ // TODO - Query other values and capabilities
+
+error:
+
+ if (!NT_SUCCESS(Status))
+ {
+ otLwfUninitializeTunnelMode(pFilter);
+ }
+
+ LogFuncExitNDIS(DRIVER_DEFAULT, Status);
+
+ return Status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+otLwfUninitializeTunnelMode(
+ _In_ PMS_FILTER pFilter
+ )
+{
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ // Clean up worker thread
+ if (pFilter->TunWorkerThread)
+ {
+ LogInfo(DRIVER_DEFAULT, "Stopping tunnel worker thread and waiting for it to complete.");
+
+ // Send event to shutdown worker thread
+ KeSetEvent(&pFilter->TunWorkerThreadStopEvent, 0, FALSE);
+
+ // Wait for worker thread to finish
+ KeWaitForSingleObject(
+ pFilter->TunWorkerThread,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ // Free worker thread
+ ObDereferenceObject(pFilter->TunWorkerThread);
+ pFilter->TunWorkerThread = NULL;
+
+ LogInfo(DRIVER_DEFAULT, "Tunnel worker thread cleaned up.");
+ }
+
+ // TODO - Clean up command handlers
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+// Worker thread for processing all tunnel events
+_Use_decl_annotations_
+VOID
+otLwfTunWorkerThread(
+ PVOID Context
+ )
+{
+ PMS_FILTER pFilter = (PMS_FILTER)Context;
+ NT_ASSERT(pFilter);
+
+ LogFuncEntry(DRIVER_DEFAULT);
+
+ PKEVENT WaitEvents[] =
+ {
+ &pFilter->TunWorkerThreadStopEvent,
+ &pFilter->TunWorkerThreadAddressChangedEvent
+ };
+
+ LogFuncExit(DRIVER_DEFAULT);
+
+ while (true)
+ {
+ // Wait for event to stop or process event to fire
+ NTSTATUS status =
+ KeWaitForMultipleObjects(
+ ARRAYSIZE(WaitEvents),
+ (PVOID*)WaitEvents,
+ WaitAny,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL,
+ NULL);
+
+ // If it is the first event, then we are shutting down. Exit loop and terminate thread
+ if (status == STATUS_WAIT_0)
+ {
+ LogInfo(DRIVER_DEFAULT, "Received tunnel worker thread shutdown event.");
+ break;
+ }
+ else if (status == STATUS_WAIT_0 + 1) // TunWorkerThreadAddressChangedEvent fired
+ {
+ PVOID DataBuffer = NULL;
+ const uint8_t* value_data_ptr = NULL;
+ spinel_size_t value_data_len = 0;
+
+ // Query the current addresses
+ status =
+ otLwfGetTunProp(
+ pFilter,
+ &DataBuffer,
+ SPINEL_PROP_IPV6_ADDRESS_TABLE,
+ SPINEL_DATATYPE_DATA_S,
+ &value_data_ptr,
+ &value_data_len);
+ if (NT_SUCCESS(status))
+ {
+ uint32_t aNotifFlags = 0;
+ otLwfTunAddressesUpdated(pFilter, value_data_ptr, value_data_len, &aNotifFlags);
+
+ // Send notification
+ if (aNotifFlags != 0)
+ {
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_STATE_CHANGE;
+ NotifEntry->Notif.StateChangePayload.Flags = aNotifFlags;
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+ }
+ }
+ else
+ {
+ LogWarning(DRIVER_DEFAULT, "Failed to query addresses, %!STATUS!", status);
+ }
+
+ if (DataBuffer) FILTER_FREE_MEM(DataBuffer);
+ }
+ else
+ {
+ LogWarning(DRIVER_DEFAULT, "Unexpected wait result, %!STATUS!", status);
+ }
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfProcessSpinelValueIs(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ spinel_prop_key_t key,
+ _In_reads_bytes_(value_data_len) const uint8_t* value_data_ptr,
+ _In_ spinel_size_t value_data_len
+ )
+{
+ uint32_t aNotifFlags = 0;
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "[%p] received Value for %s", pFilter, spinel_prop_key_to_cstr(key));
+
+ if (key == SPINEL_PROP_LAST_STATUS)
+ {
+ spinel_status_t status = SPINEL_STATUS_OK;
+ spinel_datatype_unpack(value_data_ptr, value_data_len, "i", &status);
+
+ LogWarning(DRIVER_DEFAULT, "[%p] received %d for SPINEL_PROP_LAST_STATUS", pFilter, status);
+
+ if ((status >= SPINEL_STATUS_RESET__BEGIN) && (status <= SPINEL_STATUS_RESET__END))
+ {
+ LogInfo(DRIVER_DEFAULT, "Interface %!GUID! was reset.", &pFilter->InterfaceGuid);
+ // TODO - Handle reset
+ }
+ }
+ else if (key == SPINEL_PROP_NET_ROLE)
+ {
+ uint8_t value;
+ spinel_datatype_unpack(value_data_ptr, value_data_len, SPINEL_DATATYPE_UINT8_S, &value);
+
+ LogInfo(DRIVER_DEFAULT, "Interface %!GUID! new spinel role: %u", &pFilter->InterfaceGuid, value);
+
+ // Make sure we are in the correct media connect state
+ otLwfIndicateLinkState(
+ pFilter,
+ value > SPINEL_NET_ROLE_DETACHED ?
+ MediaConnectStateConnected :
+ MediaConnectStateDisconnected);
+
+ // Set flag to indicate we should send a notification
+ aNotifFlags = OT_NET_ROLE;
+ }
+ else if (key == SPINEL_PROP_IPV6_LL_ADDR)
+ {
+ // Set flag to indicate we should send a notification
+ aNotifFlags = OT_IP6_LL_ADDR_CHANGED;
+ }
+ else if (key == SPINEL_PROP_IPV6_ML_ADDR)
+ {
+ // Set flag to indicate we should send a notification
+ aNotifFlags = OT_IP6_ML_ADDR_CHANGED;
+ }
+ else if (key == SPINEL_PROP_NET_PARTITION_ID)
+ {
+ // Set flag to indicate we should send a notification
+ aNotifFlags = OT_NET_PARTITION_ID;
+ }
+ else if (key == SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER)
+ {
+ // Set flag to indicate we should send a notification
+ aNotifFlags = OT_NET_KEY_SEQUENCE_COUNTER;
+ }
+ else if (key == SPINEL_PROP_IPV6_ADDRESS_TABLE)
+ {
+ KeSetEvent(&pFilter->TunWorkerThreadAddressChangedEvent, IO_NO_INCREMENT, FALSE);
+ }
+ else if (key == SPINEL_PROP_THREAD_CHILD_TABLE)
+ {
+ // TODO - Update cached children
+ // TODO - Send notification
+ }
+ else if (key == SPINEL_PROP_THREAD_ON_MESH_NETS)
+ {
+ // TODO - Slaac
+
+ // Set flag to indicate we should send a notification
+ aNotifFlags = OT_THREAD_NETDATA_UPDATED;
+ }
+ else if ((key == SPINEL_PROP_STREAM_NET) || (key == SPINEL_PROP_STREAM_NET_INSECURE))
+ {
+ const uint8_t* frame_ptr = NULL;
+ UINT frame_len = 0;
+ spinel_ssize_t ret;
+
+ ret = spinel_datatype_unpack(
+ value_data_ptr,
+ value_data_len,
+ SPINEL_DATATYPE_DATA_S SPINEL_DATATYPE_DATA_S,
+ &frame_ptr,
+ &frame_len,
+ NULL,
+ NULL);
+
+ NT_ASSERT(ret > 0);
+ if (ret > 0)
+ {
+ otLwfProcessSpinelIPv6Packet(
+ pFilter,
+ DispatchLevel,
+ (SPINEL_PROP_STREAM_NET_INSECURE == key) ? FALSE : TRUE,
+ frame_ptr,
+ frame_len);
+ }
+ }
+ else if (key == SPINEL_PROP_MAC_SCAN_STATE)
+ {
+ // TODO - If pending scan, send notification of completion
+ }
+ else if (key == SPINEL_PROP_STREAM_RAW)
+ {
+ // May be used in the future
+ }
+ else if (key == SPINEL_PROP_STREAM_DEBUG)
+ {
+ const uint8_t* output = NULL;
+ UINT output_len = 0;
+ spinel_ssize_t ret;
+
+ ret = spinel_datatype_unpack(
+ value_data_ptr,
+ value_data_len,
+ SPINEL_DATATYPE_DATA_S,
+ &output,
+ &output_len);
+
+ NT_ASSERT(ret > 0);
+ if (ret > 0 && output && output_len <= (UINT)ret)
+ {
+ if (strnlen((char*)output, output_len) != output_len)
+ {
+ LogInfo(DRIVER_DEFAULT, "DEBUG_STREAM: %s", (char*)output);
+ }
+ else if (output_len < 128)
+ {
+ char strOutput[128] = {0};
+ memcpy(strOutput, output, output_len);
+ LogInfo(DRIVER_DEFAULT, "DEBUG_STREAM: %s", strOutput);
+ }
+ }
+ }
+
+ // Send notification
+ if (aNotifFlags != 0)
+ {
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_STATE_CHANGE;
+ NotifEntry->Notif.StateChangePayload.Flags = aNotifFlags;
+
+ otLwfIndicateNotification(NotifEntry);
+ }
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfProcessSpinelValueInserted(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ spinel_prop_key_t key,
+ _In_reads_bytes_(value_data_len) const uint8_t* value_data_ptr,
+ _In_ spinel_size_t value_data_len
+ )
+{
+ LogFuncEntryMsg(DRIVER_DEFAULT, "[%p] received Value Inserted for %s", pFilter, spinel_prop_key_to_cstr(key));
+
+ UNREFERENCED_PARAMETER(pFilter);
+ UNREFERENCED_PARAMETER(DispatchLevel);
+ UNREFERENCED_PARAMETER(value_data_ptr);
+ UNREFERENCED_PARAMETER(value_data_len);
+
+ if (key == SPINEL_PROP_MAC_SCAN_BEACON)
+ {
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_ACTIVE_SCAN;
+ NotifEntry->Notif.ActiveScanPayload.Valid = TRUE;
+
+ const uint8_t *aExtAddr = NULL;
+ const uint8_t *aExtPanId = NULL;
+ const char *aNetworkName = NULL;
+ unsigned int xpanid_len = 0;
+
+ //chan,rssi,(laddr,saddr,panid,lqi),(proto,flags,networkid,xpanid) [CcT(ESSC)T(iCUD.).]
+ if (try_spinel_datatype_unpack(
+ value_data_ptr,
+ value_data_len,
+ "CcT(ESSC.)T(iCUD.).",
+ &NotifEntry->Notif.ActiveScanPayload.Results.mChannel,
+ &NotifEntry->Notif.ActiveScanPayload.Results.mRssi,
+ &aExtAddr,
+ NULL, // saddr (don't care)
+ &NotifEntry->Notif.ActiveScanPayload.Results.mPanId,
+ &NotifEntry->Notif.ActiveScanPayload.Results.mLqi,
+ NULL, // proto (don't care)
+ NULL, // flags (don't care)
+ &aNetworkName,
+ &aExtPanId,
+ &xpanid_len
+ ) &&
+ aExtAddr != NULL && aExtPanId != NULL && aNetworkName != NULL &&
+ xpanid_len == OT_EXT_PAN_ID_SIZE)
+ {
+ memcpy_s(NotifEntry->Notif.ActiveScanPayload.Results.mExtAddress.m8,
+ sizeof(NotifEntry->Notif.ActiveScanPayload.Results.mExtAddress.m8),
+ aExtAddr, sizeof(otExtAddress));
+ memcpy_s(NotifEntry->Notif.ActiveScanPayload.Results.mExtendedPanId.m8,
+ sizeof(NotifEntry->Notif.ActiveScanPayload.Results.mExtendedPanId.m8),
+ aExtPanId, sizeof(otExtendedPanId));
+ strcpy_s(NotifEntry->Notif.ActiveScanPayload.Results.mNetworkName.m8,
+ sizeof(NotifEntry->Notif.ActiveScanPayload.Results.mNetworkName.m8),
+ aNetworkName);
+ otLwfIndicateNotification(NotifEntry);
+ }
+ else
+ {
+ FILTER_FREE_MEM(NotifEntry);
+ }
+ }
+ }
+ else if (key == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT)
+ {
+ PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter);
+ if (NotifEntry)
+ {
+ RtlZeroMemory(NotifEntry, sizeof(FILTER_NOTIFICATION_ENTRY));
+ NotifEntry->Notif.InterfaceGuid = pFilter->InterfaceGuid;
+ NotifEntry->Notif.NotifType = OTLWF_NOTIF_ENERGY_SCAN;
+ NotifEntry->Notif.EnergyScanPayload.Valid = TRUE;
+
+ if (try_spinel_datatype_unpack(
+ value_data_ptr,
+ value_data_len,
+ "Cc",
+ &NotifEntry->Notif.EnergyScanPayload.Results.mChannel,
+ &NotifEntry->Notif.EnergyScanPayload.Results.mMaxRssi
+ ))
+ {
+ otLwfIndicateNotification(NotifEntry);
+ }
+ else
+ {
+ FILTER_FREE_MEM(NotifEntry);
+ }
+ }
+ }
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfProcessSpinelCommand(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ UINT command,
+ _In_reads_bytes_(cmd_data_len) const uint8_t* cmd_data_ptr,
+ _In_ spinel_size_t cmd_data_len
+ )
+{
+ uint8_t Header;
+ spinel_prop_key_t key;
+ uint8_t* value_data_ptr = NULL;
+ spinel_size_t value_data_len = 0;
+
+ // Make sure it's an expected command
+ if (command < SPINEL_CMD_PROP_VALUE_IS || command > SPINEL_CMD_PROP_VALUE_REMOVED)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Recieved unhandled command, %u", command);
+ return;
+ }
+
+ // Decode the key and data
+ if (spinel_datatype_unpack(cmd_data_ptr, cmd_data_len, "CiiD", &Header, NULL, &key, &value_data_ptr, &value_data_len) == -1)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Failed to unpack command key & data");
+ return;
+ }
+
+ if (SPINEL_HEADER_GET_TID(Header) == 0)
+ {
+ // If this is a 'Value Is' command, process it for notification of state changes.
+ if (command == SPINEL_CMD_PROP_VALUE_IS)
+ {
+ otLwfProcessSpinelValueIs(pFilter, DispatchLevel, key, value_data_ptr, value_data_len);
+ }
+ else if (command == SPINEL_CMD_PROP_VALUE_INSERTED)
+ {
+ otLwfProcessSpinelValueInserted(pFilter, DispatchLevel, key, value_data_ptr, value_data_len);
+ }
+ }
+ // If there was a transaction ID, then look for the corresponding command handler
+ else
+ {
+ PLIST_ENTRY Link;
+ SPINEL_CMD_HANDLER_ENTRY* Handler = NULL;
+
+ FILTER_ACQUIRE_LOCK(&pFilter->tunCommandLock, DispatchLevel);
+
+ // Search for matching handlers for this command
+ Link = pFilter->tunCommandHandlers.Flink;
+ while (Link != &pFilter->tunCommandHandlers)
+ {
+ SPINEL_CMD_HANDLER_ENTRY* pEntry = CONTAINING_RECORD(Link, SPINEL_CMD_HANDLER_ENTRY, Link);
+ Link = Link->Flink;
+
+ if (SPINEL_HEADER_GET_TID(Header) == pEntry->TransactionId)
+ {
+ // Remove from the main list
+ RemoveEntryList(&pEntry->Link);
+
+ Handler = pEntry;
+
+ // Remove the transaction ID from the 'in use' bit field
+ pFilter->tunTIDsInUse &= ~(1 << pEntry->TransactionId);
+
+ break;
+ }
+ }
+
+ FILTER_RELEASE_LOCK(&pFilter->tunCommandLock, DispatchLevel);
+
+ // TODO - Set event
+
+ // Process the handler we found, outside the lock
+ if (Handler)
+ {
+ // Call the handler function
+ Handler->Handler(pFilter, Handler->Context, command, key, value_data_ptr, value_data_len);
+
+ // Free the entry
+ FILTER_FREE_MEM(Handler);
+ }
+ }
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfReceiveTunnelPacket(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_reads_bytes_(BufferLength) const PUCHAR Buffer,
+ _In_ ULONG BufferLength
+ )
+{
+ uint8_t Header;
+ UINT Command;
+
+ // Unpack the header from the buffer
+ if (spinel_datatype_unpack(Buffer, BufferLength, "Ci", &Header, &Command) <= 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Failed to unpack header and command");
+ return;
+ }
+
+ // Validate the header
+ if ((Header & SPINEL_HEADER_FLAG) != SPINEL_HEADER_FLAG)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Recieved unrecognized frame, header=0x%x", Header);
+ return;
+ }
+
+ // We only support IID zero for now
+ if (SPINEL_HEADER_GET_IID(Header) != 0)
+ {
+ LogVerbose(DRIVER_DEFAULT, "Recieved unsupported IID, %u", SPINEL_HEADER_GET_IID(Header));
+ return;
+ }
+
+ // Process the received command
+ otLwfProcessSpinelCommand(pFilter, DispatchLevel, Command, Buffer, BufferLength);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfSendTunnelPacket(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ PNET_BUFFER IpNetBuffer,
+ _In_ BOOLEAN Secured
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PNET_BUFFER_LIST NetBufferList = NULL;
+ PNET_BUFFER NetBuffer = NULL;
+ ULONG NetBufferLength = 0;
+ PUCHAR DataBuffer = NULL;
+ PUCHAR IpDataBuffer = NULL;
+ spinel_ssize_t PackedLength;
+ IPV6_HEADER* v6Header;
+
+ NetBufferList =
+ NdisAllocateNetBufferAndNetBufferList(
+ pFilter->NetBufferListPool, // PoolHandle
+ 0, // ContextSize
+ 0, // ContextBackFill
+ NULL, // MdlChain
+ 0, // DataOffset
+ 0 // DataLength
+ );
+ if (NetBufferList == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogWarning(DRIVER_DEFAULT, "Failed to create command NetBufferList");
+ goto exit;
+ }
+
+ // Initialize NetBuffer fields
+ NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ NET_BUFFER_CURRENT_MDL(NetBuffer) = NULL;
+ NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_DATA_LENGTH(NetBuffer) = 0;
+ NET_BUFFER_DATA_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_FIRST_MDL(NetBuffer) = NULL;
+
+ // Calculate length of NetBuffer
+ NetBufferLength = 20 + IpNetBuffer->DataLength;
+ if (NetBufferLength < 64) NetBufferLength = 64;
+
+ // Allocate the NetBuffer for NetBufferList
+ if (NdisRetreatNetBufferDataStart(NetBuffer, NetBufferLength, 0, NULL) != NDIS_STATUS_SUCCESS)
+ {
+ NetBuffer = NULL;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogError(DRIVER_DEFAULT, "Failed to allocate NB for command NetBufferList, %u bytes", NetBufferLength);
+ goto exit;
+ }
+
+ // Get the pointer to the data buffer for the header data
+ DataBuffer = (PUCHAR)NdisGetDataBuffer(NetBuffer, NetBufferLength, NULL, 1, 0);
+ NT_ASSERT(DataBuffer);
+
+ // Save the true NetBuffer length in the protocol reserved
+ NetBuffer->ProtocolReserved[0] = (PVOID)NetBufferLength;
+ NetBuffer->DataLength = 0;
+
+ // Pack the header, command and key
+ PackedLength =
+ spinel_datatype_pack(
+ DataBuffer,
+ NetBufferLength,
+ "Cii",
+ (spinel_tid_t)(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0),
+ (UINT)SPINEL_CMD_PROP_VALUE_SET,
+ (Secured ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE));
+ if (PackedLength < 0 || PackedLength + NetBuffer->DataLength > NetBufferLength)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ NT_ASSERT(PackedLength >= 3);
+ NetBuffer->DataLength += (ULONG)PackedLength;
+
+ // Copy over the data length
+ DataBuffer[NetBuffer->DataLength+1] = (((USHORT)IpNetBuffer->DataLength) >> 8) & 0xff;
+ DataBuffer[NetBuffer->DataLength] = (((USHORT)IpNetBuffer->DataLength) >> 0) & 0xff;
+ NetBuffer->DataLength += 2;
+
+ v6Header = (IPV6_HEADER*)(DataBuffer + NetBuffer->DataLength);
+
+ // Copy the IP packet data
+ IpDataBuffer = (PUCHAR)NdisGetDataBuffer(IpNetBuffer, IpNetBuffer->DataLength, v6Header, 1, 0);
+ if (IpDataBuffer != (PUCHAR)v6Header)
+ {
+ RtlCopyMemory(v6Header, IpDataBuffer, IpNetBuffer->DataLength);
+ }
+
+ NetBuffer->DataLength += IpNetBuffer->DataLength;
+
+ LogVerbose(DRIVER_DATA_PATH, "Filter: %p, IP6_SEND: %p : %!IPV6ADDR! => %!IPV6ADDR! (%u bytes)",
+ pFilter, NetBufferList, &v6Header->SourceAddress, &v6Header->DestinationAddress,
+ NET_BUFFER_DATA_LENGTH(IpNetBuffer));
+
+ // Send the NBL down
+ NdisFSendNetBufferLists(
+ pFilter->FilterHandle,
+ NetBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ DispatchLevel ? NDIS_SEND_FLAGS_DISPATCH_LEVEL : 0);
+
+ // Clear local variable because we don't own the NBL any more
+ NetBufferList = NULL;
+
+exit:
+
+ if (NetBufferList)
+ {
+ if (NetBuffer)
+ {
+ NetBuffer->DataLength = (ULONG)(ULONG_PTR)NetBuffer->ProtocolReserved[0];
+ NdisAdvanceNetBufferDataStart(NetBuffer, NetBuffer->DataLength, TRUE, NULL);
+ }
+ NdisFreeNetBufferList(NetBufferList);
+ }
+
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+spinel_tid_t
+otLwfGetNextTunnelTransactionId(
+ _In_ PMS_FILTER pFilter
+ )
+{
+ spinel_tid_t TID = 0;
+ while (TID == 0)
+ {
+ NdisAcquireSpinLock(&pFilter->tunCommandLock);
+
+ if (((1 << pFilter->tunNextTID) & pFilter->tunTIDsInUse) == 0)
+ {
+ TID = pFilter->tunNextTID;
+ pFilter->tunNextTID = SPINEL_GET_NEXT_TID(pFilter->tunNextTID);
+ pFilter->tunTIDsInUse |= (1 << TID);
+ }
+
+ NdisReleaseSpinLock(&pFilter->tunCommandLock);
+
+ if (TID == 0)
+ {
+ // TODO - Wait for event
+ }
+ }
+ return TID;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+otLwfAddCommandHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_ SPINEL_CMD_HANDLER_ENTRY *pEntry
+ )
+{
+ // Get the next transaction ID. This call will block if there are
+ // none currently available.
+ pEntry->TransactionId = otLwfGetNextTunnelTransactionId(pFilter);
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "tid=%u", (ULONG)pEntry->TransactionId);
+
+ NdisAcquireSpinLock(&pFilter->tunCommandLock);
+
+ // Add to the handlers list
+ InsertTailList(&pFilter->tunCommandHandlers, &pEntry->Link);
+
+ NdisReleaseSpinLock(&pFilter->tunCommandLock);
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+BOOLEAN
+otLwfCancelCommandHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ spinel_tid_t tid
+ )
+{
+ PLIST_ENTRY Link;
+ SPINEL_CMD_HANDLER_ENTRY* Handler = NULL;
+ BOOLEAN Found = FALSE;
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "tid=%u", (ULONG)tid);
+
+ FILTER_ACQUIRE_LOCK(&pFilter->tunCommandLock, DispatchLevel);
+
+ // Search for matching handlers for this transaction ID
+ Link = pFilter->tunCommandHandlers.Flink;
+ while (Link != &pFilter->tunCommandHandlers)
+ {
+ SPINEL_CMD_HANDLER_ENTRY* pEntry = CONTAINING_RECORD(Link, SPINEL_CMD_HANDLER_ENTRY, Link);
+ Link = Link->Flink;
+
+ if (tid == pEntry->TransactionId)
+ {
+ // Remove from the main list
+ RemoveEntryList(&pEntry->Link);
+
+ // Save handler to cancel outside lock
+ Handler = pEntry;
+ Found = TRUE;
+
+ // Remove the transaction ID from the 'in use' bit field
+ pFilter->tunTIDsInUse &= ~(1 << pEntry->TransactionId);
+
+ break;
+ }
+ }
+
+ FILTER_RELEASE_LOCK(&pFilter->tunCommandLock, DispatchLevel);
+
+ if (Handler)
+ {
+ // Call the handler function
+ Handler->Handler(pFilter, Handler->Context, 0, 0, NULL, 0);
+
+ // Free the entry
+ FILTER_FREE_MEM(Handler);
+ }
+
+ LogFuncExitMsg(DRIVER_DEFAULT, "Found=%u", Found);
+
+ return Found;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandV(
+ _In_ PMS_FILTER pFilter,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ spinel_tid_t tid,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ _In_opt_ va_list args
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PNET_BUFFER_LIST NetBufferList = NULL;
+ PNET_BUFFER NetBuffer = NULL;
+ ULONG NetBufferLength = 0;
+ PUCHAR DataBuffer = NULL;
+ spinel_ssize_t PackedLength;
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "Cmd=%u Key=%u tid=%u", (ULONG)Command, (ULONG)Key, (ULONG)tid);
+
+ NetBufferList =
+ NdisAllocateNetBufferAndNetBufferList(
+ pFilter->NetBufferListPool, // PoolHandle
+ 0, // ContextSize
+ 0, // ContextBackFill
+ NULL, // MdlChain
+ 0, // DataOffset
+ 0 // DataLength
+ );
+ if (NetBufferList == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogWarning(DRIVER_DEFAULT, "Failed to create command NetBufferList");
+ goto exit;
+ }
+
+ // Initialize NetBuffer fields
+ NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ NET_BUFFER_CURRENT_MDL(NetBuffer) = NULL;
+ NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_DATA_LENGTH(NetBuffer) = 0;
+ NET_BUFFER_DATA_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_FIRST_MDL(NetBuffer) = NULL;
+
+ // Calculate length of NetBuffer
+ NetBufferLength = 16 + MaxDataLength;
+ if (NetBufferLength < 64) NetBufferLength = 64;
+
+ // Allocate the NetBuffer for NetBufferList
+ if (NdisRetreatNetBufferDataStart(NetBuffer, NetBufferLength, 0, NULL) != NDIS_STATUS_SUCCESS)
+ {
+ NetBuffer = NULL;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogError(DRIVER_DEFAULT, "Failed to allocate NB for command NetBufferList, %u bytes", NetBufferLength);
+ goto exit;
+ }
+
+ // Get the pointer to the data buffer
+ DataBuffer = (PUCHAR)NdisGetDataBuffer(NetBuffer, NetBufferLength, NULL, 1, 0);
+ NT_ASSERT(DataBuffer);
+
+ // Save the true NetBuffer length in the protocol reserved
+ NetBuffer->ProtocolReserved[0] = (PVOID)NetBufferLength;
+ NetBuffer->DataLength = 0;
+
+ // Save the transaction ID in the protocol reserved
+ NetBuffer->ProtocolReserved[1] = (PVOID)tid;
+
+ // Pack the header, command and key
+ PackedLength =
+ spinel_datatype_pack(
+ DataBuffer,
+ NetBufferLength,
+ "Cii",
+ SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0 | tid,
+ Command,
+ Key);
+ if (PackedLength < 0 || PackedLength + NetBuffer->DataLength > NetBufferLength)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ NetBuffer->DataLength += (ULONG)PackedLength;
+
+ // Pack the data (if any)
+ if (pack_format)
+ {
+ PackedLength =
+ spinel_datatype_vpack(
+ DataBuffer + NetBuffer->DataLength,
+ NetBufferLength - NetBuffer->DataLength,
+ pack_format,
+ args);
+ if (PackedLength < 0 || PackedLength + NetBuffer->DataLength > NetBufferLength)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ NetBuffer->DataLength += (ULONG)PackedLength;
+ }
+
+ // Send the NBL down
+ NdisFSendNetBufferLists(
+ pFilter->FilterHandle,
+ NetBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 0);
+
+ // Clear local variable because we don't own the NBL any more
+ NetBufferList = NULL;
+
+exit:
+
+ if (NetBufferList)
+ {
+ if (NetBuffer)
+ {
+ NetBuffer->DataLength = (ULONG)(ULONG_PTR)NetBuffer->ProtocolReserved[0];
+ NdisAdvanceNetBufferDataStart(NetBuffer, NetBuffer->DataLength, TRUE, NULL);
+ }
+ NdisFreeNetBufferList(NetBufferList);
+ }
+
+ LogFuncExitNT(DRIVER_DEFAULT, status);
+
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandWithHandlerV(
+ _In_ PMS_FILTER pFilter,
+ _In_opt_ SPINEL_CMD_HANDLER *Handler,
+ _In_opt_ PVOID HandlerContext,
+ _Out_opt_ spinel_tid_t *pTid,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ _In_opt_ va_list args
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ SPINEL_CMD_HANDLER_ENTRY *pEntry = NULL;
+
+ if (pTid) *pTid = 0;
+
+ // Create the handler entry and add it to the list
+ if (Handler)
+ {
+ pEntry = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(SPINEL_CMD_HANDLER_ENTRY));
+ if (pEntry == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogWarning(DRIVER_DEFAULT, "Failed to allocate handler entry");
+ goto exit;
+ }
+
+ pEntry->Handler = Handler;
+ pEntry->Context = HandlerContext;
+
+ otLwfAddCommandHandler(pFilter, pEntry);
+
+ if (pTid) *pTid = pEntry->TransactionId;
+ }
+
+ status = otLwfSendTunnelCommandV(pFilter, Command, Key, pEntry ? pEntry->TransactionId : 0, MaxDataLength, pack_format, args);
+
+ // Remove the handler entry from the list
+ if (!NT_SUCCESS(status) && pEntry)
+ {
+ NdisAcquireSpinLock(&pFilter->tunCommandLock);
+
+ // Remove from the main list
+ RemoveEntryList(&pEntry->Link);
+
+ // Remove the transaction ID from the 'in use' bit field
+ pFilter->tunTIDsInUse &= ~(1 << pEntry->TransactionId);
+
+ NdisReleaseSpinLock(&pFilter->tunCommandLock);
+
+ // TODO - Set event
+
+ FILTER_FREE_MEM(pEntry);
+ }
+
+exit:
+
+ return status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandWithHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_opt_ SPINEL_CMD_HANDLER *Handler,
+ _In_opt_ PVOID HandlerContext,
+ _Out_opt_ spinel_tid_t *pTid,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ ...
+ )
+{
+ va_list args;
+ va_start(args, pack_format);
+ NTSTATUS status =
+ otLwfSendTunnelCommandWithHandlerV(pFilter, Handler, HandlerContext, pTid, Command, Key, MaxDataLength, pack_format, args);
+ va_end(args);
+ return status;
+}
+
+SPINEL_CMD_HANDLER otLwfIrpCommandHandler;
+
+typedef struct _SPINEL_IRP_CMD_CONTEXT
+{
+ PMS_FILTER pFilter;
+ PIRP Irp;
+ SPINEL_IRP_CMD_HANDLER *Handler;
+ spinel_tid_t tid;
+} SPINEL_IRP_CMD_CONTEXT;
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfIrpCommandHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_ PVOID Context,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength
+ )
+{
+ SPINEL_IRP_CMD_CONTEXT* CmdContext = (SPINEL_IRP_CMD_CONTEXT*)Context;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(CmdContext->Irp);
+
+ ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
+ PVOID OutBuffer = CmdContext->Irp->AssociatedIrp.SystemBuffer;
+ ULONG OutBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ ULONG OrigOutBufferLength = OutBufferLength;
+
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(pFilter);
+
+ // Clear the cancel routine
+ IoSetCancelRoutine(CmdContext->Irp, NULL);
+
+ if (Data == NULL)
+ {
+ status = STATUS_CANCELLED;
+ OutBufferLength = 0;
+ }
+ else if (Command == SPINEL_CMD_PROP_VALUE_IS && Key == SPINEL_PROP_LAST_STATUS)
+ {
+ spinel_status_t spinel_status = SPINEL_STATUS_OK;
+ spinel_ssize_t packed_len = spinel_datatype_unpack(Data, DataLength, "i", &spinel_status);
+ if (packed_len < 0 || (ULONG)packed_len > DataLength)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ status = ThreadErrorToNtstatus(SpinelStatusToThreadError(spinel_status));
+ }
+ }
+ else if (CmdContext->Handler)
+ {
+ status = CmdContext->Handler(Key, Data, DataLength, OutBuffer, &OutBufferLength);
+ }
+ else // No handler, so no output
+ {
+ status = STATUS_SUCCESS;
+ OutBufferLength = 0;
+ }
+
+ // Clear any leftover output buffer
+ if (OutBufferLength < OrigOutBufferLength)
+ {
+ RtlZeroMemory((PUCHAR)OutBuffer + OutBufferLength, OrigOutBufferLength - OutBufferLength);
+ }
+
+ LogVerbose(DRIVER_IOCTL, "Completing Irp=%p, with %!STATUS! for %s (Out:%u)",
+ CmdContext->Irp, status, IoCtlString(IoControlCode), OutBufferLength);
+
+ // Complete the IRP
+ CmdContext->Irp->IoStatus.Information = OutBufferLength;
+ CmdContext->Irp->IoStatus.Status = status;
+ IoCompleteRequest(CmdContext->Irp, IO_NO_INCREMENT);
+
+ FILTER_FREE_MEM(Context);
+}
+
+_Function_class_(DRIVER_CANCEL)
+_Requires_lock_held_(_Global_cancel_spin_lock_)
+_Releases_lock_(_Global_cancel_spin_lock_)
+_IRQL_requires_min_(DISPATCH_LEVEL)
+_IRQL_requires_(DISPATCH_LEVEL)
+VOID
+otLwfTunCancelIrp(
+ _Inout_ struct _DEVICE_OBJECT *DeviceObject,
+ _Inout_ _IRQL_uses_cancel_ struct _IRP *Irp
+ )
+{
+ PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
+ SPINEL_IRP_CMD_CONTEXT* CmdContext = (SPINEL_IRP_CMD_CONTEXT*)IrpStack->Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ LogFuncEntryMsg(DRIVER_IOCTL, "Irp=%p", Irp);
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ // Try to cancel pending command
+ otLwfCancelCommandHandler(
+ CmdContext->pFilter,
+ (Irp->CancelIrql == DISPATCH_LEVEL) ? TRUE : FALSE,
+ CmdContext->tid);
+
+ LogFuncExit(DRIVER_IOCTL);
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandForIrp(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP Irp,
+ _In_opt_ SPINEL_IRP_CMD_HANDLER *Handler,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ ...
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ SPINEL_IRP_CMD_CONTEXT *pContext = NULL;
+ PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ // Create the context structure
+ pContext = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(SPINEL_IRP_CMD_CONTEXT));
+ if (pContext == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogWarning(DRIVER_DEFAULT, "Failed to allocate irp cmd context");
+ goto exit;
+ }
+
+ pContext->pFilter = pFilter;
+ pContext->Irp = Irp;
+ pContext->Handler = Handler;
+
+ NT_ASSERT(IrpStack->Context == NULL);
+ IrpStack->Context = pContext;
+
+ // Set the cancel routine
+ IoSetCancelRoutine(Irp, otLwfTunCancelIrp);
+
+ va_list args;
+ va_start(args, pack_format);
+ status =
+ otLwfSendTunnelCommandWithHandlerV(
+ pFilter,
+ otLwfIrpCommandHandler,
+ pContext,
+ &pContext->tid,
+ Command,
+ Key,
+ MaxDataLength,
+ pack_format,
+ args);
+ va_end(args);
+
+ // Remove the handler entry from the list
+ if (!NT_SUCCESS(status))
+ {
+ // Clear the cancel routine
+ IoSetCancelRoutine(Irp, NULL);
+
+ FILTER_FREE_MEM(pContext);
+ }
+
+exit:
+
+ return status;
+}
+
+typedef struct _SPINEL_GET_PROP_CONTEXT
+{
+ KEVENT CompletionEvent;
+ spinel_prop_key_t Key;
+ PVOID *DataBuffer;
+ const char* Format;
+ va_list Args;
+ NTSTATUS Status;
+} SPINEL_GET_PROP_CONTEXT;
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfGetPropHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_ PVOID Context,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength
+ )
+{
+ SPINEL_GET_PROP_CONTEXT* CmdContext = (SPINEL_GET_PROP_CONTEXT*)Context;
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "Key=%u", (ULONG)Key);
+
+ UNREFERENCED_PARAMETER(pFilter);
+
+ if (Data == NULL)
+ {
+ CmdContext->Status = STATUS_CANCELLED;
+ }
+ else if (Command != SPINEL_CMD_PROP_VALUE_IS)
+ {
+ CmdContext->Status = STATUS_INVALID_PARAMETER;
+ }
+ else if (Key == SPINEL_PROP_LAST_STATUS)
+ {
+ spinel_status_t spinel_status = SPINEL_STATUS_OK;
+ spinel_ssize_t packed_len = spinel_datatype_unpack(Data, DataLength, "i", &spinel_status);
+ if (packed_len < 0 || (ULONG)packed_len > DataLength)
+ {
+ CmdContext->Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ CmdContext->Status = ThreadErrorToNtstatus(SpinelStatusToThreadError(spinel_status));
+ }
+ }
+ else if (Key == CmdContext->Key)
+ {
+ if (CmdContext->DataBuffer)
+ {
+ CmdContext->DataBuffer = FILTER_ALLOC_MEM(pFilter->FilterHandle, DataLength);
+ if (CmdContext->DataBuffer == NULL)
+ {
+ CmdContext->Status = STATUS_INSUFFICIENT_RESOURCES;
+ DataLength = 0;
+ }
+ else
+ {
+ memcpy(CmdContext->DataBuffer, Data, DataLength);
+ Data = (uint8_t*)CmdContext->DataBuffer;
+ }
+ }
+
+ spinel_ssize_t packed_len = spinel_datatype_vunpack(Data, DataLength, CmdContext->Format, CmdContext->Args);
+ if (packed_len < 0 || (ULONG)packed_len > DataLength)
+ {
+ CmdContext->Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ CmdContext->Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ CmdContext->Status = STATUS_INVALID_PARAMETER;
+ }
+
+ // Set the completion event
+ KeSetEvent(&CmdContext->CompletionEvent, 0, FALSE);
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfGetTunProp(
+ _In_ PMS_FILTER pFilter,
+ _Out_opt_ PVOID *DataBuffer,
+ _In_ spinel_prop_key_t Key,
+ _In_ const char *pack_format,
+ ...
+ )
+{
+ NTSTATUS status;
+ LARGE_INTEGER WaitTimeout;
+ spinel_tid_t tid;
+
+ // Create the context structure
+ SPINEL_GET_PROP_CONTEXT Context;
+ KeInitializeEvent(&Context.CompletionEvent, SynchronizationEvent, FALSE);
+ Context.Key = Key;
+ Context.DataBuffer = DataBuffer;
+ Context.Format = pack_format;
+ Context.Status = STATUS_SUCCESS;
+ va_start(Context.Args, pack_format);
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "Key=%u", (ULONG)Key);
+
+ // Send the request transaction
+ status =
+ otLwfSendTunnelCommandWithHandlerV(
+ pFilter,
+ otLwfGetPropHandler,
+ &Context,
+ &tid,
+ SPINEL_CMD_PROP_VALUE_GET,
+ Key,
+ 0,
+ NULL,
+ NULL);
+ if (NT_SUCCESS(status))
+ {
+ // Set a 1 second wait timeout
+ WaitTimeout.QuadPart = -1000 * 10000;
+
+ // Wait for the response
+ if (KeWaitForSingleObject(
+ &Context.CompletionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ &WaitTimeout) != STATUS_SUCCESS)
+ {
+ if (!otLwfCancelCommandHandler(pFilter, FALSE, tid))
+ {
+ KeWaitForSingleObject(
+ &Context.CompletionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ }
+ }
+ else
+ {
+ Context.Status = status;
+ }
+
+ va_end(Context.Args);
+
+ LogFuncExitNT(DRIVER_DEFAULT, Context.Status);
+
+ return Context.Status;
+}
+
+typedef struct _SPINEL_SET_PROP_CONTEXT
+{
+ KEVENT CompletionEvent;
+ spinel_prop_key_t Key;
+ NTSTATUS Status;
+} SPINEL_SET_PROP_CONTEXT;
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+otLwfSetPropHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_ PVOID Context,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength
+ )
+{
+ SPINEL_SET_PROP_CONTEXT* CmdContext = (SPINEL_SET_PROP_CONTEXT*)Context;
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "Key=%u", (ULONG)Key);
+
+ UNREFERENCED_PARAMETER(pFilter);
+
+ if (Data == NULL)
+ {
+ CmdContext->Status = STATUS_CANCELLED;
+ }
+ else if (Command != SPINEL_CMD_PROP_VALUE_IS)
+ {
+ CmdContext->Status = STATUS_INVALID_PARAMETER;
+ }
+ else if (Key == SPINEL_PROP_LAST_STATUS)
+ {
+ spinel_status_t spinel_status = SPINEL_STATUS_OK;
+ spinel_ssize_t packed_len = spinel_datatype_unpack(Data, DataLength, "i", &spinel_status);
+ if (packed_len < 0 || (ULONG)packed_len > DataLength)
+ {
+ CmdContext->Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ CmdContext->Status = ThreadErrorToNtstatus(SpinelStatusToThreadError(spinel_status));
+ }
+ }
+ else if (Key == CmdContext->Key)
+ {
+ CmdContext->Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ CmdContext->Status = STATUS_INVALID_PARAMETER;
+ }
+
+ // Set the completion event
+ KeSetEvent(&CmdContext->CompletionEvent, 0, FALSE);
+
+ LogFuncExit(DRIVER_DEFAULT);
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSetTunProp(
+ _In_ PMS_FILTER pFilter,
+ _In_ spinel_prop_key_t Key,
+ _In_ const char *pack_format,
+ ...
+ )
+{
+ NTSTATUS status;
+ LARGE_INTEGER WaitTimeout;
+ spinel_tid_t tid;
+
+ // Create the context structure
+ SPINEL_SET_PROP_CONTEXT Context;
+ KeInitializeEvent(&Context.CompletionEvent, SynchronizationEvent, FALSE);
+ Context.Key = Key;
+ Context.Status = STATUS_SUCCESS;
+
+ LogFuncEntryMsg(DRIVER_DEFAULT, "Key=%u", (ULONG)Key);
+
+ va_list args;
+ va_start(args, pack_format);
+
+ // Send the request transaction
+ status =
+ otLwfSendTunnelCommandWithHandlerV(
+ pFilter,
+ otLwfGetPropHandler,
+ &Context,
+ &tid,
+ SPINEL_CMD_PROP_VALUE_SET,
+ Key,
+ 8,
+ pack_format,
+ args);
+ if (NT_SUCCESS(status))
+ {
+ // Set a 1 second wait timeout
+ WaitTimeout.QuadPart = -1000 * 10000;
+
+ // Wait for the response
+ if (KeWaitForSingleObject(
+ &Context.CompletionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ &WaitTimeout) != STATUS_SUCCESS)
+ {
+ if (!otLwfCancelCommandHandler(pFilter, FALSE, tid))
+ {
+ KeWaitForSingleObject(
+ &Context.CompletionEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+ }
+ }
+ else
+ {
+ Context.Status = status;
+ }
+
+ va_end(args);
+
+ LogFuncExitNT(DRIVER_DEFAULT, Context.Status);
+
+ return Context.Status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfProcessSpinelIPv6Packet(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ BOOLEAN Secure,
+ _In_reads_bytes_(BufferLength) const uint8_t* Buffer,
+ _In_ UINT BufferLength
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PNET_BUFFER_LIST NetBufferList = NULL;
+ PNET_BUFFER NetBuffer = NULL;
+ PUCHAR DataBuffer = NULL;
+ IPV6_HEADER* v6Header;
+
+ UNREFERENCED_PARAMETER(Secure); // TODO - What should we do with unsecured packets?
+
+ NetBufferList =
+ NdisAllocateNetBufferAndNetBufferList(
+ pFilter->NetBufferListPool, // PoolHandle
+ 0, // ContextSize
+ 0, // ContextBackFill
+ NULL, // MdlChain
+ 0, // DataOffset
+ 0 // DataLength
+ );
+ if (NetBufferList == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogWarning(DRIVER_DEFAULT, "Failed to create command NetBufferList");
+ goto exit;
+ }
+
+ // Set the flag to indicate its a IPv6 packet
+ NdisSetNblFlag(NetBufferList, NDIS_NBL_FLAGS_IS_IPV6);
+ NET_BUFFER_LIST_INFO(NetBufferList, NetBufferListFrameType) =
+ UlongToPtr(RtlUshortByteSwap(ETHERNET_TYPE_IPV6));
+
+ // Initialize NetBuffer fields
+ NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ NET_BUFFER_CURRENT_MDL(NetBuffer) = NULL;
+ NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_DATA_LENGTH(NetBuffer) = 0;
+ NET_BUFFER_DATA_OFFSET(NetBuffer) = 0;
+ NET_BUFFER_FIRST_MDL(NetBuffer) = NULL;
+
+ // Allocate the NetBuffer for NetBufferList
+ if (NdisRetreatNetBufferDataStart(NetBuffer, BufferLength, 0, NULL) != NDIS_STATUS_SUCCESS)
+ {
+ NetBuffer = NULL;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ LogError(DRIVER_DEFAULT, "Failed to allocate NB for command NetBufferList, %u bytes", BufferLength);
+ goto exit;
+ }
+
+ // Get the pointer to the data buffer for the header data
+ DataBuffer = (PUCHAR)NdisGetDataBuffer(NetBuffer, BufferLength, NULL, 1, 0);
+ NT_ASSERT(DataBuffer);
+
+ // Copy the data over
+ RtlCopyMemory(DataBuffer, Buffer, BufferLength);
+
+ v6Header = (IPV6_HEADER*)DataBuffer;
+
+ // Filter messages to addresses we expose
+ if (!IN6_IS_ADDR_MULTICAST(&v6Header->DestinationAddress) &&
+ otLwfFindCachedAddrIndex(pFilter, &v6Header->DestinationAddress) == -1)
+ {
+ LogVerbose(DRIVER_DATA_PATH, "Filter: %p dropping internal address message.", pFilter);
+ goto exit;
+ }
+
+ LogVerbose(DRIVER_DATA_PATH, "Filter: %p, IP6_RECV: %p : %!IPV6ADDR! => %!IPV6ADDR! (%u bytes)",
+ pFilter, NetBufferList, &v6Header->SourceAddress, &v6Header->DestinationAddress,
+ BufferLength);
+
+#ifdef LOG_BUFFERS
+ otLogBuffer(DataBuffer, BufferLength);
+#endif
+
+ // Send the NBL down
+ NdisFIndicateReceiveNetBufferLists(
+ pFilter->FilterHandle,
+ NetBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1,
+ DispatchLevel ? NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL : 0);
+
+ // Clear local variable because we don't own the NBL any more
+ NetBufferList = NULL;
+
+exit:
+
+ if (NetBufferList)
+ {
+ if (NetBuffer)
+ {
+ NdisAdvanceNetBufferDataStart(NetBuffer, NetBuffer->DataLength, TRUE, NULL);
+ }
+ NdisFreeNetBufferList(NetBufferList);
+ }
+}
diff --git a/examples/drivers/windows/otLwf/tunnel.h b/examples/drivers/windows/otLwf/tunnel.h
new file mode 100644
index 000000000..f75cf7887
--- /dev/null
+++ b/examples/drivers/windows/otLwf/tunnel.h
@@ -0,0 +1,195 @@
+/*
+ * 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 functions for the otLwf Filter Tunnel mode.
+ */
+
+#ifndef _TUNNEL_H_
+#define _TUNNEL_H_
+
+typedef
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+(SPINEL_CMD_HANDLER)(
+ _In_ PMS_FILTER pFilter,
+ _In_ PVOID Context,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_reads_bytes_(DataLength) const uint8_t* Data,
+ _In_ spinel_size_t DataLength
+ );
+
+typedef struct _SPINEL_CMD_HANDLER_ENTRY
+{
+ LIST_ENTRY Link;
+ SPINEL_CMD_HANDLER *Handler;
+ PVOID Context;
+ spinel_tid_t TransactionId;
+} SPINEL_CMD_HANDLER_ENTRY;
+
+//
+// Initialization Functions
+//
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NDIS_STATUS
+otLwfInitializeTunnelMode(
+ _In_ PMS_FILTER pFilter
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+otLwfUninitializeTunnelMode(
+ _In_ PMS_FILTER pFilter
+ );
+
+//
+// Spinel Packet Functions
+//
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+BOOLEAN
+otLwfCancelCommandHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ spinel_tid_t tid
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandWithHandlerV(
+ _In_ PMS_FILTER pFilter,
+ _In_opt_ SPINEL_CMD_HANDLER *Handler,
+ _In_opt_ PVOID HandlerContext,
+ _Out_opt_ spinel_tid_t *pTid,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ _In_opt_ va_list args
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandWithHandler(
+ _In_ PMS_FILTER pFilter,
+ _In_opt_ SPINEL_CMD_HANDLER *Handler,
+ _In_opt_ PVOID HandlerContext,
+ _Out_opt_ spinel_tid_t *pTid,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ ...
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+otLwfSendTunnelPacket(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ PNET_BUFFER IpNetBuffer,
+ _In_ BOOLEAN Secured
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfReceiveTunnelPacket(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_reads_bytes_(BufferLength) const PUCHAR Buffer,
+ _In_ ULONG BufferLength
+ );
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+otLwfProcessSpinelIPv6Packet(
+ _In_ PMS_FILTER pFilter,
+ _In_ BOOLEAN DispatchLevel,
+ _In_ BOOLEAN Secure,
+ _In_reads_bytes_(BufferLength) const uint8_t* Buffer,
+ _In_ UINT BufferLength
+ );
+
+//
+// Irp Commands
+//
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSendTunnelCommandForIrp(
+ _In_ PMS_FILTER pFilter,
+ _In_ PIRP Irp,
+ _In_opt_ SPINEL_IRP_CMD_HANDLER *Handler,
+ _In_ UINT Command,
+ _In_ spinel_prop_key_t Key,
+ _In_ ULONG MaxDataLength,
+ _In_opt_ const char *pack_format,
+ ...
+ );
+
+//
+// Spinel Helper Functions
+//
+
+ThreadError
+SpinelStatusToThreadError(
+ spinel_status_t error
+ );
+
+BOOLEAN
+try_spinel_datatype_unpack(
+ const uint8_t *data_in,
+ spinel_size_t data_len,
+ const char *pack_format,
+ ...
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfGetTunProp(
+ _In_ PMS_FILTER pFilter,
+ _Out_opt_ PVOID *DataBuffer,
+ _In_ spinel_prop_key_t Key,
+ _In_ const char *pack_format,
+ ...
+ );
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfSetTunProp(
+ _In_ PMS_FILTER pFilter,
+ _In_ spinel_prop_key_t Key,
+ _In_ const char *pack_format,
+ ...
+ );
+
+#endif //_TUNNEL_H_
diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c
index 6f7e8a1c6..f8baa674d 100644
--- a/src/ncp/spinel.c
+++ b/src/ncp/spinel.c
@@ -70,6 +70,12 @@
#define EINVAL 1
#endif
+#ifdef _KERNEL_MODE
+#define va_copy(destination, source) ((destination) = (source))
+#undef errno
+#define assert_printf(fmt, ...)
+#endif
+
#if defined(errno) && SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR
#error "SPINEL_PLATFORM_DOESNT_IMPLEMENT_ERRNO_VAR is set but errno is already defined."
#endif
@@ -443,7 +449,7 @@ spinel_datatype_vunpack_(const uint8_t *data_ptr, spinel_size_t data_len, const
*block_len_ptr = block_len;
}
- block_len += pui_len;
+ block_len += (uint16_t)pui_len;
ret += block_len;
data_ptr += block_len;
data_len -= block_len;
@@ -480,7 +486,7 @@ spinel_datatype_vunpack_(const uint8_t *data_ptr, spinel_size_t data_len, const
if (pui_len)
{
- block_len += pui_len;
+ block_len += (uint16_t)pui_len;
}
else
{
@@ -525,6 +531,7 @@ spinel_datatype_unpack(const uint8_t *data_ptr, spinel_size_t data_len, const ch
return ret;
}
+
spinel_ssize_t
spinel_datatype_vunpack(const uint8_t *data_ptr, spinel_size_t data_len, const char *pack_format, va_list args)
{