首页
社区
课程
招聘
[原创]NDIS中间层驱动,PassThru贴码析
发表于: 2013-2-7 18:23 7686

[原创]NDIS中间层驱动,PassThru贴码析

2013-2-7 18:23
7686
windows内核中的网络架构大致如下:

TDI驱动       -----把win32的网络请求转换成NDIS认识的方式
.
NDIS协议驱动  -----对应一个网络协议
.
NDIS小端口驱动-----对应一个网卡

本来协议驱动和小端口驱动结合在一起,当NDIS中间层驱动被安装到系统时,NDIS机制会断开协议驱动与小端口驱动的连结,把中间层驱动强势插入。中间层驱动对上(协议驱动)表现为一个小端口驱动,对下(小端口驱动)表现为一个协议驱动,它作为一个“中间人”,可以拦截或修改流经的网络数据。

因为要扮演中间人或者叫双面人,它必须具有协议驱动与小端口驱动两者的所有特征。从代码角度来看,就是既要有构成协议驱动的函数,也要有构成小端口驱动的函数。

PassThru是DDK中的NDIS中间层驱动示例,先看passthru.c:

开头定义了如下的全局变量:

NDIS_HANDLE        ProtHandle   = NULL;       // 协议句柄
NDIS_HANDLE        LayerHandle  = NULL;       // 中间层驱动句柄
//
NDIS_SPIN_LOCK     GlobalLock;              // 操作pListAdapter,注册控制设备(PtRegisterDevice)时使用
PADAPT             pListAdapter  = NULL;    // 一个由ADAPT结构构成的list,ADAPT结构后述
//
LONG               MiniportCount = 0;       // 小端口实例计数,或者说本机网卡数
//
NDIS_HANDLE     NdisWrapperHandle = NULL;    // 包装句柄,注册小端口驱动时用
NDIS_HANDLE     NdisDeviceHandle  = NULL;    // 不透明,NdisMRegisterDevice生成,NdisMDeregisterDevice使用
//
PDEVICE_OBJECT   pControlDeviceObject = NULL; // 控制设备

NDIS_MEDIUM  MediumArray[4] =        // 代表支持的媒质类型,以太网,令牌环网等。。
{
    NdisMedium802_3,    // Ethernet
    NdisMedium802_5,    // Token-ring
    NdisMediumFddi,     // Fddi
    NdisMediumWan       // NDISWAN
};

enum _DEVICE_STATE                   // 由于要和用户层交互,需要生成一个控制设备,这个代表控制设备的状态,用于保障互斥操作
{
    PS_DEVICE_STATE_READY = 0,   // ready for create/delete
    PS_DEVICE_STATE_CREATING,    // create operation in progress
    PS_DEVICE_STATE_DELETING     // delete operation in progress
} ControlDeviceState = PS_DEVICE_STATE_READY;

下面是DriverEntry:

首先分配(初始化)GlobalLock,第一个中间层驱动实例初始化时就要用到,所以尽先初始化。

接着初始化包装句柄,NdisMInitializeWrapper,NDIS内部用这个结构来管理小端口驱动。

然后注册小端口驱动,其实是调用NdisIMRegisterLayeredMiniport,它内部除了注册小端口驱动,还有一些属于中间层驱动的动作。
然后注册协议驱动。
这里必须先注册小端口驱动,再注册协议驱动,因为协议驱动的绑定函数中就有初始化小端口实例的操作,如果此时小端口驱动还没注册,那应该是一个蓝屏。

如果有哪一步失败,释放所有的资源(GlobalLock,NdisWrapperHandle)。

最后调用NdisIMAssociateMiniport把我们的协议驱动和小端口驱动关联在一起,就成了一个中间层驱动。


PtUnload和PtDispatch从略。

passthru.c还有PtRegisterDevice和PtDeregisterDevice函数,前者负责注册控制设备,后者负责撤销控制设备。

常规驱动中,我们用IoCreateDevice来创建控制设备,而NDIS中间层驱动的设备对象的分发函数已经被NDIS征用,所以应该用NDIS推荐的方式来注册控制设备。

前文中提到全局变量中有个MiniportCount,用来计数小端口实例,或者说本机网卡数,当中间层驱动的初始化完成,第一个网卡被插入中间层驱动时,MiniportCount为1,这时候注册控制设备。当中间层驱动从所有网卡unload时,也就是MiniportCount减为0时,撤销控制设备。

为了保证注册控制设备与撤销控制设备互斥,注册控制设备与(撤销控制设备再)注册控制设备互斥,应该保证(加减MiniportCount并操作控制设备)的原子性。本来把这些操作放到一个函数中,然后前面加锁,完成解锁即可。但是NdisMRegisterDevice函数不能在DISPATCH_LEVEL运行。于是引入了前面全局变量中的ControlDeviceState,把(加减MiniportCount和设置ControlDeviceState)放到一个锁里,这样即使NdisMRegisterDevice时被打断,其他线程欲NdisMRegisterDevice时见到ControlDeviceState,也就只能等待或失败了。

这里笔者曾试想把PtRegisterDevice放到DriverEntry中,把PtDeregisterDevice放到PtUnload里,但是这样当停止中间层驱动的时候,中间某部分会停住,并不会执行到PtUnload,应该与NdisMRegisterDevice的实现机制有关。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 288
活跃值: (212)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
2
谢谢,拿走,以后再仔细看
2013-2-7 19:01
0
雪    币: 14
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
正在研究这块,拿来看看!
2014-7-11 10:19
0
雪    币: 2375
活跃值: (433)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
研究得怎么样了?
2014-8-27 08:57
0
游客
登录 | 注册 方可回帖
返回
//