?? ptextend.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 + -