/*++

    Copyright (c) Microsoft Corporation.  All rights reserved.

Rule Name:

    PeriodicTimer

Domain:

    ndis

Rule ID:

    Not Applicable

Description:

    The PeriodicTimer rule specifies that the caller of NdisCancelTimerObject must be running at IRQL = PASSIVE_LEVEL 
    if a nonzero value was specified in the MillisecondsPeriod parameter of the NdisSetTimerObject function. 
    If the MillisecondsPeriod parameter of the NdisSetTimerObject function was zero, 
    callers of NdisCancelTimerObject can be running at IRQL <= DISPATCH_LEVEL.
    
        NdisCancelTimer is called at IRQL <= DISPATCH_LEVEL 
            if the timer IS NOT a periodic timer (MillisecondsPeriod = 0 in NdisSetTimerObject call)
                
        NdisCancelTimer is called at IRQL = PASSIVE_LEVEL
            if the timer IS a periodic timer (MillisecondsPeriod > 0 ), in this case the Timer is a "periodic timer"
    
    Related Rule:

Help Link:

    https://go.microsoft.com/fwlink/?LinkId=507208

--*/




#include "slic_base.h"

state{
   enum {normalTimer, periodicTimer} t = normalTimer;
} 

NdisSetTimerObject.exit
{
    if ($1 == g_TimerObject)
    {
      if ($3 == 0) {
          t = normalTimer;
      }
      else if ($3 > 0) {
          t = periodicTimer;
      } 
      else
      {
        abort "Invalid parameter passed to $fname";
      }
    }
   
}

NdisCancelTimerObject.entry
{
    if ($1 == g_TimerObject)
    {
      if ((t == periodicTimer) && (sdv_irql_current != PASSIVE_LEVEL))
      {
          abort "Periodic timer must be cancelled at IRQL = PASSIVE";
      }
      else if ((t == normalTimer) && SDV_IRQL_ELEVATED_LEVEL(sdv_irql_current))
      {
          abort "Non-periodic timer must be cancelled at IRQL <= DISPATCH";
      } 
    }
}
