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

📄 ptextend.c

📁 vc++网络程序设计实例详解 人民邮电出版社5-6章源码
💻 C
字号:
/////////////////////////////////////////////////
// PTEXTEND.c文件


#include "precomp.h"
#pragma hdrstop
#include "iocommon.h"

extern NDIS_SPIN_LOCK	GlobalLock;
extern PADAPT pAdaptList;


//////////////////////////////////////////
// 派遣例程

// 这是处理IRP_MJ_CREATE的派遣例程,我们仅简单的返回成功
NTSTATUS DevOpen(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	PIO_STACK_LOCATION pIrpStack;

	// 初始化这个新的文件对象

	pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

	pIrpStack->FileObject->FsContext = NULL;
	pIrpStack->FileObject->FsContext2 = NULL;


	DBGPRINT(("  DevOpen: FileObject %p\n", pIrpStack->FileObject));

	// 完成此IRP请求
	pIrp->IoStatus.Information = 0;
	pIrp->IoStatus.Status = status;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return status;
}

// 这是处理IRP_MJ_CLEANUP的派遣例程
NTSTATUS DevCleanup(PDEVICE_OBJECT pDeviceObject,PIRP pIrp)
{
    PIO_STACK_LOCATION  pIrpSp;
    NTSTATUS            status = STATUS_SUCCESS;
    POPEN_CONTEXT       pOpenContext;
	
	// 取得句柄
    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;
	
    if(pOpenContext)
    {
		// 在这里取消所有未决的IRP。这个例子里没有。
    }

    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = status;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	
    return status;
} 

// 这是处理IRP_MJ_CLOSE的派遣例程,如果是适配器句柄,我们要减小对打开环境的引用
NTSTATUS DevClose(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	PIO_STACK_LOCATION pIrpStack;
	POPEN_CONTEXT pOpenContext;

	pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
	pOpenContext = (POPEN_CONTEXT)pIrpStack->FileObject->FsContext;


	pIrpStack->FileObject->FsContext = NULL;
	pIrpStack->FileObject->FsContext2 = NULL;

	if(pOpenContext != NULL) // 关闭的是一个适配器句柄
	{
		if(pOpenContext->pAdapt != NULL)
		{
			NdisAcquireSpinLock(&(pOpenContext->pAdapt)->Lock);
			(pOpenContext->pAdapt)->pOpenContext = NULL;
			NdisReleaseSpinLock(&(pOpenContext->pAdapt)->Lock);
		}
		DevDerefOpenContext(pOpenContext);
	}

	// 完成此IRP请求
	pIrp->IoStatus.Information = 0;
	pIrp->IoStatus.Status = status;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return status;
}


// 这是处理IRP_MJ_DEVICE_CONTROL的派遣例程,如果是适配器句柄,我们要减小对打开环境的引用
NTSTATUS DevIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	// 假设失败
	NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;

	// 取得此IRP(pIrp)的I/O堆栈指针
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

	// 取得I/O控制代码
	ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
	// 取得I/O缓冲区指针和它的长度
	PVOID pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
	ULONG uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
	ULONG uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

	ULONG uTransLen = 0;

	DBGPRINT((" DevIoControl... \n"));

	switch(uIoControlCode)
	{
	case IOCTL_PTUSERIO_ENUMERATE:
		{
			status = DevGetBindingList(pIoBuffer, uOutSize, &uTransLen);
		}
		break;
	case IOCTL_PTUSERIO_OPEN_ADAPTER: // 打开一个适配器。实际上是为适配器关联一个OPEN_CONTEXT结构
		{
			POPEN_CONTEXT pOpenContext;
			PADAPT pAdapt = LookupAdaptByName((PUCHAR)pIoBuffer, uInSize);
			if(pAdapt == NULL)
			{
				status = STATUS_OBJECT_NAME_NOT_FOUND;
				break;
			}

			
			// 如果正在Unbind,则失败
			NdisAcquireSpinLock(&pAdapt->Lock);  
			if(pAdapt->UnbindingInProcess)
			{
				NdisReleaseSpinLock(&pAdapt->Lock);
				PtDerefAdapter(pAdapt);
				status = STATUS_INVALID_DEVICE_STATE;
				break;
			}
			NdisReleaseSpinLock(&pAdapt->Lock);

			// 如果适配器已经打开,则失败
			if(pAdapt->pOpenContext != NULL)
			{
				PtDerefAdapter(pAdapt);
				status = STATUS_DEVICE_BUSY;
				break;
			}

			// 为新的OPEN_CONTEXT结构申请内存空间
			pOpenContext = DevAllocateOpenContext(pAdapt);
			if(pOpenContext == NULL)
			{
				PtDerefAdapter(pAdapt);
				status = STATUS_INSUFFICIENT_RESOURCES;
				break;
			}


				// 在ADAPT结构中保存pOpenContext指针
			// InterlockedXXX函数执行原子操作:首先它将pAdapt->pOpenContext
			// 与NULL检查,如果它们相等,这个函数将pOpenContext放入pAdapt->pOpenContext,
			// 返回NULL。否则,它仅返回现存的Adapt->pOpenContext,不改变任何值。
	
			/* 功能上相当于 
			if(pAdapt->pOpenContext == NULL)
			{
				pAdapt->pOpenContext = pOpenContext;
			}
			else
			{
				// error 
			}*/
			if(InterlockedCompareExchangePointer(&(pAdapt->pOpenContext), 
													pOpenContext, NULL) != NULL)
			{
				PtDerefAdapter(pAdapt);
				status = STATUS_DEVICE_BUSY;
				break;
			}

			// 将打开环境与句柄关联
			pIrpStack->FileObject->FsContext = pOpenContext;

			status = STATUS_SUCCESS;
		}
		break;
	case IOCTL_PTUSERIO_QUERY_OID:
	case IOCTL_PTUSERIO_SET_OID: 
		{
			return DevHandleOidRequest(pDeviceObject, pIrp);
		}
		break;
	default:
		return FltDevIoControl(pDeviceObject, pIrp);
	}


	if(status == STATUS_SUCCESS)
		pIrp->IoStatus.Information = uTransLen;
	else
		pIrp->IoStatus.Information = 0;

	pIrp->IoStatus.Status = status;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return status;
}


//////////////////////////////////
// 处理IOCTL时要使用的函数

// 处理用户的OID请求
NTSTATUS DevHandleOidRequest(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
	// 假设失败
	NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;

	// 取得此IRP(pIrp)的I/O堆栈指针
	PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

	// 取得I/O控制代码
	ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
	// 取得I/O缓冲区指针和它的长度
	PPTUSERIO_OID_DATA pOidData = (PPTUSERIO_OID_DATA)pIrp->AssociatedIrp.SystemBuffer;
	ULONG uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
	ULONG uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
	ULONG uTransLen = 0;

	POPEN_CONTEXT pOpenContext;
	PADAPT pAdapt;
	do
	{
		// 取得与此句柄关联的OPEN_CONTEXT结构的指针	// 首先检查此句柄是否打开适配器
		pOpenContext = (POPEN_CONTEXT)pIrpStack->FileObject->FsContext;
		if(pOpenContext == NULL)
		{
			status = STATUS_INVALID_HANDLE;
			break;
		}
		pAdapt = pOpenContext->pAdapt;
		if(pAdapt == NULL)
		{
			status = STATUS_INVALID_HANDLE;
			break;
		}
		
		// 检查缓冲区
		if(uOutSize != uInSize || uOutSize < sizeof(PTUSERIO_OID_DATA) ||
					uOutSize < sizeof(PTUSERIO_OID_DATA) - 1 + pOidData->Length)
		{
			status = STATUS_INVALID_PARAMETER;
			break;
		}
		

		
		// 如果Unbind正在进行,则失败
		NdisAcquireSpinLock(&pAdapt->Lock);
		
		if( pAdapt->UnbindingInProcess )
		{
			NdisReleaseSpinLock(&pAdapt->Lock);
			DBGPRINT(( "      Unbind In Process\n" ));
			status = STATUS_INVALID_DEVICE_STATE;
			break;
		}
		
		//
		// All other queries are failed, if the miniport is not at D0,
		//
		if (pAdapt->MPDeviceState > NdisDeviceStateD0)
		{
			NdisReleaseSpinLock(&pAdapt->Lock);
			DBGPRINT(( "      Invalid Miniport Device State\n" ));
			status = STATUS_INVALID_DEVICE_STATE;
			break;
		}
		
		//
		// This is in the process of powering down the system, always fail the request
		// 
		if (pAdapt->StandingBy == TRUE)
		{
			NdisReleaseSpinLock(&pAdapt->Lock);
			DBGPRINT(( "      Miniport Powering Down\n" ));
			
			status = STATUS_INVALID_DEVICE_STATE;
			break;
		}
		
		NdisReleaseSpinLock(&pAdapt->Lock);
		
			// 检查完毕,最后,进行这个请求

		DevRefOpenContext(pOpenContext);	
		
		// 初始化NDIS_REQUEST结构
		NdisZeroMemory(&pOpenContext->Request, sizeof(pOpenContext->Request));
		if(uIoControlCode == IOCTL_PTUSERIO_SET_OID)
		{ 
			pOpenContext->Request.RequestType = NdisRequestSetInformation;
			pOpenContext->Request.DATA.SET_INFORMATION.Oid = pOidData->Oid;
			pOpenContext->Request.DATA.SET_INFORMATION.InformationBuffer = pOidData->Data;
			pOpenContext->Request.DATA.SET_INFORMATION.InformationBufferLength = pOidData->Length;
		}
		else
		{
			pOpenContext->Request.RequestType = NdisRequestQueryInformation;
			pOpenContext->Request.DATA.QUERY_INFORMATION.Oid = pOidData->Oid;
			pOpenContext->Request.DATA.QUERY_INFORMATION.InformationBuffer = pOidData->Data;
			pOpenContext->Request.DATA.QUERY_INFORMATION.InformationBufferLength = pOidData->Length;
		}
		
		NdisResetEvent( &pOpenContext->RequestEvent);
		
		// 提交这个请求
		NdisRequest(&status, pAdapt->BindingHandle, &pOpenContext->Request);
		
		
		if(status != NDIS_STATUS_PENDING)
		{
			DevRequestComplete(pAdapt, &pOpenContext->Request, status);
		}
		
		// 等待请求的完成,即等待Ndis调用DevRequestComplete例程
		NdisWaitEvent(&pOpenContext->RequestEvent, 0);
		
		if(pOpenContext->RequestStatus == NDIS_STATUS_SUCCESS)
		{
			//  将大小返回到用户缓冲区
			if(uIoControlCode == IOCTL_PTUSERIO_SET_OID) 
			{
				pOidData->Length = pOpenContext->Request.DATA.SET_INFORMATION.BytesRead;
			} 
			else if(uIoControlCode == IOCTL_PTUSERIO_QUERY_OID) 
			{
				pOidData->Length = pOpenContext->Request.DATA.QUERY_INFORMATION.BytesWritten;
			}	
			
			// 设置返回给I/O管理器的信息
			uTransLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
			status = STATUS_SUCCESS;
		}
		else
		{
			status = STATUS_UNSUCCESSFUL;
		}
		
		DevDerefOpenContext(pOpenContext);
	}
	while(FALSE);

	if(status == STATUS_SUCCESS)
		pIrp->IoStatus.Information = uTransLen;
	else
		pIrp->IoStatus.Information = 0;

	pIrp->IoStatus.Status = status;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return status;
}

VOID DevRequestComplete(PADAPT pAdapt, PNDIS_REQUEST NdisRequest,NDIS_STATUS Status)
{
	POPEN_CONTEXT pOpenContext = CONTAINING_RECORD(NdisRequest, OPEN_CONTEXT, Request);
	pOpenContext->RequestStatus = Status;
    NdisSetEvent(&pOpenContext->RequestEvent);
}

// 获取绑定列表
NTSTATUS DevGetBindingList(
    IN  PVOID              Buffer,		// 缓冲区
    IN  ULONG              Length,		// 缓冲区大小
    IN  OUT PULONG         DataLength	// 返回实际需要的长度
    )
{
	PADAPT pAdapt ;

		// 遍历列表,计算所需的缓冲区大小
	ULONG nRequiredLength = 0;
	ULONG nAdapters = 0;

	NdisAcquireSpinLock(&GlobalLock);

	pAdapt = pAdaptList;
	while(pAdapt != NULL)
	{
		nRequiredLength += pAdapt->DeviceName.Length + sizeof(UNICODE_NULL); 
		nRequiredLength += pAdapt->LowerDeviceName.Length + sizeof(UNICODE_NULL);
		nAdapters++;

		pAdapt = pAdapt->Next;
	}

	// 我们将要以下面的格式返回数据:
	// nAdapters + 一个或者多个("DeviceName\0" + "LowerDeviceName\0") + UNICODE_NULL
	// 所以,下面要包含上nAapters和UNICODE_NULL的大小
	nRequiredLength += sizeof(nAdapters) + sizeof(UNICODE_NULL); 

	*DataLength = nRequiredLength;
	if(nRequiredLength > Length) 
	{
       NdisReleaseSpinLock(&GlobalLock);
       return STATUS_BUFFER_TOO_SMALL;
    }

		// 填充缓冲区
	// 首先是适配器数量
	*(PULONG)Buffer = nAdapters;
	Buffer = (PCHAR)Buffer + sizeof(ULONG);

	// 然后复制适配器和符号连接名称
	pAdapt = pAdaptList;
	while(pAdapt != NULL)
	{
		NdisMoveMemory(Buffer,pAdapt->DeviceName.Buffer, pAdapt->DeviceName.Length + sizeof(WCHAR));

		Buffer = (PCHAR)Buffer + pAdapt->DeviceName.Length + sizeof(WCHAR);

        NdisMoveMemory(Buffer,pAdapt->LowerDeviceName.Buffer, pAdapt->LowerDeviceName.Length + sizeof(WCHAR)); 

		Buffer = (PCHAR)Buffer + pAdapt->LowerDeviceName.Length + sizeof(WCHAR);    

		pAdapt = pAdapt->Next;
    }
	
	// 最后的结束标志
    *(PWCHAR)Buffer = UNICODE_NULL;
    
    NdisReleaseSpinLock(&GlobalLock);

	return STATUS_SUCCESS;
}



////////////////////////////////////////////
// 帮助函数

// 更加适配器名称查找适配器的PADAPT结构
PADAPT LookupAdaptByName(PUCHAR pNameBuffer, ULONG nNameLength)
{
	PADAPT pAdapt;

	NdisAcquireSpinLock(&GlobalLock);

	pAdapt = pAdaptList;
	while(pAdapt != NULL)
	{
		if(pAdapt->LowerDeviceName.Length == nNameLength &&
			NdisEqualMemory(pAdapt->LowerDeviceName.Buffer, pNameBuffer, nNameLength))
			break;


		pAdapt = pAdapt->Next;
	}

	// 防止在引用适配器期间,系统释放缓冲区
	if(pAdapt != NULL)
		PtRefAdapter(pAdapt);

	NdisReleaseSpinLock(&GlobalLock);
	return pAdapt;
}

// 申请和初始化一个POPEN_CONTEXT结构
POPEN_CONTEXT DevAllocateOpenContext(PADAPT pAdapt)
{
	POPEN_CONTEXT pOpenContext = NULL;

	// 为OPEN_CONTEXT结构申请内存空间
	NdisAllocateMemoryWithTag(&pOpenContext, sizeof(OPEN_CONTEXT), TAG);
	if(pOpenContext == NULL)
	{
		return NULL;
	}

	// 初始化这个内存空间
	NdisZeroMemory(pOpenContext, sizeof(OPEN_CONTEXT));

	NdisAllocateSpinLock(&pOpenContext->Lock);

	NdisInitializeEvent(&pOpenContext->RequestEvent);

	pOpenContext->RefCount = 1;
	pOpenContext->pAdapt = pAdapt;

	return pOpenContext;
}

// 增加对适配器(PADAPT结构)的引用
VOID PtRefAdapter(PADAPT pAdapt)	
{
   NdisInterlockedIncrement(&pAdapt->RefCount);
}


// 减小对适配器(PADAPT结构)的引用,如果减为0,则释放它占用的内存
VOID PtDerefAdapter(PADAPT pAdapt) 
{
	if(pAdapt == NULL)
		return;
 
	if(NdisInterlockedDecrement(&pAdapt->RefCount) == 0) // 已经没有代码再引用它了,释放内存
	{
		MPFreeAllPacketPools (pAdapt);

// BEGIN_PTEX_FILTER
      //
      // 反初始化此适配器上的过滤相关数据
      //
      FltOnDeinitAdapter(pAdapt);
// END_PTEX_FILTER

		NdisFreeMemory(pAdapt, 0, 0);
	}
}




// 增加对打开环境的引用
VOID DevRefOpenContext(POPEN_CONTEXT pOpenContext) 
{
	// 首先增加对适配器的引用,然后再增加OPEN_CONTEXT的引用计数
   PtRefAdapter(pOpenContext->pAdapt);
   NdisInterlockedIncrement(&pOpenContext->RefCount);
}

// 减少对打开环境的引用,如果减为0,则释放它占用的内存
VOID DevDerefOpenContext(POPEN_CONTEXT pOpenContext) 
{
   PADAPT pAdapt = NULL;
   if(pOpenContext == NULL)
	   return;

   // 首先保存对应的适配器指针,以便后面对它调用PtDerefAdapter函数
   pAdapt = pOpenContext->pAdapt;

   // 减小引用计数,如果没有代码再引用它了,则清除资源
   if(NdisInterlockedDecrement(&pOpenContext->RefCount) == 0)
   {
      NdisFreeSpinLock(&pOpenContext->Lock);
      NdisFreeMemory(pOpenContext, 0, 0);
   }

   // 减少对适配器的引用
   PtDerefAdapter(pAdapt);
}




/*NTSTATUS DevOpenAdapter(PUCHAR pNameBuffer, ULONG nNameLength, )
{

}*/


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -