⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 read.c

📁 使用NDIS协议完成的一个较为简单的驱动程序编程范例(windons驱动程序编程)
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

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 + -