NTSTATUS PerformBasicPacketModificationAtInboundNetwork()

in network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp [2370:2984]


NTSTATUS PerformBasicPacketModificationAtInboundNetwork(_In_ CLASSIFY_DATA** ppClassifyData,
                                                        _In_ INJECTION_DATA** ppInjectionData,
                                                        _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData,
                                                        _In_ BOOLEAN isInline = FALSE)
{
#if DBG

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

#endif /// DBG

   NT_ASSERT(ppClassifyData);
   NT_ASSERT(ppInjectionData);
   NT_ASSERT(pModificationData);
   NT_ASSERT(*ppClassifyData);
   NT_ASSERT(*ppInjectionData);

   NTSTATUS                                   status              = STATUS_SUCCESS;
   FWPS_INCOMING_VALUES*                      pClassifyValues     = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues;
   FWPS_INCOMING_METADATA_VALUES*             pMetadata           = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues;
   COMPARTMENT_ID                             compartmentID       = DEFAULT_COMPARTMENT_ID;
   IF_INDEX                                   interfaceIndex      = 0;
   IF_INDEX                                   subInterfaceIndex   = 0;
   UINT32                                     flags               = 0;
   NET_BUFFER_LIST*                           pNetBufferList      = 0;
   BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData     = 0;
   UINT32                                     ipHeaderSize        = 0;
   UINT32                                     bytesRetreated      = 0;
   UINT64                                     endpointHandle      = 0;
   IPPROTO                                    protocol            = IPPROTO_MAX;
   FWP_VALUE*                                 pInterfaceIndex     = 0;
   FWP_VALUE*                                 pSubInterfaceIndex  = 0;
   FWP_VALUE*                                 pFlags              = 0;
   BYTE*                                      pSourceAddress      = 0;
   BYTE*                                      pDestinationAddress = 0;
   NDIS_TCP_IP_CHECKSUM_PACKET_INFO           checksumInfo        = {0};

#if DBG

   KIRQL                                      irql               = KeGetCurrentIrql();

#endif /// DBG

#pragma warning(push)
#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy

   HLPR_NEW(pCompletionData,
            BASIC_PACKET_MODIFICATION_COMPLETION_DATA,
            WFPSAMPLER_CALLOUT_DRIVER_TAG);
   HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData,
                              status);

#pragma warning(pop)

   KeInitializeSpinLock(&(pCompletionData->spinLock));

   pCompletionData->performedInline = isInline;
   pCompletionData->pClassifyData   = *ppClassifyData;
   pCompletionData->pInjectionData  = *ppInjectionData;

   /// Responsibility for freeing this memory has been transferred to the pCompletionData
   *ppClassifyData = 0;

   *ppInjectionData = 0;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_COMPARTMENT_ID))
      compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId;

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

   pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                               &FWPM_CONDITION_INTERFACE_INDEX);
   if(pInterfaceIndex &&
      pInterfaceIndex->type == FWP_UINT32)
      interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32;

   pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                  &FWPM_CONDITION_SUB_INTERFACE_INDEX);
   if(pSubInterfaceIndex &&
      pSubInterfaceIndex->type == FWP_UINT32)
      subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32;

   pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                      &FWPM_CONDITION_FLAGS);
   if(pFlags &&
      pFlags->type == FWP_UINT32)
      flags = pFlags->uint32;

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

   checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket,
                                                               TcpIpChecksumNetBufferListInfo);

   /// Initial offset is at the Transport Header, so retreat the size of the IP Header ...
   status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket),
                                          bytesRetreated,
                                          0,
                                          0);
   if(status != STATUS_SUCCESS)
   {
      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! PerformBasicPacketModificationAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   /// ... clone the entire NET_BUFFER_LIST ...
   status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket,
                                           g_pNDISPoolData->nblPoolHandle,
                                           g_pNDISPoolData->nbPoolHandle,
                                           0,
                                           &pNetBufferList);

   /// ... and advance the offset back to the original position.
   NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket),
                                 bytesRetreated,
                                 FALSE,
                                 0);

   if(status != STATUS_SUCCESS ||
      !pNetBufferList)
   {
      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! PerformBasicPacketModificationAtInboundNetwork: FwpsAllocateCloneNetBufferList() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   /// Handle if this packet had the IP checksum offloaded or if it's loopback
   if(checksumInfo.Receive.NdisPacketIpChecksumSucceeded ||
      flags & FWP_CONDITION_FLAG_IS_LOOPBACK)
   {
      /// Prevent TCP/IP Zone crossing and recalculate the checksums
      if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK)
      {
         FWP_VALUE* pLocalAddress    = 0;
         FWP_VALUE* pRemoteAddress   = 0;
         FWP_VALUE* pLoopbackAddress = 0;

         pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                    &FWPM_CONDITION_IP_REMOTE_ADDRESS);
         if(pLocalAddress &&
            ((pLocalAddress->type == FWP_UINT32 &&
            RtlCompareMemory(&(pLocalAddress->uint32),
                             IPV4_LOOPBACK_ADDRESS,
                             IPV4_ADDRESS_SIZE)) ||
            (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE &&
            RtlCompareMemory(pLocalAddress->byteArray16->byteArray16,
                             IPV6_LOOPBACK_ADDRESS,
                             IPV6_ADDRESS_SIZE))))
            pLoopbackAddress = pLocalAddress;

         if(!pLoopbackAddress)
         {
            pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                       &FWPM_CONDITION_IP_REMOTE_ADDRESS);
            if(pRemoteAddress &&
               ((pRemoteAddress->type == FWP_UINT32 &&
               RtlCompareMemory(&(pRemoteAddress->uint32),
                                IPV4_LOOPBACK_ADDRESS,
                                IPV4_ADDRESS_SIZE)) ||
               (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE &&
               RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16,
                                IPV6_LOOPBACK_ADDRESS,
                                IPV6_ADDRESS_SIZE))))
               pLoopbackAddress = pRemoteAddress;
         }

         if(pLoopbackAddress)
         {
            status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata,
                                                           pLoopbackAddress,
                                                           ipHeaderSize,
                                                           pNetBufferList,
                                                           (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData,
                                                           pCompletionData->pInjectionData->controlDataLength);
            if(status != STATUS_SUCCESS)
            {
               DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                          DPFLTR_ERROR_LEVEL,
                          " !!!! PerformBasicPacketModificationAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n",
                          status);

               HLPR_BAIL;
            }
         }
      }
      else
      {
         /// Recalculate the checksum
         if(pCompletionData->pInjectionData->addressFamily == AF_INET)
            KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList,
                                                ipHeaderSize);
      }
   }

   pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList);

   protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList,
                                               pCompletionData->pInjectionData->addressFamily);

   if(pModificationData->flags)
   {
      if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER)
      {
         NTSTATUS tmpStatus = STATUS_SUCCESS;

         /// The clone is at the IP Header, so advance by the size of the IP Header.
         NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList),
                                       ipHeaderSize,
                                       FALSE,
                                       0);

         switch(protocol)
         {
            case IPPROTO_ICMP:
            {
               UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE;
         
               if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                                 FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
                  icmpHeaderSize = pMetadata->transportHeaderSize;
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE)
               {
                  FWP_VALUE0 icmpType;
         
                  icmpType.type  = FWP_UINT8;
                  icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort);
         
                  status = KrnlHlprICMPv4HeaderModifyType(&icmpType,
                                                          pNetBufferList,
                                                          icmpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE)
               {
                  FWP_VALUE0 icmpCode;
               
                  icmpCode.type  = FWP_UINT8;
                  icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort);
         
                  status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode,
                                                          pNetBufferList,
                                                          icmpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               break;
            }
            case IPPROTO_TCP:
            {
               UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE;
         
               if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                                 FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
                  tcpHeaderSize = pMetadata->transportHeaderSize;
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT)
               {
                  FWP_VALUE0 srcPort;
         
                  srcPort.type   = FWP_UINT16;
                  srcPort.uint16 = pModificationData->transportData.sourcePort;
         
                  status = KrnlHlprTCPHeaderModifySourcePort(&srcPort,
                                                             pNetBufferList,
                                                             tcpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT)
               {
                  FWP_VALUE0 dstPort;
         
                  dstPort.type   = FWP_UINT16;
                  dstPort.uint16 = pModificationData->transportData.destinationPort;
         
                  status = KrnlHlprTCPHeaderModifyDestinationPort(&dstPort,
                                                                  pNetBufferList,
                                                                  tcpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               break;
            }
            case IPPROTO_UDP:
            {
               UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE;
         
               if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                                 FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
                  udpHeaderSize = pMetadata->transportHeaderSize;
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT)
               {
                  FWP_VALUE0 srcPort;
         
                  srcPort.type   = FWP_UINT16;
                  srcPort.uint16 = pModificationData->transportData.sourcePort;
         
                  status = KrnlHlprUDPHeaderModifySourcePort(&srcPort,
                                                             pNetBufferList,
                                                             udpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT)
               {
                  FWP_VALUE0 dstPort;
         
                  dstPort.type   = FWP_UINT16;
                  dstPort.uint16 = pModificationData->transportData.destinationPort;
         
                  status = KrnlHlprUDPHeaderModifyDestinationPort(&dstPort,
                                                                  pNetBufferList,
                                                                  udpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               break;
            }
            case IPPROTO_ICMPV6:
            {
               UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE;
         
               if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                                 FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
                  icmpHeaderSize = pMetadata->transportHeaderSize;
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE)
               {
                  FWP_VALUE0 icmpType;
         
                  icmpType.type  = FWP_UINT8;
                  icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort);
         
                  status = KrnlHlprICMPv6HeaderModifyType(&icmpType,
                                                          pNetBufferList,
                                                          icmpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE)
               {
                  FWP_VALUE0 icmpCode;
         
                  icmpCode.type  = FWP_UINT8;
                  icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort);
         
                  status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode,
                                                          pNetBufferList,
                                                          icmpHeaderSize);
                  HLPR_BAIL_ON_FAILURE_2(status);
               }
         
               break;
            }
         }

         HLPR_BAIL_LABEL_2:

         /// return the data offset to the beginning of the IP Header
         tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList),
                                                   ipHeaderSize,
                                                   0,
                                                   0);
         if(tmpStatus != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! PerformBasicPacketModificationAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);
         
            HLPR_BAIL;
         }

         HLPR_BAIL_ON_FAILURE(status);
      }

      if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER)
      {
         if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_INTERFACE_INDEX)
            interfaceIndex = pModificationData->ipData.interfaceIndex;

         if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS)
         {
            FWP_VALUE value;

            RtlZeroMemory(&value,
                          sizeof(FWP_VALUE));

            if(pCompletionData->pInjectionData->addressFamily == AF_INET)
            {
               value.type = FWP_UINT32;

               RtlCopyMemory(&(value.uint32),
                             pModificationData->ipData.sourceAddress.pIPv4,
                             IPV4_ADDRESS_SIZE);
            }
            else
            {
               HLPR_NEW(value.byteArray16,
                        FWP_BYTE_ARRAY16,
                        WFPSAMPLER_CALLOUT_DRIVER_TAG);
               HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16,
                                          status);

               value.type = FWP_BYTE_ARRAY16_TYPE;

               RtlCopyMemory(value.byteArray16->byteArray16,
                             pModificationData->ipData.sourceAddress.pIPv6,
                             IPV6_ADDRESS_SIZE);
            }

            status = KrnlHlprIPHeaderModifySourceAddress(&value,
                                                         pNetBufferList,
                                                         TRUE);

            KrnlHlprFwpValuePurgeLocalCopy(&value);

            HLPR_BAIL_ON_FAILURE(status);
         }

         if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS)
         {
            FWP_VALUE value;

            RtlZeroMemory(&value,
                          sizeof(FWP_VALUE));

            if(pCompletionData->pInjectionData->addressFamily == AF_INET)
            {
               value.type = FWP_UINT32;

               RtlCopyMemory(&(value.uint32),
                             pModificationData->ipData.destinationAddress.pIPv4,
                             IPV4_ADDRESS_SIZE);
            }
            else
            {
#pragma warning(push)
#pragma warning(disable: 6014) /// value.byteArray16 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy

               HLPR_NEW(value.byteArray16,
                        FWP_BYTE_ARRAY16,
                        WFPSAMPLER_CALLOUT_DRIVER_TAG);
               HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16,
                                          status);

#pragma warning(pop)

               value.type = FWP_BYTE_ARRAY16_TYPE;

               RtlCopyMemory(value.byteArray16->byteArray16,
                             pModificationData->ipData.destinationAddress.pIPv6,
                             IPV6_ADDRESS_SIZE);
            }

            status = KrnlHlprIPHeaderModifyDestinationAddress(&value,
                                                              pNetBufferList,
                                                              TRUE);

            KrnlHlprFwpValuePurgeLocalCopy(&value);

            HLPR_BAIL_ON_FAILURE(status);
         }
      }
   }

   /// Handle if this packet is destined for the software loopback
   if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK)
   {
      FWP_VALUE* pLocalAddress    = 0;
      FWP_VALUE* pRemoteAddress   = 0;
      FWP_VALUE* pLoopbackAddress = 0;

      pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                 &FWPM_CONDITION_IP_REMOTE_ADDRESS);
      if(pLocalAddress &&
         ((pLocalAddress->type == FWP_UINT32 &&
         RtlCompareMemory(&(pLocalAddress->uint32),
                          IPV4_LOOPBACK_ADDRESS,
                          IPV4_ADDRESS_SIZE)) ||
         (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE &&
         RtlCompareMemory(pLocalAddress->byteArray16->byteArray16,
                          IPV6_LOOPBACK_ADDRESS,
                          IPV6_ADDRESS_SIZE))))
         pLoopbackAddress = pLocalAddress;

      if(!pLoopbackAddress)
      {
         pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                    &FWPM_CONDITION_IP_REMOTE_ADDRESS);
         if(pRemoteAddress &&
            ((pRemoteAddress->type == FWP_UINT32 &&
            RtlCompareMemory(&(pRemoteAddress->uint32),
                             IPV4_LOOPBACK_ADDRESS,
                             IPV4_ADDRESS_SIZE)) ||
            (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE &&
            RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16,
                             IPV6_LOOPBACK_ADDRESS,
                             IPV6_ADDRESS_SIZE))))
            pLoopbackAddress = pRemoteAddress;
      }

      if(pLoopbackAddress)
      {
         status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata,
                                                        pLoopbackAddress,
                                                        ipHeaderSize,
                                                        pNetBufferList,
                                                        (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData,
                                                        pCompletionData->pInjectionData->controlDataLength);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! PerformBasicPacketModificationAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }
   }

   pSourceAddress = KrnlHlprIPHeaderGetSourceAddressField(pNetBufferList,
                                                          pCompletionData->pInjectionData->addressFamily);

   pDestinationAddress = KrnlHlprIPHeaderGetDestinationAddressField(pNetBufferList,
                                                                    pCompletionData->pInjectionData->addressFamily);

   status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList,
                                                    ipHeaderSize,
                                                    pCompletionData->pInjectionData->addressFamily,
                                                    (UCHAR*)pSourceAddress,
                                                    (UCHAR*)pDestinationAddress,
                                                    protocol,
                                                    endpointHandle,
                                                    (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData,
                                                    pCompletionData->pInjectionData->controlDataLength,
                                                    0,
                                                    0,
                                                    interfaceIndex,
                                                    subInterfaceIndex);
   if(status != STATUS_SUCCESS)
   {
      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! PerformBasicPacketModificationAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n",
                 status);
   
      HLPR_BAIL;
   }

   status = FwpsInjectNetworkReceiveAsync(pCompletionData->pInjectionData->injectionHandle,
                                          pCompletionData->pInjectionData->injectionContext,
                                          0,
                                          compartmentID,
                                          interfaceIndex,
                                          subInterfaceIndex,
                                          pNetBufferList,
                                          CompleteBasicPacketModification,
                                          pCompletionData);

   NT_ASSERT(irql == KeGetCurrentIrql());

   if(status != STATUS_SUCCESS)
      DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                 DPFLTR_ERROR_LEVEL,
                 " !!!! PerformBasicPacketModificationAtInboundNetwork: FwpsInjectNetworkReceiveAsync() [status: %#x]\n",
                 status);

   HLPR_BAIL_LABEL:

   NT_ASSERT(status == STATUS_SUCCESS);

   if(status != STATUS_SUCCESS)
   {
      if(pNetBufferList)
      {
         FwpsFreeCloneNetBufferList(pNetBufferList,
                                    0);

         pNetBufferList = 0;
      }

      if(pCompletionData)
         BasicPacketModificationCompletionDataDestroy(&pCompletionData,
                                                      TRUE);
   }

#if DBG

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

#endif /// DBG

   return status;
}