驱动开发之五 --- TDI之二 【译文】

驱动开发之五 --- TDI之二 【译文】

接上:

传输设备接口

前面socket知识的了解是为了让你对TDI API做好准备。传输设备接口是一组用于驱动中, 与传输协议驱动通讯的API. 就像TCP。传输驱动实现了这组API,所以你的驱动能够与它通讯。

这比socket的使用多少有些复杂。MSDN上的文档资料会让你更加迷惑,而不是有帮助。所以我们将一步一步地建立一个客户端连接。一旦你理解了这个,你就能够使用这些API来执行其他的操作,例如创建一个服务端等等。

体系结构

下图描述了TDI/NDIS的关系。通常,TDI是标准的传输协议接口,协议驱动开发者可以在他们的驱动中实现这些。在这种情况下,开发者希望使用他们自己的协议来实现标准的接口,而不是希望每个他们支持的协议各自实现一套接口产生争执。这并不是说这些开发者只能被限定实现TDI..他们可以在他们驱动的顶层实现任何自己想要的接口。我不是一个NDIS方面的专家,所以我简单的说这么多,希望不会出现什么错误!总之,这些典型的信息了解了,是有好处的,但由于我们只是开发TDI客户端驱动,所以这些我们并不需要去理解。

NDIS协议驱动

在这个驱动的下层,协议驱动会调用NDIS接口API,协议驱动的作用也就是实现一个协议,并且与NDIS会话,驱动的上层可以是一个私有的接口或者TDI或者两者都有. 顺便说一下,这里没有“NDIS客户端”。他们不存在。如果其他站点有指出这些驱动是“NDIS客户端”的,那是完全错误的。我曾经跟一个NDIS专家谈到“NDIS客户端”,他们不知道我所说的是什么。

NDIS中间层驱动

下层是中间层驱动,这些驱动可以用作传输,包调度或者数据过滤。

NDIS小端口驱动

最后一层是NDIS小端口驱动,他们直接与NID物理设备通讯。


你可以在msdn上找到更多的关于TDI和NDIS的体系结构信息。


步骤1:打开传输地址

第一步是创建一个“传输地址”的句柄,你需要使用ZwCreateFile 创建一个“传输地址“实例句柄。这个“传输地址“是指本机的ip地址。这不是远程计算机的ip地址。背后的原因是例如,在本机安装了多个NIC, 在本机有多个IP地址的情况下,让你绑定一个指定的IP地址。

你也可以简单的指定为 "0.0.0.0" 使用任意一块NIC.

打开句柄的办法对于那些不熟悉驱动开发的人来讲有点生硬,你必须指定“EA"或者"Extedned Attributes",通过IRP_MJ_CREATE把它传递给驱动。你还可以在打开时,传递参数。除了可以在dos设备名的后面添加外,这时,你也能指定本地端口。如果你是在创建一个服务端,就需要在这个时候指定端口。既然我们仅仅是实现一个客户端连接,因此,我们必须无需关心端口,只要设置为0就行。

下面代码举例说明了怎样打开一个传输地址。/*

typedef struct _FILE_FULL_EA_INFORMATION {

    ULONG NextEntryOffset;

    UCHAR Flags;

    UCHAR EaNameLength;

    USHORT EaValueLength;

    CHAR EaName[1];

} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;

*/

NTSTATUS TdiFuncs_OpenTransportAddress(PHANDLE pTdiHandle,

                                      PFILE_OBJECT *pFileObject)

{

    NTSTATUS NtStatus = STATUS_INSUFFICIENT_RESOURCES;

    UNICODE_STRING usTdiDriverNameString;

    OBJECT_ATTRIBUTES oaTdiDriverNameAttributes;

    IO_STATUS_BLOCK IoStatusBlock;

    char DataBlob[sizeof(FILE_FULL_EA_INFORMATION) +

                          TDI_TRANSPORT_ADDRESS_LENGTH + 300] = {0};

    PFILE_FULL_EA_INFORMATION pExtendedAttributesInformation =

         (PFILE_FULL_EA_INFORMATION)&DataBlob;

    UINT dwEASize = 0;

    PTRANSPORT_ADDRESS pTransportAddress = NULL;

    PTDI_ADDRESS_IP pTdiAddressIp = NULL;

    

    /*

     * Initialize the name of the device to be opened. ZwCreateFile takes an

     * OBJECT_ATTRIBUTES structure as the name of the device to open.  

     * This is then a two step process.

     *

     * 1 - Create a UNICODE_STRING data structure from a unicode string.

     * 2 - Create a OBJECT_ATTRIBUTES data structure from a UNICODE_STRING.

    *

     */

    RtlInitUnicodeString(&usTdiDriverNameString, L"\\Device\\Tcp");

    InitializeObjectAttributes(&oaTdiDriverNameAttributes,

          &usTdiDriverNameString,

          OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,

          NULL, NULL);

    /*

     * The second step is to initialize the Extended Attributes data structure.

     *

     * EaName        = TdiTransportAddress, 0, TRANSPORT_ADDRESS

     * EaNameLength = Length of TdiTransportAddress

     * EaValueLength = Length of TRANSPORT_ADDRESS

     */

     RtlCopyMemory(&pExtendedAttributesInformation->EaName,

             TdiTransportAddress,

             TDI_TRANSPORT_ADDRESS_LENGTH);

     pExtendedAttributesInformation->EaNameLength =

                            TDI_TRANSPORT_ADDRESS_LENGTH;

     pExtendedAttributesInformation->EaValueLength =

                            TDI_TRANSPORT_ADDRESS_LENGTH +

              sizeof(TRANSPORT_ADDRESS) +

              sizeof(TDI_ADDRESS_IP);

     pTransportAddress =  

        (PTRANSPORT_ADDRESS)(&pExtendedAttributesInformation->EaName +

        TDI_TRANSPORT_ADDRESS_LENGTH + 1);

     /*

      * The number of transport addresses

      */

     pTransportAddress->TAAddressCount = 1;

     /*

      * This next piece will essentially describe what

      *                                    the transport being opened is.

      * AddressType   = Type of transport

      * AddressLength = Length of the address

      * Address = A data structure that is essentially

      *                          related to the chosen AddressType.

      */

     pTransportAddress->Address[0].AddressType    = TDI_ADDRESS_TYPE_IP;

     pTransportAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);

     pTdiAddressIp =

          (TDI_ADDRESS_IP *)&pTransportAddress->Address[0].Address;

     /*

      * The TDI_ADDRESS_IP data structure is essentially simmilar to  

      * the usermode sockets data structure.

      *    sin_port

      *    sin_zero

      *    in_addr

      *

      *NOTE: This is the _LOCAL ADDRESS OF THE CURRENT MACHINE_ Just as with  

      *     sockets, if you don't care what port you bind this connection to t  

      *     hen just use "0". If you also only have one network card interface,   

      *     there's no reason to set the IP. "0.0.0.0" will simply use the  

      *     current machine's IP. If you have multiple NIC's or a reason to

      *     specify the local IP address then you must set TDI_ADDRESS_IP

      *     to that IP. If you are creating a server side component you may  

      *     want to specify the port, however usually to connectto another  

      *     server you really don't care what port the client is opening.

      */

     RtlZeroMemory(pTdiAddressIp, sizeof(TDI_ADDRESS_IP));

     dwEASize = sizeof(DataBlob);

     NtStatus = ZwCreateFile(pTdiHandle, FILE_READ_EA | FILE_WRITE_EA,

        &oaTdiDriverNameAttributes,

        &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, 0,

        pExtendedAttributesInformation, dwEASize);

     if(NT_SUCCESS(NtStatus))

     {

          NtStatus = ObReferenceObjectByHandle(*pTdiHandle,

                        GENERIC_READ | GENERIC_WRITE,

                        NULL,

                        KernelMode,

                        (PVOID *)pFileObject, NULL);      

          if(!NT_SUCCESS(NtStatus))

          {

              ZwClose(*pTdiHandle);

          }

     }

     return NtStatus;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于TDI 的 TCP数据传输 1.上位机 上位机包括tcp和tcp.cpp 1.1 对外函数说明 HANDLE TdiTcpOpen(); TdiTcpOpen用于打开设备,成功返回有效的句柄,失败返回INVALID_HANDLE_VALUE. BOOL TdiTcpClose(HANDLE hDevice); TdiTcpClose用于关闭设备,成功返回TRUE,失败返回FALSE; hDevice为TdiTcpOpen返回的句柄 BOOL TdiTcpConnect(HANDLE hDevice,const PCHAR pIpAddres,USHORT uPort); TdiTcpConnect用于与服务器建链,pIpAddres为服务器IP地址,uPort为服务器端口地址。 hDevice为TdiTcpOpen返回的句柄 pIpAddres为IP地址,如”10.0.0.20” uPort为端口地址 BOOL TdiTcpSend(HANDLE hDevice,PVOID pBuff,ULONG nLen,PULONG pRtn); TdiTcpSend用于给服务器发送数据. hDevice为TdiTcpOpen返回的句柄 pBuff接向发送数据的指针 nLen发送数据长度 pRtn发送成功长度 BOOL TdiTcpRcv(HANDLE hDevice,PVOID pBuff,ULONG nLen,PULONG pRtn); TdiTcpRcv用于从服务器接收数据 hDevice为TdiTcpOpen返回的句柄 pBuff接收数据缓冲区 nLen接收数据缓冲区长度 pRtn实际接收数据长度指针 BOOL TdiTcpSetRcvTimeOut(HANDLE hDevice,ULONG ulSecond); TdiTcpSetRcvTimeOut用于设置接收数据超时时间,默认为3秒。 hDevice为TdiTcpOpen返回的句柄 ulSecond为超时时间 2.下位机 下位机包括D1603.h D1603.cpp和Tdifun.cpp TdiFun.h 2.1 关键数据结构 驱动与应用连接服务器结构体 typedef struct _CONNECT_STRUCT { ULONG ip; //服务器IP地址 USHORT port; //服务器端口 }CONNECT_STRUCT,*PCONNECT_STRUCT; //设备展结构体 typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pDeviceObject; //设备指针 UNICODE_STRING wstrDeviceName ; //设备名 UNICODE_STRING wstrSymbolicLinkName;//设备链接名 }DEVICE_EXTENSION,*PDEVICE_EXTENSION; 读数据链接 typedef struct _RCV_IPR_LIST { PIRP pIrp; //指向读IPR LIST_ENTRY ListEntry; //链表 }RCV_IPR_LIST,*PRCV_IPR_LIST; 当前链接上下文 typedef struct _SOCKET_CONTEXT { HANDLE TransportAddressHandle; //传输地址句柄 FILE_OBJECT* pTrasnportAddressFile;//传输地址指针 HANDLE ConnectionHandle;//连接地址句柄 FILE_OBJECT* pConnectionFile;//连接地址指针 LIST_ENTRY RcvHead; //接收IRP链表头 KEVENT event; //接收数据同步事件 ULONG uTimeOut; // 接收数据超时 }SOCKET_CONTEXT,*PSOCKET_CONTEXT; 2.2 外函数说明 驱动装载主入口函数 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath); 驱动卸载函数 VOID D1603Unload(PDRIVER_OBJECT DriverObject); 默认IRP回调函数 NTSTATUS D1603Dispatch(PDEVICE_OBJECT DeviceObject,PIRP Irp); TdiTcpOpen对应的IPR函数 NTSTATUS D1603Create(PDEVICE_OBJECT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值