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