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) {