NDIS小端口驱动ndisEdge学习三——打开ndisprot设备

第一部分

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值