summaryrefslogtreecommitdiff
path: root/windows/TapDriver6/rxpath.c
diff options
context:
space:
mode:
authorGrant Limberg <glimberg@gmail.com>2015-04-25 18:59:52 -0700
committerGrant Limberg <glimberg@gmail.com>2015-04-25 18:59:52 -0700
commitec45aeb42aa644b71654b0467c4aebc80e896420 (patch)
treee7d544030dfc9e279007a8455a12206e895446eb /windows/TapDriver6/rxpath.c
parenta86a0ab2b13ae19d99f4667666a25b337e0b93f1 (diff)
parent7af1f3a79ab8928a3b49bac458ee87368c46edc5 (diff)
downloadinfinitytier-ec45aeb42aa644b71654b0467c4aebc80e896420.tar.gz
infinitytier-ec45aeb42aa644b71654b0467c4aebc80e896420.zip
Merge branch 'adamierymenko-dev' into android-jni
Diffstat (limited to 'windows/TapDriver6/rxpath.c')
-rw-r--r--windows/TapDriver6/rxpath.c669
1 files changed, 669 insertions, 0 deletions
diff --git a/windows/TapDriver6/rxpath.c b/windows/TapDriver6/rxpath.c
new file mode 100644
index 00000000..318bc56a
--- /dev/null
+++ b/windows/TapDriver6/rxpath.c
@@ -0,0 +1,669 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+//======================================================================
+// TAP Receive Path Support
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceWrite)
+#endif // ALLOC_PRAGMA
+
+//===============================================================
+// Used in cases where internally generated packets such as
+// ARP or DHCP replies must be returned to the kernel, to be
+// seen as an incoming packet "arriving" on the interface.
+//===============================================================
+
+VOID
+IndicateReceivePacket(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PUCHAR packetData,
+ __in const unsigned int packetLength
+ )
+{
+ PUCHAR injectBuffer;
+
+ //
+ // Handle miniport Pause
+ // ---------------------
+ // NDIS 6 miniports implement a temporary "Pause" state normally followed
+ // by the Restart. While in the Pause state it is forbidden for the miniport
+ // to indicate receive NBLs.
+ //
+ // That is: The device interface may be "up", but the NDIS miniport send/receive
+ // interface may be temporarily "down".
+ //
+ // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path
+ // the code below will simply ignore inject packets passed to the driver while
+ // the miniport is in the Paused state.
+ //
+ // The correct implementation is to go ahead and build the NBLs corresponding
+ // to the inject packet - but queue them. When Restart is entered the
+ // queued NBLs would be dequeued and indicated to the host.
+ //
+ if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+
+ return;
+ }
+
+ // Allocate flat buffer for packet data.
+ injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority(
+ Adapter->MiniportAdapterHandle,
+ packetLength,
+ TAP_RX_INJECT_BUFFER_TAG,
+ NormalPoolPriority
+ );
+
+ if( injectBuffer)
+ {
+ PMDL mdl;
+
+ // Copy packet data to flat buffer.
+ NdisMoveMemory (injectBuffer, packetData, packetLength);
+
+ // Allocate MDL for flat buffer.
+ mdl = NdisAllocateMdl(
+ Adapter->MiniportAdapterHandle,
+ injectBuffer,
+ packetLength
+ );
+
+ if( mdl )
+ {
+ PNET_BUFFER_LIST netBufferList;
+
+ mdl->Next = NULL; // No next MDL
+
+ // Allocate the NBL and NB. Link MDL chain to NB.
+ netBufferList = NdisAllocateNetBufferAndNetBufferList(
+ Adapter->ReceiveNblPool,
+ 0, // ContextSize
+ 0, // ContextBackFill
+ mdl, // MDL chain
+ 0,
+ packetLength
+ );
+
+ if(netBufferList != NULL)
+ {
+ ULONG receiveFlags = 0;
+ LONG nblCount;
+
+ NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+ if(KeGetCurrentIrql() == DISPATCH_LEVEL)
+ {
+ receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL;
+ }
+
+ // Set flag indicating that this is an injected packet
+ TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+ TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED);
+
+ netBufferList->MiniportReserved[0] = NULL;
+ netBufferList->MiniportReserved[1] = NULL;
+
+ // Increment in-flight receive NBL count.
+ nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+
+ netBufferList->SourceHandle = Adapter->MiniportAdapterHandle;
+
+ //
+ // Indicate the packet
+ // -------------------
+ // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+ // contains the complete packet including Ethernet header and payload.
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ Adapter->MiniportAdapterHandle,
+ netBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1, // NumberOfNetBufferLists
+ receiveFlags
+ );
+
+ return;
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+ NOTE_ERROR ();
+
+ NdisFreeMdl(mdl);
+ NdisFreeMemory(injectBuffer,0,0);
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+ NOTE_ERROR ();
+
+ NdisFreeMemory(injectBuffer,0,0);
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+ NOTE_ERROR ();
+ }
+}
+
+VOID
+tapCompleteIrpAndFreeReceiveNetBufferList(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNET_BUFFER_LIST NetBufferList, // Only one NB here...
+ __in NTSTATUS IoCompletionStatus
+ )
+{
+ PIRP irp;
+ ULONG frameType, netBufferCount, byteCount;
+ LONG nblCount;
+
+ // Fetch NB frame type.
+ frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList));
+
+ // Fetch statistics for all NBs linked to the NB.
+ netBufferCount = tapGetNetBufferCountsFromNetBufferList(
+ NetBufferList,
+ &byteCount
+ );
+
+ // Update statistics by frame type
+ if(IoCompletionStatus == STATUS_SUCCESS)
+ {
+ switch(frameType)
+ {
+ case NDIS_PACKET_TYPE_DIRECTED:
+ Adapter->FramesRxDirected += netBufferCount;
+ Adapter->BytesRxDirected += byteCount;
+ break;
+
+ case NDIS_PACKET_TYPE_BROADCAST:
+ Adapter->FramesRxBroadcast += netBufferCount;
+ Adapter->BytesRxBroadcast += byteCount;
+ break;
+
+ case NDIS_PACKET_TYPE_MULTICAST:
+ Adapter->FramesRxMulticast += netBufferCount;
+ Adapter->BytesRxMulticast += byteCount;
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ //
+ // Handle P2P Packet
+ // -----------------
+ // Free MDL allocated for P2P Ethernet header.
+ //
+ if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P))
+ {
+ PNET_BUFFER netBuffer;
+ PMDL mdl;
+
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ mdl = NET_BUFFER_FIRST_MDL(netBuffer);
+ mdl->Next = NULL;
+
+ NdisFreeMdl(mdl);
+ }
+
+ //
+ // Handle Injected Packet
+ // -----------------------
+ // Free MDL and data buffer allocated for injected packet.
+ //
+ if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED))
+ {
+ PNET_BUFFER netBuffer;
+ PMDL mdl;
+ PUCHAR injectBuffer;
+
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ mdl = NET_BUFFER_FIRST_MDL(netBuffer);
+
+ injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority);
+
+ if(injectBuffer)
+ {
+ NdisFreeMemory(injectBuffer,0,0);
+ }
+
+ NdisFreeMdl(mdl);
+ }
+
+ //
+ // Complete the IRP
+ //
+ irp = (PIRP )NetBufferList->MiniportReserved[0];
+
+ if(irp)
+ {
+ irp->IoStatus.Status = IoCompletionStatus;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ }
+
+ // Decrement in-flight receive NBL count.
+ nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount >= 0 );
+ if (0 == nblCount)
+ {
+ NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
+ }
+
+ // Free the NBL
+ NdisFreeNetBufferList(NetBufferList);
+}
+
+VOID
+AdapterReturnNetBufferLists(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNET_BUFFER_LIST NetBufferLists,
+ __in ULONG ReturnFlags
+ )
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ PNET_BUFFER_LIST currentNbl, nextNbl;
+
+ UNREFERENCED_PARAMETER(ReturnFlags);
+
+ //
+ // Process each NBL individually
+ //
+ currentNbl = NetBufferLists;
+ while (currentNbl)
+ {
+ PNET_BUFFER_LIST nextNbl;
+
+ nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+ NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL;
+
+ // Complete write IRP and free NBL and associated resources.
+ tapCompleteIrpAndFreeReceiveNetBufferList(
+ adapter,
+ currentNbl,
+ STATUS_SUCCESS
+ );
+
+ // Move to next NBL
+ currentNbl = nextNbl;
+ }
+}
+
+// IRP_MJ_WRITE callback.
+NTSTATUS
+TapDeviceWrite(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success
+ PIO_STACK_LOCATION irpSp;// Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+ ULONG dataLength;
+
+ PAGED_CODE();
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Fetch adapter context for this device.
+ // --------------------------------------
+ // Adapter pointer was stashed in FsContext when handle was opened.
+ //
+ adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+ ASSERT(adapter);
+
+ //
+ // Sanity checks on state variables
+ //
+ if (!tapAdapterReadAndWriteReady(adapter))
+ {
+ //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
+ // MINIPORT_INSTANCE_ID (adapter)));
+ //NOTE_ERROR();
+
+ Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ // Save IRP-accessible copy of buffer length
+ Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
+
+ if (Irp->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ //
+ // Try to get a virtual address for the MDL.
+ //
+ NdisQueryMdl(
+ Irp->MdlAddress,
+ &Irp->AssociatedIrp.SystemBuffer,
+ &dataLength,
+ NormalPagePriority
+ );
+
+ if (Irp->AssociatedIrp.SystemBuffer == NULL)
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ ASSERT(dataLength == irpSp->Parameters.Write.Length);
+
+ Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
+
+ //
+ // Handle miniport Pause
+ // ---------------------
+ // NDIS 6 miniports implement a temporary "Pause" state normally followed
+ // by the Restart. While in the Pause state it is forbidden for the miniport
+ // to indicate receive NBLs.
+ //
+ // That is: The device interface may be "up", but the NDIS miniport send/receive
+ // interface may be temporarily "down".
+ //
+ // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path
+ // the code below will perform a "lying send" for write IRPs passed to the
+ // driver while the miniport is in the Paused state.
+ //
+ // The correct implementation is to go ahead and build the NBLs corresponding
+ // to the user-mode write - but queue them. When Restart is entered the
+ // queued NBLs would be dequeued and indicated to the host.
+ //
+ if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
+ {
+ if (/*!adapter->m_tun &&*/ ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+ {
+ PNET_BUFFER_LIST netBufferList;
+
+ DUMP_PACKET ("IRP_MJ_WRITE ETH",
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify (
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length,
+ FALSE,
+ "RX",
+ &adapter->m_RxTrunc
+ );
+#endif
+ (Irp->MdlAddress)->Next = NULL; // No next MDL
+
+ // Allocate the NBL and NB. Link MDL chain to NB.
+ netBufferList = NdisAllocateNetBufferAndNetBufferList(
+ adapter->ReceiveNblPool,
+ 0, // ContextSize
+ 0, // ContextBackFill
+ Irp->MdlAddress, // MDL chain
+ 0,
+ dataLength
+ );
+
+ if(netBufferList != NULL)
+ {
+ LONG nblCount;
+
+ NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+ // Stash IRP pointer in NBL MiniportReserved[0] field.
+ netBufferList->MiniportReserved[0] = Irp;
+ netBufferList->MiniportReserved[1] = NULL;
+
+ // This IRP is pended.
+ IoMarkIrpPending(Irp);
+
+ // This IRP cannot be cancelled while in-flight.
+ IoSetCancelRoutine(Irp,NULL);
+
+ TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+
+ // Increment in-flight receive NBL count.
+ nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+
+ //
+ // Indicate the packet
+ // -------------------
+ // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+ // contains the complete packet including Ethernet header and payload.
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ adapter->MiniportAdapterHandle,
+ netBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1, // NumberOfNetBufferLists
+ 0 // ReceiveFlags
+ );
+
+ ntStatus = STATUS_PENDING;
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+ NOTE_ERROR ();
+
+ // Fail the IRP
+ Irp->IoStatus.Information = 0;
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ /*
+ else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+ {
+ PETH_HEADER p_UserToTap = &adapter->m_UserToTap;
+ PMDL mdl; // Head of MDL chain.
+
+ // For IPv6, need to use Ethernet header with IPv6 proto
+ if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 )
+ {
+ p_UserToTap = &adapter->m_UserToTap_IPv6;
+ }
+
+ DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
+ p_UserToTap,
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify (
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length,
+ TRUE,
+ "RX",
+ &adapter->m_RxTrunc
+ );
+#endif
+
+ //
+ // Allocate MDL for Ethernet header
+ // --------------------------------
+ // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+ // contains the only the Ethernet payload. Prepend the user-mode provided
+ // payload with the Ethernet header pointed to by p_UserToTap.
+ //
+ mdl = NdisAllocateMdl(
+ adapter->MiniportAdapterHandle,
+ p_UserToTap,
+ sizeof(ETH_HEADER)
+ );
+
+ if(mdl != NULL)
+ {
+ PNET_BUFFER_LIST netBufferList;
+
+ // Chain user's Ethernet payload behind Ethernet header.
+ mdl->Next = Irp->MdlAddress;
+ (Irp->MdlAddress)->Next = NULL; // No next MDL
+
+ // Allocate the NBL and NB. Link MDL chain to NB.
+ netBufferList = NdisAllocateNetBufferAndNetBufferList(
+ adapter->ReceiveNblPool,
+ 0, // ContextSize
+ 0, // ContextBackFill
+ mdl, // MDL chain
+ 0,
+ sizeof(ETH_HEADER) + dataLength
+ );
+
+ if(netBufferList != NULL)
+ {
+ LONG nblCount;
+
+ NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+ // This IRP is pended.
+ IoMarkIrpPending(Irp);
+
+ // This IRP cannot be cancelled while in-flight.
+ IoSetCancelRoutine(Irp,NULL);
+
+ // Stash IRP pointer in NBL MiniportReserved[0] field.
+ netBufferList->MiniportReserved[0] = Irp;
+ netBufferList->MiniportReserved[1] = NULL;
+
+ // Set flag indicating that this is P2P packet
+ TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+ TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P);
+
+ // Increment in-flight receive NBL count.
+ nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+
+ //
+ // Indicate the packet
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ adapter->MiniportAdapterHandle,
+ netBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1, // NumberOfNetBufferLists
+ 0 // ReceiveFlags
+ );
+
+ ntStatus = STATUS_PENDING;
+ }
+ else
+ {
+ mdl->Next = NULL;
+ NdisFreeMdl(mdl);
+
+ DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+ NOTE_ERROR ();
+
+ // Fail the IRP
+ Irp->IoStatus.Information = 0;
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+ NOTE_ERROR ();
+
+ // Fail the IRP
+ Irp->IoStatus.Information = 0;
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ */
+ else
+ {
+ DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
+ MINIPORT_INSTANCE_ID (adapter),
+ irpSp->Parameters.Write.Length));
+ NOTE_ERROR ();
+
+ Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE;
+ Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ ntStatus = STATUS_SUCCESS;
+ }
+
+ if (ntStatus != STATUS_PENDING)
+ {
+ Irp->IoStatus.Status = ntStatus;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ return ntStatus;
+}
+