NDIS小端口驱动ndisEdge学习二——小端口驱动的初始化
目录
1 首先进入DriverEntry检查版本号(可选)
2 WDF_NO_EVENT_CALLBACK初始化驱动标志
3 设置WdfDriverInitNoDispatchOverride表示框架不能拦截IO直接发给驱动的Irps
4 创建WDFDriver对象
5 初始化一个包装句柄(Wrapper Handler)
6 填写小端口特征
7 注册小端口 其中因为要保护全局变量 所以需要有一个锁 另外需要有一个链表储存需要的信息 所以要初始化它们
8 小端口驱动的Adapter结构
9 配置信息的读取
10 设置适配器上下文(adapter context)
11 最后 MPInitialize的实现以及MPHalt的实现
1 首先进入DriverEntry检查版本号(可选)
// 检查版本号。这里主版本号为5,次版本号为0,要求最低版本为5.0if (NdisGetVersion() < ((MP_NDIS_MAJOR_VERSION << 16) | MP_NDIS_MINOR_VERSION)
{DEBUGP(MP_ERROR, ("This version of driver is not support on this OS\n"));
// 如果版本太低,则直接返回失败即可。return NDIS_STATUS_FAILURE;
}
2 WDF_NO_EVENT_CALLBACK初始化驱动标志
WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
3 设置WdfDriverInitNoDispatchOverride表示框架不能拦截IO直接发给驱动的Irps
具体参考WDF_DRIVER_INIT_FLAGS枚举
config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
4 创建WDFDriver对象
ntStatus = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&config,WDF_NO_HANDLE);if (!NT_SUCCESS(ntStatus)){DEBUGP(MP_ERROR, ("WdfDriverCreate failed\n"));return NDIS_STATUS_FAILURE;}
5 初始化一个包装句柄(Wrapper Handler)
NDIS使用这个包装句柄来管理小端口的配置信息,但是我们不需要调用这个句柄获取任何信息,只是需要持有它来管理API调用
// 初始化包装句柄。这个句柄是注册小端口必须的。但是对小端口// 驱动的开发者而言,除了调用一些NDIS函数需要提供这个句柄之// 外,并没有什么实质的意义。NdisMInitializeWrapper(&NdisWrapperHandle,DriverObject,RegistryPath,NULL);if (!NdisWrapperHandle){DEBUGP(MP_ERROR, ("NdisMInitializeWrapper failed\n"));return NDIS_STATUS_FAILURE;}
6 填写小端口特征
// 然后开始填写小端口特征。MPChar.MajorNdisVersion = MP_NDIS_MAJOR_VERSION;MPChar.MinorNdisVersion = MP_NDIS_MINOR_VERSION;MPChar.InitializeHandler = MPInitialize;MPChar.HaltHandler = MPHalt;MPChar.SetInformationHandler = MPSetInformation;MPChar.QueryInformationHandler = MPQueryInformation;MPChar.SendPacketsHandler = MPSendPackets;MPChar.ReturnPacketHandler = MPReturnPacket;MPChar.ResetHandler = NULL;//MPReset;MPChar.CheckForHangHandler = MPCheckForHang; //optional
#ifdef NDIS51_MINIPORTMPChar.CancelSendPacketsHandler = MPCancelSendPackets;MPChar.PnPEventNotifyHandler = MPPnPEventNotify;MPChar.AdapterShutdownHandler = MPShutdown;
#endifDEBUGP(MP_LOUD, ("Calling NdisMRegisterMiniport...\n"));
7 注册小端口 其中因为要保护全局变量 所以需要有一个锁 另外需要有一个链表储存需要的信息 所以要初始化它们
另外为了释放这些全局资源,防止内存泄露 还需要注册一个Unload函数在驱动卸载的时候调用
// 注册小端口。注意需要包装句柄与小端口特征。Status = NdisMRegisterMiniport(NdisWrapperHandle,&MPChar,sizeof(NDIS_MINIPORT_CHARACTERISTICS));if (Status != NDIS_STATUS_SUCCESS) {DEBUGP(MP_ERROR, ("Status = 0x%08x\n", Status));NdisTerminateWrapper(NdisWrapperHandle, NULL);} else {// 初始化全局变量。这些全局变量是在整个驱动中使用的NdisAllocateSpinLock(&GlobalData.Lock);NdisInitializeListHead(&GlobalData.AdapterList);// 注册一个Unload函数。请注意Unload是整个驱动卸载的时候调用。// 而协议特征中的MPHalt则是每个实例(网卡)卸载的时候调用的。NdisMRegisterUnloadHandler(NdisWrapperHandle, MPUnload);}
到这里 小端口DriverEntry就结束了,逻辑很简单 和协议驱动完全一致
下面就是DriverEntry中提到的链表和锁结构介绍
8 小端口驱动的Adapter结构
一个小端口驱动对应一个网卡(物理或者虚拟均可) 这个结构包含了我们需要的所有信息,所以部分回调函数会使用这个结构作为形参,
而且一台电脑上可能会有多块网卡(物理或虚拟的),小端口需要为每个网卡设置一个Adapter结构保存相关信息,这就是为什么需要链表(存储信息)以及锁(同步)的原因
结构太长可以不看
我们只需要知道这个结构包含;链表结点、引用计数、锁、事件、物理设备和功能设备、缓冲池、句柄、适配器名字等信息
typedef struct _MP_ADAPTER
{LIST_ENTRY List;LONG RefCount;NDIS_SPIN_LOCK Lock;NDIS_EVENT InitEvent;NDIS_EVENT HaltEvent;//// Keep track of various device objects.//PDEVICE_OBJECT Pdo;PDEVICE_OBJECT Fdo;PDEVICE_OBJECT NextDeviceObject;WDFDEVICE WdfDevice;NDIS_HANDLE AdapterHandle;WCHAR AdapterName[NIC_ADAPTER_NAME_SIZE];WCHAR AdapterDesc[NIC_ADAPTER_NAME_SIZE];ULONG Flags;UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS];UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS];WDFWORKITEM WorkItemForNdisRequest;BOOLEAN Promiscuous;BOOLEAN RequestPending;BOOLEAN ResetPending;BOOLEAN IsHardwareDevice;BOOLEAN IsTargetSupportChainedMdls;//// Variables to track resources for the send operation//NDIS_HANDLE SendBufferPoolHandle;LIST_ENTRY SendFreeList;LIST_ENTRY SendWaitList;LIST_ENTRY SendBusyList;PUCHAR TCBMem;LONG nBusySend;NDIS_SPIN_LOCK SendLock;//// Variables to track resources for the Receive operation//LIST_ENTRY RecvFreeList;LIST_ENTRY RecvBusyList;NDIS_SPIN_LOCK RecvLock;LONG nBusyRecv;NDIS_HANDLE RecvPacketPoolHandle;NDIS_HANDLE RecvBufferPoolHandle;PUCHAR RCBMem;WDFWORKITEM ReadWorkItem;WDFWORKITEM ExecutiveCallbackWorkItem;LONG IsReadWorkItemQueued;//// Packet Filter and look ahead size.//ULONG PacketFilter;ULONG ulLookAhead;ULONG ulLinkSpeed;// multicast listULONG ulMCListSize;UCHAR MCList[NIC_MAX_MCAST_LIST][ETH_LENGTH_OF_ADDRESS];// Packet countsULONG64 GoodTransmits;ULONG64 GoodReceives;ULONG NumTxSinceLastAdjust;// Count of transmit errorsULONG TxAbortExcessCollisions;ULONG TxLateCollisions;ULONG TxDmaUnderrun;ULONG TxLostCRS;ULONG TxOKButDeferred;ULONG OneRetry;ULONG MoreThanOneRetry;ULONG TotalRetries;ULONG TransmitFailuresOther;// Count of receive errorsULONG RcvCrcErrors;ULONG RcvAlignmentErrors;ULONG RcvResourceErrors;ULONG RcvDmaOverrunErrors;ULONG RcvCdtFrames;ULONG RcvRuntErrors;//// Talking to NDISPROT protocol//HANDLE FileHandle;PFILE_OBJECT FileObject;WDFIOTARGET IoTarget;UCHAR PhyNicMacAddress[ETH_LENGTH_OF_ADDRESS];PCALLBACK_OBJECT CallbackObject;PVOID CallbackRegisterationHandle;WDFREQUEST StatusIndicationRequest;NDISPROT_INDICATE_STATUS NdisProtIndicateStatus;WDFMEMORY WdfStatusIndicationBuffer;//// Statistic for debugging & validation purposes//ULONG nReadsPosted;ULONG nReadsCompletedWithError;ULONG nPacketsIndicated;ULONG nPacketsReturned;ULONG nBytesRead;ULONG nPacketsArrived;ULONG nWritesPosted;ULONG nWritesCompletedWithError;ULONG nBytesArrived;ULONG nBytesWritten;ULONG nReadWorkItemScheduled;
} MP_ADAPTER, *PMP_ADAPTER;
9 配置信息的读取
配置信息读取是在NICReadRegParameters中实现的,这个函数又是在MPInitialize中被调用。
而实现的主要步骤是利用NdisOpneConfiguration函数打开包装句柄,然后利用NdisReadConfiguration函数读取信息
NDIS_STATUS
NICReadRegParameters(PMP_ADAPTER Adapter,NDIS_HANDLE WrapperConfigurationContext)
/*++
Routine Description:Read device configuration parameters from the registryArguments:Adapter Pointer to our adapterWrapperConfigurationContext For use by NdisOpenConfigurationShould be called at IRQL = PASSIVE_LEVEL.Return Value:NDIS_STATUS_SUCCESSNDIS_STATUS_FAILURENDIS_STATUS_RESOURCES--*/
{NDIS_STATUS Status = NDIS_STATUS_SUCCESS;NDIS_HANDLE ConfigurationHandle;PUCHAR NetworkAddress;UINT Length;PUCHAR pAddr;PNDIS_CONFIGURATION_PARAMETER pParameterValue;NDIS_STRING strMiniportName = NDIS_STRING_CONST("MiniportName");NDIS_STRING strFilterName = NDIS_STRING_CONST("Promiscuous");DEBUGP(MP_TRACE, ("--> NICReadRegParameters\n"));PAGED_CODE();//// Open the registry for this adapter to read advanced// configuration parameters stored by the INF file.//NdisOpenConfiguration(&Status,&ConfigurationHandle,WrapperConfigurationContext);if (Status != NDIS_STATUS_SUCCESS){DEBUGP(MP_ERROR, ("NdisOpenConfiguration failed\n"));return NDIS_STATUS_FAILURE;}do{//// Read the Miniport Name.// This feature is available only XP and above.//NdisReadConfiguration(&Status,&pParameterValue,ConfigurationHandle,&strMiniportName,NdisParameterString);if (Status != NDIS_STATUS_SUCCESS) {DEBUGP(MP_ERROR, ("NdisReadConfiguration for miniport name failed\n"));} else {Length = min(NIC_ADAPTER_NAME_SIZE-1,pParameterValue->ParameterData.StringData.Length/sizeof(WCHAR));RtlStringCchCopyW(Adapter->AdapterName, Length+1,(PWCHAR)pParameterValue->ParameterData.StringData.Buffer);}//// Read the Promiscuous filter value.//NdisReadConfiguration(&Status,&pParameterValue,ConfigurationHandle,&strFilterName,NdisParameterInteger);if (Status != NDIS_STATUS_SUCCESS){DEBUGP(MP_ERROR, ("NdisReadConfiguration for promiscuous key failed\n"));break;}Adapter->Promiscuous = (BOOLEAN)pParameterValue->ParameterData.IntegerData;} WHILE (FALSE);
10 设置适配器上下文(adapter context)
适配器上下文是一个指针,这个指针指向的空间就是适配器结构,这个指针必须在MPInitialize中设置好,然后在多个小端口特征中的回调函数中作为实参传入,而设置适配器上下文是通过NdisMSetAttributesEx这个NDIS内核API函数做到的
这个函数原型如下:
VOID NdisMSetAttributesEx(_In_ NDIS_HANDLE MiniportAdapterHandle,_In_ NDIS_HANDLE MiniportAdapterContext,_In_opt_ UINT CheckForHangTimeInSeconds,_In_ ULONG AttributeFlags,_In_opt_ NDIS_INTERFACE_TYPE AdapterType
);
对于形参的解释请参考MSDN
11 最后 MPInitialize的实现以及MPHalt的实现
MPInitialize就是对应小端口特征中的InitializeHandler特征的回调函数
这个函数在发现每个实例(网卡)时被Windows内核调用,因此我们应该在这个函数中实现对adapter结构的初始化
另外需要在这个回调中生成一个小端口设备对象
然后就是MPHalt,这个回调负责网卡被拔出或者停止工作时负责释放所有资源,在MPHalt中有一个MPShutdown函数,在MPSHoutdown中完成关闭网卡硬件等操作:
1 释放并解除所有映射过的IO端口的映射
2 取消注册的所有中断
NDIS小端口驱动ndisEdge学习二——小端口驱动的初始化相关推荐
- JAVA小项目实例源码—学习娱乐小助手
代码地址如下: http://www.demodashi.com/demo/11456.html 一.程序实现 项目目录: MyJFrame:实现项目界面样式: AppProcess:实现调用api或 ...
- 友盟分享小程序_在线学习应用“小打卡”小程序分享
目前疫情导致只能线上开学,多采用微信群或QQ群发布作业.打卡,结合直播平台在线授课.各科老师加入群,打卡及发布的作业.教师辅导信息容易覆盖同时不能记录下来. 在以上应用不变的情况下,应用"小 ...
- 超值的收藏得Python 100个小技巧,入门学习必备小知识
前言 大家早好.午好.晚好吖 ❤ ~ 我给大家准备了一些资料,包括: 2022最新Python视频教程.Python电子书10个G (涵盖基础.爬虫.数据分析.web开发.机器学习.人工智能.面试题) ...
- Linux USB 驱动开发(二)—— USB 驱动几个重要数据结构
前面我们学习了USB 驱动的一个描述符,下面来学习 USB 驱动的几个重要数据结构 一.struct usb_interface 接口函数 [cpp] view plaincopy struct u ...
- Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发
前面在Exynos4412 IIC总线驱动开发(一)-- IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程 首先看一张代码层次图,有助于我们的理解 上面这些代码的展 ...
- Linux驱动开发学习笔记-电容触摸屏驱动
<电容触摸屏驱动框架> 电容触摸屏驱动其实是以下几种 linux 驱动框架的组合: ① IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动. ...
- 1.5万字详述 | 全开源:python写小游戏+AI强化学习与传统DFS/BFS控制分别实现
简介:本周的强化学习我们来到实践部分.我以我在 GitHub 上开源的项目 PiperLiu / Amazing-Brick-DFS-and-DRL 为对象,从零开始与各位朋友分享:如何用 pytho ...
- 深度学习之小目标检测
深度学习之小目标检测深度学习之小目标检测深度学习之小目标检测 百度网盘 提取码:1234 1.<小目标检测技术研究综述_梁鸿> 小目标检测是针对图像中像素占比少的目标,借助计算机视觉在图像 ...
- 无限制端口服务器,怎样限制服务器的端口
Window XP自带了"TCP/IP筛选"功能即可限制服务器的端口.下面学习啦小编整理了限制服务器的端口的解决方法,供你参考. 限制服务器的端口的解决方法 打开"网络连 ...
最新文章
- 各种flash的不同
- (基础篇)PHP字符串函数
- Java容器--Map
- Python编程基础:第四十三节 多继承Multiple Inheritance
- Tomcat【环境搭建 02】Web端403 Access Denied You are not authorized to view this page解决方法(Tomcat 10.2.12 版本)
- linux获取ad用户列表,Powershell小技巧之查询AD用户
- nagios监控-多用户管理
- 杭电60题--part 1 HDU1003 Max Sum(DP 动态规划)
- 16位调色板和32位调色板_使调色板可访问
- pythonfillcolor_openpyxl 填充颜色(单元格)
- SpringBoot精选项目
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):目录
- 私有网络解决方案Start9 Labs完成120万美元融资,以推动其硬件Embassy后续发展
- 【个人笔记】OpenCV4 C++ 快速入门 04课
- shell初学之nginx(负载均衡)
- 大数据技术原理与应用-林子雨版-课后习题答案
- python强制删除文件夹_python删除文件夹下的文件保留但清空子文件夹
- 2019计算机专业英语国家线,2019英语一国家线多少
- [Android]网页内图片点击查看大图/识别二维码/下载
- 【uni-app】基础