📄 read.c
字号:
/*++
Copyright (c) 1990-2000 Microsoft Corporation
Module Name:
Read.c
Abstract:
Author:
Environment:
Kernel mode only.
Notes:
Future:
Revision History:
Updated for Windows 2000 - Eliyas Yakub June, 1999
--*/
#include "ntddk.h"
#include "ndis.h"
#include "packet.h"
NTSTATUS
PacketRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the dispatch routine for read requests.
本例程负责处理数据读取;
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
NT status code.
--*/
{
POPEN_INSTANCE open;
PNDIS_PACKET pPacket;
NDIS_STATUS status;
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpSp;
PLIST_ENTRY packetListEntry;
PPACKET_RESERVED reserved;
UINT TotalLength = 0;
UINT RemainingSpace;
PNDIS_BUFFER pBuffer;
PNDIS_BUFFER pFirstBuffer;
PVOID VirtualAddress;
UINT Length;
PVOID MdlBaseVirtualAddress;
PVOID CurrentAddress;
DebugPrint(("Read\n"));
open = DeviceObject->DeviceExtension;
//
// Check to see whether you are still bound to the adapter
//确认当前驱动与目标适配器处于绑定状态;
//
IoIncrement(open);
if (!open->Bound) {
ntStatus = STATUS_DEVICE_NOT_READY;
goto ERROR;
}
irpSp = IoGetCurrentIrpStackLocation(Irp);
//
// See if the buffer is at least big enough to hold the
// ethernet header and calculate the RemainingSpace according to it.
//
if (irpSp->Parameters.Read.Length < ETHERNET_HEADER_LENGTH) {
ntStatus = STATUS_BUFFER_TOO_SMALL;
goto ERROR;
}
//
// Retrieve the information about the total space provided by the client application
// from I/O stack location in this given IRP .
//
RemainingSpace = irpSp->Parameters.Read.Length;
//
// Get the base virtual address of Mdl and initialize CurrentAddress for the copy request.
//
MdlBaseVirtualAddress = MmGetMdlVirtualAddress(Irp->MdlAddress);
CurrentAddress = MdlBaseVirtualAddress;
//send a packet to the crueent irp---if there is packet buffered(LFY)
//
// Fetch the packet in RcvPackQ.
//
packetListEntry = ExInterlockedRemoveHeadList(
&open->RcvPackQList,
&open->RcvPackQSpinLock
);
if (packetListEntry != NULL) {
do {
reserved = CONTAINING_RECORD(packetListEntry, PACKET_RESERVED, RcvPackQListElement);
pPacket = CONTAINING_RECORD(reserved, NDIS_PACKET, ProtocolReserved);
NdisQueryPacket(pPacket, NULL, NULL, &pFirstBuffer, NULL);
NdisQueryBuffer(pFirstBuffer, &VirtualAddress, &Length);
//
// Move the ethernet header to the front.
// Note: we have placed the ethernet header at the end of each packet when we received them from NIC.
//
NdisMoveMemory(
CurrentAddress,
(PUCHAR)VirtualAddress + Length - ETHERNET_HEADER_LENGTH,
ETHERNET_HEADER_LENGTH
);
NdisMoveMemory(
(PUCHAR)CurrentAddress + ETHERNET_HEADER_LENGTH,
VirtualAddress,
Length - ETHERNET_HEADER_LENGTH
);
//
// Update the pointer and the counters.
//
CurrentAddress = (PUCHAR)CurrentAddress + Length;
RemainingSpace -= Length;
TotalLength += Length;
//
// Free pPacket for future use.
//
NdisFreeMemory(VirtualAddress, Length, 0);
NdisFreeBuffer(pFirstBuffer);
NdisFreePacket(pPacket);
if( RemainingSpace > 0) {
packetListEntry = ExInterlockedRemoveHeadList(
&open->RcvPackQList,
&open->RcvPackQSpinLock
);
}
} while (packetListEntry != NULL && RemainingSpace > 0);
}
else{
//
// Try to get a packet from our list of free ones.
// 从数据包池中获取一个数据报描述符,用于构造一个数据包,
// 该数据包被放入一个队列,等待低层到来数据时往里填写;
//
NdisAllocatePacket(
&status,
&pPacket,
open->PacketPool
);
if (status != NDIS_STATUS_SUCCESS) {
DebugPrint(("Packet: Read- No free packets\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto ERROR;
}
//
// Get a pointer to the packet itself.
//
RESERVED(pPacket)->Irp=Irp;
RESERVED(pPacket)->pMdl=NULL;
IoMarkIrpPending(Irp);
//
// Set the cancel routine so that we can cancel the requests
// pending in the queue if the application terminates.
//
IoSetCancelRoutine(Irp, PacketCancelRoutine);
//
// Put this packet in a list of pending reads.
// The PacketReceiveIndicate or PacketReceivePacket handler will
// attempt to remove packets from this list.
//
ExInterlockedInsertTailList(
&open->RcvList,
&RESERVED(pPacket)->ListElement,
&open->RcvQSpinLock);
return STATUS_PENDING;
}
ntStatus = (TotalLength != 0) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
Irp->IoStatus.Status = ntStatus;
ERROR:
//
// On successful completion of a transfer request, this is set to the number of bytes transferred.
// If a transfer request is completed with another STATUS_XXX, this member is set to zero.
//
Irp->IoStatus.Information = (ntStatus == STATUS_SUCCESS) ? TotalLength : 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
IoDecrement(open);
return ntStatus;
}
NDIS_STATUS
PacketReceiveIndicate (
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookaheadBufferSize,
IN UINT PacketSize
)
/*++
Routine Description:
PacketReceiveIndicate is called with a pointer to a
lookaheadbuffer. If this buffer contains less than
the full, received network packet, it
calls NdisTransferData with a protocol-allocated packet
descriptor specifying protocol-allocated buffer(s) to obtain
the remainder of the received packet.
Arguments:
Return Value:
--*/
{
POPEN_INSTANCE open;
PIO_STACK_LOCATION irpSp;
PIRP irp;
PLIST_ENTRY packetListEntry;
PNDIS_PACKET pPacket = NULL;
ULONG sizeToTransfer;
NDIS_STATUS status = NDIS_STATUS_FAILURE;
UINT bytesTransfered = 0;
ULONG bufferLength;
PPACKET_RESERVED reserved;
PMDL pMdl;
PNDIS_BUFFER pBuffer;
PVOID VirtualAddress;
UINT TotalLength;
NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress = {0xFFFFFFFF, 0xFFFFFFFF};
DebugPrint(("ReceiveIndicate\n"));
open= (POPEN_INSTANCE)ProtocolBindingContext;
open->Buffer_Handin=FALSE;
if (HeaderBufferSize != ETHERNET_HEADER_LENGTH) {
return NDIS_STATUS_SUCCESS;
}
//
// See if there are any pending read that we can satisfy
//
packetListEntry=ExInterlockedRemoveHeadList(
&open->RcvList,
&open->RcvQSpinLock
);
if (packetListEntry != NULL){
open->Buffer_Handin=TRUE; //indicate that the actions of pakettransferdatacomplete;
reserved=CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement);
pPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);
irp=RESERVED(pPacket)->Irp;
irpSp = IoGetCurrentIrpStackLocation(irp);
//
// We don't have to worry about the situation where the IRP is cancelled
// after we remove it from the queue and before we reset the cancel
// routine because the cancel routine has been coded to cancel an IRP
// only if it's in the queue.
//
IoSetCancelRoutine(irp, NULL);
//
// This is the length of our partial MDL
//
bufferLength=irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH;
//
// Find out how much to transfer
//
sizeToTransfer = (PacketSize < bufferLength) ?
PacketSize : bufferLength;
//
// copy the ethernet header into the actual readbuffer
//
NdisMoveMappedMemory(
MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority),
HeaderBuffer,
HeaderBufferSize
);
//
// Allocate an MDL to map the portion of the buffer following the
// header
//
pMdl=IoAllocateMdl(
MmGetMdlVirtualAddress(irp->MdlAddress),
MmGetMdlByteCount(irp->MdlAddress),
FALSE,
FALSE,
NULL
);
if (pMdl == NULL) {
DebugPrint(("Packet: Read-Failed to allocate Mdl\n"));
status = NDIS_STATUS_RESOURCES;
goto ERROR;
}
//
// Build the mdl to point to the the portion of the buffer following
// the header
//
IoBuildPartialMdl(
irp->MdlAddress,
pMdl,
((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH,
0
);
//
// Clear the next link in the new MDL
//
pMdl->Next=NULL;
RESERVED(pPacket)->pMdl=pMdl;
//
// Attach our partial MDL to the packet
//
NdisChainBufferAtFront(pPacket,pMdl);
//
// Call the Mac to transfer the packet
//
NdisTransferData(
&status,
open->AdapterHandle,
MacReceiveContext,
0,
sizeToTransfer,
pPacket,
&bytesTransfered);
if (status == NDIS_STATUS_PENDING) {
return NDIS_STATUS_SUCCESS;
}
goto ERROR;
}
IoIncrement(open);
//
// build a packet to accomodate the received data
//
NdisAllocatePacket(
&status,
&pPacket,
open->PacketPool
);
if (status != NDIS_STATUS_SUCCESS) {
DebugPrint(("Packet: Read- No free packets\n"));
pPacket = NULL;
goto ERROR;
}
TotalLength = HeaderBufferSize + PacketSize;
status = NdisAllocateMemory(
&VirtualAddress,
TotalLength,
0, //THE MEMORY TYPE:nonpaged system-space
HighestAcceptableAddress
);
if (status != NDIS_STATUS_SUCCESS) {
DebugPrint(("Memory allocation failed!\n"));
NdisFreePacket(pPacket);
pPacket = NULL;
goto ERROR;
}
NdisAllocateBuffer(
&status,
&pBuffer,
open->BufferPool,
VirtualAddress,
TotalLength
);
if (status != NDIS_STATUS_SUCCESS) {
DebugPrint(("No free buffer descriptor!\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -