目录

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学习二——小端口驱动的初始化相关推荐

  1. JAVA小项目实例源码—学习娱乐小助手

    代码地址如下: http://www.demodashi.com/demo/11456.html 一.程序实现 项目目录: MyJFrame:实现项目界面样式: AppProcess:实现调用api或 ...

  2. 友盟分享小程序_在线学习应用“小打卡”小程序分享

    目前疫情导致只能线上开学,多采用微信群或QQ群发布作业.打卡,结合直播平台在线授课.各科老师加入群,打卡及发布的作业.教师辅导信息容易覆盖同时不能记录下来. 在以上应用不变的情况下,应用"小 ...

  3. 超值的收藏得Python 100个小技巧,入门学习必备小知识

    前言 大家早好.午好.晚好吖 ❤ ~ 我给大家准备了一些资料,包括: 2022最新Python视频教程.Python电子书10个G (涵盖基础.爬虫.数据分析.web开发.机器学习.人工智能.面试题) ...

  4. Linux USB 驱动开发(二)—— USB 驱动几个重要数据结构

    前面我们学习了USB 驱动的一个描述符,下面来学习 USB 驱动的几个重要数据结构 一.struct usb_interface  接口函数 [cpp] view plaincopy struct u ...

  5. Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发

    前面在Exynos4412 IIC总线驱动开发(一)-- IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程 首先看一张代码层次图,有助于我们的理解 上面这些代码的展 ...

  6. Linux驱动开发学习笔记-电容触摸屏驱动

    <电容触摸屏驱动框架> 电容触摸屏驱动其实是以下几种 linux 驱动框架的组合: ① IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动. ...

  7. 1.5万字详述 | 全开源:python写小游戏+AI强化学习与传统DFS/BFS控制分别实现

    简介:本周的强化学习我们来到实践部分.我以我在 GitHub 上开源的项目 PiperLiu / Amazing-Brick-DFS-and-DRL 为对象,从零开始与各位朋友分享:如何用 pytho ...

  8. 深度学习之小目标检测

    深度学习之小目标检测深度学习之小目标检测深度学习之小目标检测 百度网盘 提取码:1234 1.<小目标检测技术研究综述_梁鸿> 小目标检测是针对图像中像素占比少的目标,借助计算机视觉在图像 ...

  9. 无限制端口服务器,怎样限制服务器的端口

    Window XP自带了"TCP/IP筛选"功能即可限制服务器的端口.下面学习啦小编整理了限制服务器的端口的解决方法,供你参考. 限制服务器的端口的解决方法 打开"网络连 ...

最新文章

  1. 各种flash的不同
  2. (基础篇)PHP字符串函数
  3. Java容器--Map
  4. Python编程基础:第四十三节 多继承Multiple Inheritance
  5. Tomcat【环境搭建 02】Web端403 Access Denied You are not authorized to view this page解决方法(Tomcat 10.2.12 版本)
  6. linux获取ad用户列表,Powershell小技巧之查询AD用户
  7. nagios监控-多用户管理
  8. 杭电60题--part 1 HDU1003 Max Sum(DP 动态规划)
  9. 16位调色板和32位调色板_使调色板可访问
  10. pythonfillcolor_openpyxl 填充颜色(单元格)
  11. SpringBoot精选项目
  12. C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):目录
  13. 私有网络解决方案Start9 Labs完成120万美元融资,以推动其硬件Embassy后续发展
  14. 【个人笔记】OpenCV4 C++ 快速入门 04课
  15. shell初学之nginx(负载均衡)
  16. 大数据技术原理与应用-林子雨版-课后习题答案
  17. python强制删除文件夹_python删除文件夹下的文件保留但清空子文件夹
  18. 2019计算机专业英语国家线,2019英语一国家线多少
  19. [Android]网页内图片点击查看大图/识别二维码/下载
  20. 【uni-app】基础

热门文章

  1. spring的@Value注解使用
  2. Java技术栈学习路线
  3. 红帽考试RHCSA练习
  4. C和C++中的register变量和volatile变量理解
  5. 简单面试题,但是容易忘记
  6. 多线程与高并发day04
  7. 非门,NOT Gate
  8. python: 七段数码管
  9. 计算机用word做海报,用Word设计制作广告海报实验.doc
  10. 这份 pip 使用方法,应该算是全网最全了