?? ndisbind.cpp
字號:
///////////////////////////////////////////////
// ndisbind.cpp文件
// NDIS協議入口點,處理綁定和解除綁定的例程
extern "C"
{
#include <ndis.h>
#include <ntddk.h>
#include <stdio.h>
}
#include "nuiouser.h"
#include "ndisprot.h"
VOID
ProtocolBindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
)
{
DbgPrint(" ProtoDrv: ProtocolBindAdapter... \n");
NDIS_STATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT pDeviceObj = NULL;
UNICODE_STRING ustrDevName = { 0 };
OPEN_INSTANCE *pOpen = NULL;
do
{
// 為新發現的設備創建設備對象和符號連接名稱
// 構建設備對象名稱。
// 設備名稱的格式是“\Device\{GUID}”,我們的設備對象名稱的格式為“\Device\Packet_{GUID}”,
// 即在設備名稱前加前綴“Packet_”
int nLen = DeviceName->Length + 7*sizeof(WCHAR) + sizeof(UNICODE_NULL);
PWSTR strName = (PWSTR)ExAllocatePool(NonPagedPool, nLen);
if(strName == NULL)
{
*Status = NDIS_STATUS_FAILURE;
break;
}
swprintf(strName, L"\\Device\\Packet_%ws", &DeviceName->Buffer[8]);
RtlInitUnicodeString(&ustrDevName, strName);
// 創建設備對象,同時在設備對象的DeviceExtension域申請一個OPEN_INSTANCE結構
status = IoCreateDevice(g_data.pDriverObj,
sizeof(OPEN_INSTANCE), // 指定DeviceExtension域的大小
&ustrDevName,
FILE_DEVICE_PROTOCOL,
0,
TRUE, // 在同一時間,僅允許用戶打開一個到此對象的句柄
&pDeviceObj);
if(status != STATUS_SUCCESS)
{
DbgPrint(" ProtoDrv: CreateDevice() failed \n ");
*Status = NDIS_STATUS_FAILURE;
break;
}
// 使用直接I/O傳輸數據,這種方式適合大塊數據的傳輸
pDeviceObj->Flags |= DO_DIRECT_IO;
// 取得與本設備對象關聯的OPEN_INSTANCE結構的指針
pOpen = (OPEN_INSTANCE*)pDeviceObj->DeviceExtension;
// 保存設備對象指針
pOpen->pDeviceObj = pDeviceObj;
// 構建符號連接名稱
// 符號連接名稱格式為“\DosDevices\Packet_{GUID}”,比設備名稱多4個字
nLen = ustrDevName.Length + 4*sizeof(WCHAR) + sizeof(UNICODE_NULL);
strName = (PWSTR)ExAllocatePool(NonPagedPool, nLen);
if(strName == NULL)
{
*Status = NDIS_STATUS_FAILURE;
break;
}
swprintf(strName, L"\\DosDevices\\%ws", &ustrDevName.Buffer[8]);
RtlInitUnicodeString(&pOpen->ustrLinkName, strName);
// 為新建設備對象創建符號連接名稱
status = IoCreateSymbolicLink(&pOpen->ustrLinkName, &ustrDevName);
if(status != STATUS_SUCCESS)
{
*Status = NDIS_STATUS_FAILURE;
DbgPrint(" ProtoDrv: Create symbolic failed \n");
break;
}
// 我們不再使用設備對象名稱了,釋放它占用的內存
ExFreePool(ustrDevName.Buffer);
ustrDevName.Buffer = NULL;
// 初始化OPEN_INSTANCE結構. 上面已經初始化了pDeviceObj和ustrLinkName域
// 申請封包池
NdisAllocatePacketPool(&status,
&pOpen->hPacketPool, 16, sizeof(PACKET_RESERVED));
if(status != NDIS_STATUS_SUCCESS)
{
*Status = NDIS_STATUS_FAILURE;
break;
}
// 初始化用來同步打開和關閉的事件
NdisInitializeEvent(&pOpen->BindEvent);
// 初始化重置列表和它對應的spinlock
InitializeListHead(&pOpen->ResetIrpList);
KeInitializeSpinLock(&pOpen->ResetQueueLock);
// 初始化保存未決讀請求的列表和它對應的spinlock
InitializeListHead(&pOpen->RcvList);
KeInitializeSpinLock(&pOpen->RcvSpinLock);
// 現在打開下面的適配器
NDIS_MEDIUM mediumArray = NdisMedium802_3;
UINT mediumIndex;
NdisOpenAdapter(Status,
&status,
&pOpen->hAdapter,
&mediumIndex,
&mediumArray,
sizeof(mediumArray)/sizeof(NDIS_MEDIUM),
g_data.hNdisProtocol,
pOpen,
DeviceName,
0,
NULL);
if(*Status == NDIS_STATUS_PENDING)
{
// 打開操作完成之后,NDIS會調用我們注冊的ProtocolOpenAdapterComplete函數,
// ProtocolOpenAdapterComplete函數設置BindEvent事件,使下面的語句返回。它也設置狀態代碼Status
NdisWaitEvent(&pOpen->BindEvent, 0);
*Status = pOpen->Status;
}
if(*Status != NDIS_STATUS_SUCCESS)
{
DbgPrint(" ProtoDrv: OpenAdapter failed! \n");
break;
}
// 繼續初始化OPEN_INSTANCE結構
// IRP請求數量初始值為0
pOpen->nIrpCount = 0;
// 已經綁定
InterlockedExchange((PLONG)&pOpen->bBound, TRUE);
NdisInitializeEvent(&pOpen->CleanupEvent);
// 可以清除
NdisSetEvent(&pOpen->CleanupEvent);
// 保存MAC驅動的名稱
NdisQueryAdapterInstanceName(&pOpen->ustrAdapterName, pOpen->hAdapter);
pOpen->Medium = mediumArray;
// 連接此OPEN_INSTANCE實例到全局的適配器列表(AdapterList),準備接收用戶的I/O請求
InitializeListHead(&pOpen->AdapterListEntry);
ExInterlockedInsertTailList(&g_data.AdapterList,
&pOpen->AdapterListEntry,
&g_data.GlobalLock);
// 清除設備對象中的DO_DEVICE_INITIALIZING標記。
// 如果你在DriverEntry之外創建設備對象,必須要這么做。否則,應用程序不能發送I/O請求
pDeviceObj->Flags &= ~DO_DEVICE_INITIALIZING;
}
while(FALSE);
// 出錯處理
if(*Status != NDIS_STATUS_SUCCESS)
{
if(pOpen != NULL && pOpen->hPacketPool != NULL)
{
NdisFreePacketPool(pOpen->hPacketPool);
}
if(pDeviceObj != NULL)
IoDeleteDevice(pDeviceObj);
if(ustrDevName.Buffer != NULL)
ExFreePool(ustrDevName.Buffer);
if(pOpen->ustrLinkName.Buffer != NULL)
{
IoDeleteSymbolicLink(&pOpen->ustrLinkName);
ExFreePool(pOpen->ustrLinkName.Buffer);
}
}
}
VOID
ProtocolOpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
)
{
POPEN_INSTANCE pOpen = (POPEN_INSTANCE)ProtocolBindingContext;
pOpen->Status = Status;
// 指示綁定已經完成
NdisSetEvent(&pOpen->BindEvent);
}
VOID
ProtocolUnbindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
)
{
OPEN_INSTANCE *pOpen = (OPEN_INSTANCE *)ProtocolBindingContext;
if(pOpen->hAdapter != NULL)
{
// 關閉下層適配器
NdisResetEvent(&pOpen->BindEvent);
// 說明不再有綁定了
InterlockedExchange((PLONG)&pOpen->bBound, FALSE);
// 取消所有未決的讀IRP請求
CancelReadIrp(pOpen->pDeviceObj);
// 等待所有IRP完成
NdisWaitEvent(&pOpen->CleanupEvent, 0);
// 釋放建立的綁定
NdisCloseAdapter(Status, pOpen->hAdapter);
// 等待這個操作完成
if(*Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&pOpen->BindEvent, 0); // ProtocolCloseAdapterComplete函數使事件受信
*Status = pOpen->Status;
}
else
{
*Status = NDIS_STATUS_FAILURE;
}
// 從全局的適配器列表(AdapterList)中刪除這個實例
KIRQL oldIrql;
KeAcquireSpinLock(&g_data.GlobalLock, &oldIrql);
RemoveEntryList(&pOpen->AdapterListEntry);
KeReleaseSpinLock(&g_data.GlobalLock, oldIrql);
// 釋放綁定時申請的資源
NdisFreePacketPool(pOpen->hPacketPool);
NdisFreeMemory(pOpen->ustrAdapterName.Buffer, pOpen->ustrAdapterName.Length, 0);
IoDeleteSymbolicLink(&pOpen->ustrLinkName);
ExFreePool(pOpen->ustrLinkName.Buffer);
IoDeleteDevice(pOpen->pDeviceObj);
}
}
VOID
ProtocolCloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
{
POPEN_INSTANCE pOpen = (POPEN_INSTANCE)ProtocolBindingContext;
pOpen->Status = Status;
NdisSetEvent(&pOpen->BindEvent);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -