From 8a8c8cde41d7d42bc5490e75952d988f8e09d0d3 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 1 Feb 2017 10:15:32 -0800 Subject: [PATCH] =?UTF-8?q?Windows=20Host=20Side=C2=A0Updates=20(#1217)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add otLinkRaw API * Separate Mac and otLinkRaw* * Make pretty * otLinkRawSetEnabled doen't change radio enable state. Assumed to always be enabled right now. * NCP usage of otLinkRaw * Make otLinkRaw compile time removal (on by default). Disable otLinkRaw on Windows kernel mode. Check for mLinkRawEnabled state in otLinkRaw APIs and return errors. * Make raw usage compile time removable. * Additional cleanup * Fix Linux build breaks * Merge otlwf changes for new Spinel command interface * CC2538 Add Support for ACK timeouts * Revert "CC2538 Add Support for ACK timeouts" This reverts commit 7dcc4caebc3dc50dc56401cf7e009f315b4c196c. * Updates for the energy scan interface --- etc/visual-studio/otLwf.vcxproj | 2 + etc/visual-studio/otLwf.vcxproj.filters | 3 + examples/drivers/windows/otApi/otApi.cpp | 189 +- examples/drivers/windows/otLwf/address.c | 23 +- examples/drivers/windows/otLwf/command.c | 1276 ++++++++++++++ examples/drivers/windows/otLwf/command.h | 179 ++ examples/drivers/windows/otLwf/datapath.c | 408 ++--- examples/drivers/windows/otLwf/device.c | 24 +- examples/drivers/windows/otLwf/device.h | 8 - examples/drivers/windows/otLwf/driver.c | 103 +- .../drivers/windows/otLwf/eventprocessing.c | 309 ++-- examples/drivers/windows/otLwf/filter.c | 520 +++--- examples/drivers/windows/otLwf/filter.h | 103 +- examples/drivers/windows/otLwf/iocontrol.c | 166 +- examples/drivers/windows/otLwf/precomp.h | 5 +- examples/drivers/windows/otLwf/radio.c | 551 +++--- examples/drivers/windows/otLwf/radio.h | 2 +- examples/drivers/windows/otLwf/thread.c | 178 +- examples/drivers/windows/otLwf/thread.h | 36 +- examples/drivers/windows/otLwf/tunnel.c | 1569 +++-------------- examples/drivers/windows/otLwf/tunnel.h | 149 +- examples/drivers/windows/ottmp/serial.cpp | 2 +- 22 files changed, 3219 insertions(+), 2586 deletions(-) create mode 100644 examples/drivers/windows/otLwf/command.c create mode 100644 examples/drivers/windows/otLwf/command.h diff --git a/etc/visual-studio/otLwf.vcxproj b/etc/visual-studio/otLwf.vcxproj index fea7869b4..ccf3f592e 100644 --- a/etc/visual-studio/otLwf.vcxproj +++ b/etc/visual-studio/otLwf.vcxproj @@ -86,6 +86,7 @@ + @@ -103,6 +104,7 @@ + diff --git a/etc/visual-studio/otLwf.vcxproj.filters b/etc/visual-studio/otLwf.vcxproj.filters index bb43d0104..7e2442a36 100644 --- a/etc/visual-studio/otLwf.vcxproj.filters +++ b/etc/visual-studio/otLwf.vcxproj.filters @@ -98,6 +98,9 @@ Source Files + + Source Files + diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index 41ee80dfc..4844bbfa0 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -3205,6 +3205,157 @@ otIp6PrefixMatch( return rval; } +OTAPI +const char * +OTCALL +otThreadErrorToString( + ThreadError aError + ) +{ + const char *retval; + + switch (aError) + { + case kThreadError_None: + retval = "None"; + break; + + case kThreadError_Failed: + retval = "Failed"; + break; + + case kThreadError_Drop: + retval = "Drop"; + break; + + case kThreadError_NoBufs: + retval = "NoBufs"; + break; + + case kThreadError_NoRoute: + retval = "NoRoute"; + break; + + case kThreadError_Busy: + retval = "Busy"; + break; + + case kThreadError_Parse: + retval = "Parse"; + break; + + case kThreadError_InvalidArgs: + retval = "InvalidArgs"; + break; + + case kThreadError_Security: + retval = "Security"; + break; + + case kThreadError_AddressQuery: + retval = "AddressQuery"; + break; + + case kThreadError_NoAddress: + retval = "NoAddress"; + break; + + case kThreadError_NotReceiving: + retval = "NotReceiving"; + break; + + case kThreadError_Abort: + retval = "Abort"; + break; + + case kThreadError_NotImplemented: + retval = "NotImplemented"; + break; + + case kThreadError_InvalidState: + retval = "InvalidState"; + break; + + case kThreadError_NoTasklets: + retval = "NoTasklets"; + break; + + case kThreadError_NoAck: + retval = "NoAck"; + break; + + case kThreadError_ChannelAccessFailure: + retval = "ChannelAccessFailure"; + break; + + case kThreadError_Detached: + retval = "Detached"; + break; + + case kThreadError_FcsErr: + retval = "FcsErr"; + break; + + case kThreadError_NoFrameReceived: + retval = "NoFrameReceived"; + break; + + case kThreadError_UnknownNeighbor: + retval = "UnknownNeighbor"; + break; + + case kThreadError_InvalidSourceAddress: + retval = "InvalidSourceAddress"; + break; + + case kThreadError_WhitelistFiltered: + retval = "WhitelistFiltered"; + break; + + case kThreadError_DestinationAddressFiltered: + retval = "DestinationAddressFiltered"; + break; + + case kThreadError_NotFound: + retval = "NotFound"; + break; + + case kThreadError_Already: + retval = "Already"; + break; + + case kThreadError_BlacklistFiltered: + retval = "BlacklistFiltered"; + break; + + case kThreadError_Ipv6AddressCreationFailure: + retval = "Ipv6AddressCreationFailure"; + break; + + case kThreadError_NotCapable: + retval = "NotCapable"; + break; + + case kThreadError_ResponseTimeout: + retval = "ResponseTimeout"; + break; + + case kThreadError_Duplicated: + retval = "Duplicated"; + break; + + case kThreadError_Error: + retval = "GenericError"; + break; + + default: + retval = "UnknownErrorType"; + break; + } + + return retval; +} + OTAPI ThreadError OTCALL @@ -3267,7 +3418,7 @@ OTAPI ThreadError OTCALL otCommissionerStart( - _In_ otInstance *aInstance + _In_ otInstance *aInstance ) { if (aInstance == nullptr) return kThreadError_InvalidArgs; @@ -3278,7 +3429,7 @@ OTAPI ThreadError OTCALL otCommissionerAddJoiner( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, const otExtAddress *aExtAddress, const char *aPSKd ) @@ -3308,7 +3459,7 @@ OTAPI ThreadError OTCALL otCommissionerRemoveJoiner( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, const otExtAddress *aExtAddress ) { @@ -3329,7 +3480,7 @@ OTAPI ThreadError OTCALL otCommissionerSetProvisioningUrl( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, const char *aProvisioningUrl ) { @@ -3371,7 +3522,7 @@ OTAPI ThreadError OTCALL otCommissionerStop( - _In_ otInstance *aInstance + _In_ otInstance *aInstance ) { if (aInstance == nullptr) return kThreadError_InvalidArgs; @@ -3382,7 +3533,7 @@ OTAPI ThreadError OTCALL otCommissionerEnergyScan( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod, @@ -3407,12 +3558,12 @@ OTAPI ThreadError OTCALL otCommissionerPanIdQuery( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, uint16_t aPanId, uint32_t aChannelMask, const otIp6Address *aAddress, - _In_ otCommissionerPanIdConflictCallback aCallback, - _In_ void *aContext + _In_ otCommissionerPanIdConflictCallback aCallback, + _In_ void *aContext ) { if (aInstance == nullptr) return kThreadError_InvalidArgs; @@ -3430,7 +3581,7 @@ OTAPI ThreadError OTCALL otSendMgmtCommissionerGet( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, const uint8_t *aTlvs, uint8_t aLength ) @@ -3458,7 +3609,7 @@ OTAPI ThreadError OTCALL otSendMgmtCommissionerSet( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, const otCommissioningDataset *aDataset, const uint8_t *aTlvs, uint8_t aLength @@ -3484,11 +3635,23 @@ otSendMgmtCommissionerSet( return result; } +OTAPI +uint16_t +OTCALL +otCommissionerGetSessionId( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return 0; + // TODO + return 0; +} + OTAPI ThreadError OTCALL otJoinerStart( - _In_ otInstance *aInstance, + _In_ otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl, const char *aVendorName, @@ -3534,7 +3697,7 @@ OTAPI ThreadError OTCALL otJoinerStop( - _In_ otInstance *aInstance + _In_ otInstance *aInstance ) { if (aInstance == nullptr) return kThreadError_InvalidArgs; diff --git a/examples/drivers/windows/otLwf/address.c b/examples/drivers/windows/otLwf/address.c index 2dd6b917e..521930cfe 100644 --- a/examples/drivers/windows/otLwf/address.c +++ b/examples/drivers/windows/otLwf/address.c @@ -256,12 +256,19 @@ otLwfAddressChangeCallback( // Since we don't pass in the initial flag, we shouldn't get this type NT_ASSERT(NotificationType != MibInitialNotification); - // Queue up the event for processing - otLwfEventProcessingIndicateAddressChange( - pFilter, - NotificationType, - &Row->Address.Ipv6.sin6_addr - ); + // Make sure we can reference the interface + if (ExAcquireRundownProtection(&pFilter->ExternalRefs)) + { + // Queue up the event for processing + otLwfEventProcessingIndicateAddressChange( + pFilter, + NotificationType, + &Row->Address.Ipv6.sin6_addr + ); + + // Release reference on the interface + ExReleaseRundownProtection(&pFilter->ExternalRefs); + } LogFuncExit(DRIVER_DEFAULT); } @@ -382,7 +389,7 @@ otLwfRadioAddressesUpdated( ULONG FoundInOpenThread = 0; // Bit field ULONG OriginalCacheLength = pFilter->otCachedAddrCount; - NT_ASSERT(pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO); + NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE); const otNetifAddress* addr = otGetUnicastAddresses(pFilter->otCtx); @@ -428,7 +435,7 @@ otLwfTunAddressesUpdated( LogFuncEntry(DRIVER_DEFAULT); - NT_ASSERT (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD); + NT_ASSERT (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE); *aNotifFlags = 0; diff --git a/examples/drivers/windows/otLwf/command.c b/examples/drivers/windows/otLwf/command.c new file mode 100644 index 000000000..5c63cfe61 --- /dev/null +++ b/examples/drivers/windows/otLwf/command.c @@ -0,0 +1,1276 @@ +/* + * 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 functions for sending/receiving Spinel commands to the miniport. + */ + +#include "precomp.h" +#include "command.tmh" + +typedef struct _SPINEL_CMD_HANDLER_ENTRY +{ + LIST_ENTRY Link; + volatile LONG RefCount; + SPINEL_CMD_HANDLER *Handler; + PVOID Context; + spinel_tid_t TransactionId; +} SPINEL_CMD_HANDLER_ENTRY; + +void AddEntryRef(SPINEL_CMD_HANDLER_ENTRY *pEntry) { InterlockedIncrement(&pEntry->RefCount); } +void ReleaseEntryRef(SPINEL_CMD_HANDLER_ENTRY *pEntry) +{ + if (InterlockedDecrement(&pEntry->RefCount) == 0) + { + FILTER_FREE_MEM(pEntry); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NDIS_STATUS +otLwfCmdInitialize( + _In_ PMS_FILTER pFilter + ) +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + NTSTATUS NtStatus = STATUS_SUCCESS; + uint32_t InterfaceType = 0; + + NET_BUFFER_LIST_POOL_PARAMETERS PoolParams = + { + { NDIS_OBJECT_TYPE_DEFAULT, NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1, NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1 }, + NDIS_PROTOCOL_ID_DEFAULT, + TRUE, + 0, + 'lbNC', // CNbl + 0 + }; + + LogFuncEntry(DRIVER_DEFAULT); + + do + { + pFilter->cmdTIDsInUse = 0; + pFilter->cmdNextTID = 1; + + NdisAllocateSpinLock(&pFilter->cmdLock); + InitializeListHead(&pFilter->cmdHandlers); + + // Enable rundown protection + ExReInitializeRundownProtection(&pFilter->cmdRundown); + + // Create the NDIS pool for creating the SendNetBufferList + pFilter->cmdNblPool = NdisAllocateNetBufferListPool(pFilter->FilterHandle, &PoolParams); + if (pFilter->cmdNblPool == NULL) + { + Status = NDIS_STATUS_RESOURCES; + LogWarning(DRIVER_DEFAULT, "Failed to create NetBufferList pool for Spinel commands"); + break; + } + + // Query the interface type to make sure it is a Thread device +#if DBG + pFilter->cmdInitTryCount = 0; + while (pFilter->cmdInitTryCount < 10) + { + NtStatus = otLwfCmdGetProp(pFilter, NULL, SPINEL_PROP_INTERFACE_TYPE, SPINEL_DATATYPE_UINT_PACKED_S, &InterfaceType); + if (!NT_SUCCESS(NtStatus)) + { + pFilter->cmdInitTryCount++; + NdisMSleep(100); + continue; + } + break; + } + if (pFilter->cmdInitTryCount >= 10) + { +#else + NtStatus = otLwfCmdGetProp(pFilter, NULL, SPINEL_PROP_INTERFACE_TYPE, SPINEL_DATATYPE_UINT_PACKED_S, &InterfaceType); + if (!NT_SUCCESS(NtStatus)) + { +#endif + Status = NDIS_STATUS_NOT_SUPPORTED; + LogError(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_INTERFACE_TYPE, %!STATUS!", NtStatus); + break; + } + if (InterfaceType != SPINEL_PROTOCOL_TYPE_THREAD) + { + Status = NDIS_STATUS_NOT_SUPPORTED; + LogError(DRIVER_DEFAULT, "SPINEL_PROP_INTERFACE_TYPE is invalid, %d", InterfaceType); + break; + } + + } while (FALSE); + + LogFuncExitNDIS(DRIVER_DEFAULT, Status); + + // Clean up on failure + if (Status != NDIS_STATUS_SUCCESS) + { + otLwfCmdUninitialize(pFilter); + } + + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +otLwfCmdUninitialize( + _In_ PMS_FILTER pFilter + ) +{ + LogFuncEntry(DRIVER_DEFAULT); + + // Release and wait for run down. This will block waiting for any pending sends to complete + ExWaitForRundownProtectionRelease(&pFilter->cmdRundown); + + // Use the NBL Pool variable as a flag for initialization + if (pFilter->cmdNblPool) + { + // Clean up any pending handlers + PLIST_ENTRY Link = pFilter->cmdHandlers.Flink; + while (Link != &pFilter->cmdHandlers) + { + SPINEL_CMD_HANDLER_ENTRY* pEntry = CONTAINING_RECORD(Link, SPINEL_CMD_HANDLER_ENTRY, Link); + Link = Link->Flink; + + if (pEntry->Handler) + { + pEntry->Handler(pFilter, pEntry->Context, 0, 0, NULL, 0); + } + + ReleaseEntryRef(pEntry); + } + InitializeListHead(&pFilter->cmdHandlers); + + // Free NBL Pool + NdisFreeNetBufferPool(pFilter->cmdNblPool); + pFilter->cmdNblPool = NULL; + } + + LogFuncExit(DRIVER_DEFAULT); +} + +// +// Receive Spinel Encoded Command +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfCmdProcess( + _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; + } + + // Get the transaction ID + if (SPINEL_HEADER_GET_TID(Header) == 0) + { + if (ExAcquireRundownProtection(&pFilter->ExternalRefs)) + { + // If this is a 'Value Is' command, process it for notification of state changes. + if (command == SPINEL_CMD_PROP_VALUE_IS) + { + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) + { + otLwfThreadValueIs(pFilter, DispatchLevel, key, value_data_ptr, value_data_len); + } + else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) + { + otLwfTunValueIs(pFilter, DispatchLevel, key, value_data_ptr, value_data_len); + } + } + else if (command == SPINEL_CMD_PROP_VALUE_INSERTED) + { + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) + { + otLwfThreadValueInserted(pFilter, DispatchLevel, key, value_data_ptr, value_data_len); + } + else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) + { + otLwfTunValueInserted(pFilter, DispatchLevel, key, value_data_ptr, value_data_len); + } + } + + ExReleaseRundownProtection(&pFilter->ExternalRefs); + } + } + // 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->cmdLock, DispatchLevel); + + // Search for matching handlers for this command + Link = pFilter->cmdHandlers.Flink; + while (Link != &pFilter->cmdHandlers) + { + 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); + + // Cache the handler + Handler = pEntry; + + // Remove the transaction ID from the 'in use' bit field + pFilter->cmdTIDsInUse &= ~(1 << pEntry->TransactionId); + + break; + } + } + + FILTER_RELEASE_LOCK(&pFilter->cmdLock, 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 + ReleaseEntryRef(Handler); + } + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfCmdRecveive( + _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 + otLwfCmdProcess(pFilter, DispatchLevel, Command, Buffer, BufferLength); +} + +// +// Send Async Spinel Encoded Command +// + +_IRQL_requires_max_(PASSIVE_LEVEL) +spinel_tid_t +otLwfCmdGetNextTID( + _In_ PMS_FILTER pFilter + ) +{ + spinel_tid_t TID = 0; + while (TID == 0) + { + NdisAcquireSpinLock(&pFilter->cmdLock); + + if (((1 << pFilter->cmdNextTID) & pFilter->cmdTIDsInUse) == 0) + { + TID = pFilter->cmdNextTID; + pFilter->cmdNextTID = SPINEL_GET_NEXT_TID(pFilter->cmdNextTID); + pFilter->cmdTIDsInUse |= (1 << TID); + } + + NdisReleaseSpinLock(&pFilter->cmdLock); + + if (TID == 0) + { + // TODO - Wait for event + } + } + return TID; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +otLwfCmdAddHandler( + _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 = otLwfCmdGetNextTID(pFilter); + + LogFuncEntryMsg(DRIVER_DEFAULT, "tid=%u", (ULONG)pEntry->TransactionId); + + NdisAcquireSpinLock(&pFilter->cmdLock); + + // Add to the handlers list + AddEntryRef(pEntry); + InsertTailList(&pFilter->cmdHandlers, &pEntry->Link); + + NdisReleaseSpinLock(&pFilter->cmdLock); + + LogFuncExit(DRIVER_DEFAULT); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdEncodeAndSendAsync( + _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->cmdNblPool, // 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; + } + + // Grab a ref for rundown protection + if (!ExAcquireRundownProtection(&pFilter->cmdRundown)) + { + status = STATUS_DEVICE_NOT_READY; + LogWarning(DRIVER_DEFAULT, "Failed to acquire rundown protection"); + goto exit; + } + + // 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 +otLwfCmdSendAsyncV( + _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->RefCount = 1; + pEntry->Handler = Handler; + pEntry->Context = HandlerContext; + + otLwfCmdAddHandler(pFilter, pEntry); + + if (pTid) *pTid = pEntry->TransactionId; + } + + status = otLwfCmdEncodeAndSendAsync(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->cmdLock); + + // Remove from the main list + RemoveEntryList(&pEntry->Link); + + // Remove the transaction ID from the 'in use' bit field + pFilter->cmdTIDsInUse &= ~(1 << pEntry->TransactionId); + + NdisReleaseSpinLock(&pFilter->cmdLock); + + // TODO - Set event + + ReleaseEntryRef(pEntry); + } + +exit: + + if (pEntry) ReleaseEntryRef(pEntry); + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdSendAsync( + _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 = + otLwfCmdSendAsyncV(pFilter, Handler, HandlerContext, pTid, Command, Key, MaxDataLength, pack_format, args); + va_end(args); + return status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +otLwfCmdCancel( + _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->cmdLock, DispatchLevel); + + // Search for matching handlers for this transaction ID + Link = pFilter->cmdHandlers.Flink; + while (Link != &pFilter->cmdHandlers) + { + 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->cmdTIDsInUse &= ~(1 << pEntry->TransactionId); + + break; + } + } + + FILTER_RELEASE_LOCK(&pFilter->cmdLock, DispatchLevel); + + if (Handler) + { + // Call the handler function + Handler->Handler(pFilter, Handler->Context, 0, 0, NULL, 0); + + // Free the entry + ReleaseEntryRef(Handler); + } + + LogFuncExitMsg(DRIVER_DEFAULT, "Found=%u", Found); + + return Found; +} + +// +// Send Packet/Frame +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +otLwfCmdSendIp6PacketAsync( + _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->cmdNblPool, // 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; + + // Grab a ref for rundown protection + if (!ExAcquireRundownProtection(&pFilter->cmdRundown)) + { + status = STATUS_DEVICE_NOT_READY; + LogWarning(DRIVER_DEFAULT, "Failed to acquire rundown protection"); + goto exit; + } + + 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_(DISPATCH_LEVEL) +VOID +otLwfCmdSendMacFrameComplete( + _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 + ) +{ + UNREFERENCED_PARAMETER(Context); + + pFilter->otLastTransmitError = kThreadError_Abort; + + if (Data && Command == SPINEL_CMD_PROP_VALUE_IS) + { + 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) + { + if (spinel_status == SPINEL_STATUS_OK) + { + pFilter->otLastTransmitError = kThreadError_None; + (void)spinel_datatype_unpack( + Data + packed_len, + DataLength - (spinel_size_t)packed_len, + "b", + &pFilter->otLastTransmitFramePending); + } + else + { + pFilter->otLastTransmitError = SpinelStatusToThreadError(spinel_status); + } + } + } + } + + // Set the completion event + KeSetEvent(&pFilter->SendNetBufferListComplete, IO_NO_INCREMENT, FALSE); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +otLwfCmdSendMacFrameAsync( + _In_ PMS_FILTER pFilter, + _In_ RadioPacket* Packet + ) +{ + // Reset the completion event + KeResetEvent(&pFilter->SendNetBufferListComplete); + pFilter->SendPending = TRUE; + + NTSTATUS status = + otLwfCmdSendAsync( + pFilter, + otLwfCmdSendMacFrameComplete, + NULL, + NULL, + SPINEL_CMD_PROP_VALUE_SET, + SPINEL_PROP_STREAM_RAW, + Packet->mLength + 20, + "DCc", + Packet->mPsdu, + (uint32_t)Packet->mLength, + Packet->mChannel, + Packet->mPower + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_STREAM_RAW failed, %!STATUS!", status); + pFilter->otLastTransmitError = kThreadError_Abort; + KeSetEvent(&pFilter->SendNetBufferListComplete, IO_NO_INCREMENT, FALSE); + } +} + +// +// Send Synchronous Spinel Encoded Command +// + +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 + { + ThreadError errorCode = SpinelStatusToThreadError(spinel_status); + LogVerbose(DRIVER_DEFAULT, "Get key=%u failed with %!otError!", CmdContext->Key, errorCode); + CmdContext->Status = ThreadErrorToNtstatus(errorCode); + } + } + 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 +otLwfCmdGetProp( + _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 = + otLwfCmdSendAsyncV( + 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 (!otLwfCmdCancel(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 + { + ThreadError errorCode = SpinelStatusToThreadError(spinel_status); + LogVerbose(DRIVER_DEFAULT, "Set key=%u failed with %!otError!", CmdContext->Key, errorCode); + CmdContext->Status = ThreadErrorToNtstatus(errorCode); + } + } + 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 +otLwfCmdSetProp( + _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 = + otLwfCmdSendAsyncV( + pFilter, + otLwfSetPropHandler, + &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 (!otLwfCmdCancel(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; +} + +// +// General Spinel Helpers +// + +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; +} + +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); +} diff --git a/examples/drivers/windows/otLwf/command.h b/examples/drivers/windows/otLwf/command.h new file mode 100644 index 000000000..293bea0a3 --- /dev/null +++ b/examples/drivers/windows/otLwf/command.h @@ -0,0 +1,179 @@ +/* + * 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 sending/receiving Spinel commands to the miniport. + */ + +#ifndef _COMMAND_H_ +#define _COMMAND_H_ + +// +// Initialization +// + +_IRQL_requires_max_(PASSIVE_LEVEL) +NDIS_STATUS +otLwfCmdInitialize( + _In_ PMS_FILTER pFilter + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +otLwfCmdUninitialize( + _In_ PMS_FILTER pFilter + ); + +// +// Receive Spinel Encoded Command +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfCmdRecveive( + _In_ PMS_FILTER pFilter, + _In_ BOOLEAN DispatchLevel, + _In_reads_bytes_(BufferLength) const PUCHAR Buffer, + _In_ ULONG BufferLength + ); + +// +// Send Async Spinel Encoded Command +// + +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 + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdSendAsyncV( + _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 +otLwfCmdSendAsync( + _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) +BOOLEAN +otLwfCmdCancel( + _In_ PMS_FILTER pFilter, + _In_ BOOLEAN DispatchLevel, + _In_ spinel_tid_t tid + ); + +// +// Send Packet/Frame +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +otLwfCmdSendIp6PacketAsync( + _In_ PMS_FILTER pFilter, + _In_ BOOLEAN DispatchLevel, + _In_ PNET_BUFFER IpNetBuffer, + _In_ BOOLEAN Secured + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +otLwfCmdSendMacFrameAsync( + _In_ PMS_FILTER pFilter, + _In_ RadioPacket* Packet + ); + +// +// Send Synchronous Spinel Encoded Command +// + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfCmdGetProp( + _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 +otLwfCmdSetProp( + _In_ PMS_FILTER pFilter, + _In_ spinel_prop_key_t Key, + _In_ const char *pack_format, + ... + ); + +// +// General Spinel Helpers +// + +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, + ... + ); + +#endif //_COMMAND_H_ diff --git a/examples/drivers/windows/otLwf/datapath.c b/examples/drivers/windows/otLwf/datapath.c index 4188d3d68..80223b4ad 100644 --- a/examples/drivers/windows/otLwf/datapath.c +++ b/examples/drivers/windows/otLwf/datapath.c @@ -74,52 +74,6 @@ otLogBuffer( #endif -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID -otLwfEnableDataPath( - _In_ PMS_FILTER pFilter - ) -/*++ - -Routine Description: - - Enables the datapath to allow NLBs to go through to OpenThread. - ---*/ -{ - LogFuncEntry(DRIVER_DEFAULT); - - LogInfo(DRIVER_DEFAULT, "Interface %!GUID! enabling data path.", &pFilter->InterfaceGuid); - - // Re-enabling data path - ExReInitializeRundownProtection(&pFilter->DataPathRundown); - - LogFuncExit(DRIVER_DEFAULT); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID -otLwfDisableDataPath( - _In_ PMS_FILTER pFilter - ) -/*++ - -Routine Description: - - Disables the datapath and waits for any outstanding calls - into OpenThread to complete. - ---*/ -{ - LogFuncEntry(DRIVER_DEFAULT); - - LogInfo(DRIVER_DEFAULT, "Interface %!GUID! disabling data path.", &pFilter->InterfaceGuid); - - ExWaitForRundownProtectionRelease(&pFilter->DataPathRundown); - - LogFuncExit(DRIVER_DEFAULT); -} - _Use_decl_annotations_ VOID FilterSendNetBufferListsComplete( @@ -151,32 +105,35 @@ Arguments: LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, NBL: %p %!STATUS!", FilterModuleContext, NetBufferLists, NetBufferLists->Status); - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) + PNET_BUFFER_LIST NBL = NetBufferLists; + while (NBL) { - 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); + PNET_BUFFER_LIST NextNBL = NBL->Next; + PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB(NBL); // Cancel command if we failed to send the NBL - if (!NT_SUCCESS(NetBufferLists->Status)) + if (!NT_SUCCESS(NBL->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); +#if DBG + NT_ASSERT(pFilter->cmdInitTryCount < 9 || NBL->Status != NDIS_STATUS_PAUSED); +#endif + otLwfCmdCancel(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); + NdisFreeNetBufferList(NBL); + + // Release the command rundown protection + ExReleaseRundownProtection(&pFilter->cmdRundown); + + NBL = NextNBL; } - + LogFuncExit(DRIVER_DATA_PATH); } @@ -211,11 +168,13 @@ Arguments: { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; BOOLEAN DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); - + + UNREFERENCED_PARAMETER(PortNumber); + LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, NBL: %p", FilterModuleContext, NetBufferLists); - + // Try to grab a ref on the data path first, to make sure we are allowed - if (!ExAcquireRundownProtection(&pFilter->DataPathRundown)) + if (!ExAcquireRundownProtection(&pFilter->ExternalRefs)) { LogVerbose(DRIVER_DEFAULT, "Failing SendNetBufferLists because data path isn't active."); @@ -234,14 +193,12 @@ Arguments: } else { - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) { // Indicate a new NBL to process on our worker thread otLwfEventProcessingIndicateNewNetBufferLists( pFilter, DispatchLevel, - FALSE, - PortNumber, NetBufferLists ); } @@ -253,7 +210,7 @@ Arguments: PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl); while (CurrNb) { - otLwfSendTunnelPacket(pFilter, DispatchLevel, CurrNb, TRUE); + otLwfCmdSendIp6PacketAsync(pFilter, DispatchLevel, CurrNb, TRUE); CurrNb = NET_BUFFER_NEXT_NB(CurrNb); } @@ -269,12 +226,48 @@ Arguments: } // Release the data path ref now - ExReleaseRundownProtection(&pFilter->DataPathRundown); + ExReleaseRundownProtection(&pFilter->ExternalRefs); } LogFuncExit(DRIVER_DATA_PATH); } +_Use_decl_annotations_ +VOID +FilterCancelSendNetBufferLists( + NDIS_HANDLE FilterModuleContext, + PVOID CancelId + ) +/*++ + +Routine Description: + + This function cancels any NET_BUFFER_LISTs pended in the filter and then + calls the NdisFCancelSendNetBufferLists to propagate the cancel operation. + + If your driver does not queue any send NBLs, you may omit this routine. + NDIS will propagate the cancelation on your behalf more efficiently. + +Arguments: + + FilterModuleContext - our filter context area. + CancelId - an identifier for all NBLs that should be dequeued + +*/ +{ + PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; + + LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, CancelId: %p", FilterModuleContext, CancelId); + + // Only cancel if we are 'Thread on Host', otherwise we do everything inline + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) + { + otLwfEventProcessingIndicateNetBufferListsCancelled(pFilter, CancelId); + } + + LogFuncExit(DRIVER_DATA_PATH); +} + _Use_decl_annotations_ VOID FilterReturnNetBufferLists( @@ -318,19 +311,15 @@ 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); - CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); - NET_BUFFER_LIST_NEXT_NBL(NblToFree) = NULL; + PNET_BUFFER_LIST NblToFree = CurrNbl; + PNET_BUFFER NbToFree = NET_BUFFER_LIST_FIRST_NB(NblToFree); - NdisAdvanceNetBufferDataStart(NbToFree, NET_BUFFER_DATA_LENGTH(NbToFree), TRUE, NULL); - NdisFreeNetBufferList(NblToFree); - } + 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); } LogFuncExit(DRIVER_DATA_PATH); @@ -375,143 +364,55 @@ N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; BOOLEAN DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags); - + + UNREFERENCED_PARAMETER(PortNumber); + UNREFERENCED_PARAMETER(NumberOfNetBufferLists); + LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, NBL: %p", FilterModuleContext, NetBufferLists); - ASSERT(NumberOfNetBufferLists >= 1); - UNREFERENCED_PARAMETER(NumberOfNetBufferLists); - - // We don't support non-pending NBLs - NT_ASSERT(NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags)); - if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags)) + // Iterate through each NBL/NB and grab the data as a contiguous buffer to + // indicate to the Spinel command layer. + PNET_BUFFER_LIST CurrNbl = NetBufferLists; + while (CurrNbl) { - PNET_BUFFER_LIST CurrNbl = NetBufferLists; - while (CurrNbl) + PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl); + while (CurrNb) { - NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_NOT_SUPPORTED; - 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) { - 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) { - 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); + if (_Buffer) { - 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); + otLwfCmdRecveive(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); + else + { + otLwfCmdRecveive(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); + } + + if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags)) + { 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)) - { - LogVerbose(DRIVER_DATA_PATH, "Failing ReceiveNetBufferLists because data path isn't active."); - // Ignore any NBLs we get if we aren't active (can't get a ref) - PNET_BUFFER_LIST CurrNbl = NetBufferLists; - while (CurrNbl) - { - NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED; - CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); - } - NdisFReturnNetBufferLists( - pFilter->FilterHandle, - NetBufferLists, - DispatchLevel ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0 - ); - } - else - { -#if DBG - PNET_BUFFER_LIST CurrNbl = NetBufferLists; - while (CurrNbl) - { - POT_NBL_CONTEXT NblContext = GetNBLContext(CurrNbl); - NT_ASSERT(NblContext->Channel >= 11 && NblContext->Channel <= 26); - CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); - } - -#endif - // Indicate a new NBL to process on our worker thread - otLwfEventProcessingIndicateNewNetBufferLists( - pFilter, - DispatchLevel, - TRUE, - PortNumber, - NetBufferLists - ); - - // Release the data path ref now - ExReleaseRundownProtection(&pFilter->DataPathRundown); - } - - LogFuncExit(DRIVER_DATA_PATH); -} - -_Use_decl_annotations_ -VOID -FilterCancelSendNetBufferLists( - NDIS_HANDLE FilterModuleContext, - PVOID CancelId - ) -/*++ - -Routine Description: - - This function cancels any NET_BUFFER_LISTs pended in the filter and then - calls the NdisFCancelSendNetBufferLists to propagate the cancel operation. - - If your driver does not queue any send NBLs, you may omit this routine. - NDIS will propagate the cancelation on your behalf more efficiently. - -Arguments: - - FilterModuleContext - our filter context area. - CancelId - an identifier for all NBLs that should be dequeued - -*/ -{ - PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; - - LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p, CancelId: %p", FilterModuleContext, CancelId); - - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) - { - otLwfEventProcessingIndicateNetBufferListsCancelled(pFilter, CancelId); - } - else - { - NT_ASSERT(FALSE); // TODO - } - LogFuncExit(DRIVER_DATA_PATH); } @@ -539,7 +440,7 @@ otLwfReceiveIp6DatagramCallback( // Create the NetBufferList NetBufferList = NdisAllocateNetBufferAndNetBufferList( - pFilter->NetBufferListPool, // PoolHandle + pFilter->cmdNblPool, // PoolHandle 0, // ContextSize 0, // ContextBackFill NULL, // MdlChain @@ -556,7 +457,7 @@ otLwfReceiveIp6DatagramCallback( 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; @@ -607,7 +508,7 @@ otLwfReceiveIp6DatagramCallback( LogVerbose(DRIVER_DATA_PATH, "Filter: %p dropping internal address message.", pFilter); goto error; } - + // Filter internal Thread messages if (v6Header->NextHeader == IPPROTO_UDP && messageLength >= sizeof(IPV6_HEADER) + sizeof(UDPHeader) && @@ -624,7 +525,7 @@ otLwfReceiveIp6DatagramCallback( goto error; } } - + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, IP6_RECV: %p : %!IPV6ADDR! => %!IPV6ADDR! (%u bytes)", pFilter, NetBufferList, &v6Header->SourceAddress, &v6Header->DestinationAddress, messageLength); @@ -664,3 +565,108 @@ error: otFreeMessage(aMessage); } + +// Called in response to receiving a Spinel Ip6 packet command +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfTunReceiveIp6Packet( + _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->cmdNblPool, // 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/device.c b/examples/drivers/windows/otLwf/device.c index 57ff80aa5..81188b1ba 100644 --- a/examples/drivers/windows/otLwf/device.c +++ b/examples/drivers/windows/otLwf/device.c @@ -80,7 +80,7 @@ otLwfRegisterDevice( NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING); Status = IoCreateDeviceSecure(FilterDriverObject, // DriverObject - sizeof(OTLWF_DEVICE_EXTENSION), // DeviceExtension + sizeof(OTLWF_DEVICE_EXTENSION), // DeviceExtension &DeviceName, // DeviceName FILE_DEVICE_NETWORK, // DeviceType FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics @@ -352,7 +352,7 @@ otLwfDeviceIoControl( ULONG OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; - ULONG FuncCode = (IoControlCode >> 2) & 0xFFF; + ULONG FuncCode = (IoControlCode >> 2) & 0xFFF; LogFuncEntryMsg(DRIVER_IOCTL, "%p", IrpSp->FileObject); @@ -442,9 +442,10 @@ otLwfFindAndRefInterface( if (pFilter->State == FilterRunning && memcmp(InterfaceGuid, &pFilter->InterfaceGuid, sizeof(GUID)) == 0) { - // Increment ref count on interface - RtlIncrementReferenceCount(&pFilter->IoControlReferences); - pOutput = pFilter; + if (ExAcquireRundownProtection(&pFilter->ExternalRefs)) + { + pOutput = pFilter; + } break; } } @@ -454,19 +455,6 @@ otLwfFindAndRefInterface( return pOutput; } -_Use_decl_annotations_ -VOID -otLwfReleaseInterface( - _In_ PMS_FILTER pFilter - ) -{ - // Decrement ref count, and set shutdown event if it goes to 0 - if (RtlDecrementReferenceCount(&pFilter->IoControlReferences)) - { - NdisSetEvent(&pFilter->IoControlShutdownComplete); - } -} - // // Notification Functions // diff --git a/examples/drivers/windows/otLwf/device.h b/examples/drivers/windows/otLwf/device.h index 45daedd84..5bba716a4 100644 --- a/examples/drivers/windows/otLwf/device.h +++ b/examples/drivers/windows/otLwf/device.h @@ -132,14 +132,6 @@ otLwfFindAndRefInterface( _In_ PGUID InterfaceGuid ); -// Releases a successfully referenced Thread interface from a previous -// call to otLwfFindAndRefInterface. -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID -otLwfReleaseInterface( - _In_ PMS_FILTER pFilter - ); - // // Notification Type and Functions // diff --git a/examples/drivers/windows/otLwf/driver.c b/examples/drivers/windows/otLwf/driver.c index 6b2f2934e..bc3d9e7d1 100644 --- a/examples/drivers/windows/otLwf/driver.c +++ b/examples/drivers/windows/otLwf/driver.c @@ -75,68 +75,67 @@ Return Value: --*/ { - NDIS_STATUS Status; - NDIS_FILTER_DRIVER_CHARACTERISTICS FChars; - NDIS_STRING ServiceName = RTL_CONSTANT_STRING(FILTER_SERVICE_NAME); - NDIS_STRING UniqueName = RTL_CONSTANT_STRING(FILTER_UNIQUE_NAME); - NDIS_STRING FriendlyName = RTL_CONSTANT_STRING(FILTER_FRIENDLY_NAME); - BOOLEAN bFalse = FALSE; + NDIS_STATUS Status; - // // Initialize WPP logging - // WPP_INIT_TRACING(DriverObject, RegistryPath); - // // Save global DriverObject - // FilterDriverObject = DriverObject; - // Cache perf freq + // Set the driver unload handler + DriverObject->DriverUnload = DriverUnload; + + // Cache performance counter frequency (VOID)KeQueryPerformanceCounter(&FilterPerformanceFrequency); - LogFuncEntry(DRIVER_DEFAULT); + LogFuncEntryMsg(DRIVER_DEFAULT, "Registry: %S", RegistryPath->Buffer); do { - NdisZeroMemory(&FChars, sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS)); - FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS; - FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS); + NDIS_FILTER_DRIVER_CHARACTERISTICS FChars = + { + { + NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS, #if NDIS_SUPPORT_NDIS61 - FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_2; + NDIS_FILTER_CHARACTERISTICS_REVISION_2, #else - FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1; + NDIS_FILTER_CHARACTERISTICS_REVISION_1, #endif + sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS) + }, + NDIS_FILTER_MAJOR_VERSION, + NDIS_FILTER_MINOR_VERSION, + 1, + 0, + 0, + RTL_CONSTANT_STRING(FILTER_FRIENDLY_NAME), + RTL_CONSTANT_STRING(FILTER_UNIQUE_NAME), + RTL_CONSTANT_STRING(FILTER_SERVICE_NAME), - FChars.MajorNdisVersion = NDIS_FILTER_MAJOR_VERSION; - FChars.MinorNdisVersion = NDIS_FILTER_MINOR_VERSION; - FChars.MajorDriverVersion = 1; - FChars.MinorDriverVersion = 0; - FChars.Flags = 0; - - FChars.FriendlyName = FriendlyName; - FChars.UniqueName = UniqueName; - FChars.ServiceName = ServiceName; - - DriverObject->DriverUnload = DriverUnload; - - FChars.AttachHandler = FilterAttach; - FChars.DetachHandler = FilterDetach; - FChars.RestartHandler = FilterRestart; - FChars.PauseHandler = FilterPause; - FChars.StatusHandler = FilterStatus; - - FChars.OidRequestHandler = FilterOidRequest; - FChars.OidRequestCompleteHandler = FilterOidRequestComplete; - - FChars.DevicePnPEventNotifyHandler = FilterDevicePnPEventNotify; - FChars.NetPnPEventHandler = FilterNetPnPEvent; - - FChars.SendNetBufferListsHandler = FilterSendNetBufferLists; - FChars.ReturnNetBufferListsHandler = FilterReturnNetBufferLists; - FChars.SendNetBufferListsCompleteHandler = FilterSendNetBufferListsComplete; - FChars.ReceiveNetBufferListsHandler = FilterReceiveNetBufferLists; - FChars.CancelSendNetBufferListsHandler = FilterCancelSendNetBufferLists; + NULL, + NULL, + FilterAttach, + FilterDetach, + FilterRestart, + FilterPause, + FilterSendNetBufferLists, + FilterSendNetBufferListsComplete, + FilterCancelSendNetBufferLists, + FilterReceiveNetBufferLists, + FilterReturnNetBufferLists, + FilterOidRequest, + FilterOidRequestComplete, + NULL, + NULL, + NULL, + FilterStatus, +#if (NDIS_SUPPORT_NDIS61) + NULL, + NULL, + NULL, +#endif + }; // // Initialize global variables @@ -147,7 +146,6 @@ Return Value: // // Register the filter with NDIS // - FilterDriverHandle = NULL; Status = NdisFRegisterFilterDriver( DriverObject, @@ -157,7 +155,6 @@ Return Value: ); if (Status != NDIS_STATUS_SUCCESS) { - NdisFreeSpinLock(&FilterListLock); LogError(DRIVER_DEFAULT, "Register filter driver failed, %!NDIS_STATUS!", Status); break; } @@ -168,18 +165,21 @@ Return Value: Status = otLwfRegisterDevice(); if (Status != NDIS_STATUS_SUCCESS) { - NdisFDeregisterFilterDriver(FilterDriverHandle); - NdisFreeSpinLock(&FilterListLock); LogError(DRIVER_DEFAULT, "Register device for the filter driver failed, %!NDIS_STATUS!", Status); break; } - } while (bFalse); + } while (FALSE); LogFuncExitNDIS(DRIVER_DEFAULT, Status); if (Status != NDIS_STATUS_SUCCESS) { + if (FilterDriverHandle) + { + NdisFDeregisterFilterDriver(FilterDriverHandle); + FilterDriverHandle = NULL; + } WPP_CLEANUP(DriverObject); } @@ -223,6 +223,7 @@ Return Value: // Deregister the NDIS filter // NdisFDeregisterFilterDriver(FilterDriverHandle); + FilterDriverHandle = NULL; // Validate we have no outstanding filter instances NT_ASSERT(IsListEmpty(&FilterModuleList)); diff --git a/examples/drivers/windows/otLwf/eventprocessing.c b/examples/drivers/windows/otLwf/eventprocessing.c index 8111a5692..61e831525 100644 --- a/examples/drivers/windows/otLwf/eventprocessing.c +++ b/examples/drivers/windows/otLwf/eventprocessing.c @@ -46,12 +46,19 @@ typedef struct _OTLWF_ADDR_EVENT typedef struct _OTLWF_NBL_EVENT { LIST_ENTRY Link; - BOOLEAN Received; - NDIS_PORT_NUMBER PortNumber; PNET_BUFFER_LIST NetBufferLists; } OTLWF_NBL_EVENT, *POTLWF_NBL_EVENT; +typedef struct _OTLWF_MAC_FRAME_EVENT +{ + LIST_ENTRY Link; + uint8_t BufferLength; + uint8_t Buffer[0]; + +} OTLWF_MAC_FRAME_EVENT, *POTLWF_MAC_FRAME_EVENT; + + KSTART_ROUTINE otLwfEventWorkerThread; _IRQL_requires_max_(DISPATCH_LEVEL) @@ -59,7 +66,6 @@ VOID otLwfCompleteNBLs( _In_ PMS_FILTER pFilter, _In_ BOOLEAN DispatchLevel, - _In_ BOOLEAN Received, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ NTSTATUS Status ); @@ -196,7 +202,21 @@ otLwfEventProcessingStop( 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->NetBufferLists, STATUS_CANCELLED); + + // Delete the event + NdisFreeMemory(Event, 0, 0); + } + } + + // Clean up any left over events + if (pFilter->MacFramesHead.Flink) + { + Link = pFilter->MacFramesHead.Flink; + while (Link != &pFilter->MacFramesHead) + { + POTLWF_MAC_FRAME_EVENT Event = CONTAINING_RECORD(Link, OTLWF_MAC_FRAME_EVENT, Link); + Link = Link->Flink; // Delete the event NdisFreeMemory(Event, 0, 0); @@ -206,6 +226,7 @@ otLwfEventProcessingStop( // Reinitialize the list head InitializeListHead(&pFilter->AddressChangesHead); InitializeListHead(&pFilter->NBLsHead); + InitializeListHead(&pFilter->MacFramesHead); if (pFilter->EventIrpListHead.Flink) { @@ -318,12 +339,7 @@ otLwfEventProcessingIndicateAddressChange( _In_ PIN6_ADDR pAddr ) { - if (pFilter->InternalStateInitialized == FALSE) - { - return; - } - - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) + if (pFilter->DeviceCapabilities == OTLWF_DEVICE_STATUS_RADIO_MODE) { POTLWF_ADDR_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, sizeof(OTLWF_ADDR_EVENT)); if (Event == NULL) @@ -351,8 +367,6 @@ VOID otLwfEventProcessingIndicateNewNetBufferLists( _In_ PMS_FILTER pFilter, _In_ BOOLEAN DispatchLevel, - _In_ BOOLEAN Received, - _In_ NDIS_PORT_NUMBER PortNumber, _In_ PNET_BUFFER_LIST NetBufferLists ) { @@ -360,17 +374,14 @@ otLwfEventProcessingIndicateNewNetBufferLists( if (Event == NULL) { LogWarning(DRIVER_DATA_PATH, "Failed to alloc new OTLWF_NBL_EVENT"); - otLwfCompleteNBLs(pFilter, DispatchLevel, Received, NetBufferLists, STATUS_INSUFFICIENT_RESOURCES); + otLwfCompleteNBLs(pFilter, DispatchLevel, NetBufferLists, STATUS_INSUFFICIENT_RESOURCES); return; } - Event->Received = Received; - Event->PortNumber = PortNumber; Event->NetBufferLists = NetBufferLists; // Add the event to the queue FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, DispatchLevel); - if (Received) pFilter->CountPendingRecvNBLs++; InsertTailList(&pFilter->NBLsHead, &Event->Link); FILTER_RELEASE_LOCK(&pFilter->EventsLock, DispatchLevel); @@ -378,6 +389,35 @@ otLwfEventProcessingIndicateNewNetBufferLists( KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); } +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +otLwfEventProcessingIndicateNewMacFrameCommand( + _In_ PMS_FILTER pFilter, + _In_ BOOLEAN DispatchLevel, + _In_reads_bytes_(BufferLength) + const uint8_t* Buffer, + _In_ uint8_t BufferLength + ) +{ + POTLWF_MAC_FRAME_EVENT Event = FILTER_ALLOC_MEM(pFilter->FilterHandle, FIELD_OFFSET(OTLWF_MAC_FRAME_EVENT, Buffer) + BufferLength); + if (Event == NULL) + { + LogWarning(DRIVER_DATA_PATH, "Failed to alloc new OTLWF_MAC_FRAME_EVENT"); + return; + } + + Event->BufferLength = BufferLength; + memcpy(Event->Buffer, Buffer, BufferLength); + + // Add the event to the queue + FILTER_ACQUIRE_LOCK(&pFilter->EventsLock, DispatchLevel); + InsertTailList(&pFilter->MacFramesHead, &Event->Link); + FILTER_RELEASE_LOCK(&pFilter->EventsLock, DispatchLevel); + + // Set the event to indicate we have a new Mac Frame to process + KeSetEvent(&pFilter->EventWorkerThreadProcessMacFrames, 0, FALSE); +} + _IRQL_requires_max_(DISPATCH_LEVEL) VOID otLwfEventProcessingIndicateNetBufferListsCancelled( @@ -412,7 +452,7 @@ otLwfEventProcessingIndicateNetBufferListsCancelled( 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->NetBufferLists, STATUS_CANCELLED); // Delete the event NdisFreeMemory(Event, 0, 0); @@ -425,12 +465,11 @@ VOID otLwfCompleteNBLs( _In_ PMS_FILTER pFilter, _In_ BOOLEAN DispatchLevel, - _In_ BOOLEAN Received, _In_ PNET_BUFFER_LIST NetBufferLists, _In_ NTSTATUS Status ) { - LogVerbose(DRIVER_DATA_PATH, "otLwfCompleteNBLs, Filter:%p, NBL:%p, Recv:%u, Status:%!STATUS!", pFilter, NetBufferLists, Received, Status); + LogVerbose(DRIVER_DATA_PATH, "otLwfCompleteNBLs, Filter:%p, NBL:%p, Status:%!STATUS!", pFilter, NetBufferLists, Status); // Set the status for all the NBLs PNET_BUFFER_LIST CurrNbl = NetBufferLists; @@ -443,22 +482,11 @@ otLwfCompleteNBLs( NT_ASSERT(NetBufferLists); // Indicate the completion - if (Received) - { - NdisFReturnNetBufferLists( - pFilter->FilterHandle, - NetBufferLists, - DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0 - ); - } - else - { - NdisFSendNetBufferListsComplete( - pFilter->FilterHandle, - NetBufferLists, - DispatchLevel ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0 - ); - } + NdisFSendNetBufferListsComplete( + pFilter->FilterHandle, + NetBufferLists, + DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0 + ); } _Function_class_(DRIVER_CANCEL) @@ -689,6 +717,7 @@ otLwfEventWorkerThread( { &pFilter->EventWorkerThreadStopEvent, &pFilter->EventWorkerThreadProcessNBLs, + &pFilter->EventWorkerThreadProcessMacFrames, &pFilter->EventWorkerThreadWaitTimeUpdated, &pFilter->EventWorkerThreadProcessTasklets, &pFilter->SendNetBufferListComplete, @@ -823,7 +852,7 @@ otLwfEventWorkerThread( // if (status == STATUS_TIMEOUT || - (pFilter->EventTimerState == OT_EVENT_TIMER_FIRED && status == STATUS_WAIT_0 + 2)) + (pFilter->EventTimerState == OT_EVENT_TIMER_FIRED && status == STATUS_WAIT_0 + 3)) { // Reset the wait timeout pFilter->NextAlarmTickCount.QuadPart = 0; @@ -840,12 +869,11 @@ otLwfEventWorkerThread( POTLWF_NBL_EVENT Event = NULL; NdisAcquireSpinLock(&pFilter->EventsLock); - // Just get the first item ('send' or 'recv'), if available + // Just get the first item, if available if (!IsListEmpty(&pFilter->NBLsHead)) { PLIST_ENTRY Link = RemoveHeadList(&pFilter->NBLsHead); Event = CONTAINING_RECORD(Link, OTLWF_NBL_EVENT, Link); - if (Event->Received) pFilter->CountPendingRecvNBLs--; } NdisReleaseSpinLock(&pFilter->EventsLock); @@ -857,135 +885,162 @@ otLwfEventWorkerThread( NTSTATUS NblStatus = STATUS_INSUFFICIENT_RESOURCES; // Process the event - if (Event->Received) // Received a MAC frame + PNET_BUFFER_LIST CurrNbl = Event->NetBufferLists; + while (CurrNbl != NULL) { - PNET_BUFFER_LIST CurrNbl = Event->NetBufferLists; - NT_ASSERT(CurrNbl); - while (CurrNbl != NULL) + PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl); + while (CurrNb != NULL) { - LogVerbose(DRIVER_DATA_PATH, "Passing NBL:%p to OpenThread to recv.", CurrNbl); - - PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl); - NT_ASSERT(CurrNb); - while (CurrNb != NULL) + NT_ASSERT(NET_BUFFER_DATA_LENGTH(CurrNb) <= MessageBufferSize); + if (NET_BUFFER_DATA_LENGTH(CurrNb) <= MessageBufferSize) { - NT_ASSERT(NET_BUFFER_DATA_LENGTH(CurrNb) <= sizeof(pFilter->otReceiveMessage)); - if (NET_BUFFER_DATA_LENGTH(CurrNb) <= sizeof(pFilter->otReceiveMessage)) + // Copy NB data into message + if (NT_SUCCESS(CopyDataBuffer(CurrNb, NET_BUFFER_DATA_LENGTH(CurrNb), MessageBuffer))) { - // Copy NB data into message - if (NT_SUCCESS(CopyDataBuffer(CurrNb, NET_BUFFER_DATA_LENGTH(CurrNb), &pFilter->otReceiveMessage))) + ThreadError error = kThreadError_None; + + // Create a new message + otMessage message = otNewIp6Message(pFilter->otCtx, TRUE); + if (message) { - POT_NBL_CONTEXT NblContext = GetNBLContext(CurrNbl); - pFilter->otReceiveFrame.mChannel = NblContext->Channel; - pFilter->otReceiveFrame.mPower = NblContext->Power; - pFilter->otReceiveFrame.mLqi = NblContext->Lqi; - pFilter->otReceiveFrame.mLength = (uint8_t)NET_BUFFER_DATA_LENGTH(CurrNb); - otLwfRadioReceiveFrame(pFilter, CurrNbl); - NblStatus = STATUS_SUCCESS; - } - } - - CurrNb = NET_BUFFER_NEXT_NB(CurrNb); - } - - CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); - } - } - else // Sending an IPv6 packet - { - PNET_BUFFER_LIST CurrNbl = Event->NetBufferLists; - while (CurrNbl != NULL) - { - PNET_BUFFER CurrNb = NET_BUFFER_LIST_FIRST_NB(CurrNbl); - while (CurrNb != NULL) - { - NT_ASSERT(NET_BUFFER_DATA_LENGTH(CurrNb) <= MessageBufferSize); - if (NET_BUFFER_DATA_LENGTH(CurrNb) <= MessageBufferSize) - { - // Copy NB data into message - if (NT_SUCCESS(CopyDataBuffer(CurrNb, NET_BUFFER_DATA_LENGTH(CurrNb), MessageBuffer))) - { - ThreadError error = kThreadError_None; - - // Create a new message - otMessage message = otNewIp6Message(pFilter->otCtx, TRUE); - if (message) + // Write to the message + error = otAppendMessage(message, MessageBuffer, (uint16_t)NET_BUFFER_DATA_LENGTH(CurrNb)); + if (error != kThreadError_None) { - // Write to the message - error = otAppendMessage(message, MessageBuffer, (uint16_t)NET_BUFFER_DATA_LENGTH(CurrNb)); - if (error != kThreadError_None) - { - LogError(DRIVER_DATA_PATH, "otAppendMessage failed with %!otError!", error); - otFreeMessage(message); - } - else - { - IPV6_HEADER* v6Header = (IPV6_HEADER*)MessageBuffer; - - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, IP6_SEND: %p : %!IPV6ADDR! => %!IPV6ADDR! (%u bytes)", - pFilter, CurrNbl, &v6Header->SourceAddress, &v6Header->DestinationAddress, - NET_BUFFER_DATA_LENGTH(CurrNb)); - - #ifdef LOG_BUFFERS - otLogBuffer(MessageBuffer, NET_BUFFER_DATA_LENGTH(CurrNb)); - #endif - - // Send message (it will free 'message') - error = otSendIp6Datagram(pFilter->otCtx, message); - if (error != kThreadError_None) - { - LogError(DRIVER_DATA_PATH, "otSendIp6Datagram failed with %!otError!", error); - } - else - { - NblStatus = STATUS_SUCCESS; - } - } + LogError(DRIVER_DATA_PATH, "otAppendMessage failed with %!otError!", error); + otFreeMessage(message); } else { - LogError(DRIVER_DATA_PATH, "otNewIPv6Message failed!"); + IPV6_HEADER* v6Header = (IPV6_HEADER*)MessageBuffer; + + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, IP6_SEND: %p : %!IPV6ADDR! => %!IPV6ADDR! (%u bytes)", + pFilter, CurrNbl, &v6Header->SourceAddress, &v6Header->DestinationAddress, + NET_BUFFER_DATA_LENGTH(CurrNb)); + +#ifdef LOG_BUFFERS + otLogBuffer(MessageBuffer, NET_BUFFER_DATA_LENGTH(CurrNb)); +#endif + + // Send message (it will free 'message') + error = otSendIp6Datagram(pFilter->otCtx, message); + if (error != kThreadError_None) + { + LogError(DRIVER_DATA_PATH, "otSendIp6Datagram failed with %!otError!", error); + } + else + { + NblStatus = STATUS_SUCCESS; + } } } + else + { + LogError(DRIVER_DATA_PATH, "otNewIPv6Message failed!"); + } } - - CurrNb = NET_BUFFER_NEXT_NB(CurrNb); } - CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); + CurrNb = NET_BUFFER_NEXT_NB(CurrNb); } + + CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); } if (Event->NetBufferLists) { // Complete the NBLs - otLwfCompleteNBLs(pFilter, FALSE, Event->Received, Event->NetBufferLists, NblStatus); + otLwfCompleteNBLs(pFilter, FALSE, Event->NetBufferLists, NblStatus); } // Free the event NdisFreeMemory(Event, 0, 0); } } - else if (status == STATUS_WAIT_0 + 2) // EventWorkerThreadWaitTimeUpdated fired + else if (status == STATUS_WAIT_0 + 2) // EventWorkerThreadProcessMacFrames fired + { + // Go through the queue until there are no more items + for (;;) + { + POTLWF_MAC_FRAME_EVENT Event = NULL; + NdisAcquireSpinLock(&pFilter->EventsLock); + + // Just get the first item, if available + if (!IsListEmpty(&pFilter->MacFramesHead)) + { + PLIST_ENTRY Link = RemoveHeadList(&pFilter->MacFramesHead); + Event = CONTAINING_RECORD(Link, OTLWF_MAC_FRAME_EVENT, Link); + } + + NdisReleaseSpinLock(&pFilter->EventsLock); + + // Break out of the loop if we have emptied the queue + if (Event == NULL) break; + + // Read the initial length value and validate + uint16_t packetLength = 0; + if (try_spinel_datatype_unpack( + Event->Buffer, + Event->BufferLength, + SPINEL_DATATYPE_UINT16_S, + &packetLength) && + packetLength <= sizeof(pFilter->otReceiveMessage) && + Event->BufferLength > sizeof(uint16_t) + packetLength) + { + pFilter->otReceiveFrame.mLength = (uint8_t)packetLength; + + uint8_t offset = 2; + uint8_t length = Event->BufferLength - 2; + + if (packetLength != 0) + { + memcpy(&pFilter->otReceiveMessage, Event->Buffer + offset, packetLength); + offset += pFilter->otReceiveFrame.mLength; + length -= pFilter->otReceiveFrame.mLength; + } + + ThreadError errorCode; + int8_t noiseFloor = -128; + uint16_t flags = 0; + if (try_spinel_datatype_unpack( + Event->Buffer + offset, + length, + "ccSiCC", + &pFilter->otReceiveFrame.mPower, + &noiseFloor, + &flags, + &errorCode, + &pFilter->otReceiveFrame.mChannel, + &pFilter->otReceiveFrame.mLqi)) + { + otLwfRadioReceiveFrame(pFilter, errorCode); + } + } + + // Free the event + NdisFreeMemory(Event, 0, 0); + } + } + else if (status == STATUS_WAIT_0 + 3) // EventWorkerThreadWaitTimeUpdated fired { // Nothing to do, the next time we wait, we will be using the updated time } - else if (status == STATUS_WAIT_0 + 3) // EventWorkerThreadProcessTasklets fired + else if (status == STATUS_WAIT_0 + 4) // EventWorkerThreadProcessTasklets fired { // Process all tasklets that were indicated to us from OpenThread otProcessQueuedTasklets(pFilter->otCtx); } - else if (status == STATUS_WAIT_0 + 4) // SendNetBufferListComplete fired + else if (status == STATUS_WAIT_0 + 5) // SendNetBufferListComplete fired { // Handle the completion of the NBL send otLwfRadioTransmitFrameDone(pFilter); } - else if (status == STATUS_WAIT_0 + 5) // EventWorkerThreadProcessIrp fired + else if (status == STATUS_WAIT_0 + 6) // EventWorkerThreadProcessIrp fired { // Process any IRPs that were pended otLwfEventProcessingNextIrp(pFilter); } - else if (status == STATUS_WAIT_0 + 6) // EventWorkerThreadProcessAddressChanges fired + else if (status == STATUS_WAIT_0 + 7) // EventWorkerThreadProcessAddressChanges fired { // Go through the queue until there are no more items for (;;) @@ -1012,7 +1067,7 @@ otLwfEventWorkerThread( NdisFreeMemory(Event, 0, 0); } } - else if (status == STATUS_WAIT_0 + 7) // EventWorkerThreadEnergyScanComplete fired + else if (status == STATUS_WAIT_0 + 8) // EventWorkerThreadEnergyScanComplete fired { // Indicate energy scan complete otPlatRadioEnergyScanDone(pFilter->otCtx, pFilter->otLastEnergyScanMaxRssi); diff --git a/examples/drivers/windows/otLwf/filter.c b/examples/drivers/windows/otLwf/filter.c index 61f3ed36c..62d290314 100644 --- a/examples/drivers/windows/otLwf/filter.c +++ b/examples/drivers/windows/otLwf/filter.c @@ -93,8 +93,12 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper NTSTATUS NtStatus; NDIS_FILTER_ATTRIBUTES FilterAttributes; ULONG Size; - ULONG bytesProcessed = 0; COMPARTMENT_ID OriginalCompartmentID; + OBJECT_ATTRIBUTES ObjectAttributes = {0}; + + const ULONG RegKeyOffset = ARRAYSIZE(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\otlwf\\Parameters\\NdisAdapters\\") - 1; + DECLARE_CONST_UNICODE_STRING(RegKeyPath, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\otlwf\\Parameters\\NdisAdapters\\{00000000-0000-0000-0000-000000000000}"); + RtlCopyMemory(RegKeyPath.Buffer + RegKeyOffset, AttachParameters->BaseMiniportName->Buffer + 8, sizeof(L"{00000000-0000-0000-0000-000000000000}")); LogFuncEntry(DRIVER_DEFAULT); @@ -113,7 +117,6 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper if (AttachParameters->MiniportMediaType != NdisMediumIP) { LogError(DRIVER_DEFAULT, "Unsupported media type, 0x%x.", (ULONG)AttachParameters->MiniportMediaType); - Status = NDIS_STATUS_INVALID_PARAMETER; break; } @@ -130,6 +133,24 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper NdisZeroMemory(pFilter, sizeof(MS_FILTER)); + LogVerbose(DRIVER_DEFAULT, "Opening interface registry key %S", RegKeyPath.Buffer); + + InitializeObjectAttributes( + &ObjectAttributes, + (PUNICODE_STRING)&RegKeyPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + // Open the registry key + NtStatus = ZwOpenKey(&pFilter->InterfaceRegKey, KEY_ALL_ACCESS, &ObjectAttributes); + if (!NT_SUCCESS(NtStatus)) + { + LogError(DRIVER_DEFAULT, "ZwOpenKey failed to open %S, %!STATUS!", RegKeyPath.Buffer, NtStatus); + Status = NDIS_STATUS_FAILURE; + break; + } + // Format of "\DEVICE\{5BA90C49-0D7E-455B-8D3B-614F6714A212}" AttachParameters->BaseMiniportName->Buffer += 8; AttachParameters->BaseMiniportName->Length -= 8 * sizeof(WCHAR); @@ -142,12 +163,12 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper Status = NDIS_STATUS_FAILURE; break; } - - pFilter->MiniportFriendlyName.Length = pFilter->MiniportFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length; - pFilter->MiniportFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER)); - NdisMoveMemory(pFilter->MiniportFriendlyName.Buffer, + + pFilter->InterfaceFriendlyName.Length = pFilter->InterfaceFriendlyName.MaximumLength = AttachParameters->BaseMiniportInstanceName->Length; + pFilter->InterfaceFriendlyName.Buffer = (PWSTR)((PUCHAR)pFilter + sizeof(MS_FILTER)); + NdisMoveMemory(pFilter->InterfaceFriendlyName.Buffer, AttachParameters->BaseMiniportInstanceName->Buffer, - pFilter->MiniportFriendlyName.Length); + pFilter->InterfaceFriendlyName.Length); pFilter->InterfaceIndex = AttachParameters->BaseMiniportIfIndex; pFilter->InterfaceLuid = AttachParameters->BaseMiniportNetLuid; @@ -170,40 +191,18 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper // 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 = - { - { NDIS_OBJECT_TYPE_DEFAULT, NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1, NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1 }, - NDIS_PROTOCOL_ID_DEFAULT, - TRUE, - 0, - 'BNto', // otNB - 0 - }; - pFilter->NetBufferListPool = NdisAllocateNetBufferListPool(pFilter->FilterHandle, &PoolParams); - if (pFilter->NetBufferListPool == NULL) - { - Status = NDIS_STATUS_RESOURCES; - LogWarning(DRIVER_DEFAULT, "Failed to create NetBufferList pool"); - break; - } + // Initialize rundowns to disabled with no active references + pFilter->ExternalRefs.Count = EX_RUNDOWN_ACTIVE; + pFilter->cmdRundown.Count = EX_RUNDOWN_ACTIVE; // 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); @@ -227,45 +226,6 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper break; } - // Little hack to pass the IfIndex to the VMP - *((ULONG*)&pFilter->MiniportCapabilities) = AttachParameters->BaseMiniportIfIndex; - - // Query the MP capabilities - Status = - otLwfSendInternalRequest( - pFilter, - NdisRequestQueryInformation, - OID_OT_CAPABILITIES, - &pFilter->MiniportCapabilities, - sizeof(OT_CAPABILITIES), - &bytesProcessed - ); - if (Status != NDIS_STATUS_SUCCESS) - { - LogError(DRIVER_DEFAULT, "Query for OID_OT_CAPABILITIES failed, %!NDIS_STATUS!", Status); - break; - } - - // Validate the return header - if (bytesProcessed != SIZEOF_OT_CAPABILITIES_REVISION_1 || - pFilter->MiniportCapabilities.Header.Type != NDIS_OBJECT_TYPE_DEFAULT || - pFilter->MiniportCapabilities.Header.Revision != OT_CAPABILITIES_REVISION_1 || - pFilter->MiniportCapabilities.Header.Size != SIZEOF_OT_CAPABILITIES_REVISION_1) - { - Status = NDIS_STATUS_INVALID_DATA; - LogError(DRIVER_DEFAULT, "Query for OID_OT_CAPABILITIES returned invalid data"); - break; - } - - // Make sure we are in RADIO mode - 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 or THREAD mode!"); - break; - } - // Add Filter to global list of Thread Filters NdisAcquireSpinLock(&FilterListLock); InsertTailList(&FilterModuleList, &pFilter->FilterModuleLink); @@ -275,6 +235,7 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper } while (FALSE); + // Clean up on failure if (Status != NDIS_STATUS_SUCCESS) { if (pFilter != NULL) @@ -285,12 +246,6 @@ N.B.: FILTER can use NdisRegisterDeviceEx to create a device, so the upper pFilter->AddressChangeHandle = NULL; } - // Free NBL Pool - if (pFilter->NetBufferListPool) - { - NdisFreeNetBufferPool(pFilter->NetBufferListPool); - } - NdisFreeMemory(pFilter, 0, 0); } } @@ -330,49 +285,27 @@ NOTE: Called at PASSIVE_LEVEL and the filter is in paused state // Filter must be in paused state and pretty much inactive NT_ASSERT(pFilter->State == FilterPaused); - NT_ASSERT(pFilter->IoControlReferences > 0); + NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_UNINTIALIZED); // // Detach must not fail, so do not put any code here that can possibly fail. // - // Release IoControl reference and wait for shutdown if there are active refernces - NdisResetEvent(&pFilter->IoControlShutdownComplete); - if (!RtlDecrementReferenceCount(&pFilter->IoControlReferences)) - { - LogInfo(DRIVER_DEFAULT, "Waiting for Io Control shutdown..."); - NdisWaitEvent(&pFilter->IoControlShutdownComplete, 0); - NT_ASSERT(pFilter->IoControlReferences == 0); - LogInfo(DRIVER_DEFAULT, "Received Io Control shutdown event."); - } - - // Unregister from address change notifications - CancelMibChangeNotify2(pFilter->AddressChangeHandle); - pFilter->AddressChangeHandle = NULL; - - 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 Pool - NdisFreeNetBufferPool(pFilter->NetBufferListPool); + // Unregister from address change notifications + CancelMibChangeNotify2(pFilter->AddressChangeHandle); + pFilter->AddressChangeHandle = NULL; + + // Close the registry key + if (pFilter->InterfaceRegKey) + { + ZwClose(pFilter->InterfaceRegKey); + pFilter->InterfaceRegKey = NULL; + } // Free the memory allocated NdisFreeMemory(pFilter, 0, 0); @@ -400,6 +333,74 @@ otLwfNotifyDeviceAvailabilityChange( } } +PAGED +NTSTATUS +GetRegDWORDValue( + _In_ PMS_FILTER pFilter, + _In_ PCWSTR ValueName, + _Out_ PULONG ValueData +) +{ + NTSTATUS status; + ULONG resultLength; + UCHAR keybuf[128] = {0}; + UNICODE_STRING UValueName; + + PAGED_CODE(); + + RtlInitUnicodeString(&UValueName, ValueName); + + status = ZwQueryValueKey( + pFilter->InterfaceRegKey, + &UValueName, + KeyValueFullInformation, + keybuf, + sizeof(keybuf), + &resultLength); + + if (NT_SUCCESS(status)) + { + PKEY_VALUE_FULL_INFORMATION keyInfo = (PKEY_VALUE_FULL_INFORMATION)keybuf; + + if (keyInfo->Type != REG_DWORD) + { + status = STATUS_INVALID_PARAMETER_MIX; + } + else + { + *ValueData = *((ULONG UNALIGNED *)(keybuf + keyInfo->DataOffset)); + } + } + + return status; +} + +PAGED +NTSTATUS +SetRegDWORDValue( + _In_ PMS_FILTER pFilter, + _In_ PCWSTR ValueName, + _In_ ULONG ValueData +) +{ + NTSTATUS status; + UNICODE_STRING UValueName; + + PAGED_CODE(); + + RtlInitUnicodeString(&UValueName, ValueName); + + status = ZwSetValueKey( + pFilter->InterfaceRegKey, + &UValueName, + 0, + REG_DWORD, + (PVOID)&ValueData, + sizeof(ValueData)); + + return status; +} + _Use_decl_annotations_ NDIS_STATUS FilterRestart( @@ -428,8 +429,12 @@ Return Value: NTSTATUS NtStatus = STATUS_SUCCESS; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; + PVOID SpinelCapsDataBuffer = NULL; + const uint8_t* SpinelCapsPtr = NULL; + spinel_size_t SpinelCapsLen = 0; NL_INTERFACE_KEY key = {0}; NL_INTERFACE_RW interfaceRw; + ULONG ThreadOnHost = TRUE; PNDIS_RESTART_GENERAL_ATTRIBUTES NdisGeneralAttributes; PNDIS_RESTART_ATTRIBUTES NdisRestartAttributes; @@ -459,52 +464,116 @@ Return Value: // NdisGeneralAttributes->LookaheadSize = 128; } - - - // Initialize the processing logic - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) + + // Initialize the Spinel command processing + NdisStatus = otLwfCmdInitialize(pFilter); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + LogError(DRIVER_DEFAULT, "otLwfCmdInitialize failed, %!NDIS_STATUS!", NdisStatus); + goto exit; + } + + // Query the device capabilities + NtStatus = otLwfCmdGetProp(pFilter, SpinelCapsDataBuffer, SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, &SpinelCapsPtr, &SpinelCapsLen); + if (!NT_SUCCESS(NtStatus)) + { + NdisStatus = NDIS_STATUS_NOT_SUPPORTED; + LogError(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_CAPS, %!STATUS!", NtStatus); + goto exit; + } + + // Iterate and process returned capabilities + while (SpinelCapsLen > 0) + { + ULONG SpinelCap = 0; + spinel_ssize_t len = spinel_datatype_unpack(SpinelCapsPtr, SpinelCapsLen, SPINEL_DATATYPE_UINT_PACKED_S, &SpinelCap); + if (len < 1) break; + SpinelCapsLen -= (spinel_size_t)len; + + switch (SpinelCap) + { + case SPINEL_CAP_MAC_RAW: + pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO; + pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT; + pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN; + break; + case SPINEL_CAP_NET_THREAD_1_0: + pFilter->DeviceCapabilities |= OTLWF_DEVICE_CAP_THREAD_1_0; + break; + default: + break; + } + } + + // Set the state indicating where we should be running the Thread logic (Host or Device). + if (!NT_SUCCESS(GetRegDWORDValue(pFilter, L"RunOnHost", &ThreadOnHost))) + { + // Default to running on the host if the key isn't present + ThreadOnHost = TRUE; + SetRegDWORDValue(pFilter, L"RunOnHost", ThreadOnHost); + } + + LogInfo(DRIVER_DEFAULT, "Filter: %p initializing ThreadOnHost=%d", FilterModuleContext, ThreadOnHost); + + // Initialize the processing logic + if (ThreadOnHost) + { + // Ensure the device has the capabilities to support raw radio commands + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO) == 0) + { + LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support raw radio commands"); + NdisStatus = NDIS_STATUS_NOT_SUPPORTED; + goto exit; + } + + pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_RADIO_MODE; NtStatus = otLwfInitializeThreadMode(pFilter); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "otLwfInitializeThreadMode failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; + pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; goto exit; } - pFilter->InternalStateInitialized = TRUE; } - else if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_THREAD) + else { - NtStatus = otLwfInitializeTunnelMode(pFilter); + // Ensure the device has the capabilities to support Thread commands + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_THREAD_1_0) == 0) + { + LogError(DRIVER_DEFAULT, "Failed to start because device doesn't support thread commands"); + NdisStatus = NDIS_STATUS_NOT_SUPPORTED; + goto exit; + } + + pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_THREAD_MODE; + NtStatus = otLwfTunInitialize(pFilter); if (!NT_SUCCESS(NtStatus)) { LogError(DRIVER_DEFAULT, "otLwfInitializeTunnelMode failed, %!STATUS!", NtStatus); NdisStatus = NDIS_STATUS_FAILURE; + pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; goto exit; } - pFilter->InternalStateInitialized = TRUE; } - else - { - NT_ASSERT(FALSE); - NdisStatus = NDIS_STATUS_FAILURE; - goto exit; - } - + + // + // Disable DAD and Neighbor advertisements + // key.Luid = pFilter->InterfaceLuid; NlInitializeInterfaceRw(&interfaceRw); interfaceRw.DadTransmits = 0; interfaceRw.SendUnsolicitedNeighborAdvertisementOnDad = FALSE; - NtStatus = + NtStatus = NsiSetAllParameters( - NsiActive, - NsiSetDefault, - &NPI_MS_IPV6_MODULEID, - NlInterfaceObject, - &key, - sizeof(key), - &interfaceRw, + NsiActive, + NsiSetDefault, + &NPI_MS_IPV6_MODULEID, + NlInterfaceObject, + &key, + sizeof(key), + &interfaceRw, sizeof(interfaceRw)); if (!NT_SUCCESS(NtStatus)) { @@ -514,9 +583,9 @@ Return Value: } // - // Enable the data path + // Enable the external references to the filter // - otLwfEnableDataPath(pFilter); + ExReInitializeRundownProtection(&pFilter->ExternalRefs); // // If everything is OK, set the filter in running state. @@ -534,18 +603,25 @@ exit: { pFilter->State = FilterPaused; - if (pFilter->InternalStateInitialized) + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) { - pFilter->InternalStateInitialized = FALSE; - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) - { - otLwfUninitializeThreadMode(pFilter); - } - else - { - otLwfUninitializeTunnelMode(pFilter); - } + otLwfUninitializeThreadMode(pFilter); } + else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) + { + otLwfTunUninitialize(pFilter); + } + + pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; + + // Clean up Spinel command processing + otLwfCmdUninitialize(pFilter); + } + + // Free the buffer for the capabilities we queried + if (SpinelCapsDataBuffer != NULL) + { + FILTER_FREE_MEM(SpinelCapsDataBuffer); } LogFuncExitNDIS(DRIVER_DEFAULT, NdisStatus); @@ -592,24 +668,49 @@ N.B.: When the filter is in Pausing state, it can still process OID requests, LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p", FilterModuleContext); - // Reset the pause complete event - NdisResetEvent(&pFilter->FilterPauseComplete); - // // Set the flag that the filter is going to pause // NT_ASSERT(pFilter->State == FilterRunning); + NdisAcquireSpinLock(&FilterListLock); pFilter->State = FilterPausing; - + NdisReleaseSpinLock(&FilterListLock); + + // + // Send final notification of interface removal + // otLwfNotifyDeviceAvailabilityChange(pFilter, FALSE); LogInfo(DRIVER_DEFAULT, "Interface %!GUID! removal.", &pFilter->InterfaceGuid); // - // Disable the data path + // Disable external references and wait for existing calls to complete // - otLwfDisableDataPath(pFilter); + LogInfo(DRIVER_DEFAULT, "Disabling and waiting for external references to release"); + ExWaitForRundownProtectionRelease(&pFilter->ExternalRefs); + LogInfo(DRIVER_DEFAULT, "External references released."); + // + // Clean up based on the device mode + // + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) + { + otLwfUninitializeThreadMode(pFilter); + } + else if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_THREAD_MODE) + { + otLwfTunUninitialize(pFilter); + } + + pFilter->DeviceStatus = OTLWF_DEVICE_STATUS_UNINTIALIZED; + + // + // Clean up the Spinel command processing + // + otLwfCmdUninitialize(pFilter); + + // // Set the state back to Paused now that we are done + // pFilter->State = FilterPaused; LogFuncExitNDIS(DRIVER_DEFAULT, Status); @@ -653,21 +754,6 @@ NOTE: called at <= DISPATCH_LEVEL // Cache the link state from the miniport memcpy(&pFilter->MiniportLinkState, LinkState, sizeof(NDIS_LINK_STATE)); } - else if (StatusIndication->StatusCode == NDIS_STATUS_OT_ENERGY_SCAN_RESULT) - { - NT_ASSERT(StatusIndication->StatusBufferSize == sizeof(OT_ENERGY_SCAN_RESULT)); - if (StatusIndication->StatusBufferSize != sizeof(OT_ENERGY_SCAN_RESULT)) goto exit; - - POT_ENERGY_SCAN_RESULT ScanResult = (POT_ENERGY_SCAN_RESULT)StatusIndication->StatusBuffer; - - 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); - } - -exit: NdisFIndicateStatus(pFilter->FilterHandle, StatusIndication); @@ -706,106 +792,6 @@ otLwfIndicateLinkState( NdisFIndicateStatus(pFilter->FilterHandle, &StatusIndication); } -_Use_decl_annotations_ -VOID -FilterDevicePnPEventNotify( - NDIS_HANDLE FilterModuleContext, - PNET_DEVICE_PNP_EVENT NetDevicePnPEvent - ) -/*++ - -Routine Description: - - Device PNP event handler - -Arguments: - - FilterModuleContext - our filter context - NetDevicePnPEvent - a Device PnP event - -NOTE: called at PASSIVE_LEVEL - ---*/ -{ - PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; - NDIS_DEVICE_PNP_EVENT DevicePnPEvent = NetDevicePnPEvent->DevicePnPEvent; -#if DBG - BOOLEAN bFalse = FALSE; -#endif - - LogFuncEntryMsg(DRIVER_DEFAULT, "Filter: %p, DevicePnPEvent: %u", FilterModuleContext, NetDevicePnPEvent->DevicePnPEvent); - - // - // The filter may do processing on the event here, including intercepting - // and dropping it entirely. However, the sample does nothing with Device - // PNP events, except pass them down to the next lower* layer. It is more - // efficient to omit the FilterDevicePnPEventNotify handler entirely if it - // does nothing, but it is included in this sample for illustrative purposes. - // - // * Trivia: Device PNP events percolate DOWN the stack, instead of upwards - // like status indications and Net PNP events. So the next layer is the - // LOWER layer. - // - - switch (DevicePnPEvent) - { - case NdisDevicePnPEventQueryRemoved: - case NdisDevicePnPEventRemoved: - case NdisDevicePnPEventSurpriseRemoved: - case NdisDevicePnPEventQueryStopped: - case NdisDevicePnPEventStopped: - case NdisDevicePnPEventPowerProfileChanged: - case NdisDevicePnPEventFilterListChanged: - break; - - default: - LogError(DRIVER_DEFAULT, "FilterDevicePnPEventNotify: Invalid event.\n"); - NT_ASSERT(bFalse); - break; - } - - NdisFDevicePnPEventNotify(pFilter->FilterHandle, NetDevicePnPEvent); - - LogFuncExit(DRIVER_DEFAULT); -} - -_Use_decl_annotations_ -NDIS_STATUS -FilterNetPnPEvent( - NDIS_HANDLE FilterModuleContext, - PNET_PNP_EVENT_NOTIFICATION NetPnPEventNotification - ) -/*++ - -Routine Description: - - Net PNP event handler - -Arguments: - - FilterModuleContext - our filter context - NetPnPEventNotification - a Net PnP event - -NOTE: called at PASSIVE_LEVEL - ---*/ -{ - PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - - // - // The filter may do processing on the event here, including intercepting - // and dropping it entirely. However, the sample does nothing with Net PNP - // events, except pass them up to the next higher layer. It is more - // efficient to omit the FilterNetPnPEvent handler entirely if it does - // nothing, but it is included in this sample for illustrative purposes. - // - - Status = NdisFNetPnPEvent(pFilter->FilterHandle, NetPnPEventNotification); - - return Status; -} - _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS otLwfSetCompartment( diff --git a/examples/drivers/windows/otLwf/filter.h b/examples/drivers/windows/otLwf/filter.h index e65dd018f..582059ff7 100644 --- a/examples/drivers/windows/otLwf/filter.h +++ b/examples/drivers/windows/otLwf/filter.h @@ -78,10 +78,45 @@ typedef enum _FILTER_STATE FilterRunning, } FILTER_STATE; +// Flags for the different device capabilities +typedef enum OTLWF_DEVICE_CAPABILITY +{ + // Device supports raw Radio commands + OTLWF_DEVICE_CAP_RADIO = 1 << 0, + + // Device supports Ack timeouts internally + OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT = 1 << 1, + + // Device supports MAC retry logic and timers; as well as collision avoidance. + OTLWF_DEVICE_CAP_RADIO_MAC_RETRY_AND_COLLISION_AVOIDANCE = 1 << 2, + + // Device supports the energy scan command. + OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN = 1 << 3, + + // Device supports sleeping. If the device supports sleeping, it is assumed to + // default to the sleep state on bring up. + OTLWF_DEVICE_CAP_RADIO_SLEEP = 1 << 4, + + // Device support Net & Thread commands. + OTLWF_DEVICE_CAP_THREAD_1_0 = 1 << 16, + +} OTLWF_DEVICE_CAPABILITY; + +// Flags for the different device capabilities +typedef enum OTLWF_DEVICE_STATUS +{ + OTLWF_DEVICE_STATUS_UNINTIALIZED, // Not yet initialzied. + OTLWF_DEVICE_STATUS_RADIO_MODE, // The device is just operating as a simple radio. + OTLWF_DEVICE_STATUS_THREAD_MODE // The device is managing the Thread stack. + +} OTLWF_DEVICE_STATUS; + #define OT_EVENT_TIMER_NOT_RUNNING 0 #define OT_EVENT_TIMER_RUNNING 1 #define OT_EVENT_TIMER_FIRED 2 +#define MAX_PENDING_MAC_SIZE 32 // TODO + // // Define the filter struct // @@ -95,26 +130,24 @@ typedef struct _MS_FILTER // Current state (Running or not) of the Filter instance FILTER_STATE State; - NDIS_EVENT FilterPauseComplete; // Handle for unicast IP address notifications HANDLE AddressChangeHandle; - + // - // Interface / Adapter variables + // Interface variables // GUID InterfaceGuid; NET_IFINDEX InterfaceIndex; NET_LUID InterfaceLuid; COMPARTMENT_ID InterfaceCompartmentID; - NDIS_STRING MiniportFriendlyName; - volatile LONG PendingDisconnectTasks; + NDIS_STRING InterfaceFriendlyName; + HANDLE InterfaceRegKey; // - // Miniport Capabilities + // Miniport Link State // - OT_CAPABILITIES MiniportCapabilities; - NDIS_LINK_STATE MiniportLinkState; + NDIS_LINK_STATE MiniportLinkState; // // Pending OID Handling @@ -123,18 +156,29 @@ typedef struct _MS_FILTER PNDIS_OID_REQUEST PendingOidRequest; // - // Io Control Path Synchronization + // External references management + // Used for IOCTLs, SendNBLs, and Address Changed callbacks // - RTL_REFERENCE_COUNT IoControlReferences; - NDIS_EVENT IoControlShutdownComplete; + EX_RUNDOWN_REF ExternalRefs; // - // Data Path + // Spinel Command State // - EX_RUNDOWN_REF DataPathRundown; - NDIS_HANDLE NetBufferListPool; + EX_RUNDOWN_REF cmdRundown; + NDIS_SPIN_LOCK cmdLock; + LIST_ENTRY cmdHandlers; + USHORT cmdTIDsInUse; + spinel_tid_t cmdNextTID; + NDIS_HANDLE cmdNblPool; +#if DBG + ULONG cmdInitTryCount; +#endif - BOOLEAN InternalStateInitialized; + // + // Device Capabilities / State + // + OTLWF_DEVICE_CAPABILITY DeviceCapabilities; + OTLWF_DEVICE_STATUS DeviceStatus; // // OpenThread addresses @@ -158,10 +202,11 @@ typedef struct _MS_FILTER KEVENT EventWorkerThreadStopEvent; KEVENT EventWorkerThreadProcessAddressChanges; KEVENT EventWorkerThreadProcessNBLs; + KEVENT EventWorkerThreadProcessMacFrames; NDIS_SPIN_LOCK EventsLock; LIST_ENTRY AddressChangesHead; LIST_ENTRY NBLsHead; - ULONG CountPendingRecvNBLs; + LIST_ENTRY MacFramesHead; LARGE_INTEGER NextAlarmTickCount; KEVENT EventWorkerThreadWaitTimeUpdated; KEVENT EventWorkerThreadProcessTasklets; @@ -180,7 +225,6 @@ typedef struct _MS_FILTER // OpenThread data path state // BOOLEAN SendPending; - PNET_BUFFER_LIST SendNetBufferList; KEVENT SendNetBufferListComplete; // @@ -193,6 +237,8 @@ typedef struct _MS_FILTER uint8_t otTransmitMessage[kMaxPHYPacketSize]; RadioPacket otReceiveFrame; RadioPacket otTransmitFrame; + ThreadError otLastTransmitError; + BOOLEAN otLastTransmitFramePending; CHAR otLastEnergyScanMaxRssi; BOOLEAN otPromiscuous; @@ -224,11 +270,6 @@ typedef struct _MS_FILTER }; struct // Tunnel Mode Variables { - NDIS_SPIN_LOCK tunCommandLock; - LIST_ENTRY tunCommandHandlers; - USHORT tunTIDsInUse; - spinel_tid_t tunNextTID; - PVOID TunWorkerThread; KEVENT TunWorkerThreadStopEvent; KEVENT TunWorkerThreadAddressChangedEvent; @@ -246,8 +287,6 @@ FILTER_DETACH FilterDetach; FILTER_RESTART FilterRestart; FILTER_PAUSE FilterPause; FILTER_STATUS FilterStatus; -FILTER_DEVICE_PNP_EVENT_NOTIFY FilterDevicePnPEventNotify; -FILTER_NET_PNP_EVENT FilterNetPnPEvent; FILTER_SEND_NET_BUFFER_LISTS FilterSendNetBufferLists; FILTER_RETURN_NET_BUFFER_LISTS FilterReturnNetBufferLists; FILTER_SEND_NET_BUFFER_LISTS_COMPLETE FilterSendNetBufferListsComplete; @@ -282,22 +321,6 @@ otLwfRevertCompartment( _In_ COMPARTMENT_ID OriginalCompartment ); -// -// Data Path functions -// - -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID -otLwfEnableDataPath( - _In_ PMS_FILTER pFilter - ); - -_IRQL_requires_max_(PASSIVE_LEVEL) -VOID -otLwfDisableDataPath( - _In_ PMS_FILTER pFilter - ); - // // Address Functions // diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index 075194980..d86ceb64d 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -152,22 +152,6 @@ IoCtlString( 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 @@ -275,7 +259,7 @@ otLwfIoCtlQueryInterface( pDevice->CompartmentID = pFilter->InterfaceCompartmentID; // Release the ref on the interface - otLwfReleaseInterface(pFilter); + ExReleaseRundownProtection(&pFilter->ExternalRefs); error: @@ -318,7 +302,7 @@ otLwfIoCtlOpenThreadControl( goto error; } - if (pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO) + if (pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE) { // Pend the Irp for processing on the OpenThread event processing thread otLwfEventProcessingIndicateIrp(pFilter, Irp); @@ -329,7 +313,7 @@ otLwfIoCtlOpenThreadControl( } // Release our ref on the filter - otLwfReleaseInterface(pFilter); + ExReleaseRundownProtection(&pFilter->ExternalRefs); error: @@ -521,7 +505,7 @@ otLwfTunIoCtl_otInterface( } status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -534,7 +518,7 @@ otLwfTunIoCtl_otInterface( else if (OutBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otInterface_Handler, @@ -628,7 +612,7 @@ otLwfTunIoCtl_otThread( if (InBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -641,7 +625,7 @@ otLwfTunIoCtl_otThread( else if (OutBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otThread_Handler, @@ -740,11 +724,11 @@ otLwfTunIoCtl_otActiveScan( // TODO - Send down scan channel & duration first UNREFERENCED_PARAMETER(aScanChannels); - status = otLwfSetTunProp(pFilter, SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_UINT16_S, aScanDuration); + status = otLwfCmdSetProp(pFilter, SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_UINT16_S, aScanDuration); if (!NT_SUCCESS(status)) goto error; status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -757,7 +741,7 @@ otLwfTunIoCtl_otActiveScan( else if (OutBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otActiveScan_Handler, @@ -860,11 +844,11 @@ otLwfTunIoCtl_otEnergyScan( // TODO - Send down scan channel & duration first UNREFERENCED_PARAMETER(aScanChannels); - status = otLwfSetTunProp(pFilter, SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_UINT16_S, aScanDuration); + status = otLwfCmdSetProp(pFilter, SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_UINT16_S, aScanDuration); if (!NT_SUCCESS(status)) goto error; status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -877,7 +861,7 @@ otLwfTunIoCtl_otEnergyScan( else if (OutBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otEnergyScan_Handler, @@ -1009,7 +993,7 @@ otLwfTunIoCtl_otChannel( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1022,7 +1006,7 @@ otLwfTunIoCtl_otChannel( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otChannel_Handler, @@ -1108,7 +1092,7 @@ otLwfTunIoCtl_otChildTimeout( if (InBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1121,7 +1105,7 @@ otLwfTunIoCtl_otChildTimeout( else if (OutBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otChildTimeout_Handler, @@ -1206,7 +1190,7 @@ otLwfTunIoCtl_otExtendedAddress( if (InBufferLength >= sizeof(otExtAddress)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1219,7 +1203,7 @@ otLwfTunIoCtl_otExtendedAddress( else if (OutBufferLength >= sizeof(otExtAddress)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otExtendedAddress_Handler, @@ -1307,7 +1291,7 @@ otLwfTunIoCtl_otExtendedPanId( if (InBufferLength >= sizeof(otExtendedPanId)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1321,7 +1305,7 @@ otLwfTunIoCtl_otExtendedPanId( else if (OutBufferLength >= sizeof(otExtendedPanId)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otExtendedPanId_Handler, @@ -1469,7 +1453,7 @@ otLwfTunIoCtl_otLeaderRloc( if (InBufferLength >= sizeof(otIp6Address)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1482,7 +1466,7 @@ otLwfTunIoCtl_otLeaderRloc( else if (OutBufferLength >= sizeof(otIp6Address)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otLeaderRloc_Handler, @@ -1586,7 +1570,7 @@ otLwfTunIoCtl_otLinkMode( if (aLinkMode->mNetworkData) numeric_mode |= kThreadMode_FullNetworkData; status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1599,7 +1583,7 @@ otLwfTunIoCtl_otLinkMode( else if (OutBufferLength >= sizeof(otLinkModeConfig)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otLinkMode_Handler, @@ -1698,7 +1682,7 @@ otLwfTunIoCtl_otMasterKey( spinel_size_t aKeyLength = *(uint8_t*)(InBuffer + sizeof(otMasterKey)); status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1712,7 +1696,7 @@ otLwfTunIoCtl_otMasterKey( else if (OutBufferLength >= sizeof(otMasterKey) + sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otMasterKey_Handler, @@ -1802,7 +1786,7 @@ otLwfTunIoCtl_otMeshLocalEid( if (OutBufferLength >= sizeof(otIp6Address)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otMeshLocalEid_Handler, @@ -1892,7 +1876,7 @@ otLwfTunIoCtl_otMeshLocalPrefix( memcpy(&aAddress, InBuffer, sizeof(otMeshLocalPrefix)); status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -1905,7 +1889,7 @@ otLwfTunIoCtl_otMeshLocalPrefix( else if (OutBufferLength >= sizeof(otMeshLocalPrefix)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otMeshLocalPrefix_Handler, @@ -1995,7 +1979,7 @@ otLwfTunIoCtl_otNetworkName( if (InBufferLength >= sizeof(otNetworkName)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2008,7 +1992,7 @@ otLwfTunIoCtl_otNetworkName( else if (OutBufferLength >= sizeof(otNetworkName)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otNetworkName_Handler, @@ -2095,7 +2079,7 @@ otLwfTunIoCtl_otPanId( if (InBufferLength >= sizeof(otPanId)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2108,7 +2092,7 @@ otLwfTunIoCtl_otPanId( else if (OutBufferLength >= sizeof(otPanId)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otPanId_Handler, @@ -2194,7 +2178,7 @@ otLwfTunIoCtl_otRouterRollEnabled( if (InBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2207,7 +2191,7 @@ otLwfTunIoCtl_otRouterRollEnabled( else if (OutBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otRouterRollEnabled_Handler, @@ -2293,7 +2277,7 @@ otLwfTunIoCtl_otShortAddress( if (OutBufferLength >= sizeof(otShortAddress)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otShortAddress_Handler, @@ -2445,7 +2429,7 @@ otLwfTunIoCtl_otLocalLeaderWeight( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2458,7 +2442,7 @@ otLwfTunIoCtl_otLocalLeaderWeight( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otLocalLeaderWeight_Handler, @@ -2558,7 +2542,7 @@ otLwfTunIoCtl_otAddBorderRouter( if (aConfig->mOnMesh) flags |= kOnMeshFlag; status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2623,7 +2607,7 @@ otLwfTunIoCtl_otRemoveBorderRouter( memcpy_s(&prefix, sizeof(prefix), &aPrefix->mPrefix, aPrefix->mLength); status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2693,7 +2677,7 @@ otLwfTunIoCtl_otAddExternalRoute( if (aConfig->mOnMesh) flags |= kOnMeshFlag; status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2758,7 +2742,7 @@ otLwfTunIoCtl_otRemoveExternalRoute( memcpy_s(&prefix, sizeof(prefix), &aPrefix->mPrefix, aPrefix->mLength); status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2847,7 +2831,7 @@ otLwfTunIoCtl_otContextIdReuseDelay( if (InBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2860,7 +2844,7 @@ otLwfTunIoCtl_otContextIdReuseDelay( else if (OutBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otContextIdReuseDelay_Handler, @@ -2946,7 +2930,7 @@ otLwfTunIoCtl_otKeySequenceCounter( if (InBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -2959,7 +2943,7 @@ otLwfTunIoCtl_otKeySequenceCounter( else if (OutBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otKeySequenceCounter_Handler, @@ -3045,7 +3029,7 @@ otLwfTunIoCtl_otNetworkIdTimeout( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3058,7 +3042,7 @@ otLwfTunIoCtl_otNetworkIdTimeout( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otNetworkIdTimeout_Handler, @@ -3144,7 +3128,7 @@ otLwfTunIoCtl_otRouterUpgradeThreshold( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3157,7 +3141,7 @@ otLwfTunIoCtl_otRouterUpgradeThreshold( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otRouterUpgradeThreshold_Handler, @@ -3243,7 +3227,7 @@ otLwfTunIoCtl_otRouterDowngradeThreshold( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3256,7 +3240,7 @@ otLwfTunIoCtl_otRouterDowngradeThreshold( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otRouterDowngradeThreshold_Handler, @@ -3335,7 +3319,7 @@ otLwfTunIoCtl_otReleaseRouterId( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3407,7 +3391,7 @@ otLwfTunIoCtl_otMacWhitelistEnabled( if (InBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3420,7 +3404,7 @@ otLwfTunIoCtl_otMacWhitelistEnabled( else if (OutBufferLength >= sizeof(BOOLEAN)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otMacWhitelistEnabled_Handler, @@ -3512,7 +3496,7 @@ otLwfTunIoCtl_otAddMacWhitelist( } status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3571,7 +3555,7 @@ otLwfTunIoCtl_otRemoveMacWhitelist( if (InBufferLength >= sizeof(otExtAddress)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3660,7 +3644,7 @@ otLwfTunIoCtl_otClearMacWhitelist( UNREFERENCED_PARAMETER(OutBufferLength); status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3768,7 +3752,7 @@ otLwfTunIoCtl_otDeviceRole( } status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -3781,7 +3765,7 @@ otLwfTunIoCtl_otDeviceRole( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otDeviceRole_Handler, @@ -4014,7 +3998,7 @@ otLwfTunIoCtl_otLeaderRouterId( if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otLeaderRouterId_Handler, @@ -4100,7 +4084,7 @@ otLwfTunIoCtl_otLeaderWeight( if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otLeaderWeight_Handler, @@ -4186,7 +4170,7 @@ otLwfTunIoCtl_otNetworkDataVersion( if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otNetworkDataVersion_Handler, @@ -4272,7 +4256,7 @@ otLwfTunIoCtl_otPartitionId( if (OutBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otPartitionId_Handler, @@ -4358,7 +4342,7 @@ otLwfTunIoCtl_otRloc16( if (OutBufferLength >= sizeof(uint16_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otRloc16_Handler, @@ -4508,7 +4492,7 @@ otLwfTunIoCtl_otStableNetworkDataVersion( if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otStableNetworkDataVersion_Handler, @@ -4945,7 +4929,7 @@ otLwfTunIoCtl_otPlatformReset( UNREFERENCED_PARAMETER(OutBufferLength); status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -5007,7 +4991,7 @@ otLwfTunIoCtl_otParentInfo( if (OutBufferLength >= sizeof(otRouterInfo)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otParentInfo_Handler, @@ -5157,7 +5141,7 @@ otLwfTunIoCtl_otMaxChildren( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -5170,7 +5154,7 @@ otLwfTunIoCtl_otMaxChildren( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otMaxChildren_Handler, @@ -5439,7 +5423,7 @@ otLwfTunIoCtl_otRouterSelectionJitter( if (InBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -5452,7 +5436,7 @@ otLwfTunIoCtl_otRouterSelectionJitter( else if (OutBufferLength >= sizeof(uint8_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otRouterSelectionJitter_Handler, @@ -6020,7 +6004,7 @@ otLwfTunIoCtl_otKeySwitchGuardtime( if (InBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, NULL, @@ -6033,7 +6017,7 @@ otLwfTunIoCtl_otKeySwitchGuardtime( else if (OutBufferLength >= sizeof(uint32_t)) { status = - otLwfSendTunnelCommandForIrp( + otLwfTunSendCommandForIrp( pFilter, pIrp, otLwfTunIoCtl_otKeySwitchGuardtime_Handler, diff --git a/examples/drivers/windows/otLwf/precomp.h b/examples/drivers/windows/otLwf/precomp.h index 4e10ac1ef..a1eeb8c55 100644 --- a/examples/drivers/windows/otLwf/precomp.h +++ b/examples/drivers/windows/otLwf/precomp.h @@ -78,8 +78,6 @@ RtlCopyBufferToMdl( #include #include -#include -#include #ifdef _KERNEL_MODE #define CODE_SEG(segment) __declspec(code_seg(segment)) @@ -109,7 +107,7 @@ typedef struct UDPHeader //#define DEBUG_TIMING //#define DEBUG_ALLOC -//#define LOG_BUFFERS +#define LOG_BUFFERS //#define FORCE_SYNCHRONOUS_RECEIVE #include "driver.h" @@ -118,5 +116,6 @@ typedef struct UDPHeader #include "oid.h" #include "radio.h" #include "filter.h" +#include "command.h" #include "thread.h" #include "tunnel.h" diff --git a/examples/drivers/windows/otLwf/radio.c b/examples/drivers/windows/otLwf/radio.c index d9ad431f1..fe855a2db 100644 --- a/examples/drivers/windows/otLwf/radio.c +++ b/examples/drivers/windows/otLwf/radio.c @@ -39,7 +39,6 @@ void LogMac( _In_ PCSTR szDir, _In_ PMS_FILTER pFilter, - _In_ PNET_BUFFER_LIST NetBufferList, ULONG frameLength, _In_reads_bytes_(frameLength) PUCHAR frame ); @@ -47,8 +46,8 @@ LogMac( const char MacSend[] = "MAC_SEND"; const char MacRecv[] = "MAC_RECV"; -#define LogMacSend(pFilter, NBL, frameLength, frame) LogMac(MacSend, pFilter, NBL, frameLength, frame) -#define LogMacRecv(pFilter, NBL, frameLength, frame) LogMac(MacRecv, pFilter, NBL, frameLength, frame) +#define LogMacSend(pFilter, frameLength, frame) LogMac(MacSend, pFilter, frameLength, frame) +#define LogMacRecv(pFilter, frameLength, frame) LogMac(MacRecv, pFilter, frameLength, frame) void otPlatReset( @@ -56,8 +55,27 @@ otPlatReset( ) { NT_ASSERT(otCtx); - // This function does nothing currently. - UNREFERENCED_PARAMETER(otCtx); + PMS_FILTER pFilter = otCtxToFilter(otCtx); + NTSTATUS status; + + LogInfo(DRIVER_DEFAULT, "Interface %!GUID! resetting...", &pFilter->InterfaceGuid); + + // Indicate to the miniport + status = + otLwfCmdSendAsync( + pFilter, + NULL, + NULL, + NULL, + SPINEL_CMD_RESET, + 0, + 0, + NULL + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Send SPINEL_CMD_RESET failed, %!STATUS!", status); + } } otPlatResetReason @@ -66,56 +84,38 @@ otPlatGetResetReason( ) { NT_ASSERT(otCtx); - UNREFERENCED_PARAMETER(otCtx); + UNREFERENCED_PARAMETER(otCtx); // TODO - Cache from last status for RESET return kPlatResetReason_PowerOn; } -VOID -otLwfRadioSendPacket( - _In_ PMS_FILTER pFilter, - _In_ RadioPacket* Packet - ); - VOID otLwfRadioGetFactoryAddress( _In_ PMS_FILTER pFilter ) { - NDIS_STATUS status; - ULONG bytesProcessed; - OT_FACTORY_EXTENDED_ADDRESS OidBuffer = { {0} }; + NTSTATUS status; + uint8_t *hwAddress = NULL; RtlZeroMemory(&pFilter->otFactoryAddress, sizeof(pFilter->otFactoryAddress)); // Query the MP for the address - status = - otLwfSendInternalRequest( + status = + otLwfCmdGetProp( pFilter, - NdisRequestQueryInformation, - OID_OT_FACTORY_EXTENDED_ADDRESS, - &OidBuffer, - sizeof(OT_FACTORY_EXTENDED_ADDRESS), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + NULL, + SPINEL_PROP_HWADDR, + SPINEL_DATATYPE_EUI64_S, + &hwAddress + ); + if (!NT_SUCCESS(status) || hwAddress == NULL) { - LogError(DRIVER_DEFAULT, "Query for OID_FACTORY_EXTENDED_ADDRESS failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Get SPINEL_PROP_HWADDR failed, %!STATUS!", status); return; } - // Validate the return header - if (bytesProcessed != SIZEOF_OT_FACTORY_EXTENDED_ADDRESS_REVISION_1 || - OidBuffer.Header.Type != NDIS_OBJECT_TYPE_DEFAULT || - OidBuffer.Header.Revision != OT_FACTORY_EXTENDED_ADDRESS_REVISION_1 || - OidBuffer.Header.Size != SIZEOF_OT_FACTORY_EXTENDED_ADDRESS_REVISION_1) - { - LogError(DRIVER_DEFAULT, "Query for OID_OT_FACTORY_EXTENDED_ADDRESS returned invalid data"); - return; - } + memcpy(&pFilter->otFactoryAddress, hwAddress, sizeof(pFilter->otFactoryAddress)); - LogInfo(DRIVER_DEFAULT, "Interface %!GUID! cached factory Extended Mac Address: %llX", &pFilter->InterfaceGuid, OidBuffer.ExtendedAddress); - - pFilter->otFactoryAddress = OidBuffer.ExtendedAddress; + LogInfo(DRIVER_DEFAULT, "Interface %!GUID! cached factory Extended Mac Address: %llX", &pFilter->InterfaceGuid, pFilter->otFactoryAddress); } VOID @@ -125,14 +125,17 @@ otLwfRadioInit( { LogFuncEntry(DRIVER_DEFAULT); - NT_ASSERT(pFilter->MiniportCapabilities.MiniportMode == OT_MP_MODE_RADIO); + NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE); + //NT_ASSERT((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_SLEEP) != 0); // Initialize the OpenThread radio capability flags - pFilter->otRadioCapabilities = kRadioCapsEnergyScan; - if ((pFilter->MiniportCapabilities.RadioCapabilities & OT_RADIO_CAP_ACK_TIMEOUT) != 0) + pFilter->otRadioCapabilities = 0; + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_ACK_TIMEOUT) != 0) pFilter->otRadioCapabilities |= kRadioCapsAckTimeout; - if ((pFilter->MiniportCapabilities.RadioCapabilities & OT_RADIO_CAP_MAC_RETRY_AND_COLLISION_AVOIDANCE) != 0) + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_MAC_RETRY_AND_COLLISION_AVOIDANCE) != 0) pFilter->otRadioCapabilities |= kRadioCapsTransmitRetries; + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_ENERGY_SCAN) != 0) + pFilter->otRadioCapabilities |= kRadioCapsEnergyScan; pFilter->otPhyState = kStateDisabled; pFilter->otCurrentListenChannel = 0xFF; @@ -164,27 +167,23 @@ void otPlatRadioSetPanId(_In_ otInstance *otCtx, uint16_t panid) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - NDIS_STATUS status; - ULONG bytesProcessed; - OT_PAND_ID OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_PAND_ID_REVISION_1, SIZEOF_OT_PAND_ID_REVISION_1}, panid }; + NTSTATUS status; LogInfo(DRIVER_DEFAULT, "Interface %!GUID! set PanID: %X", &pFilter->InterfaceGuid, panid); pFilter->otPanID = panid; // Indicate to the miniport - status = - otLwfSendInternalRequest( + status = + otLwfCmdSetProp( pFilter, - NdisRequestSetInformation, - OID_OT_PAND_ID, - &OidBuffer, - sizeof(OidBuffer), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + SPINEL_PROP_MAC_15_4_PANID, + SPINEL_DATATYPE_UINT16_S, + panid + ); + if (!NT_SUCCESS(status)) { - LogError(DRIVER_DEFAULT, "Set for OID_OT_PAND_ID failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_PANID failed, %!STATUS!", status); } } @@ -192,28 +191,29 @@ void otPlatRadioSetExtendedAddress(_In_ otInstance *otCtx, uint8_t *address) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - NDIS_STATUS status; - ULONG bytesProcessed; - OT_EXTENDED_ADDRESS OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_EXTENDED_ADDRESS_REVISION_1, SIZEOF_OT_EXTENDED_ADDRESS_REVISION_1} }; + NTSTATUS status; + spinel_eui64_t extAddr; LogInfo(DRIVER_DEFAULT, "Interface %!GUID! set Extended Mac Address: %llX", &pFilter->InterfaceGuid, *(ULONGLONG*)address); pFilter->otExtendedAddress = *(ULONGLONG*)address; - OidBuffer.ExtendedAddress = *(ULONGLONG*)address; + + for (size_t i = 0; i < OT_EXT_ADDRESS_SIZE; i++) + { + extAddr.bytes[i] = address[7 - i]; + } // Indicate to the miniport - status = - otLwfSendInternalRequest( + status = + otLwfCmdSetProp( pFilter, - NdisRequestSetInformation, - OID_OT_EXTENDED_ADDRESS, - &OidBuffer, - sizeof(OidBuffer), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + SPINEL_PROP_MAC_15_4_LADDR, + SPINEL_DATATYPE_EUI64_S, + &extAddr + ); + if (!NT_SUCCESS(status)) { - LogError(DRIVER_DEFAULT, "Set for OID_OT_EXTENDED_ADDRESS failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_LADDR failed, %!STATUS!", status); } } @@ -221,27 +221,23 @@ void otPlatRadioSetShortAddress(_In_ otInstance *otCtx, uint16_t address) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - NDIS_STATUS status; - ULONG bytesProcessed; - OT_SHORT_ADDRESS OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_SHORT_ADDRESS_REVISION_1, SIZEOF_OT_SHORT_ADDRESS_REVISION_1}, address }; + NTSTATUS status; LogInfo(DRIVER_DEFAULT, "Interface %!GUID! set Short Mac Address: %X", &pFilter->InterfaceGuid, address); pFilter->otShortAddress = address; // Indicate to the miniport - status = - otLwfSendInternalRequest( + status = + otLwfCmdSetProp( pFilter, - NdisRequestSetInformation, - OID_OT_SHORT_ADDRESS, - &OidBuffer, - sizeof(OidBuffer), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + SPINEL_PROP_MAC_15_4_SADDR, + SPINEL_DATATYPE_UINT16_S, + address + ); + if (!NT_SUCCESS(status)) { - LogError(DRIVER_DEFAULT, "Set for OID_OT_SHORT_ADDRESS failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_15_4_SADDR failed, %!STATUS!", status); } } @@ -249,25 +245,21 @@ void otPlatRadioSetPromiscuous(_In_ otInstance *otCtx, bool aEnable) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - NDIS_STATUS status; - ULONG bytesProcessed; - OT_PROMISCUOUS_MODE OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_PROMISCUOUS_MODE_REVISION_1, SIZEOF_OT_PROMISCUOUS_MODE_REVISION_1}, (BOOLEAN)aEnable }; + NTSTATUS status; pFilter->otPromiscuous = (BOOLEAN)aEnable; // Indicate to the miniport - status = - otLwfSendInternalRequest( + status = + otLwfCmdSetProp( pFilter, - NdisRequestSetInformation, - OID_OT_PROMISCUOUS_MODE, - &OidBuffer, - sizeof(OidBuffer), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + SPINEL_PROP_MAC_PROMISCUOUS_MODE, + SPINEL_DATATYPE_UINT8_S, + aEnable != 0 ? SPINEL_MAC_PROMISCUOUS_MODE_NETWORK : SPINEL_MAC_PROMISCUOUS_MODE_OFF + ); + if (!NT_SUCCESS(status)) { - LogError(DRIVER_DEFAULT, "Set for OID_OT_PROMISCUOUS_MODE failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_PROMISCUOUS_MODE failed, %!STATUS!", status); } } @@ -275,56 +267,90 @@ bool otPlatRadioIsEnabled(_In_ otInstance *otCtx) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - return pFilter->otPhyState != kStateSleep; + return pFilter->otPhyState != kStateDisabled; } ThreadError otPlatRadioEnable(_In_ otInstance *otCtx) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - + NTSTATUS status; + NT_ASSERT(pFilter->otPhyState <= kStateSleep); if (pFilter->otPhyState > kStateSleep) return kThreadError_Busy; pFilter->otPhyState = kStateSleep; - + + // Indicate to the miniport + status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_PHY_ENABLED, + SPINEL_DATATYPE_BOOL_S, + TRUE + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_ENABLED (true) failed, %!STATUS!", status); + } + LogInfo(DRIVER_DEFAULT, "Filter %p PhyState = kStateSleep.", pFilter); - return kThreadError_None; + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } ThreadError otPlatRadioDisable(_In_ otInstance *otCtx) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - - NT_ASSERT(pFilter->otPhyState <= kStateSleep); - if (pFilter->otPhyState > kStateSleep) return kThreadError_Busy; + NTSTATUS status; + + // First make sure we are in the Sleep state if we weren't already + if (pFilter->otPhyState > kStateSleep) + { + (void)otPlatRadioSleep(otCtx); + } pFilter->otPhyState = kStateDisabled; - + + // Indicate to the miniport + status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_PHY_ENABLED, + SPINEL_DATATYPE_BOOL_S, + FALSE + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_ENABLED (false) failed, %!STATUS!", status); + } + LogInfo(DRIVER_DEFAULT, "Filter %p PhyState = kStateDisabled.", pFilter); - return kThreadError_None; + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } ThreadError otPlatRadioSleep(_In_ otInstance *otCtx) { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - - NT_ASSERT(pFilter->otPhyState != kStateDisabled); - //NT_ASSERT(pFilter->otPhyState == kStateSleep || pFilter->otPhyState == kStateReceive); - if (pFilter->otPhyState != kStateSleep && pFilter->otPhyState != kStateReceive) - return kThreadError_Busy; + + // If we were in the transmit state, cancel the transmit + if (pFilter->otPhyState == kStateTransmit) + { + pFilter->otLastTransmitError = kThreadError_Abort; + otLwfRadioTransmitFrameDone(pFilter); + } if (pFilter->otPhyState != kStateSleep) { pFilter->otPhyState = kStateSleep; LogInfo(DRIVER_DEFAULT, "Filter %p PhyState = kStateSleep.", pFilter); - - if ((pFilter->MiniportCapabilities.RadioCapabilities & OT_RADIO_CAP_SLEEP) != 0) + + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_SLEEP) != 0) { + /* TODO NDIS_STATUS status; ULONG bytesProcessed; OT_SLEEP_MODE OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_SLEEP_MODE_REVISION_1, SIZEOF_OT_SLEEP_MODE_REVISION_1}, TRUE }; @@ -342,7 +368,20 @@ ThreadError otPlatRadioSleep(_In_ otInstance *otCtx) if (status != NDIS_STATUS_SUCCESS) { LogError(DRIVER_DEFAULT, "Set for OID_OT_SLEEP_MODE failed, %!NDIS_STATUS!", status); - } + }*/ + } + + // Indicate to the miniport + NTSTATUS status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_RAW_STREAM_ENABLED, + SPINEL_DATATYPE_BOOL_S, + FALSE + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_RAW_STREAM_ENABLED (false) failed, %!STATUS!", status); } } @@ -362,9 +401,10 @@ ThreadError otPlatRadioReceive(_In_ otInstance *otCtx, uint8_t aChannel) // If we are currently in the sleep state and the minport supports sleep // mode, come out of sleep mode now. if (pFilter->otPhyState == kStateSleep) - { - if ((pFilter->MiniportCapabilities.RadioCapabilities & OT_RADIO_CAP_SLEEP) != 0) + { + if ((pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO_SLEEP) != 0) { + /* TODO NDIS_STATUS status; ULONG bytesProcessed; OT_SLEEP_MODE OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_SLEEP_MODE_REVISION_1, SIZEOF_OT_SLEEP_MODE_REVISION_1}, FALSE }; @@ -382,35 +422,31 @@ ThreadError otPlatRadioReceive(_In_ otInstance *otCtx, uint8_t aChannel) if (status != NDIS_STATUS_SUCCESS) { LogError(DRIVER_DEFAULT, "Set for OID_OT_SLEEP_MODE failed, %!NDIS_STATUS!", status); - } + }*/ } } // Update current channel if different if (pFilter->otCurrentListenChannel != aChannel) { - NDIS_STATUS status; - ULONG bytesProcessed; - OT_CURRENT_CHANNEL OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_CURRENT_CHANNEL_REVISION_1, SIZEOF_OT_CURRENT_CHANNEL_REVISION_1}, aChannel }; - + NTSTATUS status; + NT_ASSERT(aChannel >= 11 && aChannel <= 26); LogInfo(DRIVER_DEFAULT, "Filter %p new Listen Channel = %u.", pFilter, aChannel); pFilter->otCurrentListenChannel = aChannel; - + // Indicate to the miniport - status = - otLwfSendInternalRequest( + status = + otLwfCmdSetProp( pFilter, - NdisRequestSetInformation, - OID_OT_CURRENT_CHANNEL, - &OidBuffer, - sizeof(OidBuffer), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + SPINEL_PROP_PHY_CHAN, + SPINEL_DATATYPE_UINT8_S, + aChannel + ); + if (!NT_SUCCESS(status)) { - LogError(DRIVER_DEFAULT, "Set for OID_OT_CURRENT_CHANNEL failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_PHY_CHAN failed, %!STATUS!", status); } } @@ -420,7 +456,19 @@ ThreadError otPlatRadioReceive(_In_ otInstance *otCtx, uint8_t aChannel) { pFilter->otPhyState = kStateReceive; LogInfo(DRIVER_DEFAULT, "Filter %p PhyState = kStateReceive.", pFilter); - + + NTSTATUS status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_RAW_STREAM_ENABLED, + SPINEL_DATATYPE_BOOL_S, + TRUE + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_RAW_STREAM_ENABLED (true) failed, %!STATUS!", status); + } + // Set the event to indicate we can process NBLs KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); } @@ -461,19 +509,18 @@ bool otPlatRadioGetPromiscuous(_In_ otInstance *otCtx) VOID otLwfRadioReceiveFrame( _In_ PMS_FILTER pFilter, - _In_ PNET_BUFFER_LIST NetBufferList + _In_ ThreadError errorCode ) { NT_ASSERT(pFilter->otReceiveFrame.mChannel >= 11 && pFilter->otReceiveFrame.mChannel <= 26); LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); - LogMacRecv(pFilter, NetBufferList, pFilter->otReceiveFrame.mLength, pFilter->otReceiveFrame.mPsdu); + LogMacRecv(pFilter, pFilter->otReceiveFrame.mLength, pFilter->otReceiveFrame.mPsdu); - NT_ASSERT(pFilter->otPhyState > kStateDisabled); if (pFilter->otPhyState > kStateDisabled) { - otPlatRadioReceiveDone(pFilter->otCtx, &pFilter->otReceiveFrame, kThreadError_None); + otPlatRadioReceiveDone(pFilter->otCtx, &pFilter->otReceiveFrame, errorCode); } else { @@ -511,59 +558,15 @@ VOID otLwfRadioTransmitFrame(_In_ PMS_FILTER pFilter) { NT_ASSERT(pFilter->otPhyState == kStateTransmit); + LogMacSend(pFilter, pFilter->otTransmitFrame.mLength, pFilter->otTransmitFrame.mPsdu); + LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); - otLwfRadioSendPacket(pFilter, &pFilter->otTransmitFrame); + otLwfCmdSendMacFrameAsync(pFilter, &pFilter->otTransmitFrame); LogFuncExit(DRIVER_DATA_PATH); } -VOID -otLwfRadioSendPacket( - _In_ PMS_FILTER pFilter, - _In_ RadioPacket* Packet - ) -{ - SIZE_T BytesCopied = 0; - PNET_BUFFER SendNetBuffer = NET_BUFFER_LIST_FIRST_NB(pFilter->SendNetBufferList); - OT_NBL_CONTEXT NblContext = { 0 /* Flags */, Packet->mChannel, Packet->mPower, 0 /* Lqi */ }; - - NT_ASSERT(NblContext.Channel >= 11 && NblContext.Channel <= 26); - NT_ASSERT(!pFilter->SendPending); - - NT_ASSERT(Packet->mLength <= kMaxPHYPacketSize); - - LogMacSend(pFilter, pFilter->SendNetBufferList, Packet->mLength, Packet->mPsdu); - - // Copy to the NetBufferList - RtlCopyBufferToMdl( - Packet->mPsdu, - SendNetBuffer->CurrentMdl, - SendNetBuffer->CurrentMdlOffset, - Packet->mLength, - &BytesCopied - ); - NT_ASSERT(BytesCopied == Packet->mLength); - - // Set the length field - NET_BUFFER_DATA_LENGTH(SendNetBuffer) = Packet->mLength; - - // Set the context - SetNBLContext(pFilter->SendNetBufferList, &NblContext); - - // Reset the completion event - KeResetEvent(&pFilter->SendNetBufferListComplete); - pFilter->SendPending = TRUE; - - // Send the NetBufferList - NdisFSendNetBufferLists( - pFilter->FilterHandle, - pFilter->SendNetBufferList, - NDIS_DEFAULT_PORT_NUMBER, - 0 - ); -} - VOID otLwfRadioTransmitFrameDone( _In_ PMS_FILTER pFilter @@ -571,33 +574,23 @@ otLwfRadioTransmitFrameDone( { LogFuncEntryMsg(DRIVER_DATA_PATH, "Filter: %p", pFilter); - pFilter->SendPending = FALSE; - - NT_ASSERT(pFilter->otPhyState == kStateTransmit); + if (pFilter->otPhyState == kStateTransmit) + { + pFilter->SendPending = FALSE; - // Now that we are completing a send, fall back to receive state and set the event - pFilter->otPhyState = kStateReceive; - LogInfo(DRIVER_DEFAULT, "Filter %p PhyState = kStateReceive.", pFilter); - KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); + // Now that we are completing a send, fall back to receive state and set the event + pFilter->otPhyState = kStateReceive; + LogInfo(DRIVER_DEFAULT, "Filter %p PhyState = kStateReceive.", pFilter); + KeSetEvent(&pFilter->EventWorkerThreadProcessNBLs, 0, FALSE); - if (STATUS_SUCCESS == pFilter->SendNetBufferList->Status) - { - POT_NBL_CONTEXT SendNblContext = GetNBLContext(pFilter->SendNetBufferList); - BOOLEAN FramePending = (SendNblContext->Flags & OT_NBL_FLAG_ACK_FRAME_PENDING) != 0 || pFilter->CountPendingRecvNBLs != 0; + if (pFilter->otLastTransmitError != kThreadError_None && + pFilter->otLastTransmitError != kThreadError_ChannelAccessFailure && + pFilter->otLastTransmitError != kThreadError_NoAck) + { + pFilter->otLastTransmitError = kThreadError_Abort; + } - otPlatRadioTransmitDone(pFilter->otCtx, &pFilter->otTransmitFrame, FramePending, kThreadError_None); - } - else if (STATUS_DEVICE_BUSY == pFilter->SendNetBufferList->Status) - { - otPlatRadioTransmitDone(pFilter->otCtx, &pFilter->otTransmitFrame, false, kThreadError_ChannelAccessFailure); - } - else if (STATUS_TIMEOUT == pFilter->SendNetBufferList->Status) - { - otPlatRadioTransmitDone(pFilter->otCtx, &pFilter->otTransmitFrame, false, kThreadError_NoAck); - } - else - { - otPlatRadioTransmitDone(pFilter->otCtx, &pFilter->otTransmitFrame, false, kThreadError_Abort); + otPlatRadioTransmitDone(pFilter->otCtx, &pFilter->otTransmitFrame, pFilter->otLastTransmitFramePending, pFilter->otLastTransmitError); } LogFuncExit(DRIVER_DATA_PATH); @@ -608,7 +601,10 @@ otPlatRadioSendPendingMacOffload( _In_ PMS_FILTER pFilter ) { - NDIS_STATUS status; + // TODO + UNREFERENCED_PARAMETER(pFilter); + return STATUS_NOT_SUPPORTED; + /*NDIS_STATUS status; ULONG bytesProcessed; UCHAR ShortAddressCount = pFilter->otPendingMacOffloadEnabled == TRUE ? pFilter->otPendingShortAddressCount : 0; UCHAR ExtendedAddressCount = pFilter->otPendingMacOffloadEnabled == TRUE ? pFilter->otPendingExtendedAddressCount : 0; @@ -655,7 +651,7 @@ otPlatRadioSendPendingMacOffload( FILTER_FREE_MEM(OidBuffer); - return status; + return status;*/ } void otPlatRadioEnableSrcMatch(_In_ otInstance *otCtx, bool aEnable) @@ -675,11 +671,6 @@ ThreadError otPlatRadioAddSrcMatchShortEntry(_In_ otInstance *otCtx, const uint1 { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - - // Make sure we are enabled - NT_ASSERT(pFilter->otPendingMacOffloadEnabled); - if (pFilter->otPendingMacOffloadEnabled == FALSE) - return kThreadError_InvalidState; // Check to see if it is in the list BOOLEAN Found = false; @@ -702,8 +693,11 @@ ThreadError otPlatRadioAddSrcMatchShortEntry(_In_ otInstance *otCtx, const uint1 pFilter->otPendingShortAddresses[pFilter->otPendingShortAddressCount] = aShortAddress; pFilter->otPendingShortAddressCount++; - // Update the miniport - otPlatRadioSendPendingMacOffload(pFilter); + // Update the miniport if enabled + if (pFilter->otPendingMacOffloadEnabled) + { + otPlatRadioSendPendingMacOffload(pFilter); + } return kThreadError_None; } @@ -712,11 +706,6 @@ ThreadError otPlatRadioAddSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - - // Make sure we are enabled - NT_ASSERT(pFilter->otPendingMacOffloadEnabled); - if (pFilter->otPendingMacOffloadEnabled == FALSE) - return kThreadError_InvalidState; // Check to see if it is in the list BOOLEAN Found = false; @@ -739,8 +728,11 @@ ThreadError otPlatRadioAddSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8_t memcpy(&pFilter->otPendingExtendedAddresses[pFilter->otPendingExtendedAddressCount], aExtAddress, sizeof(ULONGLONG)); pFilter->otPendingExtendedAddressCount++; - // Update the miniport - otPlatRadioSendPendingMacOffload(pFilter); + // Update the miniport if enabled + if (pFilter->otPendingMacOffloadEnabled) + { + otPlatRadioSendPendingMacOffload(pFilter); + } return kThreadError_None; } @@ -749,11 +741,6 @@ ThreadError otPlatRadioClearSrcMatchShortEntry(_In_ otInstance *otCtx, const uin { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - - // Make sure we are enabled - NT_ASSERT(pFilter->otPendingMacOffloadEnabled); - if (pFilter->otPendingMacOffloadEnabled == FALSE) - return kThreadError_InvalidState; // Check to see if it is in the list BOOLEAN Found = false; @@ -773,8 +760,11 @@ ThreadError otPlatRadioClearSrcMatchShortEntry(_In_ otInstance *otCtx, const uin // Wasn't in the list, return failure if (Found == FALSE) return kThreadError_NotFound; - // Update the miniport - otPlatRadioSendPendingMacOffload(pFilter); + // Update the miniport if enabled + if (pFilter->otPendingMacOffloadEnabled) + { + otPlatRadioSendPendingMacOffload(pFilter); + } return kThreadError_None; } @@ -783,11 +773,6 @@ ThreadError otPlatRadioClearSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8 { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - - // Make sure we are enabled - NT_ASSERT(pFilter->otPendingMacOffloadEnabled); - if (pFilter->otPendingMacOffloadEnabled == FALSE) - return kThreadError_InvalidState; // Check to see if it is in the list BOOLEAN Found = false; @@ -807,8 +792,11 @@ ThreadError otPlatRadioClearSrcMatchExtEntry(_In_ otInstance *otCtx, const uint8 // Wasn't in the list, return failure if (Found == FALSE) return kThreadError_NotFound; - // Update the miniport - otPlatRadioSendPendingMacOffload(pFilter); + // Update the miniport if enabled + if (pFilter->otPendingMacOffloadEnabled) + { + otPlatRadioSendPendingMacOffload(pFilter); + } return kThreadError_None; } @@ -843,30 +831,48 @@ ThreadError otPlatRadioEnergyScan(_In_ otInstance *otCtx, uint8_t aScanChannel, { NT_ASSERT(otCtx); PMS_FILTER pFilter = otCtxToFilter(otCtx); - NDIS_STATUS status; - ULONG bytesProcessed; - OT_ENERGY_SCAN OidBuffer = { {NDIS_OBJECT_TYPE_DEFAULT, OT_ENERGY_SCAN_REVISION_1, SIZEOF_OT_ENERGY_SCAN_REVISION_1}, aScanChannel, aScanDuration }; - - LogInfo(DRIVER_DEFAULT, "Filter %p starting energy scan on channel %d (%d ms).", pFilter, aScanChannel, aScanDuration); - // Cache the listening channel - pFilter->otCurrentListenChannel = aScanChannel; - - // Indicate to the miniport - status = - otLwfSendInternalRequest( + NTSTATUS status = + otLwfCmdSetProp( pFilter, - NdisRequestSetInformation, - OID_OT_ENERGY_SCAN, - &OidBuffer, - sizeof(OidBuffer), - &bytesProcessed - ); - if (status != NDIS_STATUS_SUCCESS) + SPINEL_PROP_MAC_SCAN_MASK, + SPINEL_DATATYPE_UINT8_S, + aScanChannel + ); + if (!NT_SUCCESS(status)) { - LogError(DRIVER_DEFAULT, "Set for OID_OT_ENERGY_SCAN failed, %!NDIS_STATUS!", status); + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SCAN_MASK failed, %!STATUS!", status); + goto error; } + status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_SCAN_PERIOD, + SPINEL_DATATYPE_UINT16_S, + aScanDuration + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SCAN_PERIOD failed, %!STATUS!", status); + goto error; + } + + status = + otLwfCmdSetProp( + pFilter, + SPINEL_PROP_MAC_SCAN_STATE, + SPINEL_DATATYPE_UINT8_S, + SPINEL_SCAN_STATE_ENERGY + ); + if (!NT_SUCCESS(status)) + { + LogError(DRIVER_DEFAULT, "Set SPINEL_PROP_MAC_SCAN_STATE failed, %!STATUS!", status); + goto error; + } + +error: + return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed; } @@ -894,7 +900,6 @@ void LogMac( _In_ PCSTR szDir, _In_ PMS_FILTER pFilter, - _In_ PNET_BUFFER_LIST NetBufferList, ULONG frameLength, _In_reads_bytes_(frameLength) PUCHAR frame ) @@ -909,42 +914,42 @@ LogMac( switch (frame[1] & (IEEE802154_DST_ADDR_MASK | IEEE802154_SRC_ADDR_MASK)) { case IEEE802154_DST_ADDR_NONE | IEEE802154_SRC_ADDR_NONE: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : null => null (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: null => null (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_NONE | IEEE802154_SRC_ADDR_SHORT: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : %X => null (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %X => null (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_NONE | IEEE802154_SRC_ADDR_EXT: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : %llX => null (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %llX => null (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_SHORT | IEEE802154_SRC_ADDR_NONE: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : null => %X (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getDstShortAddress(frame), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: null => %X (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getDstShortAddress(frame), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_SHORT | IEEE802154_SRC_ADDR_SHORT: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : %X => %X (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+2), getDstShortAddress(frame), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %X => %X (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+2), getDstShortAddress(frame), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_SHORT | IEEE802154_SRC_ADDR_EXT: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : %llX => %X (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+2), getDstShortAddress(frame), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %llX => %X (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+2), getDstShortAddress(frame), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_EXT | IEEE802154_SRC_ADDR_NONE: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : null => %llX (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getDstExtAddress(frame), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: null => %llX (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getDstExtAddress(frame), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_EXT | IEEE802154_SRC_ADDR_SHORT: - LogVerbose(DRIVER_DATA_PATH, "Filt: %p, %s: %p : %X => %llX (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+8), getDstExtAddress(frame), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %X => %llX (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getSrcShortAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+8), getDstExtAddress(frame), frameLength, AckRequested, FramePending); break; case IEEE802154_DST_ADDR_EXT | IEEE802154_SRC_ADDR_EXT: - LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %p : %llX => %llX (%u bytes, AckReq=%u, FramePending=%u)", - pFilter, szDir, NetBufferList, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+8), getDstExtAddress(frame), frameLength, AckRequested, FramePending); + LogVerbose(DRIVER_DATA_PATH, "Filter: %p, %s: %llX => %llX (%u bytes, AckReq=%u, FramePending=%u)", + pFilter, szDir, getSrcExtAddress(frameLength, frame, IEEE802154_DSTADDR_OFFSET+8), getDstExtAddress(frame), frameLength, AckRequested, FramePending); break; } diff --git a/examples/drivers/windows/otLwf/radio.h b/examples/drivers/windows/otLwf/radio.h index a0c37a1d0..578ec8102 100644 --- a/examples/drivers/windows/otLwf/radio.h +++ b/examples/drivers/windows/otLwf/radio.h @@ -81,7 +81,7 @@ enum VOID otLwfRadioInit(_In_ PMS_FILTER pFilter); // Indicates a received frame from the radio layer -VOID otLwfRadioReceiveFrame(_In_ PMS_FILTER pFilter, _In_ PNET_BUFFER_LIST NetBufferList); +VOID otLwfRadioReceiveFrame(_In_ PMS_FILTER pFilter, _In_ ThreadError errorCode); // Indicates the transmit frame is ready to send to the radio layer VOID otLwfRadioTransmitFrame(_In_ PMS_FILTER pFilter); diff --git a/examples/drivers/windows/otLwf/thread.c b/examples/drivers/windows/otLwf/thread.c index 256d49d8f..acbf93818 100644 --- a/examples/drivers/windows/otLwf/thread.c +++ b/examples/drivers/windows/otLwf/thread.c @@ -42,45 +42,13 @@ otLwfInitializeThreadMode( ) { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - PNET_BUFFER SendNetBuffer; LogFuncEntry(DRIVER_DEFAULT); + NT_ASSERT(pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_RADIO); + 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 @@ -92,6 +60,7 @@ otLwfInitializeThreadMode( NdisAllocateSpinLock(&pFilter->EventsLock); InitializeListHead(&pFilter->AddressChangesHead); InitializeListHead(&pFilter->NBLsHead); + InitializeListHead(&pFilter->MacFramesHead); InitializeListHead(&pFilter->EventIrpListHead); KeInitializeEvent( &pFilter->EventWorkerThreadStopEvent, @@ -118,6 +87,11 @@ otLwfInitializeThreadMode( SynchronizationEvent, // auto-clearing event FALSE // event initially non-signalled ); + KeInitializeEvent( + &pFilter->EventWorkerThreadProcessMacFrames, + SynchronizationEvent, // auto-clearing event + FALSE // event initially non-signalled + ); KeInitializeEvent( &pFilter->EventWorkerThreadProcessIrp, SynchronizationEvent, // auto-clearing event @@ -140,6 +114,19 @@ otLwfInitializeThreadMode( break; } + // Query the interface state (best effort, since it might not be supported) + BOOLEAN IfUp = FALSE; + Status = otLwfCmdGetProp(pFilter, NULL, SPINEL_PROP_NET_IF_UP, SPINEL_DATATYPE_BOOL_S, &IfUp); + if (!NT_SUCCESS(Status)) + { + LogVerbose(DRIVER_DEFAULT, "Failed to query SPINEL_PROP_INTERFACE_TYPE, %!STATUS!", Status); + Status = NDIS_STATUS_SUCCESS; + } + else + { + NT_ASSERT(IfUp == FALSE); + } + // Initialize the event processing thread if (!NT_SUCCESS(otLwfEventProcessingStart(pFilter))) { @@ -159,13 +146,6 @@ otLwfInitializeThreadMode( { 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); @@ -185,11 +165,10 @@ otLwfUninitializeThreadMode( 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); + if (pFilter->EventHighPrecisionTimer) + { + ExDeleteTimer(pFilter->EventHighPrecisionTimer, TRUE, FALSE, NULL); + } LogFuncExit(DRIVER_DEFAULT); } @@ -551,3 +530,110 @@ void otLwfCommissionerPanIdConflictCallback(uint16_t aPanId, uint32_t aChannelMa LogFuncExit(DRIVER_DEFAULT); } + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfThreadValueIs( + _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 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); + + if ((status >= SPINEL_STATUS_RESET__BEGIN) && (status <= SPINEL_STATUS_RESET__END)) + { + LogInfo(DRIVER_DEFAULT, "Interface %!GUID! was reset (status %d).", &pFilter->InterfaceGuid, status); + // TODO - Handle reset + } + } + else if (key == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT) + { + uint8_t scanChannel; + int8_t maxRssi; + spinel_ssize_t ret; + + ret = spinel_datatype_unpack( + value_data_ptr, + value_data_len, + "Cc", + &scanChannel, + &maxRssi); + + NT_ASSERT(ret > 0); + if (ret > 0) + { + LogInfo(DRIVER_DEFAULT, "Filter: %p, completed energy scan: Rssi:%d", pFilter, maxRssi); + otLwfEventProcessingIndicateEnergyScanResult(pFilter, maxRssi); + } + } + else if (key == SPINEL_PROP_STREAM_RAW) + { + if (value_data_len < 256) + { + otLwfEventProcessingIndicateNewMacFrameCommand( + pFilter, + DispatchLevel, + value_data_ptr, + (uint8_t)value_data_len); + } + } + 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, "DEVICE: %s", (char*)output); + } + else if (output_len < 128) + { + char strOutput[128] = { 0 }; + memcpy(strOutput, output, output_len); + LogInfo(DRIVER_DEFAULT, "DEVICE: %s", strOutput); + } + } + } + + LogFuncExit(DRIVER_DEFAULT); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfThreadValueInserted( + _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(key); + UNREFERENCED_PARAMETER(value_data_ptr); + UNREFERENCED_PARAMETER(value_data_len); + + LogFuncExit(DRIVER_DEFAULT); +} diff --git a/examples/drivers/windows/otLwf/thread.h b/examples/drivers/windows/otLwf/thread.h index c0b77a9a0..fe3377f98 100644 --- a/examples/drivers/windows/otLwf/thread.h +++ b/examples/drivers/windows/otLwf/thread.h @@ -107,11 +107,19 @@ 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 +otLwfEventProcessingIndicateNewMacFrameCommand( + _In_ PMS_FILTER pFilter, + _In_ BOOLEAN DispatchLevel, + _In_reads_bytes_(BufferLength) + const uint8_t* Buffer, + _In_ uint8_t BufferLength + ); + _IRQL_requires_max_(DISPATCH_LEVEL) VOID otLwfEventProcessingIndicateNetBufferListsCancelled( @@ -145,4 +153,28 @@ 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); +// +// Value Callbacks +// + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfThreadValueIs( + _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 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfThreadValueInserted( + _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 + ); + #endif //_THREAD_H_ diff --git a/examples/drivers/windows/otLwf/tunnel.c b/examples/drivers/windows/otLwf/tunnel.c index de81d825a..edde26215 100644 --- a/examples/drivers/windows/otLwf/tunnel.c +++ b/examples/drivers/windows/otLwf/tunnel.c @@ -37,99 +37,28 @@ KSTART_ROUTINE otLwfTunWorkerThread; -ThreadError -SpinelStatusToThreadError( - spinel_status_t error - ) +SPINEL_CMD_HANDLER otLwfIrpCommandHandler; + +typedef struct _SPINEL_IRP_CMD_CONTEXT { - 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; -} + PMS_FILTER pFilter; + PIRP Irp; + SPINEL_IRP_CMD_HANDLER *Handler; + spinel_tid_t tid; +} SPINEL_IRP_CMD_CONTEXT; _IRQL_requires_max_(PASSIVE_LEVEL) NDIS_STATUS -otLwfInitializeTunnelMode( +otLwfTunInitialize( _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); + NT_ASSERT(pFilter->DeviceCapabilities & OTLWF_DEVICE_CAP_THREAD_1_0); KeInitializeEvent( &pFilter->TunWorkerThreadStopEvent, @@ -173,27 +102,13 @@ otLwfInitializeTunnelMode( 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); + otLwfTunUninitialize(pFilter); } LogFuncExitNDIS(DRIVER_DEFAULT, Status); @@ -203,7 +118,7 @@ error: _IRQL_requires_max_(PASSIVE_LEVEL) void -otLwfUninitializeTunnelMode( +otLwfTunUninitialize( _In_ PMS_FILTER pFilter ) { @@ -233,8 +148,6 @@ otLwfUninitializeTunnelMode( LogInfo(DRIVER_DEFAULT, "Tunnel worker thread cleaned up."); } - // TODO - Clean up command handlers - LogFuncExit(DRIVER_DEFAULT); } @@ -286,7 +199,7 @@ otLwfTunWorkerThread( // Query the current addresses status = - otLwfGetTunProp( + otLwfCmdGetProp( pFilter, &DataBuffer, SPINEL_PROP_IPV6_ADDRESS_TABLE, @@ -329,847 +242,6 @@ otLwfTunWorkerThread( 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( @@ -1262,7 +334,7 @@ otLwfTunCancelIrp( IoReleaseCancelSpinLock(Irp->CancelIrql); // Try to cancel pending command - otLwfCancelCommandHandler( + otLwfCmdCancel( CmdContext->pFilter, (Irp->CancelIrql == DISPATCH_LEVEL) ? TRUE : FALSE, CmdContext->tid); @@ -1272,7 +344,7 @@ otLwfTunCancelIrp( _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS -otLwfSendTunnelCommandForIrp( +otLwfTunSendCommandForIrp( _In_ PMS_FILTER pFilter, _In_ PIRP Irp, _In_opt_ SPINEL_IRP_CMD_HANDLER *Handler, @@ -1309,7 +381,7 @@ otLwfSendTunnelCommandForIrp( va_list args; va_start(args, pack_format); status = - otLwfSendTunnelCommandWithHandlerV( + otLwfCmdSendAsyncV( pFilter, otLwfIrpCommandHandler, pContext, @@ -1335,397 +407,260 @@ 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( +void +otLwfTunValueIs( _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 + _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 ) { - SPINEL_GET_PROP_CONTEXT* CmdContext = (SPINEL_GET_PROP_CONTEXT*)Context; + uint32_t aNotifFlags = 0; - LogFuncEntryMsg(DRIVER_DEFAULT, "Key=%u", (ULONG)Key); + 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); + + if ((status >= SPINEL_STATUS_RESET__BEGIN) && (status <= SPINEL_STATUS_RESET__END)) + { + LogInfo(DRIVER_DEFAULT, "Interface %!GUID! was reset (status %d).", &pFilter->InterfaceGuid, status); + // 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) + { + otLwfTunReceiveIp6Packet( + 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, "DEVICE: %s", (char*)output); + } + else if (output_len < 128) + { + char strOutput[128] = { 0 }; + memcpy(strOutput, output, output_len); + LogInfo(DRIVER_DEFAULT, "DEVICE: %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 +otLwfTunValueInserted( + _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); - - if (Data == NULL) + UNREFERENCED_PARAMETER(DispatchLevel); + UNREFERENCED_PARAMETER(value_data_ptr); + UNREFERENCED_PARAMETER(value_data_len); + + if (key == SPINEL_PROP_MAC_SCAN_BEACON) { - 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) + PFILTER_NOTIFICATION_ENTRY NotifEntry = FILTER_ALLOC_NOTIF(pFilter); + if (NotifEntry) { - 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) + 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) { - CmdContext->Status = STATUS_INSUFFICIENT_RESOURCES; - DataLength = 0; + 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 { - memcpy(CmdContext->DataBuffer, Data, DataLength); - Data = (uint8_t*)CmdContext->DataBuffer; + FILTER_FREE_MEM(NotifEntry); } } - - 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 + else if (key == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT) { - CmdContext->Status = STATUS_INVALID_PARAMETER; - } + 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; - // Set the completion event - KeSetEvent(&CmdContext->CompletionEvent, 0, FALSE); + 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_(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 index f75cf7887..83112076f 100644 --- a/examples/drivers/windows/otLwf/tunnel.h +++ b/examples/drivers/windows/otLwf/tunnel.h @@ -35,117 +35,29 @@ #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 +// Initialization // _IRQL_requires_max_(PASSIVE_LEVEL) NDIS_STATUS -otLwfInitializeTunnelMode( +otLwfTunInitialize( _In_ PMS_FILTER pFilter ); _IRQL_requires_max_(PASSIVE_LEVEL) void -otLwfUninitializeTunnelMode( +otLwfTunUninitialize( _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( +otLwfTunSendCommandForIrp( _In_ PMS_FILTER pFilter, _In_ PIRP Irp, _In_opt_ SPINEL_IRP_CMD_HANDLER *Handler, @@ -157,39 +69,38 @@ otLwfSendTunnelCommandForIrp( ); // -// Spinel Helper Functions +// Value Callbacks // -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( +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfTunValueIs( _In_ PMS_FILTER pFilter, - _Out_opt_ PVOID *DataBuffer, - _In_ spinel_prop_key_t Key, - _In_ const char *pack_format, - ... + _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 ); -_IRQL_requires_max_(PASSIVE_LEVEL) -NTSTATUS -otLwfSetTunProp( +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfTunValueInserted( _In_ PMS_FILTER pFilter, - _In_ spinel_prop_key_t Key, - _In_ const char *pack_format, - ... + _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 + ); + +// Called in response to receiving a Spinel Ip6 packet command +_IRQL_requires_max_(DISPATCH_LEVEL) +void +otLwfTunReceiveIp6Packet( + _In_ PMS_FILTER pFilter, + _In_ BOOLEAN DispatchLevel, + _In_ BOOLEAN Secure, + _In_reads_bytes_(BufferLength) const uint8_t* Buffer, + _In_ UINT BufferLength ); #endif //_TUNNEL_H_ diff --git a/examples/drivers/windows/ottmp/serial.cpp b/examples/drivers/windows/ottmp/serial.cpp index 6fe5e2e06..ff85d7ea0 100644 --- a/examples/drivers/windows/ottmp/serial.cpp +++ b/examples/drivers/windows/ottmp/serial.cpp @@ -404,7 +404,7 @@ Return Value: // Xon and Xoff characters { - const SERIAL_CHARS sc = { 0, 0, 0, 0, 11, 13 }; + const SERIAL_CHARS sc = { 0, 0, 0, 0, 0x11, 0x13 }; WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDesc, (PVOID)&sc, sizeof(sc)); status = SerialSendIoctl(AdapterContext, IOCTL_SERIAL_SET_CHARS, &wrso, &inputDesc);