summaryrefslogtreecommitdiff
path: root/network/wwan/cxwmbclass/txqueue.cpp
diff options
context:
space:
mode:
authorAdonais Romero González <[email protected]>2024-05-06 16:21:31 -0700
committerGitHub <[email protected]>2024-05-06 16:21:31 -0700
commita74a241c664c4e1d7c0838287b34076c19d9858a (patch)
tree6ff7562612967b122acf8acf8a69c4dcfd5905db /network/wwan/cxwmbclass/txqueue.cpp
parentdef8e8e34ed2b7b1deb2fc9112ac4255f1a0f2ba (diff)
parent15477ce52bbb6b42ca591ecdfb484cac089f89ab (diff)
Merge develop changes prior to upcoming WDK release (May 2024)
Diffstat (limited to 'network/wwan/cxwmbclass/txqueue.cpp')
-rw-r--r--network/wwan/cxwmbclass/txqueue.cpp988
1 files changed, 988 insertions, 0 deletions
diff --git a/network/wwan/cxwmbclass/txqueue.cpp b/network/wwan/cxwmbclass/txqueue.cpp
new file mode 100644
index 00000000..9708b8b2
--- /dev/null
+++ b/network/wwan/cxwmbclass/txqueue.cpp
@@ -0,0 +1,988 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+
+#include "precomp.h"
+
+#include "device.h"
+#include "txqueue.h"
+
+void MbbNotifyTxReady(_In_ NETPACKETQUEUE TxQueue)
+{
+ PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue);
+
+ if (InterlockedExchange(&txQueueContext->NotificationEnabled, FALSE) == TRUE)
+ {
+ NetTxQueueNotifyMoreCompletedPacketsAvailable(TxQueue);
+ }
+}
+
+ULONG
+MbbGetNetPacketDataLength(_In_ NET_PACKET* NetPacket, _In_ NET_RING_COLLECTION const* Rings)
+{
+ ULONG length = 0;
+ auto fr = NetRingCollectionGetFragmentRing(Rings);
+ for (UINT32 i = 0; i < NetPacket->FragmentCount; i++)
+ {
+ auto fragment = NetRingGetFragmentAtIndex(fr, (NetPacket->FragmentIndex + i) & fr->ElementIndexMask);
+ length += static_cast<ULONG>(fragment->ValidLength);
+ }
+
+ return length;
+}
+
+VOID MbbPacketRestoreMdl(_In_ PMBB_PACKET_CONTEXT PacketContext)
+{
+ if (PacketContext->ModifiedMdl != NULL)
+ {
+ *PacketContext->ModifiedMdl = PacketContext->OriginalMdl;
+ PacketContext->ModifiedMdl = NULL;
+ }
+}
+
+VOID MbbPacketCleanupContext(_In_ PMBB_PACKET_CONTEXT PacketContext)
+{
+ MbbPacketRestoreMdl(PacketContext);
+ if (PacketContext->PaddingMdl != NULL)
+ {
+ IoFreeMdl(PacketContext->PaddingMdl);
+ PacketContext->PaddingMdl = NULL;
+ }
+ if (PacketContext->DataEndMdl != NULL)
+ {
+ IoFreeMdl(PacketContext->DataEndMdl);
+ PacketContext->DataEndMdl = NULL;
+ }
+ if (PacketContext->DataStartMdl != NULL)
+ {
+ IoFreeMdl(PacketContext->DataStartMdl);
+ PacketContext->DataStartMdl = NULL;
+ }
+}
+
+FORCEINLINE
+PMDL MbbPacketGetFirstMdl(_In_ PMBB_PACKET_CONTEXT PacketContext)
+{
+ if (PacketContext->PaddingMdl != NULL)
+ return PacketContext->PaddingMdl;
+ else
+ return PacketContext->DataStartMdl;
+}
+
+FORCEINLINE
+PMDL MbbPacketGetLastMdl(_In_ PMBB_PACKET_CONTEXT PacketContext)
+{
+ if (PacketContext->DataEndMdl != NULL)
+ return PacketContext->DataEndMdl;
+ else
+ return PacketContext->DataStartMdl;
+}
+
+VOID MbbPacketSaveAndSetMdl(_In_ PMBB_PACKET_CONTEXT PacketContext, _In_ PMDL MdlToSave, _In_ PMDL MdlToSet)
+{
+ if (PacketContext->ModifiedMdl == NULL)
+ {
+ PacketContext->ModifiedMdl = MdlToSave;
+ PacketContext->OriginalMdl = *MdlToSave;
+ }
+ *MdlToSave = *MdlToSet;
+}
+
+VOID MbbCleanupDssPacket(_In_ PDSS_PACKET Packet)
+{
+ if (Packet->Mdl != NULL)
+ {
+ IoFreeMdl(Packet->Mdl);
+ }
+ if (Packet != NULL)
+ {
+ FREE_POOL(Packet);
+ }
+}
+
+VOID MbbNtbCleanupContext(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext, _In_ NTSTATUS NtStatus)
+{
+ ULONG DatagramIndex;
+ BOOLEAN NeedReturnCompletedPackets = FALSE;
+
+ for (DatagramIndex = 0; DatagramIndex < NtbContext->DatagramCount; DatagramIndex++)
+ {
+ MbbPacketCleanupContext(&NtbContext->NdpDatagramEntries[DatagramIndex].NetPacketContext);
+ if (NtbContext->NdpDatagramEntries[DatagramIndex].NdpType == MbbNdpTypeIps)
+ {
+ NtbContext->NdpDatagramEntries[DatagramIndex].NetPacket->Scratch = 1;
+ NeedReturnCompletedPackets = TRUE;
+ }
+ else if (NtbContext->NdpDatagramEntries[DatagramIndex].NdpType == MbbNdpTypeVendor_1)
+ {
+ MbbDeviceSendDeviceServiceSessionDataComplete(NtbContext->NdpDatagramEntries[DatagramIndex].DssPacket->Data, NtStatus);
+
+ MbbCleanupDssPacket(NtbContext->NdpDatagramEntries[DatagramIndex].DssPacket);
+ }
+ }
+ if (NtbContext->NdpMdl != NULL)
+ {
+ IoFreeMdl(NtbContext->NdpMdl);
+ }
+ if (NtbContext->NthMdl != NULL)
+ {
+ IoFreeMdl(NtbContext->NthMdl);
+ }
+ if (NtbContext->NdpBufferMemory != NULL)
+ {
+ WdfObjectDelete(NtbContext->NdpBufferMemory);
+ }
+#if DBG
+ if (NtbContext->ScratchBuffer != NULL)
+ {
+ FREE_POOL(NtbContext->ScratchBuffer);
+ }
+#endif
+ if (NeedReturnCompletedPackets)
+ {
+ MbbNotifyTxReady(NtbContext->NetTxQueue);
+ }
+ WdfObjectDelete(NtbContext->NtbLookasideBufferMemory);
+}
+
+FORCEINLINE
+ULONG
+MbbSendQGetNtbSequence(_In_ PWMBCLASS_DEVICE_CONTEXT DeviceContext)
+{
+ return InterlockedIncrement(&DeviceContext->NtbSequenceNumber);
+}
+
+PMBB_NTB_BUILD_CONTEXT
+MbbNtbAllocateContext(_In_ WDFLOOKASIDE NtbLookasideList, _In_ PMBB_BUS_PARAMETERS BusParams, _In_ PVOID PaddingBuffer, _In_ ULONG NtbSequence)
+{
+ NTSTATUS status = NDIS_STATUS_SUCCESS;
+ size_t ntbSize;
+ PMBB_NTB_BUILD_CONTEXT ntbContext = NULL;
+ WDFMEMORY ntbContextMemory;
+
+ do
+ {
+#pragma prefast(suppress \
+ : __WARNING_MEMORY_LEAK, "By Design: Allocate ntb context from lookaside pool, released when send completes.")
+ if (!NT_SUCCESS(status = WdfMemoryCreateFromLookaside(NtbLookasideList, &ntbContextMemory)))
+ {
+ break;
+ }
+
+ ntbContext = (PMBB_NTB_BUILD_CONTEXT)WdfMemoryGetBuffer(ntbContextMemory, &ntbSize);
+ RtlZeroMemory(ntbContext, ntbSize);
+ ntbContext->PaddingBuffer = PaddingBuffer;
+ ntbContext->NtbLookasideList = NtbLookasideList;
+ ntbContext->NtbLookasideBufferMemory = ntbContextMemory;
+
+#if DBG
+ ntbContext->ScratchLength = BusParams->MaxOutNtb;
+ if ((ntbContext->ScratchBuffer = (PCHAR)ALLOCATE_NONPAGED_POOL(ntbContext->ScratchLength)) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+#endif
+ //
+ // Initialize the NTH and the NTH MDL.
+ //
+ if ((ntbContext->IsNtb32Bit = BusParams->CurrentMode32Bit) == TRUE)
+ {
+ if ((ntbContext->NthMdl = AllocateNonPagedMdl(&ntbContext->Nth32, sizeof(ntbContext->Nth32))) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ ntbContext->Nth32.dwSignature = NCM_NTH32_SIG;
+ ntbContext->Nth32.wHeaderLength = sizeof(NCM_NTH32);
+ ntbContext->Nth32.wSequence = (USHORT)NtbSequence;
+
+ ntbContext->NtbHeaderSize = sizeof(NCM_NTH32);
+ ntbContext->NdpHeaderFixedSize = sizeof(NCM_NDP32);
+ ntbContext->NdpDatagramEntrySize = sizeof(NCM_NDP32_DATAGRAM);
+ }
+ else
+ {
+ if ((ntbContext->NthMdl = AllocateNonPagedMdl(&ntbContext->Nth16, sizeof(ntbContext->Nth16))) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ ntbContext->Nth16.dwSignature = NCM_NTH16_SIG;
+ ntbContext->Nth16.wHeaderLength = sizeof(NCM_NTH16);
+ ntbContext->Nth16.wSequence = (USHORT)NtbSequence;
+
+ ntbContext->NtbHeaderSize = sizeof(NCM_NTH16);
+ ntbContext->NdpHeaderFixedSize = sizeof(NCM_NDP16);
+ ntbContext->NdpDatagramEntrySize = sizeof(NCM_NDP16_DATAGRAM);
+ }
+
+ ntbContext->NtbOutMaxSize = BusParams->MaxOutNtb;
+ ntbContext->NtbOutMaxDatagrams = BusParams->MaxOutDatagrams;
+ ntbContext->NdpOutDivisor = BusParams->NdpOutDivisor;
+ ntbContext->NdpOutPayloadRemainder = BusParams->NdpOutRemainder;
+ ntbContext->NdpOutAlignment = BusParams->NdpOutAlignment;
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ if (ntbContext != NULL)
+ {
+ MbbNtbCleanupContext(ntbContext, status);
+ }
+ ntbContext = NULL;
+ }
+ return ntbContext;
+}
+
+NTSTATUS
+MbbFillPacketContext(
+ _In_ PMBB_PACKET_CONTEXT PacketContext,
+ _In_ PMDL PacketDataStartMdl,
+ _In_ ULONG PacketDataStartMdlDataOffset,
+ _In_ ULONG DatagramLength,
+ _In_ PVOID PaddingBuffer,
+ _In_ ULONG PaddingLength)
+{
+ ULONG packetDataStartMdlDataLength;
+ PCHAR packetDataStartBuffer;
+ PMDL packetDataEndMdl;
+ ULONG packetDataEndMdlDataLength;
+ PCHAR packetDataEndBuffer;
+ PMDL packetMdl;
+ ULONG packetMdlOffset;
+ ULONG packetMdlLength;
+ PMDL packetPenultimateMdl;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ do
+ {
+ if ((packetDataStartBuffer = (PCHAR)MmGetSystemAddressForMdlSafe(PacketDataStartMdl, NormalPagePriority | MdlMappingNoExecute)) == NULL)
+ {
+ status = STATUS_RESOURCE_DATA_NOT_FOUND;
+ break;
+ }
+ packetDataStartBuffer += PacketDataStartMdlDataOffset;
+ //
+ // Create new DataStart and DataEnd Mdls
+ // to remove the unused data space.
+ //
+ packetDataStartMdlDataLength = MmGetMdlByteCount(PacketDataStartMdl);
+ packetDataStartMdlDataLength -= PacketDataStartMdlDataOffset;
+
+ if ((PacketContext->DataStartMdl =
+ AllocateNonPagedMdl(packetDataStartBuffer, (ULONG)(MIN(DatagramLength, packetDataStartMdlDataLength)))) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ PacketContext->DataStartMdl->Next = PacketDataStartMdl->Next;
+ //
+ // Find the end MDL and the amount of data in the end MDL
+ //
+ packetMdl = PacketDataStartMdl;
+ packetMdlOffset = PacketDataStartMdlDataOffset;
+ packetPenultimateMdl = NULL;
+
+ for (packetDataEndMdlDataLength = (ULONG)DatagramLength; packetDataEndMdlDataLength > (MmGetMdlByteCount(packetMdl) - packetMdlOffset);
+ packetDataEndMdlDataLength -= packetMdlLength)
+ {
+ packetPenultimateMdl = packetMdl;
+ packetMdlLength = MmGetMdlByteCount(packetMdl) - packetMdlOffset;
+ packetMdlOffset = 0;
+ packetMdl = packetMdl->Next;
+ }
+ packetDataEndMdl = packetMdl;
+ //
+ // If the starting and ending MDLs are not the same
+ // then build another partial MDL removing any unused
+ // data space.
+ //
+ if (packetDataEndMdl != PacketDataStartMdl)
+ {
+ if ((packetDataEndBuffer = (PCHAR)MmGetSystemAddressForMdlSafe(packetDataEndMdl, NormalPagePriority | MdlMappingNoExecute)) == NULL)
+ {
+ status = STATUS_RESOURCE_DATA_NOT_FOUND;
+ break;
+ }
+
+ if ((PacketContext->DataEndMdl = AllocateNonPagedMdl(packetDataEndBuffer, packetDataEndMdlDataLength)) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ PacketContext->DataEndMdl->Next = NULL;
+
+ if (packetPenultimateMdl != PacketDataStartMdl)
+ {
+ MDL TempMdl = *packetPenultimateMdl;
+ TempMdl.Next = PacketContext->DataEndMdl;
+
+ MbbPacketSaveAndSetMdl(PacketContext, packetPenultimateMdl, &TempMdl);
+ }
+
+ if (PacketContext->DataStartMdl->Next == packetDataEndMdl)
+ {
+ PacketContext->DataStartMdl->Next = PacketContext->DataEndMdl;
+ }
+ }
+ //
+ // Allocate padding, if needed. The padding buffer is a share buffer.
+ // Every padding MDL points to this same buffer. The buffer contains
+ // all 0s.
+ //
+ if (PaddingLength != 0)
+ {
+ if ((PacketContext->PaddingMdl = AllocateNonPagedMdl(PaddingBuffer, PaddingLength)) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ PacketContext->PaddingMdl->Next = PacketContext->DataStartMdl;
+ }
+ } while (FALSE);
+
+ return status;
+}
+
+VOID MbbNtbChainNb(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext, _In_ PMBB_PACKET_CONTEXT PacketContext)
+{
+ if (NtbContext->DatagramLastMdl != NULL)
+ {
+ NtbContext->DatagramLastMdl->Next = MbbPacketGetFirstMdl(PacketContext);
+ }
+ else
+ {
+ NtbContext->NthMdl->Next = MbbPacketGetFirstMdl(PacketContext);
+ }
+
+ NtbContext->DatagramLastMdl = MbbPacketGetLastMdl(PacketContext);
+}
+
+NTSTATUS
+MbbNtbAddPacket(
+ _In_ PMBB_NTB_BUILD_CONTEXT NtbContext,
+ _In_ PVOID PacketContext,
+ _In_ ULONG DatagramLength,
+ _In_ PMDL PacketDataStartMdl,
+ _In_ ULONG PacketDataStartMdlDataOffset,
+ _In_ MBB_NDP_TYPE CurrentNdpType,
+ _In_ ULONG SessionId)
+{
+ ULONG datagramOffset;
+ ULONG paddingLength;
+ ULONG ndpSize;
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG totalLength;
+ PMBB_PACKET_CONTEXT packetContext = NULL;
+
+ do
+ {
+ if ((NtbContext->DatagramCount + 1) > NtbContext->NtbOutMaxDatagrams)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ //
+ // Size of passed in NET_BUFFER, to be updated later in the NDP Context.
+ //
+ totalLength = NtbContext->NtbHeaderSize + NtbContext->DatagramLength;
+ paddingLength = ALIGN_AT_OFFSET(totalLength, NtbContext->NdpOutDivisor, NtbContext->NdpOutPayloadRemainder) - totalLength;
+ //
+ // Calculate the new NTB size based on the passed in MBB_PACKET
+ //
+
+ //
+ // Fixed size NTH & DatagramSize along with Padding for all NDPs
+ //
+ datagramOffset = totalLength + paddingLength;
+ totalLength += DatagramLength + paddingLength;
+
+ //
+ // Calculate NDP HeaderSize for all NDPs
+ //
+ ndpSize = totalLength;
+ totalLength = ALIGN(totalLength, NtbContext->NdpOutAlignment);
+ totalLength += NtbContext->NdpHeaderFixedSize;
+ totalLength += ((NtbContext->DatagramCount + 1) * NtbContext->NdpDatagramEntrySize);
+ ndpSize = totalLength - ndpSize;
+ //
+ // Can everything fit?
+ //
+ if (totalLength > NtbContext->NtbOutMaxSize)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+ packetContext = &NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].NetPacketContext;
+ if (!NT_SUCCESS(
+ status = MbbFillPacketContext(
+ packetContext, PacketDataStartMdl, PacketDataStartMdlDataOffset, DatagramLength, NtbContext->PaddingBuffer, paddingLength)))
+ {
+ break;
+ }
+ //
+ // Update the NTB Context for the new NET_BUFFER.
+ //
+ NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].DatagramOffset = datagramOffset;
+ NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].DatagramLength = DatagramLength;
+ NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].NdpType = CurrentNdpType;
+ NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].SessionId = SessionId;
+ if (CurrentNdpType == MbbNdpTypeIps)
+ {
+ NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].NetPacket = (NET_PACKET*)PacketContext;
+ }
+ else if (CurrentNdpType == MbbNdpTypeVendor_1)
+ {
+ NtbContext->NdpDatagramEntries[NtbContext->DatagramCount].DssPacket = (PDSS_PACKET)PacketContext;
+ }
+
+ NtbContext->NdpSize = ndpSize;
+ NtbContext->DatagramCount += 1;
+ NtbContext->DatagramLength += (DatagramLength + paddingLength);
+
+ MbbNtbChainNb(NtbContext, packetContext);
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ if (packetContext != NULL)
+ {
+ MbbPacketCleanupContext(packetContext);
+ }
+ }
+ return status;
+}
+
+FORCEINLINE
+PMDL MbbNtbGetMdlChainHead(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext)
+{
+ return NtbContext->NthMdl;
+}
+
+VOID MbbSendQCompleteNtb(_In_ MBB_PROTOCOL_HANDLE ProtocolHandle, _In_ MBB_REQUEST_HANDLE RequestHandle, _In_ NTSTATUS NtStatus, _In_ PMDL Mdl)
+{
+ UNREFERENCED_PARAMETER(ProtocolHandle);
+ PMBB_NTB_BUILD_CONTEXT ntbContext = (PMBB_NTB_BUILD_CONTEXT)RequestHandle;
+ PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetNetAdapterContext(ntbContext->NetAdapter)->WmbDeviceContext;
+ UNREFERENCED_PARAMETER(Mdl);
+
+ if (!NT_SUCCESS(NtStatus))
+ {
+ if (NtStatus == STATUS_NDIS_ADAPTER_NOT_READY)
+ {
+ }
+ else if (NtStatus == STATUS_CANCELLED)
+ {
+ }
+ else if (NtStatus == STATUS_NO_SUCH_DEVICE)
+ {
+ }
+ else
+ {
+ MbbBusResetDataPipes(deviceContext->BusHandle);
+ }
+ }
+
+ MbbNtbCleanupContext(ntbContext, NtStatus);
+}
+
+ULONG
+MbbNtbMapNdpTypeToSignature(_In_ MBB_NDP_TYPE MbbNdpType, _In_ BOOLEAN Is32Bit, _In_ ULONG SessionId)
+{
+ ULONG SessionMask = (SessionId << NCM_NDP_SESSION_SHIFT);
+
+ switch (MbbNdpType)
+ {
+ case MbbNdpTypeIps: return ((Is32Bit == TRUE) ? NCM_NDP32_IPS | SessionMask : NCM_NDP16_IPS | SessionMask);
+ default:
+ if ((MbbNdpType >= MbbNdpTypeVendor_1) && (MbbNdpType <= MbbNdpTypeVendor_Max))
+ {
+ return ((Is32Bit == TRUE) ? NCM_NDP32_VENDOR | SessionMask : NCM_NDP16_VENDOR | SessionMask);
+ }
+ }
+ return 0;
+}
+
+VOID MbbNtbFillNdp32Header(_In_ PNCM_NDP32 Ndp, _In_ MBB_NDP_TYPE NdpType, _In_ PMBB_NTB_BUILD_CONTEXT NtbContext)
+{
+ ULONG datagramIndex = 0;
+ ULONG ndpDatagramIndex = 0;
+ PNCM_NDP32_DATAGRAM ndpDatagramEntries;
+
+ Ndp->dwSignature = MbbNtbMapNdpTypeToSignature(NdpType, TRUE, NtbContext->NdpDatagramEntries[datagramIndex].SessionId);
+ Ndp->dwNextFpIndex = 0;
+ ndpDatagramEntries = Ndp->Datagram;
+ //
+ // Add datagram entries to the NDP Table
+ //
+
+ for (datagramIndex = 0; datagramIndex < NtbContext->DatagramCount; datagramIndex++)
+ {
+ ndpDatagramEntries[ndpDatagramIndex].dwDatagramIndex = NtbContext->NdpDatagramEntries[datagramIndex].DatagramOffset;
+ ndpDatagramEntries[ndpDatagramIndex].dwDatagramLength = NtbContext->NdpDatagramEntries[datagramIndex].DatagramLength;
+ ndpDatagramIndex++;
+ }
+ //
+ // Terminating entry is taken in to account
+ // in the fixed size NDP Header.
+ //
+ ndpDatagramEntries[ndpDatagramIndex].dwDatagramIndex = 0;
+ ndpDatagramEntries[ndpDatagramIndex].dwDatagramLength = 0;
+
+ Ndp->wLength = (USHORT)(NtbContext->NdpHeaderFixedSize + (ndpDatagramIndex * NtbContext->NdpDatagramEntrySize));
+}
+
+VOID MbbNtbFillNdp16Header(__in PNCM_NDP16 Ndp, __in MBB_NDP_TYPE NdpType, __in PMBB_NTB_BUILD_CONTEXT NtbContext)
+{
+ ULONG datagramIndex = 0;
+ ULONG ndpDatagramIndex = 0;
+ PNCM_NDP16_DATAGRAM ndpDatagramEntries;
+
+ Ndp->dwSignature = MbbNtbMapNdpTypeToSignature(NdpType, FALSE, NtbContext->NdpDatagramEntries[datagramIndex].SessionId);
+
+ Ndp->wNextFpIndex = 0;
+ ndpDatagramEntries = Ndp->Datagram;
+ //
+ // Add datagram entries to the NDP Table
+ //
+ for (datagramIndex = 0; datagramIndex < NtbContext->DatagramCount; datagramIndex++)
+ {
+ ndpDatagramEntries[ndpDatagramIndex].wDatagramIndex = (USHORT)NtbContext->NdpDatagramEntries[datagramIndex].DatagramOffset;
+ ndpDatagramEntries[ndpDatagramIndex].wDatagramLength = (USHORT)NtbContext->NdpDatagramEntries[datagramIndex].DatagramLength;
+ ndpDatagramIndex++;
+ }
+ //
+ // Terminating entry is taken in to account
+ // in the fixed size NDP Header.
+ //
+ ndpDatagramEntries[ndpDatagramIndex].wDatagramIndex = 0;
+ ndpDatagramEntries[ndpDatagramIndex].wDatagramLength = 0;
+
+ Ndp->wLength = (USHORT)(NtbContext->NdpHeaderFixedSize + (ndpDatagramIndex * NtbContext->NdpDatagramEntrySize));
+}
+
+NTSTATUS
+MbbNtbAddNdpHeaders(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext)
+{
+ // Offset from the start of the NTB buffer to the start of NDP headers
+ ULONG ndpStartOffset;
+ // Offset from the start of the NTB Buffer to the current position.
+ ULONG ntbOffset;
+ PCHAR ndpBuffer;
+ MBB_NDP_TYPE ndpType;
+ PNCM_NDP16 ndp16;
+ PNCM_NDP32 ndp32;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ do
+ {
+ //
+ // Allocate buffer for all NDP headers.
+ // This includes padding for NDP Header alignment.
+ //
+ status = CreateNonPagedWdfMemory(
+ NtbContext->NdpSize,
+ &NtbContext->NdpBufferMemory,
+ &NtbContext->NdpBuffer,
+ NtbContext->NetTxQueue == NULL ? (WDFOBJECT)NtbContext->NetAdapter : NtbContext->NetTxQueue,
+ MbbPoolTagNtbSend);
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+ RtlZeroMemory(NtbContext->NdpBuffer, NtbContext->NdpSize);
+ ndpBuffer = (PCHAR)(NtbContext->NdpBuffer);
+ //
+ // Chain the NDP Header through its MDL to datagram MDL
+ //
+ if ((NtbContext->NdpMdl = AllocateNonPagedMdl(NtbContext->NdpBuffer, NtbContext->NdpSize)) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ NtbContext->DatagramLastMdl->Next = NtbContext->NdpMdl;
+ ndpStartOffset = NtbContext->NtbHeaderSize + NtbContext->DatagramLength;
+
+ if (NtbContext->IsNtb32Bit)
+ NtbContext->Nth32.dwFpIndex = ALIGN(ndpStartOffset, NtbContext->NdpOutAlignment);
+ else
+ NtbContext->Nth16.wFpIndex = (USHORT)ALIGN(ndpStartOffset, NtbContext->NdpOutAlignment);
+
+ ntbOffset = ALIGN(ndpStartOffset, NtbContext->NdpOutAlignment);
+ ndpType = NtbContext->NdpDatagramEntries[0].NdpType;
+
+ if (NtbContext->IsNtb32Bit == TRUE)
+ {
+ ndp32 = (PNCM_NDP32)(ndpBuffer + (ntbOffset - ndpStartOffset));
+
+ MbbNtbFillNdp32Header(ndp32, ndpType, NtbContext);
+ }
+ else
+ {
+ ndp16 = (PNCM_NDP16)(ndpBuffer + (ntbOffset - ndpStartOffset));
+
+ MbbNtbFillNdp16Header(ndp16, ndpType, NtbContext);
+ }
+
+ if (NtbContext->IsNtb32Bit == TRUE)
+ {
+ NtbContext->Nth32.dwBlockLength = NtbContext->NtbHeaderSize;
+ NtbContext->Nth32.dwBlockLength += NtbContext->DatagramLength;
+ NtbContext->Nth32.dwBlockLength += NtbContext->NdpSize;
+ }
+ else
+ {
+ NtbContext->Nth16.wBlockLength = (USHORT)(NtbContext->NtbHeaderSize);
+ NtbContext->Nth16.wBlockLength += (USHORT)(NtbContext->DatagramLength);
+ NtbContext->Nth16.wBlockLength += (USHORT)(NtbContext->NdpSize);
+ }
+ } while (FALSE);
+ //
+ // No cleanup. Cleanup done by caller.
+ //
+ return status;
+}
+
+NTSTATUS
+MbbTestValidateNtb(_In_ PMBB_NTB_BUILD_CONTEXT NtbContext, _In_reads_bytes_(ScratchLength) PCHAR ScratchBuffer, _In_ ULONG ScratchLength)
+{
+ PMDL currentMdl;
+ ULONGLONG ntbLength;
+ ULONG mdlLength;
+ PVOID mdlVa;
+ PVOID nth;
+
+ nth = ScratchBuffer;
+ ntbLength = 0;
+
+ for (currentMdl = MbbNtbGetMdlChainHead(NtbContext); currentMdl != NULL; currentMdl = currentMdl->Next)
+ {
+ mdlLength = MmGetMdlByteCount(currentMdl);
+
+ if ((mdlVa = MmGetSystemAddressForMdlSafe(currentMdl, NormalPagePriority | MdlMappingNoExecute)) == NULL)
+ {
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ }
+
+ if ((ntbLength + mdlLength) > ScratchLength)
+ {
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ RtlCopyMemory(ScratchBuffer, mdlVa, mdlLength);
+
+ ScratchBuffer += mdlLength;
+ ntbLength += mdlLength;
+ }
+
+ return MbbNtbValidate(nth, (ULONG)ntbLength, NtbContext->IsNtb32Bit, NULL);
+}
+
+void EvtTxQueueDestroy(_In_ WDFOBJECT TxQueue)
+{
+ PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue);
+
+ txQueueContext->NetAdapterContext->TxQueue = NULL;
+}
+
+VOID EvtTxQueueSetNotificationEnabled(_In_ NETPACKETQUEUE TxQueue, _In_ BOOLEAN NotificationEnabled)
+{
+ PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue);
+
+ InterlockedExchange(&txQueueContext->NotificationEnabled, NotificationEnabled);
+}
+
+void EvtTxQueueCancel(_In_ NETPACKETQUEUE TxQueue)
+{
+ NET_RING_COLLECTION const* rings = MbbGetTxQueueContext(TxQueue)->DatapathDescriptor;
+
+ NET_RING * pr = NetRingCollectionGetPacketRing(rings);
+ while (pr->BeginIndex != pr->EndIndex)
+ {
+ UINT32 const packetIndex = pr->BeginIndex;
+ NetRingGetPacketAtIndex(pr, packetIndex)->Scratch = 1;
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+ }
+}
+
+bool MbbEnableTxBatching(_In_ NET_RING_COLLECTION const* Rings)
+{
+ NET_RING * ring = Rings->Rings[NetRingTypeFragment];
+ return ((ring->EndIndex - ring->BeginIndex) & ring->ElementIndexMask) > (NetRingCollectionGetPacketRing(Rings)->NumberOfElements / 2);
+}
+
+inline
+VOID
+CompleteTxPacketsBatch(
+ _In_ NET_RING_COLLECTION const * Rings,
+ _In_ UINT32 BatchSize
+)
+{
+ UINT32 packetCount = 0;
+
+ NET_RING * pr = NetRingCollectionGetPacketRing(Rings);
+
+ while (pr->BeginIndex != pr->EndIndex)
+ {
+ UINT32 const packetIndex = pr->BeginIndex;
+ auto packet = NetRingGetPacketAtIndex(pr, packetIndex);
+
+ // this function uses Scratch field as the bit for testing completion
+ if (!packet->Scratch)
+ {
+ break;
+ }
+
+ packetCount++;
+
+ NET_RING * fr = NetRingCollectionGetFragmentRing(Rings);
+ fr->BeginIndex = fr->EndIndex;
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+
+ if (packetCount >= BatchSize)
+ {
+ Rings->Rings[NetRingTypeFragment]->BeginIndex = fr->BeginIndex;
+ }
+ }
+}
+
+void EvtTxQueueAdvance(_In_ NETPACKETQUEUE TxQueue)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PMBB_TXQUEUE_CONTEXT txQueueContext = MbbGetTxQueueContext(TxQueue);
+ NET_RING_COLLECTION const* rings = txQueueContext->DatapathDescriptor;
+ PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = txQueueContext->NetAdapterContext;
+ PWMBCLASS_DEVICE_CONTEXT deviceContext = netAdapterContext->WmbDeviceContext;
+ PMBB_NTB_BUILD_CONTEXT ntbContext = NULL;
+ ULONG sessionId = netAdapterContext->SessionId;
+ ULONG batchSize = MbbEnableTxBatching(rings) ? txQueueContext->CompletionBatchSize : 1;
+
+ NET_RING * pr = NetRingCollectionGetPacketRing(rings);
+ while (pr->BeginIndex != pr->EndIndex)
+ {
+ UINT32 packetIndex = pr->BeginIndex;
+ auto packet = NetRingGetPacketAtIndex(pr, packetIndex);
+ if (packet->Ignore)
+ {
+ packet->Scratch = 1;
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+ continue;
+ }
+
+ ntbContext = MbbNtbAllocateContext(
+ netAdapterContext->NtbLookasideList, &deviceContext->BusParams, deviceContext->sharedPaddingBuffer, MbbSendQGetNtbSequence(deviceContext));
+
+ if (ntbContext == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ ntbContext->NetTxQueue = TxQueue;
+ ntbContext->NetAdapter = netAdapterContext->NetAdapter;
+ ntbContext->NetDatapathDescriptor = rings;
+
+ auto fr = NetRingCollectionGetFragmentRing(rings);
+ while (NT_SUCCESS(
+ status = MbbNtbAddPacket(
+ ntbContext,
+ packet,
+ MbbGetNetPacketDataLength(packet, rings),
+ NetExtensionGetFragmentMdl(&txQueueContext->MdlExtension, packet->FragmentIndex)->Mdl,
+ NetRingGetFragmentAtIndex(fr, packet->FragmentIndex)->Offset,
+ MbbNdpTypeIps,
+ sessionId)))
+ {
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+
+ // the ring buffer has no more net packets to send,
+ // so packing is done. break now to make USB request
+ if (pr->BeginIndex == pr->EndIndex)
+ {
+ break;
+ }
+
+ packetIndex = pr->BeginIndex;
+ packet = NetRingGetPacketAtIndex(pr, packetIndex);
+ }
+
+ if (status == STATUS_BUFFER_OVERFLOW)
+ {
+ //
+ // If the NTB was empty and this packet couldnt be added
+ // then ignore this packet to prevent retrying forever.
+ // Or send this NTB to bus then start a new NTB
+ //
+ if (ntbContext->DatagramCount == 0)
+ {
+ packet->Scratch = 1;
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+ }
+ }
+ else if (status != STATUS_SUCCESS)
+ {
+ //
+ // MbbNtbAddPacket failed, we should ignore this packet, or the loop may never complete
+ //
+ packet->Scratch = 1;
+ pr->BeginIndex = NetRingIncrementIndex(pr, pr->BeginIndex);
+ }
+
+ if (ntbContext->DatagramCount > 0)
+ {
+ status = MbbNtbAddNdpHeaders(ntbContext);
+ if (!NT_SUCCESS(status))
+ {
+ }
+ else
+ {
+#if DBG
+ if (!NT_SUCCESS(MbbTestValidateNtb(ntbContext, ntbContext->ScratchBuffer, ntbContext->ScratchLength)))
+ {
+ ASSERT(FALSE);
+ }
+#endif
+ //
+ // Send the data. On failure, cleanup.
+ //
+ status = MbbBusWriteData(deviceContext->BusHandle, ntbContext, MbbNtbGetMdlChainHead(ntbContext), MbbSendQCompleteNtb);
+ if (!NT_SUCCESS(status))
+ {
+ }
+ }
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ MbbSendQCompleteNtb(netAdapterContext, ntbContext, status, MbbNtbGetMdlChainHead(ntbContext));
+ }
+ }
+
+ CompleteTxPacketsBatch(rings, batchSize);
+}
+
+PDSS_PACKET MbbAllocateDssPacket(_In_ WDFMEMORY Data, _In_ PVOID DataBuffer, _In_ size_t DataSize)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PDSS_PACKET packet = NULL;
+ do
+ {
+// By Design: Allocate packet from NtbSend Pool, released in function MbbNtbCleanupContext called from MbbSendQCompleteNtb.
+#pragma prefast(suppress : __WARNING_MEMORY_LEAK, "Released in function MbbNtbCleanupContext")
+ packet = (PDSS_PACKET)ALLOCATE_NONPAGED_POOL_WITH_TAG(sizeof(DSS_PACKET), MbbPoolTagNtbSend);
+ if (packet == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ RtlZeroMemory(packet, sizeof(DSS_PACKET));
+
+ packet->Data = Data;
+ packet->Mdl = AllocateNonPagedMdl(DataBuffer, (ULONG)DataSize);
+
+ if (packet->Mdl == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ if (packet != NULL)
+ {
+ MbbCleanupDssPacket(packet);
+ packet = NULL;
+ }
+ }
+
+ return packet;
+}
+
+_Use_decl_annotations_ VOID EvtMbbDeviceSendDeviceServiceSessionData(WDFDEVICE Device, DSS_SESSION_ID SessionId, WDFMEMORY Data)
+{
+ PWMBCLASS_DEVICE_CONTEXT deviceContext = WmbClassGetDeviceContext(Device);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PWMBCLASS_NETADAPTER_CONTEXT netAdapterContext = deviceContext->Sessions[MBB_DEFAULT_SESSION_ID].NetAdapterContext;
+
+ PMBB_NTB_BUILD_CONTEXT ntbContext = NULL;
+ PDSS_PACKET packet = NULL;
+ BOOLEAN completeNow = TRUE;
+
+ do
+ {
+ ntbContext = MbbNtbAllocateContext(
+ netAdapterContext->NtbLookasideList, &deviceContext->BusParams, deviceContext->sharedPaddingBuffer, MbbSendQGetNtbSequence(deviceContext));
+
+ if (ntbContext == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ ntbContext->NetTxQueue = NULL;
+ ntbContext->NetAdapter = netAdapterContext->NetAdapter;
+ size_t bufferSize = 0;
+ PVOID buffer = WdfMemoryGetBuffer(Data, &bufferSize);
+
+ packet = MbbAllocateDssPacket(Data, buffer, bufferSize);
+ if (packet == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ status = MbbNtbAddPacket(ntbContext, packet, (ULONG)bufferSize, packet->Mdl, 0, MbbNdpTypeVendor_1, SessionId);
+ if (!NT_SUCCESS(status))
+ {
+ MbbCleanupDssPacket(packet);
+ break;
+ }
+
+ completeNow = FALSE;
+
+ status = MbbNtbAddNdpHeaders(ntbContext);
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+#if DBG
+ if (!NT_SUCCESS(MbbTestValidateNtb(ntbContext, ntbContext->ScratchBuffer, ntbContext->ScratchLength)))
+ {
+ ASSERT(FALSE);
+ }
+#endif
+
+ //
+ // Send the data. On failure, cleanup. It will return STATUS_PENDING when success
+ //
+ status = MbbBusWriteData(deviceContext->BusHandle, ntbContext, MbbNtbGetMdlChainHead(ntbContext), MbbSendQCompleteNtb);
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+ deviceContext->DSSPacketsSentCount++;
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ if (ntbContext != NULL)
+ {
+ MbbSendQCompleteNtb(deviceContext, ntbContext, status, MbbNtbGetMdlChainHead(ntbContext));
+ }
+ if (completeNow)
+ {
+ MbbDeviceSendDeviceServiceSessionDataComplete(Data, status);
+ }
+ }
+}