利用同步事件实现驱动主动通知应用

时间:2022-10-25 05:52:57

一、初始化 NDIS 定时器

任何NDIS驱动程序都可以有多个定时器,可以是一次性或周期性的。NDIS_TIMER_CHARACTERISTICS结构定义了定时器的若干属性,其中一项是NetTimerCallback函数入口。当定时器到期时,NDIS调用NetTimerCallback函数执行定时任务。

  • 初始化定时器:调用NdisAllocateTimerObject函数,传入自己定义的NDIS_TIMER_CHARACTERISTICS结构
  • 启动定时器:调用NdisSetTimerObject函数
  • 释放定时器:调用NdisFreeTimerObject函数

其中,NdisAllocateTimerObject函数原型为:

NDIS_STATUS NdisAllocateTimerObject(
  _In_  NDIS_HANDLE                 NdisHandle,
  _In_  PNDIS_TIMER_CHARACTERISTICS TimerCharacteristics,
  _Out_ PNDIS_HANDLE                pTimerObject
);

二、启动和清除定时器

利用NdisSetTimerObject函数可令驱动程序在指定的时间间隔或定期之后触发定时任务函数,其函数原型为:

BOOLEAN NdisSetTimerObject(
  _In_     NDIS_HANDLE   TimerObject,
  _In_     LARGE_INTEGER DueTime,
  _In_opt_ LONG          MillisecondsPeriod,
  _In_opt_ PVOID         FunctionContext
);

DueTime参数指定计时器到期的绝对或相对时间。如果为负值,则到期时间是相对于当前系统时间;否则,到期时间是绝对的。到期时间以系统时间单位(100纳秒间隔)表示。绝对到期时间跟踪系统时间的任何变化;相对过期时间不受系统时间变化的影响。

MillisecondsPeriod参数指定定时器的可选重复间隔(以毫秒为单位)。若大于或等于零,则定时器以该间隔周期性触发;若为零,则为非周期性定时器。(参考自 KeSetTimerEx 函数)

给出一些KeSetTimerEx函数的示例:

LARGE_INTEGER duetime = {0};
#define POLLING_INTERVAL 3000
// KeSetTimer(&my_timer,timeout,&KiTimerExpireDpc); // 仅仅只能设置一次 
// KeSetTimerEx(&my_timer, timeout, period, &KiTimerExpireDpc); // 这个可以循环设置 
KeSetTimerEx(&device_extension->my_timer, duetime, POLLING_INTERVAL, &deviceEx->KiTimerDpc);  
// KeSetTimerEx语句启动周期定时器。由于duetime参数是0,所以定时器立即进入信号态。然后每隔POLLING_INTERVAL=3秒触发一次。

调用NdisCancelTimerObject函数可取消之前调用NdisSetTimerObject函数设置的定时器。如果在调用NdisCancelTimerObject之前定时已经到时,则NDIS可能仍会调用NetTimerCallback

关于NdisSetTimerObject函数的更多信息,请参考 KeSetTimerEx 函数的介绍。

三、定时任务函数

定时器触发时,NDIS调用NetTimerCallback函数,其函数原型为:

NDIS_TIMER_FUNCTION NdisTimerFunction;

void NdisTimerFunction(
  PVOID SystemSpecific1,
  PVOID FunctionContext,
  PVOID SystemSpecific2,
  PVOID SystemSpecific3
)
{...}

FunctionContext参数指向驱动上下文,FunctionContext的默认值在NDIS_TIMER_CHARACTERISTICS结构中指定。值得注意的是,驱动在调用NdisSetTimerObject函数时,仍可传入一个FunctionContext参数。如此时传入了非 NULL 值,则该值会传给NetTimerCallback函数;否则,将传入NDIS_TIMER_CHARACTERISTICS结构中指定的默认值。

任何 NDIS 驱动程序都可以有多个NetTimerCallback函数,每个这样的NetTimerCallback函数都必须与不同的驱动程序初始化的定时器关联。

如果NetTimerCallback函数与其他函数共享驱动资源,则应使用自旋锁来同步对这些资源的访问。

四、Microsoft 文档链接

  1. 数据结构:NDIS_TIMER_CHARACTERISTICS
  2. 调用函数:NdisAllocateTimerObjectNdisSetTimerObjectNdisCancelTimerObjectNdisFreeTimerObject
  3. 要实现的函数:NetTimerCallback

参考链接:

  1. 关于内核定时器,DPC,线程的使用
  2. Github - Microsoft - NDIS Virtual Miniport Driver

欢迎来我的 Git Pages 博客交流,本文最早发布于 http://hoxz.me/2018/04/22/ndis-timer-implement