Sample Code

windows driver samples/ Windows Filtering Platform Sample/ C++/ syslib/ HelperFunctions_Headers.cpp/

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//   Copyright (c) 2012 Microsoft Corporation.  All Rights Reserved.
//
//   Module Name:
//      HelperFunctions_Headers.cpp
//
//   Abstract:
//      This module contains kernel helper functions that assist with IP and Transport header 
//         operations.
//
//   Naming Convention:
//
//      <Module><Object><Action><Modifier>
//  
//      i.e.
//
//       KrnlHlprIPHeaderCalculateV4Checksum
//
//       <Module>
//          KrnlHlpr               -       Function is located in syslib\ and applies to kernel mode.
//       <Object>
//          {
//            IPHeader             -       Function pertains to the network's IP_HEADER.
//            ICMPv4Header         -       Function pertains to the transport's ICMPV4_HEADER.
//            ICMPv6Header         -       Function pertains to the transport's ICMPV6_HEADER.
//            TCPHeader            -       Function pertains to the transport's TCP_HEADER.
//            UDPHeader            -       Function pertains to the transport's UDP_HEADER.
//          }
//       <Action>
//          {
//             Calculate           -       Function performs a computation on the header.
//             Modify              -       Function changes the field to the provided value.
//          }
//       <Modifier>
//          {
//             Code                -       Function acts on the ICMP Code Field.
//             Destination Address -       Function acts on the IP Destination Address Field.
//             Destination Port    -       Function acts on the TCP / UDP Destination Port Field.
//             Source Address      -       Function acts on the IP Source Address Field.
//             Source Port         -       Function acts on the TCP / UDP Source Port Field.
//             Type                -       Function acts on the ICMP Type Field.
//             V4Checksum          -       Function pertains to IPv4 packets and its Checksum Field.
//          }
//
//   Private Functions:
//
//   Public Functions:
//      KrnlHlprICMPv4HeaderModifyCode(),
//      KrnlHlprICMPv4HeaderModifyType(),
//      KrnlHlprICMPv6HeaderModifyCode(),
//      KrnlHlprICMPv6HeaderModifyType(),
//      KrnlHlprIPHeaderCalculateV4Checksum(),
//      KrnlHlprIPHeaderDestroy(),
//      KrnlHlprIPHeaderGet(),
//      KrnlHlprIPHeaderGetProtocolField(),
//      KrnlHlprIPHeaderModifyDestinationAddress(),
//      KrnlHlprIPHeaderModifyLoopbackToLocal(),
//      KrnlHlprIPHeaderModifySourceAddress(),
//      KrnlHlprMACHeaderDestroy(),
//      KrnlHlprMACHeaderGet(),
//      KrnlHlprMACHeaderModifyDestinationAddress(),
//      KrnlHlprMACHeaderModifySourceAddress(),
//      KrnlHlprTCPHeaderModifyDestinationPort(),
//      KrnlHlprTCPHeaderModifySourcePort(),
//      KrnlHlprUDPHeaderModifyDestinationPort(),
//      KrnlHlprUDPHeaderModifySourcePort(),
//
//   Author:
//      Dusty Harper      (DHarper)
//
//   Revision History:
//
//      [ Month ][Day] [Year] - [Revision]-[ Comments ]
//      May       01,   2010  -     1.0   -  Creation
//
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "HelperFunctions_Include.h"   /// .
#include "HelperFunctions_Headers.tmh" /// $(OBJ_PATH)\$(O)\

/**
 @private_kernel_helper_function="PrvKrnlHlprCopyBufferToMDL"
 
   Purpose:  Copy a flat buffer into an MDL chain.                                              <br>
                                                                                                <br>
   Notes:                                                                                       <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
NTSTATUS PrvKrnlHlprCopyBufferToMDL(_In_reads_(bytesToCopy) const BYTE* pBuffer,
                                    _In_ PMDL pMDL,
                                    _In_ SIZE_T mdlOffset,
                                    _In_ SIZE_T bytesToCopy,
                                    _Out_ SIZE_T* pBytesCopied)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> PrvKrnlHlprCopyBufferToMDL()\n");

#endif /// DBG

   NTSTATUS status               = STATUS_SUCCESS;
   SIZE_T   mdlByteCount         = 0;
   SIZE_T   remainingBytesToCopy = bytesToCopy;
   SIZE_T   copySize             = 0;

   *pBytesCopied = 0;

   if(MmGetMdlByteCount(pMDL) >= mdlOffset + bytesToCopy)
   {
      BYTE* pSystemAddress = 0;

      pSystemAddress = (BYTE*)MmGetSystemAddressForMdlSafe(pMDL,
                                                           LowPagePriority);
      if(pSystemAddress)
      {
         RtlCopyMemory(pSystemAddress + mdlOffset,
                       pBuffer,
                       bytesToCopy);

         remainingBytesToCopy = 0;

         HLPR_BAIL;
      }
   }

   /// Skip over the offset in the MDL chain
   for(mdlByteCount = MmGetMdlByteCount(pMDL);
       pMDL &&
       mdlOffset >= mdlByteCount;
       mdlByteCount = MmGetMdlByteCount(pMDL))
   {
      mdlOffset -= mdlByteCount;

      pMDL = pMDL->Next;
   }

   /// Copy data while there are MDLs to walk and data to copy
   for(;
       pMDL &&
       remainingBytesToCopy > 0;
       pMDL = pMDL->Next)
   {
      BYTE* pSystemAddress = 0;
  
      mdlByteCount = MmGetMdlByteCount(pMDL);
      if(mdlByteCount)
      {
         ASSERT(mdlOffset < mdlByteCount);

         mdlByteCount -= mdlOffset;

         copySize = min(remainingBytesToCopy,
                        mdlByteCount);  

         pSystemAddress = (BYTE*)MmGetSystemAddressForMdlSafe(pMDL,
                                                              LowPagePriority);
         if(pSystemAddress)
         {
            RtlCopyMemory(pSystemAddress + mdlOffset,
                          pBuffer,
                          copySize);

            pBuffer += copySize;

            remainingBytesToCopy -= copySize;

            mdlOffset = 0;
         }
         else
         {  
            status = STATUS_INSUFFICIENT_RESOURCES;

            HLPR_BAIL;
         }
      }
   }  

   HLPR_BAIL_LABEL:
  
   *pBytesCopied = bytesToCopy - remainingBytesToCopy;

   ASSERT(*pBytesCopied <= bytesToCopy);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- PrvKrnlHlprCopyBufferToMDL() [status: %#x]\n",
              status);

#endif /// DBG

   return status;
}

#ifndef MAC_HEADER____
#define MAC_HEADER____

/**
 @kernel_helper_function="KrnlHlprMACHeaderDestroy"
 
   Purpose:  Frees the allocated memory indicated in KrnlMACHeaderGet().                        <br>
                                                                                                <br>
   Notes:                                                                                       <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_At_(*ppMACHeader, _Pre_ _Notnull_)
_At_(*ppMACHeader, _Post_ _Null_)
_Success_(*ppMACHeader == 0)
inline VOID KrnlHlprMACHeaderDestroy(_Inout_ VOID** ppMACHeader)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprMACHeaderDestroy()\n");

#endif /// DBG
   
   NT_ASSERT(ppMACHeader);

   HLPR_DELETE_ARRAY(*ppMACHeader,
                     WFPSAMPLER_SYSLIB_TAG);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprMACHeaderDestroy()\n");

#endif /// DBG

   return;
}

/**
 @kernel_helper_function="KrnlHlprMACHeaderGet"
 
   Purpose:  Retrieve a pointer to the MAC Header from the NET_BUFFER_LIST.                     <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the MAC Header.                                 <br>
                                                                                                <br>
             Function is overloaded.                                                            <br>
                                                                                                <br>
             If needToFreeMemory is TRUE, caller should call KrnlHlprMACHeaderDestroy() when 
                finished  with the header.                                                      <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppMACHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppMACHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprMACHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                              _Outptr_ VOID** ppMACHeader,
                              _Inout_ BOOLEAN* pNeedToFreeMemory,
                              _In_ UINT32 macHeaderSize)            /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprMACHeaderGet()\n");

#endif /// DBG
   
   NT_ASSERT(pNetBufferList);
   NT_ASSERT(ppMACHeader);
   NT_ASSERT(pNeedToFreeMemory);

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = macHeaderSize ? macHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprMACHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  bytesNeeded,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprMACHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppMACHeader = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprMACHeaderDestroy((VOID**)&pBuffer);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprMACHeaderGet() [status: %#x]\n",
              status);

#endif /// DBG

   return status;
}

/**
 @kernel_helper_function="KrnlHlprMACHeaderModifySourceAddress"
 
   Purpose:  Set the Source Address field in the MAC Header to the provided value.              <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the MAC 
             Header.                                                                            <br>
                                                                                                <br>
             Assumes the Header is and Ethernet Header.                                         <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprMACHeaderModifySourceAddress(_In_ const FWP_VALUE* pValue,
                                              _Inout_ NET_BUFFER_LIST* pNetBufferList)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprMACHeaderModifySourceAddress()\n");

#endif /// DBG

   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS            status          = STATUS_SUCCESS;
   VOID*               pMACHeader      = 0;
   BOOLEAN             needToFree      = FALSE;
   ETHERNET_II_HEADER* pEthernetHeader = 0;

   status = KrnlHlprMACHeaderGet(pNetBufferList,
                                 &pMACHeader,
                                 &needToFree);
   HLPR_BAIL_ON_FAILURE(status);

   pEthernetHeader = (ETHERNET_II_HEADER*)pMACHeader;

   RtlCopyMemory(pEthernetHeader->pSourceAddress,
                 pValue->byteArray6->byteArray6,
                 ETHERNET_ADDRESS_SIZE);

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = sizeof(ETHERNET_II_HEADER);
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pEthernetHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprMACHeaderDestroy(&pMACHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprMACHeaderModifySourceAddress() [status: %#x]\n",
              status);

#endif /// DBG

   return status;
}

/**
 @kernel_helper_function="KrnlHlprMACHeaderModifyDestinationAddress"
 
   Purpose:  Set the Destination Address field in the MAC Header to the provided value.         <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the MAC 
             Header.                                                                            <br>
                                                                                                <br>
             Assumes the Header is and Ethernet Header.                                         <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprMACHeaderModifyDestinationAddress(_In_ const FWP_VALUE* pValue,
                                                   _Inout_ NET_BUFFER_LIST* pNetBufferList)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprMACHeaderModifyDestinationAddress()\n");

#endif /// DBG

   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS            status          = STATUS_SUCCESS;
   VOID*               pMACHeader      = 0;
   BOOLEAN             needToFree      = FALSE;
   ETHERNET_II_HEADER* pEthernetHeader = 0;

   status = KrnlHlprMACHeaderGet(pNetBufferList,
                                 &pMACHeader,
                                 &needToFree);
   HLPR_BAIL_ON_FAILURE(status);

   pEthernetHeader = (ETHERNET_II_HEADER*)pMACHeader;

   RtlCopyMemory(pEthernetHeader->pDestinationAddress,
                 pValue->byteArray6->byteArray6,
                 ETHERNET_ADDRESS_SIZE);

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = sizeof(ETHERNET_II_HEADER);
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pEthernetHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprMACHeaderDestroy(&pMACHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprMACHeaderModifyDestinationAddress() [status: %#x]\n",
              status);

#endif /// DBG

   return status;
}

#endif /// MAC_HEADER____

#ifndef IP_HEADER____
#define IP_HEADER____

/**
 @kernel_helper_function="KrnlHlprIPHeaderDestroy"
 
   Purpose:  Frees the allocated memory indicated in KrnlIPHeaderGet().                         <br>
                                                                                                <br>
   Notes:                                                                                       <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_At_(*ppIPHeader, _Pre_ _Notnull_)
_At_(*ppIPHeader, _Post_ _Null_)
_Success_(*ppIPHeader == 0)
inline VOID KrnlHlprIPHeaderDestroy(_Inout_ VOID** ppIPHeader)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderDestroy()\n");

#endif /// DBG
   
   NT_ASSERT(ppIPHeader);

   HLPR_DELETE_ARRAY(*ppIPHeader,
                     WFPSAMPLER_SYSLIB_TAG);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprIPHeaderDestroy()\n");

#endif /// DBG
   
   return;
}

/**
 @kernel_helper_function="KrnlHlprIPHeaderGet"
 
   Purpose:  Retrieve a pointer to the IP Header from the NET_BUFFER_LIST.                      <br>
                                                                                                <br>
   Notes:    Function is overloaded                            .                                <br>
                                                                                                <br>
             If needToFreeMemory is TRUE, caller should call KrnlHlprIPHeaderDestroy() when 
                finished  with the header.                                                      <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprIPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                             _In_ const FWPS_INCOMING_VALUES* pClassifyValues,
                             _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
                             _Outptr_ VOID** ppIPHeader,
                             _Inout_ BOOLEAN* pNeedToFreeMemory,
                             _Inout_opt_ FWP_DIRECTION* pDirection,               /* 0 */
                             _Inout_opt_ UINT32* pIPHeaderSize)                   /* 0 */
{
   NT_ASSERT(pNetBufferList);
   NT_ASSERT(pClassifyValues);
   NT_ASSERT(pMetadata);
   NT_ASSERT(ppIPHeader);
   NT_ASSERT(pNeedToFreeMemory);

   NTSTATUS      status              = STATUS_SUCCESS;
   UINT32        bytesRetreated      = 0;
   UINT32        bytesAdvanced       = 0;
   UINT32        ipHeaderSize        = 0;
   UINT32        transportHeaderSize = 0;
   FWP_DIRECTION direction           = FWP_DIRECTION_MAX;
   BOOLEAN       ipHeaderAvailable   = TRUE;

#if(NTDDI_VERSION >= NTDDI_WIN8)

   UINT32        ethernetHeaderSize  = 0;

   if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata,
                                        FWPS_L2_METADATA_FIELD_ETHERNET_MAC_HEADER_SIZE))
      ethernetHeaderSize = pMetadata->ethernetMacHeaderSize;

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_IP_HEADER_SIZE))
      ipHeaderSize = pMetadata->ipHeaderSize;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
      transportHeaderSize = pMetadata->transportHeaderSize;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_PACKET_DIRECTION))
      direction = pMetadata->packetDirection;

   switch(pClassifyValues->layerId)
   {
      case FWPS_LAYER_INBOUND_IPPACKET_V4:
      case FWPS_LAYER_INBOUND_IPPACKET_V6:
      {
         direction = FWP_DIRECTION_INBOUND;

         bytesRetreated = ipHeaderSize;

         break;
      }
      case FWPS_LAYER_INBOUND_IPPACKET_V4_DISCARD:
      case FWPS_LAYER_INBOUND_IPPACKET_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                           FWPS_METADATA_FIELD_DISCARD_REASON))
         {
            if(pMetadata->discardMetadata.discardModule == FWPS_DISCARD_MODULE_GENERAL &&
               pMetadata->discardMetadata.discardReason == FWPS_DISCARD_FIREWALL_POLICY)
               bytesRetreated = ipHeaderSize;
         }

         break;
      }
      case FWPS_LAYER_OUTBOUND_IPPACKET_V4:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V6:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         /// At the IP Header
   
         break;
      }
      case FWPS_LAYER_IPFORWARD_V4:
      case FWPS_LAYER_IPFORWARD_V4_DISCARD:
      case FWPS_LAYER_IPFORWARD_V6:
      case FWPS_LAYER_IPFORWARD_V6_DISCARD:
      {
         /// At the IP Header
   
         break;
      }
      case FWPS_LAYER_INBOUND_TRANSPORT_V4:
      case FWPS_LAYER_INBOUND_TRANSPORT_V4_DISCARD:
      case FWPS_LAYER_INBOUND_TRANSPORT_V6:
      case FWPS_LAYER_INBOUND_TRANSPORT_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         if(pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
            pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
            bytesRetreated = ipHeaderSize;
         else
            bytesRetreated = ipHeaderSize + transportHeaderSize;

         break;
      }
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         ipHeaderAvailable = FALSE;
   
         break;
      }
      case FWPS_LAYER_STREAM_V4:
      case FWPS_LAYER_STREAM_V4_DISCARD:
      case FWPS_LAYER_STREAM_V6:
      case FWPS_LAYER_STREAM_V6_DISCARD:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_DATAGRAM_DATA_V4:
      case FWPS_LAYER_DATAGRAM_DATA_V4_DISCARD:
      case FWPS_LAYER_DATAGRAM_DATA_V6:
      case FWPS_LAYER_DATAGRAM_DATA_V6_DISCARD:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
            bytesRetreated = ipHeaderSize;
         else
         {
            if(pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
               pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;
         }
   
         break;
      }
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V4:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V6:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         bytesRetreated = ipHeaderSize + transportHeaderSize;

         break;
      }
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         bytesRetreated = ipHeaderSize;

         break;
      }
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_AUTH_LISTEN_V4:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V6:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V6_DISCARD:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD:
      {
         if(direction == FWP_DIRECTION_OUTBOUND)
         {
            ipHeaderAvailable = FALSE;
         }
         else
         {
            if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
               pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;
         }

         break;
      }
      case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V6_DISCARD:
      {
         if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_TCP)
            ipHeaderAvailable = FALSE;
         else if(direction == FWP_DIRECTION_INBOUND)
            ipHeaderAvailable = FALSE;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
            bytesRetreated = ipHeaderSize;
         else
         {
            if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
               pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;
         }
   
         break;
      }

#if(NTDDI_VERSION >= NTDDI_WIN7)

      case FWPS_LAYER_NAME_RESOLUTION_CACHE_V4:
      case FWPS_LAYER_NAME_RESOLUTION_CACHE_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_RESOURCE_RELEASE_V4:
      case FWPS_LAYER_ALE_RESOURCE_RELEASE_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4:
      case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_CONNECT_REDIRECT_V4:
      case FWPS_LAYER_ALE_CONNECT_REDIRECT_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_BIND_REDIRECT_V4:
      case FWPS_LAYER_ALE_BIND_REDIRECT_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_STREAM_PACKET_V4:
      case FWPS_LAYER_STREAM_PACKET_V6:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
            bytesRetreated = ipHeaderSize;
         else
            bytesRetreated = ipHeaderSize + transportHeaderSize;

         break;
      }
   
#if(NTDDI_VERSION >= NTDDI_WIN8)
   
      case FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType != 0x86DD &&
            etherType != 0x0800)
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType == 0x86DD ||
            etherType == 0x0800)
            bytesAdvanced = ethernetHeaderSize;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE:
      case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INGRESS_VSWITCH_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType == 0x86DD ||
            etherType == 0x0800)
            bytesAdvanced = ethernetHeaderSize;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_EGRESS_VSWITCH_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_EGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType == 0x86DD ||
            etherType == 0x0800)
            bytesAdvanced = ethernetHeaderSize;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V4:
      case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V6:
      {
         /// At the IP Header

         break;
      }
      case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V4:
      case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V6:
      {
         /// At the IP Header

         break;
      }

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)
#endif /// (NTDDI_VERSION >= NTDDI_WIN7)

   }


   if(ipHeaderAvailable)
   {
      BYTE*        pBuffer         = 0;
      NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
      UINT32       bytesNeeded     = ipHeaderSize ? ipHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
      PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprIPHeaderDestroy if *pNeedToFreeMemory is TRUE

      HLPR_NEW_ARRAY(pBuffer,
                     BYTE,
                     bytesNeeded,
                     WFPSAMPLER_SYSLIB_TAG);
      HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                                 status);

#pragma warning(pop)

      *pNeedToFreeMemory = TRUE;

      if(bytesAdvanced)
         NdisAdvanceNetBufferDataStart(pNetBuffer,
                                       bytesAdvanced,
                                       0,
                                       0);
      else if(bytesRetreated)
      {
         status = NdisRetreatNetBufferDataStart(pNetBuffer,
                                                bytesRetreated,
                                                0,
                                                0);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprIPHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }

      pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                          bytesNeeded,
                                          pBuffer,
                                          1,
                                          0);

      /// Return to the original offset
      if(bytesRetreated)
         NdisAdvanceNetBufferDataStart(pNetBuffer,
                                       bytesRetreated,
                                       0,
                                       0);
      else if(bytesAdvanced)
      {
         status = NdisRetreatNetBufferDataStart(pNetBuffer,
                                                bytesAdvanced,
                                                0,
                                                0);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprIPHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }

      if(!pContiguousData)
      {
         status = STATUS_UNSUCCESSFUL;
      
         DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                    DPFLTR_ERROR_LEVEL,
                    " !!!! KrnlHlprIPHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                    status);
      
         HLPR_BAIL;
      }

      if(pBuffer != pContiguousData)
      {
         HLPR_DELETE_ARRAY(pBuffer,
                           WFPSAMPLER_SYSLIB_TAG);

         *pNeedToFreeMemory = FALSE;
      }

      *ppIPHeader = pContiguousData;

      if(pDirection)
         *pDirection = direction;

      if(pIPHeaderSize)
         *pIPHeaderSize = ipHeaderSize;

      HLPR_BAIL_LABEL:

      if(status != STATUS_SUCCESS &&
         *pNeedToFreeMemory &&
         pBuffer)
         KrnlHlprIPHeaderDestroy((VOID**)&pBuffer);
   }
   else
      status = STATUS_NO_MATCH;

   return status;
}


/**
 @kernel_helper_function="KrnlHlprIPHeaderGet"
 
   Purpose:  Retrieve a pointer to the IP Header from the NET_BUFFER_LIST.                      <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the IP Header.                                  <br>
                                                                                                <br>
             Function is overloaded.                                                            <br>
                                                                                                <br>
             If needToFreeMemory is TRUE, caller should call KrnlHlprIPHeaderDestroy() when 
                finished  with the header.                                                      <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprIPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                             _Outptr_ VOID** ppIPHeader,
                             _Inout_ BOOLEAN* pNeedToFreeMemory,
                             _In_ UINT32 ipHeaderSize)             /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderGet()\n");

#endif /// DBG
   
   NT_ASSERT(pNetBufferList);
   NT_ASSERT(ppIPHeader);
   NT_ASSERT(pNeedToFreeMemory);

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = ipHeaderSize ? ipHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprIPHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  bytesNeeded,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprIPHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppIPHeader = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprIPHeaderDestroy((VOID**)&pBuffer);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprIPHeaderGet() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprIPHeaderGetProtocolField"
 
   Purpose:  Retrieve the protocol from the IP header.                                          <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the IP Header.                                  <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
IPPROTO KrnlHlprIPHeaderGetProtocolField(_In_ NET_BUFFER_LIST* pNetBufferList,
                                         _In_ ADDRESS_FAMILY addressFamily)
{
#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderGetProtocolField()\n");

#endif /// DBG

   NT_ASSERT(pNetBufferList);

   NTSTATUS status     = STATUS_SUCCESS;
   VOID*    pIPHeader  = 0;
   BOOLEAN  needToFree = FALSE;
   IPPROTO  protocol   = IPPROTO_MAX;

   status = KrnlHlprIPHeaderGet(pNetBufferList,
                                &pIPHeader,
                                &needToFree);
   HLPR_BAIL_ON_FAILURE(status);

   if(addressFamily == AF_INET6)
   {
      IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader;

      protocol = (IPPROTO)pIPv6Header->nextHeader;
   }
   else
   {
      IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader;
   
      protocol = (IPPROTO)pIPv4Header->protocol;
   }

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = (addressFamily == AF_INET) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprIPHeaderDestroy(&pIPHeader);
   }

   HLPR_BAIL_LABEL:

#if DBG

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_INFO_LEVEL,
                 " <--- KrnlHlprIPHeaderGetProtocolField()\n");

#endif /// DBG

   return protocol;
}

/**
 @kernel_helper_function="KrnlHlprIPHeaderCalculateV4Checksum"
 
   Purpose:  Calculate the Checksum for the IPv4 Header.                                        <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the IPv4 Header.                                <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
inline VOID KrnlHlprIPHeaderCalculateV4Checksum(_Inout_ IP_HEADER_V4* pIPv4Header,
                                                _In_ UINT32 ipHeaderSize)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderCalculateV4Checksum()\n");

#endif /// DBG
   
   NT_ASSERT(pIPv4Header);
   NT_ASSERT(pIPv4Header->version == IPV4);
   NT_ASSERT(ipHeaderSize >= IPV4_HEADER_MIN_SIZE);

   UINT32            sum    = 0;
   UINT32            words  = ipHeaderSize / 2;
   UINT16 UNALIGNED* pStart = (UINT16*)pIPv4Header;

   pIPv4Header->checksum = 0;

   for(UINT8 i = 0;
       i < words;
       i++)
   {
      sum += pStart[i];
   }

   sum = (sum & 0x0000ffff) + (sum >> 16);
   sum += (sum >> 16);

   pIPv4Header->checksum = (UINT16)~sum;

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprIPHeaderCalculateV4Checksum()\n");

#endif /// DBG
   
   return;
}

/**
 @kernel_helper_function="KrnlHlprIPHeaderModifySourceAddress"
 
   Purpose:  Set the Source Address field in the IP Header to the provided value.               <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the IP Header.<br>
                                                                                                <br>
             Values should be in Network Byte Order.                                            <br>
                                                                                                <br>
             Function is IP version agnostic.                                                   <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprIPHeaderModifySourceAddress(_In_ const FWP_VALUE* pValue,
                                             _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                             _In_ BOOLEAN recalculateChecksum,        /* TRUE */
                                             _In_ BOOLEAN convertByteOrder)           /* FALSE */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderModifySourceAddress()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS status     = STATUS_SUCCESS;
   VOID*    pIPHeader  = 0;
   BOOLEAN  needToFree = FALSE;

   status = KrnlHlprIPHeaderGet(pNetBufferList,
                                &pIPHeader,
                                &needToFree);
   HLPR_BAIL_ON_FAILURE(status);

   switch(pValue->type)
   {
      case FWP_UINT32:
      {
         IP_HEADER_V4* pIPv4Header   = (IP_HEADER_V4*)pIPHeader;
         UINT32        sourceAddress = convertByteOrder ? htonl(pValue->uint32) : pValue->uint32;

         RtlCopyMemory(pIPv4Header->pDestinationAddress,
                       &sourceAddress,
                       IPV4_ADDRESS_SIZE);

         if(recalculateChecksum)
            KrnlHlprIPHeaderCalculateV4Checksum(pIPv4Header,
                                                pIPv4Header->headerLength * sizeof(UINT32));

         break;
      }
      case FWP_BYTE_ARRAY16_TYPE:
      {
         IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader;

         RtlCopyMemory(pIPv6Header->pSourceAddress,
                       &(pValue->byteArray16->byteArray16),
                       IPV6_ADDRESS_SIZE);

         break;
      }
   }

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = (pValue->type == FWP_UINT32) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprIPHeaderDestroy(&pIPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprIPHeaderModifySourceAddress() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprIPHeaderModifyDestinationAddress"
 
   Purpose:  Set the Destination Address field in the IP Header to the provided value.          <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the IP Header.<br>
                                                                                                <br>
             Values should be in Network Byte Order.                                            <br>
                                                                                                <br>
             Function is IP version agnostic.                                                   <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprIPHeaderModifyDestinationAddress(_In_ const FWP_VALUE* pValue,
                                                  _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                                  _In_ const BOOLEAN recalculateChecksum,  /* TRUE */
                                                  _In_ BOOLEAN convertByteOrder)           /* FALSE */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderModifyDestinationAddress()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS status     = STATUS_SUCCESS;
   VOID*    pIPHeader  = 0;
   BOOLEAN  needToFree = FALSE;

   status = KrnlHlprIPHeaderGet(pNetBufferList,
                                &pIPHeader,
                                &needToFree);
   HLPR_BAIL_ON_FAILURE(status);

   switch(pValue->type)
   {
      case FWP_UINT32:
      {
         IP_HEADER_V4* pIPv4Header        = (IP_HEADER_V4*)pIPHeader;
         UINT32        destinationAddress = convertByteOrder ? htonl(pValue->uint32) : pValue->uint32;

         RtlCopyMemory(pIPv4Header->pDestinationAddress,
                       &destinationAddress,
                       IPV4_ADDRESS_SIZE);

         if(recalculateChecksum)
            KrnlHlprIPHeaderCalculateV4Checksum(pIPv4Header,
                                                pIPv4Header->headerLength * sizeof(UINT32));

         break;
      }
      case FWP_BYTE_ARRAY16_TYPE:
      {
         IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader;

         RtlCopyMemory(pIPv6Header->pDestinationAddress,
                       &(pValue->byteArray16->byteArray16),
                       IPV6_ADDRESS_SIZE);

         break;
      }
   }

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = (pValue->type == FWP_UINT32) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprIPHeaderDestroy(&pIPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprIPHeaderModifyDestinationAddress() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprIPHeaderModifyLoopbackToLocal"
 
   Purpose:  Modifies the source address and destination address from software loopback to an 
             actual local IP address (i.e. 127.0.0.1 to 157.59.10.233).                         <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the IP Header.<br>
                                                                                                <br>
             The source address is modified to pass TCP/IP's source IP address validation, and 
             the destination address is modified to pass TCP/IP's zone crossing restrictions.   <br>
                                                                                                <br>
             For some protocols, the need to capture and modify a response packet's addresses 
             back to the loopback addresses will exist (i.e. ICMP Echo Requests)                <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprIPHeaderModifyLoopbackToLocal(_In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
                                               _In_ const FWP_VALUE* pLoopbackAddress,
                                               _In_ const UINT32 ipHeaderSize,
                                               _Inout_ NET_BUFFER_LIST* pNetBufferList)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprIPHeaderModifyLoopbackToLocal()\n");

#endif /// DBG
   
   NT_ASSERT(pMetadata);
   NT_ASSERT(pLoopbackAddress);
   NT_ASSERT(pNetBufferList);

   NTSTATUS       status           = STATUS_SUCCESS;
   ADDRESS_FAMILY addressFamily    = pLoopbackAddress->type == FWP_BYTE_ARRAY16_TYPE ? AF_INET6 : AF_INET;
   VOID*          pIPHeader        = 0;
   BOOLEAN        needToFreeMemory = FALSE;
   UINT8*         pLocalAddress    = 0;
   IPPROTO        nextProtocol     = IPPROTO_MAX;

   status = KrnlHlprIPHeaderGet(pNetBufferList,
                                &pIPHeader,
                                &needToFreeMemory,
                                ipHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   if(addressFamily == AF_INET)
   {
      IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader;

      nextProtocol = (IPPROTO)pIPv4Header->protocol;

      /// Only modify if the addresses are different
      if(RtlCompareMemory(pIPv4Header->pSourceAddress,
                          pIPv4Header->pDestinationAddress,
                          IPV4_ADDRESS_SIZE) != IPV4_ADDRESS_SIZE)
      {
         HLPR_NEW_ARRAY(pLocalAddress,
                        UINT8,
                        IPV4_ADDRESS_SIZE,
                        WFPSAMPLER_SYSLIB_TAG);
         HLPR_BAIL_ON_ALLOC_FAILURE(pLocalAddress,
                                    status);

         if(RtlCompareMemory(pIPv4Header->pSourceAddress,
                             IPV4_LOOPBACK_ADDRESS,
                             IPV4_ADDRESS_SIZE) == IPV4_ADDRESS_SIZE)
            RtlCopyMemory(pLocalAddress,
                          pIPv4Header->pDestinationAddress,
                          IPV4_ADDRESS_SIZE);
         else
            RtlCopyMemory(pLocalAddress,
                          pIPv4Header->pSourceAddress,
                          IPV4_ADDRESS_SIZE);
      }
   }
   else
   {
      IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader;

      nextProtocol = (IPPROTO)pIPv6Header->nextHeader;

      /// Only modify if the addresses are different
      if(RtlCompareMemory(pIPv6Header->pSourceAddress,
                          pIPv6Header->pDestinationAddress,
                          IPV6_ADDRESS_SIZE) != IPV6_ADDRESS_SIZE)
      {
         HLPR_NEW_ARRAY(pLocalAddress,
                        UINT8,
                        IPV6_ADDRESS_SIZE,
                        WFPSAMPLER_SYSLIB_TAG);
         HLPR_BAIL_ON_ALLOC_FAILURE(pLocalAddress,
                                    status);

         if(RtlCompareMemory(pIPv6Header->pSourceAddress,
                             IPV6_LOOPBACK_ADDRESS,
                             IPV6_ADDRESS_SIZE) == IPV6_ADDRESS_SIZE)
            RtlCopyMemory(pLocalAddress,
                          pIPv6Header->pDestinationAddress,
                          IPV6_ADDRESS_SIZE);
         else
            RtlCopyMemory(pLocalAddress,
                          pIPv6Header->pSourceAddress,
                          IPV6_ADDRESS_SIZE);
      }
   }

   if(pLocalAddress)
   {
      UINT64 endpointHandle = 0;

      if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                        FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE))
         endpointHandle = pMetadata->transportEndpointHandle;

      /// Rebuild the IP Header (recalculating the IP and transport checksums)
      status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList,
                                                       ipHeaderSize,
                                                       addressFamily,
                                                       pLocalAddress,
                                                       pLocalAddress,
                                                       nextProtocol,
                                                       endpointHandle,
                                                       0,
                                                       0,
                                                       0,
                                                       0,
                                                       0,
                                                       0);
      if(status != STATUS_SUCCESS)
         DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                    DPFLTR_ERROR_LEVEL,
                    " !!!! KrnlHlprIPHeaderModifyLoopbackToLocal : FwpsConstructIpHeaderForTransportPacket() [status: %#x]\n",
                    status);
   }

   HLPR_BAIL_LABEL:

   HLPR_DELETE_ARRAY(pLocalAddress,
                     WFPSAMPLER_SYSLIB_TAG);

   if(needToFreeMemory)
      KrnlHlprIPHeaderDestroy(&pIPHeader);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

#endif /// IP_HEADER____

#ifndef TRANSPORT_HEADERS____
#define TRANSPORT_HEADERS____

/**
 @kernel_helper_function="KrnlHlprTransportHeaderDestroy"
 
   Purpose:  Frees the allocated memory indicated in KrnlTransportHeaderGet().                  <br>
                                                                                                <br>
   Notes:    For use with generic and specific transport header functions.                      <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_At_(*ppTransportHeader, _Pre_ _Notnull_)
_At_(*ppTransportHeader, _Post_ _Null_)
_Success_(*ppTransportHeader == 0)
inline VOID KrnlHlprTransportHeaderDestroy(_Inout_ VOID** ppTransportHeader)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprTransportHeaderDestroy()\n");

#endif /// DBG
   
   NT_ASSERT(ppTransportHeader);

   HLPR_DELETE_ARRAY(*ppTransportHeader,
                     WFPSAMPLER_SYSLIB_TAG);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprTransportHeaderDestroy()\n");

#endif /// DBG
   
   return;
}

/**
 @kernel_helper_function="KrnlHlprTransportHeaderGet"
 
   Purpose:  Retrieve a pointer to the Transport Header from the NET_BUFFER_LIST.               <br>
                                                                                                <br>
   Notes:    Function is overloaded.                            .                               <br>
                                                                                                <br>
             If needToFreeMemory is TRUE, caller should call KrnlHlprTransportHeaderDestroy() 
                when finished with the header.                                                  <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprTransportHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                                    _In_ const FWPS_INCOMING_VALUES* pClassifyValues,
                                    _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
                                    _Outptr_ VOID** ppTransportHeader,
                                    _Inout_ BOOLEAN* pNeedToFreeMemory,
                                    _Inout_opt_ IPPROTO* pProtocol,                      /* 0 */
                                    _Inout_opt_ FWP_DIRECTION* pDirection,               /* 0 */
                                    _Inout_opt_ UINT32* pTransportHeaderSize)            /* 0 */
{
   NT_ASSERT(pNetBufferList);
   NT_ASSERT(pClassifyValues);
   NT_ASSERT(pMetadata);
   NT_ASSERT(ppTransportHeader);
   NT_ASSERT(pNeedToFreeMemory);

   NTSTATUS      status                   = STATUS_SUCCESS;
   UINT32        bytesRetreated           = 0;
   UINT32        bytesAdvanced            = 0;
   UINT32        ipHeaderSize             = 0;
   UINT32        transportHeaderSize      = 0;
   FWP_DIRECTION direction                = FWP_DIRECTION_MAX;
   IPPROTO       protocol                 = IPPROTO_MAX;
   BOOLEAN       transportHeaderAvailable = TRUE;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_IP_HEADER_SIZE))
      ipHeaderSize = pMetadata->ipHeaderSize;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
      transportHeaderSize = pMetadata->transportHeaderSize;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_PACKET_DIRECTION))
      direction = pMetadata->packetDirection;

   switch(pClassifyValues->layerId)
   {
      case FWPS_LAYER_INBOUND_IPPACKET_V4:
      case FWPS_LAYER_INBOUND_IPPACKET_V6:
      {
         /// At the Transport Header

         break;
      }
      case FWPS_LAYER_INBOUND_IPPACKET_V4_DISCARD:
      case FWPS_LAYER_INBOUND_IPPACKET_V6_DISCARD:
      {
         if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                           FWPS_METADATA_FIELD_DISCARD_REASON))
         {
            if(pMetadata->discardMetadata.discardModule == FWPS_DISCARD_MODULE_GENERAL &&
               pMetadata->discardMetadata.discardReason == FWPS_DISCARD_FIREWALL_POLICY)
            {
               /// At the Transport Header
            }
         }

         break;
      }
      case FWPS_LAYER_OUTBOUND_IPPACKET_V4:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V6:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V6_DISCARD:
      {
         bytesAdvanced = ipHeaderSize;
   
         break;
      }
      case FWPS_LAYER_IPFORWARD_V4:
      case FWPS_LAYER_IPFORWARD_V4_DISCARD:
      case FWPS_LAYER_IPFORWARD_V6:
      case FWPS_LAYER_IPFORWARD_V6_DISCARD:
      {
         bytesAdvanced = ipHeaderSize;
   
         break;
      }
      case FWPS_LAYER_INBOUND_TRANSPORT_V4:
      case FWPS_LAYER_INBOUND_TRANSPORT_V4_DISCARD:
      case FWPS_LAYER_INBOUND_TRANSPORT_V6:
      case FWPS_LAYER_INBOUND_TRANSPORT_V6_DISCARD:
      {
         protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8);

         if(protocol == IPPROTO_ICMP ||
            protocol == IPPROTO_ICMPV6)
         {
            /// At the Transport Header
         }
         else
            bytesRetreated = transportHeaderSize;

         break;
      }
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD:
      {
         protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8);

         /// At the Transport Header
   
         break;
      }
      case FWPS_LAYER_STREAM_V4:
      case FWPS_LAYER_STREAM_V4_DISCARD:
      case FWPS_LAYER_STREAM_V6:
      case FWPS_LAYER_STREAM_V6_DISCARD:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_DATAGRAM_DATA_V4:
      case FWPS_LAYER_DATAGRAM_DATA_V4_DISCARD:
      case FWPS_LAYER_DATAGRAM_DATA_V6:
      case FWPS_LAYER_DATAGRAM_DATA_V6_DISCARD:
      {
         protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8);

         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
         {
            /// At the Transport Header
         }
         else
         {
            if(protocol == IPPROTO_ICMP ||
               protocol == IPPROTO_ICMPV6)
            {
               /// At the Transport Header
            }
            else
               bytesRetreated = transportHeaderSize;
         }
   
         break;
      }
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V4:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V6:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         bytesRetreated = transportHeaderSize;

         break;
      }
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         /// At the Transport Header

         break;
      }
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_AUTH_LISTEN_V4:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V6:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V6_DISCARD:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD:
      {
         protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8);

         if(direction == FWP_DIRECTION_OUTBOUND)
         {
            /// At the Transport Header
         }
         else
         {
            if(protocol == IPPROTO_ICMP ||
               protocol == IPPROTO_ICMPV6)
            {
               /// At the Transport Header
            }
            else
               bytesRetreated = transportHeaderSize;
         }

         break;
      }
      case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V6_DISCARD:
      {
         protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8);

         if(protocol == IPPROTO_TCP)
            transportHeaderAvailable = FALSE;
         if(direction == FWP_DIRECTION_INBOUND)
         {
            /// At the Transport Header
         }
         else
         {
            /// At the Transport Header
         }
   
         break;
      }
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32;

         protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8);

         if(direction == FWP_DIRECTION_OUTBOUND)
         {
            /// At the Transport Header
         }
         else
         {
            if(protocol == IPPROTO_ICMP ||
               protocol == IPPROTO_ICMPV6)
            {
               /// At the Transport Header
            }
            else
               bytesRetreated =  transportHeaderSize;
         }
   
         break;
      }

#if(NTDDI_VERSION >= NTDDI_WIN7)

      case FWPS_LAYER_NAME_RESOLUTION_CACHE_V4:
      case FWPS_LAYER_NAME_RESOLUTION_CACHE_V6:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_RESOURCE_RELEASE_V4:
      case FWPS_LAYER_ALE_RESOURCE_RELEASE_V6:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4:
      case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_CONNECT_REDIRECT_V4:
      case FWPS_LAYER_ALE_CONNECT_REDIRECT_V6:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_BIND_REDIRECT_V4:
      case FWPS_LAYER_ALE_BIND_REDIRECT_V6:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_STREAM_PACKET_V4:
      case FWPS_LAYER_STREAM_PACKET_V6:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_DIRECTION].value.uint32;

         protocol = IPPROTO_TCP;

         if(direction == FWP_DIRECTION_OUTBOUND)
         {
            /// At the Transport Header
         }
         else
            bytesRetreated =  transportHeaderSize;

         break;
      }
   
#if(NTDDI_VERSION >= NTDDI_WIN8)
   
      case FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET:
      case FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET:
      case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE:
      case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE:
      case FWPS_LAYER_INGRESS_VSWITCH_ETHERNET:
      case FWPS_LAYER_EGRESS_VSWITCH_ETHERNET:
      {
         transportHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V4:
      case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V6:
      {
         bytesAdvanced = ipHeaderSize;

         break;
      }
      case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V4:
      case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V6:
      {
         bytesAdvanced = ipHeaderSize;

         break;
      }

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)
#endif /// (NTDDI_VERSION >= NTDDI_WIN7)

   }

   if(transportHeaderAvailable)
   {
      BYTE*       pBuffer         = 0;
      NET_BUFFER* pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
      UINT32      bytesNeeded     = transportHeaderSize ? transportHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
      PVOID       pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE

      HLPR_NEW_ARRAY(pBuffer,
                     BYTE,
                     bytesNeeded,
                     WFPSAMPLER_SYSLIB_TAG);
      HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                                 status);

#pragma warning(pop)

      *pNeedToFreeMemory = TRUE;

      if(bytesAdvanced)
         NdisAdvanceNetBufferDataStart(pNetBuffer,
                                       bytesAdvanced,
                                       0,
                                       0);
      else if(bytesRetreated)
      {
         status = NdisRetreatNetBufferDataStart(pNetBuffer,
                                                bytesRetreated,
                                                0,
                                                0);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlpTransportHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }

      pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                          bytesNeeded,
                                          pBuffer,
                                          1,
                                          0);

      /// Return to the original offset
      if(bytesRetreated)
         NdisAdvanceNetBufferDataStart(pNetBuffer,
                                       bytesRetreated,
                                       0,
                                       0);
      else if(bytesAdvanced)
      {
         status = NdisRetreatNetBufferDataStart(pNetBuffer,
                                                bytesAdvanced,
                                                0,
                                                0);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprTransportHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }

      if(!pContiguousData)
      {
         status = STATUS_UNSUCCESSFUL;
      
         DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                    DPFLTR_ERROR_LEVEL,
                    " !!!! KrnlHlprTransportHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                    status);
      
         HLPR_BAIL;
      }

      if(pBuffer != pContiguousData)
      {
         HLPR_DELETE_ARRAY(pBuffer,
                           WFPSAMPLER_SYSLIB_TAG);

         *pNeedToFreeMemory = FALSE;
      }

      *ppTransportHeader = pContiguousData;

      if(pProtocol)
         *pProtocol = protocol;

      if(pDirection)
         *pDirection = direction;

      if(pTransportHeaderSize)
         *pTransportHeaderSize = transportHeaderSize;

      HLPR_BAIL_LABEL:

      if(status != STATUS_SUCCESS &&
         *pNeedToFreeMemory &&
         pBuffer)
         KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer);
   }
   else
      status = STATUS_NO_MATCH;

   return status;
}


/**
 @kernel_helper_function="KrnlHlprTransportHeaderGet"
 
   Purpose:  Retrieve a pointer to the Transport Header from the NET_BUFFER_LIST.               <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the Transport Header.                           <br>
                                                                                                <br>
             Function is overloaded.                                                            <br>
                                                                                                <br>
             If needToFreeMemory is TRUE, caller should call KrnlHlprTransportHeaderDestroy() 
                when finished  with the header.                                                 <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprTransportHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                                    _Outptr_ VOID** ppTransportHeader,
                                    _Inout_ BOOLEAN* pNeedToFreeMemory,
                                    _In_ UINT32 transportHeaderSize)      /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprTransportHeaderGet()\n");

#endif /// DBG
   
   NT_ASSERT(pNetBufferList);
   NT_ASSERT(ppTransportHeader);
   NT_ASSERT(pNeedToFreeMemory);

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   const UINT32 BUFFER_SIZE     = 1024;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = transportHeaderSize ? transportHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  BUFFER_SIZE,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprTransportHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppTransportHeader = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprTransportHeaderGet() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

#endif /// TRANSPORT_HEADERS____

#ifndef ICMPV4_HEADER____
#define ICMPV4_HEADER____

/**
 @kernel_helper_function="KrnlHlprICMPv4HeaderGet"
 
   Purpose:  Retrieve a pointer to the ICMPv4 Header from the NET_BUFFER_LIST.                  <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the ICMPv4 Header.                              <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppICMPv4Header, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppICMPv4Header, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprICMPv4HeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                                 _Outptr_ VOID** ppICMPv4Header,
                                 _Inout_ BOOLEAN* pNeedToFreeMemory,
                                 _In_ UINT32 icmpHeaderSize)           /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv4HeaderGet()\n");

#endif /// DBG

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   const UINT32 BUFFER_SIZE     = 1024;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = icmpHeaderSize ? icmpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  BUFFER_SIZE,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprICMPv4HeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppICMPv4Header = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer);

#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv4HeaderGet() [status: %#x]\n",
              status);
   
#endif /// DBG

   return status;
}

/**
 @kernel_helper_function="KrnlHlprICMPv4HeaderModifyType"
 
   Purpose:  Set the ICMP Type field in the ICMPv4 Header to the provided value.                <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the ICMPv4 
             Header.                                                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprICMPv4HeaderModifyType(_In_ const FWP_VALUE* pValue,
                                        _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                        _In_ UINT32 icmpHeaderSize)              /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv4HeaderModifyType()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS        status      = STATUS_SUCCESS;
   ICMP_HEADER_V4* pICMPHeader = 0;
   BOOLEAN         needToFree  = FALSE;

   status = KrnlHlprICMPv4HeaderGet(pNetBufferList,
                                    (VOID**)&pICMPHeader,
                                    &needToFree,
                                    icmpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pICMPHeader->type = pValue->uint8;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprICMPv4HeaderModifyType() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprICMPv4HeaderModifyCode"
 
   Purpose:  Set the ICMP Code field in the ICMPv4 Header to the provided value.                <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the ICMPv4 
             Header.                                                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprICMPv4HeaderModifyCode(_In_ const FWP_VALUE* pValue,
                                        _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                        _In_ UINT32 icmpHeaderSize)              /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv4HeaderModifyCode()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS        status      = STATUS_SUCCESS;
   ICMP_HEADER_V4* pICMPHeader = 0;
   BOOLEAN         needToFree  = FALSE;

   status = KrnlHlprICMPv4HeaderGet(pNetBufferList,
                                    (VOID**)&pICMPHeader,
                                    &needToFree,
                                    icmpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pICMPHeader->code = pValue->uint8;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader);
   }

#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprICMPv4HeaderModifyCode() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

#endif /// ICMPV4_HEADER____

#ifndef ICMPV6_HEADER____
#define ICMPV6_HEADER____

/**
 @kernel_helper_function="KrnlHlprICMPv6HeaderGet"
 
   Purpose:  Retrieve a pointer to the ICMPv6 Header from the NET_BUFFER_LIST.                  <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the ICMPv6 Header.                              <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppICMPv6Header, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppICMPv6Header, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprICMPv6HeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                                 _Outptr_ VOID** ppICMPv6Header,
                                 _Inout_ BOOLEAN* pNeedToFreeMemory,
                                 _In_ UINT32 icmpHeaderSize)           /* 0 */
{
#if DBG
      
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv6HeaderGet()\n");
   
#endif /// DBG

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   const UINT32 BUFFER_SIZE     = 1024;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = icmpHeaderSize ? icmpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  BUFFER_SIZE,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprICMPv6HeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppICMPv6Header = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer);

#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv4HeaderGet() [status: %#x]\n",
              status);
      
#endif /// DBG

   return status;
}

/**
 @kernel_helper_function="KrnlHlprICMPv6HeaderModifyType"
 
   Purpose:  Set the ICMP Type field in the ICMPv6 Header to the provided value.                <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the ICMPv6 
             Header.                                                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprICMPv6HeaderModifyType(_In_ const FWP_VALUE* pValue,
                                        _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                        _In_ UINT32 icmpHeaderSize)              /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv6HeaderModifyType()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS        status      = STATUS_SUCCESS;
   ICMP_HEADER_V6* pICMPHeader = 0;
   BOOLEAN         needToFree  = FALSE;

   status = KrnlHlprICMPv4HeaderGet(pNetBufferList,
                                    (VOID**)&pICMPHeader,
                                    &needToFree,
                                    icmpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pICMPHeader->type = pValue->uint8;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprICMPv6HeaderModifyType() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprICMPv6HeaderModifyCode"
 
   Purpose:  Set the ICMP Code field in the ICMPv6 Header to the provided value.                <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the ICMPv6 
             Header.                                                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprICMPv6HeaderModifyCode(_In_ const FWP_VALUE* pValue,
                                        _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                        _In_ UINT32 icmpHeaderSize)              /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprICMPv6HeaderModifyCode()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS        status      = STATUS_SUCCESS;
   ICMP_HEADER_V6* pICMPHeader = 0;
   BOOLEAN         needToFree  = FALSE;

   status = KrnlHlprICMPv4HeaderGet(pNetBufferList,
                                    (VOID**)&pICMPHeader,
                                    &needToFree,
                                    icmpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pICMPHeader->code = pValue->uint8;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprICMPv6HeaderModifyCode() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

#endif /// ICMPV6_HEADER____

#ifndef TCP_HEADER____
#define TCP_HEADER____

/**
 @kernel_helper_function="KrnlHlprTCPHeaderGet"
 
   Purpose:  Retrieve a pointer to the TCP Header from the NET_BUFFER_LIST.                     <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the TCP Header.                                 <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppTCPHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppTCPHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprTCPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                              _Outptr_ VOID** ppTCPHeader,
                              _Inout_ BOOLEAN* pNeedToFreeMemory,
                              _In_ UINT32 tcpHeaderSize)            /* 0 */
{
#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprTCPHeaderGet()\n");
      
#endif /// DBG

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   const UINT32 BUFFER_SIZE     = 1024;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = tcpHeaderSize ? tcpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  BUFFER_SIZE,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprTCPHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppTCPHeader = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer);

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprTCPHeaderGet() [status: %#x]\n",
              status);
         
#endif /// DBG

   return status;
}

/**
 @kernel_helper_function="KrnlHlprTCPHeaderModifySourcePort"
 
   Purpose:  Set the Source Address field in the TCP Header to the provided value.              <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the TCP 
             Header.                                                                            <br>
                                                                                                <br>
             Values should be in Network Byte Order.                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprTCPHeaderModifySourcePort(_In_ const FWP_VALUE* pValue,
                                           _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                           _In_ UINT32 tcpHeaderSize,               /* 0 */
                                           _In_ BOOLEAN convertByteOrder)           /* FALSE */
{
#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprTCPHeaderModifySourcePort()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS    status     = STATUS_SUCCESS;
   TCP_HEADER* pTCPHeader = 0;
   BOOLEAN     needToFree = FALSE;
   UINT16      port       = convertByteOrder ? htons(pValue->uint16) : pValue->uint16;

   status = KrnlHlprTCPHeaderGet(pNetBufferList,
                                 (VOID**)&pTCPHeader,
                                 &needToFree,
                                 tcpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pTCPHeader->sourcePort = port;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = tcpHeaderSize ? tcpHeaderSize : TCP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pTCPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pTCPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprTCPHeaderModifySourcePort() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprTCPHeaderModifyDestinationPort"
 
   Purpose:  Set the Destination Address field in the TCP Header to the provided value.         <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the TCP 
             Header.                                                                            <br>
                                                                                                <br>
             Values should be in Network Byte Order.                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprTCPHeaderModifyDestinationPort(_In_ const FWP_VALUE* pValue,
                                                _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                                _In_ UINT32 tcpHeaderSize,               /* 0 */
                                                _In_ BOOLEAN convertByteOrder)           /* FALSE */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprTCPHeaderModifyDestinationPort()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS    status     = STATUS_SUCCESS;
   TCP_HEADER* pTCPHeader = 0;
   BOOLEAN     needToFree = FALSE;
   UINT16      port       = convertByteOrder ? htons(pValue->uint16) : pValue->uint16;

   status = KrnlHlprTCPHeaderGet(pNetBufferList,
                                 (VOID**)&pTCPHeader,
                                 &needToFree,
                                 tcpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pTCPHeader->destinationPort = port;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = tcpHeaderSize ? tcpHeaderSize : TCP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pTCPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pTCPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprTCPHeaderModifyDestinationPort() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

#endif /// TCP_HEADER____

#ifndef UDP_HEADER____
#define UDP_HEADER____

/**
 @kernel_helper_function="KrnlHlprUDPHeaderGet"
 
   Purpose:  Retrieve a pointer to the UDP Header from the NET_BUFFER_LIST.                     <br>
                                                                                                <br>
   Notes:    Assumes the NBL is at the start of the UDP Header.                                 <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_When_(return != STATUS_SUCCESS, _At_(*ppUDPHeader, _Post_ _Null_))
_When_(return == STATUS_SUCCESS, _At_(*ppUDPHeader, _Post_ _Notnull_))
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprUDPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                              _Outptr_ VOID** ppUDPHeader,
                              _Inout_ BOOLEAN* pNeedToFreeMemory,
                              _In_ UINT32 udpHeaderSize)            /* 0 */
{
#if DBG
            
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprUDPHeaderGet()\n");
         
#endif /// DBG

   NTSTATUS     status          = STATUS_SUCCESS;
   BYTE*        pBuffer         = 0;
   const UINT32 BUFFER_SIZE     = 1024;
   NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
   UINT32       bytesNeeded     = udpHeaderSize ? udpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
   PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE

   HLPR_NEW_ARRAY(pBuffer,
                  BYTE,
                  BUFFER_SIZE,
                  WFPSAMPLER_SYSLIB_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                              status);

#pragma warning(pop)

   *pNeedToFreeMemory = TRUE;

   pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                       bytesNeeded,
                                       pBuffer,
                                       1,
                                       0);
   if(!pContiguousData)
   {
      status = STATUS_UNSUCCESSFUL;

      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! KrnlHlprUDPHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(pBuffer != pContiguousData)
   {
      HLPR_DELETE_ARRAY(pBuffer,
                        WFPSAMPLER_SYSLIB_TAG);

      *pNeedToFreeMemory = FALSE;
   }

   *ppUDPHeader = pContiguousData;

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS &&
      *pNeedToFreeMemory &&
      pBuffer)
      KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer);

#if DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprUDPHeaderGet() [status: %#x]\n",
              status);

#endif /// DBG

   return status;
}

/**
 @kernel_helper_function="KrnlHlprUDPHeaderModifySourcePort"
 
   Purpose:  Set the Source Address field in the UDP Header to the provided value.              <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the UDP 
             Header.                                                                            <br>
                                                                                                <br>
             Values should be in Network Byte Order.                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprUDPHeaderModifySourcePort(_In_ const FWP_VALUE* pValue,
                                           _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                           _In_ UINT32 udpHeaderSize,               /* 0 */
                                           _In_ BOOLEAN convertByteOrder)           /* FALSE */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprUDPHeaderModifySourcePort()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS    status     = STATUS_SUCCESS;
   UDP_HEADER* pUDPHeader = 0;
   BOOLEAN     needToFree = FALSE;
   UINT16      port       = convertByteOrder ? htons(pValue->uint16) : pValue->uint16;

   status = KrnlHlprUDPHeaderGet(pNetBufferList,
                                 (VOID**)&pUDPHeader,
                                 &needToFree,
                                 udpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pUDPHeader->sourcePort = port;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = udpHeaderSize ? udpHeaderSize : UDP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pUDPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pUDPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprUDPHeaderModifySourcePort() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

/**
 @kernel_helper_function="KrnlHlprUDPHeaderModifyDestinationPort"
 
   Purpose:  Set the Destination Address field in the UDP Header to the provided value.         <br>
                                                                                                <br>
   Notes:    The NetBufferList parameter is expected to be offset to the start of the UDP 
             Header.                                                                            <br>
                                                                                                <br>
             Values should be in Network Byte Order.                                            <br>
                                                                                                <br>
   MSDN_Ref:                                                                                    <br>
*/
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
_IRQL_requires_same_
_Check_return_
_Success_(return == STATUS_SUCCESS)
NTSTATUS KrnlHlprUDPHeaderModifyDestinationPort(_In_ const FWP_VALUE* pValue,
                                                _Inout_ NET_BUFFER_LIST* pNetBufferList,
                                                _In_ UINT32 udpHeaderSize,               /* 0 */
                                                _In_ BOOLEAN convertByteOrder)           /* FALSE */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprUDPHeaderModifyDestinationPort()\n");

#endif /// DBG
   
   NT_ASSERT(pValue);
   NT_ASSERT(pNetBufferList);

   NTSTATUS    status     = STATUS_SUCCESS;
   UDP_HEADER* pUDPHeader = 0;
   BOOLEAN     needToFree = FALSE;
   UINT16      port       = convertByteOrder ? htons(pValue->uint16) : pValue->uint16;

   status = KrnlHlprUDPHeaderGet(pNetBufferList,
                                 (VOID**)&pUDPHeader,
                                 &needToFree,
                                 udpHeaderSize);
   HLPR_BAIL_ON_FAILURE(status);

   pUDPHeader->destinationPort = port;

   HLPR_BAIL_LABEL:

   if(needToFree)
   {
      /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer
      if(status == STATUS_SUCCESS)
      {
         NET_BUFFER* pFirstNetBuffer  = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
         PMDL        pCurrentMDL      = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer);
         SIZE_T      currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer);
         SIZE_T      headerSize       = udpHeaderSize ? udpHeaderSize : UDP_HEADER_MIN_SIZE;
         SIZE_T      bytesCopied      = 0;

         status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pUDPHeader,
                                             pCurrentMDL,
                                             currentMDLOffset,
                                             headerSize,
                                             &bytesCopied);
         if(status == STATUS_SUCCESS &&
            bytesCopied != headerSize)
            status = STATUS_INSUFFICIENT_RESOURCES;
      }

      KrnlHlprTransportHeaderDestroy((VOID**)&pUDPHeader);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprUDPHeaderModifyDestinationPort() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}

#endif /// UDP_HEADER____

Our Services

  • What our customers say about us?

© 2011-2025 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS