第一部分
ndisedge是一个WDF型的驱动,为了追赶时尚的最前沿技术,我们应该采用WDF下的新做法打开设备对象
一般的IO目标只能打开本驱动生成的设备,这种IO目标被称为本地IO目标,如果要打开其他驱动生成的设备,必须使用远程IO目标
远程IO目标使用WDF的内核API函数WdfIoTargetCreate来生成
这个函数原型如下:
NTSTATUS WdfIoTargetCreate(
WDFDEVICE Device,
PWDF_OBJECT_ATTRIBUTES IoTargetAttributes,
WDFIOTARGET *IoTarget
);
Device是我们本驱动的控制设备对象,就是在MPInitialize中调用WdfDeviceMiniportCreate获得的那个设备句柄
RtlInitUnicodeString ( &fileName, (PCWSTR) PROTOCOL_INTERFACE_NAME );
status = WdfIoTargetCreate(Adapter->WdfDevice,
WDF_NO_OBJECT_ATTRIBUTES,
&Adapter->IoTarget);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("WdfIoTargetCreate failed 0x%x\n", status));
return status;
}
WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(&openParams,
&fileName,
STANDARD_RIGHTS_ALL
);
status = WdfIoTargetOpen(Adapter->IoTarget,
&openParams);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("WdfIoTargetOpen failed 0x%x\n", status));
return status;
如上面代码所示
1.PROTOCOL_INTERFACE_NAME是一个符号链接 ,初始化为UnicodeString类型,然后生成IO目标对象,
Adapter->IoTarget就是我们生成的IO目标,但是这个时候它是一个空容器。
2.WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME填写要打开的设备名称(用户态使用符号链接打开设备)
3.然后调用WdfIoTargetOpen将空IO目标对象联系到实际的设备对象
第二部分
给IO目标发送DeviceIoControl请求
IO目标和设备对象不同,不能使用Zw系列函数来发送请求
所以要给IO目标发送同步的控制请求需要用WdfIoTargetSendIoCtlSynchronously这个API函数
这个内核API函数原型
NTSTATUS WdfIoTargetSendIoctlSynchronously(
WDFIOTARGET IoTarget,
WDFREQUEST Request,
ULONG IoctlCode,
PWDF_MEMORY_DESCRIPTOR InputBuffer,
PWDF_MEMORY_DESCRIPTOR OutputBuffer,
PWDF_REQUEST_SEND_OPTIONS RequestOptions,
PULONG_PTR BytesReturned
);
第三部分
打开ndisprot接口并完成配置设备
ndisprot是一个协议驱动,这个协议驱动绑定了所有的网卡,本质上来说协议驱动绑定了所有的小端口驱动的每个实例,所以ndisprot也会和ndisedge绑定
现在ndisedge要操纵ndisprot进行收发数据包
步骤
1:打开ndisprot的控制设备,这使用生成IO目标,打开IO目标来完成
2:给ndisprot的控制设备发送功能码为IOCTL_NDISPROT_BIND_WAIT的控制请求来等待绑定完成
3:不断发送IOCTL_NDISPROT_QUERY_BINDING来查询它的每个绑定,直到找到第一个名字与ndisedge生成的实例不同的绑定,或者遍历完都没有找到返回错误
4:找到一个就发送IOCTL_NDISPROT_OPEN_DEVICE来指定使用这个绑定发送\接收数据包
这一系列的操作在NICOpenNdisProtocolInterface中完成,这个函数最终是被MPInitialize调用
#ifdef INTERFACE_WITH_NDISPROT
NTSTATUS
NICOpenNdisProtocolInterface(
PMP_ADAPTER Adapter
)
/*++
Routine Description:
This routine opens the NDISPROT device and sends buch of IOCTLs
to get the names of NICs that it's bound to and pick the first
available one as our target phycial device.
Arguments:
Adapter Pointer to our adapter
Return Value:
NT Status code
--*/
{
UCHAR Buf[512];//should be enough to get name and description of one adapter
ULONG BufLength = sizeof(Buf);
ULONG i;
NTSTATUS status;
PWCHAR deviceName = NULL;
PWCHAR deviceDesc = NULL;
UNICODE_STRING fileName;
ULONG unUsed;
PNDISPROT_QUERY_BINDING pQueryBinding = NULL;
WDF_IO_TARGET_OPEN_PARAMS openParams;
PAGED_CODE();
DEBUGP(MP_TRACE, ("--> NICOpenNdisProtocolInterface\n"));
RtlInitUnicodeString ( &fileName, (PCWSTR) PROTOCOL_INTERFACE_NAME );
status = WdfIoTargetCreate(Adapter->WdfDevice,
WDF_NO_OBJECT_ATTRIBUTES,
&Adapter->IoTarget);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("WdfIoTargetCreate failed 0x%x\n", status));
return status;
}
WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(&openParams,
&fileName,
STANDARD_RIGHTS_ALL
);
status = WdfIoTargetOpen(Adapter->IoTarget,
&openParams);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("WdfIoTargetOpen failed 0x%x\n", status));
return status;
}
DEBUGP (MP_INFO, ( "Successfully opened the protocol interface\n"));
//
// Make sure the target device supports direct I/O operations.
//
if (!((WdfIoTargetWdmGetTargetDeviceObject(Adapter->IoTarget))->Flags
& DO_DIRECT_IO)) {
ASSERTMSG("Target device doesn't support direct I/O\n", FALSE);
return STATUS_INVALID_DEVICE_REQUEST;
}
Adapter->FileObject = WdfIoTargetWdmGetTargetFileObject(Adapter->IoTarget);
//
// Wait for the NDISPROT to completly bind to all the miniport
// instances.
//
status = NICMakeSynchronousIoctl(
Adapter->IoTarget,
Adapter->FileObject,
IOCTL_NDISPROT_BIND_WAIT,
NULL,
0,
NULL,
0,
&unUsed
);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("IOCTL_NDISIO_BIND_WAIT failed, error %x\n", status));
return status;
}
pQueryBinding = (PNDISPROT_QUERY_BINDING)Buf;
//
// Query the binding of NDISPROT one at a time and see if you can open
// the bindings and use that as our physical adapter.
//
i = 0;
for (pQueryBinding->BindingIndex = i;
/* NOTHING */;
pQueryBinding->BindingIndex = ++i)
{
status = NICMakeSynchronousIoctl(
Adapter->IoTarget,
Adapter->FileObject,
IOCTL_NDISPROT_QUERY_BINDING,
pQueryBinding,
sizeof(NDISPROT_QUERY_BINDING),
Buf,
BufLength,
&unUsed
);
if (NT_SUCCESS(status))
{
deviceName = (PWCHAR)((PUCHAR)pQueryBinding +
pQueryBinding->DeviceNameOffset);
deviceDesc = (PWCHAR)((PUCHAR )pQueryBinding +
pQueryBinding->DeviceDescrOffset);
DEBUGP(MP_WARNING, ("%2d. %ws\n - %ws\n",
pQueryBinding->BindingIndex, deviceName, deviceDesc));
//
// Make sure we are not opening our device or another instance
// of NDISWDM miniport if more than one instances is installed.
// We can just use the AdapterDesc to decide this all the time.
// There is no need to get devicename - just an illustration.
//
if (wcscmp(deviceName, Adapter->AdapterName) &&
!wcsstr(deviceDesc, Adapter->AdapterDesc))
{
Adapter->FileObject->FsContext = NULL;
status = NICMakeSynchronousIoctl(
Adapter->IoTarget,
Adapter->FileObject,
IOCTL_NDISPROT_OPEN_DEVICE,
(PVOID)deviceName,
pQueryBinding->DeviceNameLength-sizeof(WCHAR),
NULL,
0,
&unUsed
);
if (!NT_SUCCESS(status)) {
DEBUGP(MP_ERROR, ("Failed to open NDIS Device %ws %x\n", deviceDesc, status));
} else {
DEBUGP(MP_WARNING, ("Successfully opened NDIS Device: %ws\n", deviceDesc));
break;
}
}
RtlZeroMemory(Buf, BufLength);
}
else
{
if (status != STATUS_NO_MORE_ENTRIES)
{
DEBUGP(MP_ERROR, ("EnumerateDevices: terminated abnormally, error %x\n", status));
}
break;
}
}
DEBUGP(MP_TRACE, ("<-- NICOpenNdisProtocolInterface\n"));
return status;
}
#endif