You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
669 lines
22 KiB
669 lines
22 KiB
/* |
|
* 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; |
|
} |
|
|
|
|