VOID NTAPI ClassifyFastPacketInjection()

in network/trans/WFPSampler/sys/ClassifyFunctions_FastPacketInjectionCallouts.cpp [96:1100]


VOID NTAPI ClassifyFastPacketInjection(_In_ const FWPS_INCOMING_VALUES* pClassifyValues,
                                       _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
                                       _Inout_opt_ VOID* pNetBufferList,
                                       _In_opt_ const VOID* pClassifyContext,
                                       _In_ const FWPS_FILTER* pFilter,
                                       _In_ UINT64 flowContext,
                                       _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut)
{
   UNREFERENCED_PARAMETER(pFilter);
   UNREFERENCED_PARAMETER(pClassifyContext);
   UNREFERENCED_PARAMETER(flowContext);

   if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE)
   {
      NTSTATUS                    status                = STATUS_SUCCESS;
      UINT32                      ipHeaderSize          = 0;
      UINT32                      transportHeaderSize   = 0;
      COMPARTMENT_ID              compartmentID         = DEFAULT_COMPARTMENT_ID;
      UINT64                      endpointHandle        = 0;
      ADDRESS_FAMILY              addressFamily         = AF_UNSPEC;
      UINT8                       protocol              = 0;
      FWP_DIRECTION               direction             = FWP_DIRECTION_MAX;
      UINT32                      flags                 = 0;
      BOOLEAN                     isALEClassifyRequired = FALSE;
      VOID*                       pRemoteAddress        = 0;
      IF_INDEX                    interfaceIndex        = 0;
      IF_INDEX                    subInterfaceIndex     = 0;
      HANDLE                      injectionHandle       = 0;
      FWPS_PACKET_INJECTION_STATE injectionState        = FWPS_PACKET_INJECTION_STATE_MAX;
      HANDLE                      injectionContext      = 0;
      UINT32                      bytesRetreated        = 0;
      NET_BUFFER_LIST*            pClonedNetBufferList  = 0;
      UINT32                      index                 = WFPSAMPLER_INDEX;

#if(NTDDI_VERSION >= NTDDI_WIN8)

      UINT32                      ethernetHeaderSize   = 0;
      NDIS_PORT_NUMBER            ndisPort             = 0;
      NDIS_SWITCH_PORT_ID         sourcePortID         = 0;
      NDIS_SWITCH_NIC_INDEX       sourceNICIndex       = 0;
      FWP_BYTE_BLOB*              pVSwitchID           = 0;

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

      if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata,
                                           FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_PORT_ID))
         sourcePortID = pMetadata->vSwitchSourcePortId;

      if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata,
                                           FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_NIC_INDEX))
         sourceNICIndex = (NDIS_SWITCH_NIC_INDEX)pMetadata->vSwitchSourceNicIndex;

#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_COMPARTMENT_ID))
         compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId;

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

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

      if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                        FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED))
         isALEClassifyRequired = TRUE;

      if(pFilter->subLayerWeight == FWPM_SUBLAYER_UNIVERSAL_WEIGHT)
         index = UNIVERSAL_INDEX;

      switch(pClassifyValues->layerId)
      {
         case FWPS_LAYER_INBOUND_IPPACKET_V4:
         {
            addressFamily = AF_INET;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32;

            subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V4_FLAGS].value.uint32;

            injectionHandle = g_pIPv4InboundNetworkInjectionHandles[index];

            bytesRetreated = ipHeaderSize;

            break;
         }
         case FWPS_LAYER_INBOUND_IPPACKET_V6:
         {
            addressFamily = AF_INET6;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32;

            subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_IPPACKET_V6_FLAGS].value.uint32;

            injectionHandle = g_pIPv6InboundNetworkInjectionHandles[index];

            bytesRetreated = ipHeaderSize;

            break;
         }
         case FWPS_LAYER_OUTBOUND_IPPACKET_V4:
         {
            addressFamily = AF_INET;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_IPPACKET_V4_FLAGS].value.uint32;

            injectionHandle = g_pIPv4OutboundNetworkInjectionHandles[index];
      
            break;
         }
         case FWPS_LAYER_OUTBOUND_IPPACKET_V6:
         {
            addressFamily = AF_INET6;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_IPPACKET_V6_FLAGS].value.uint32;

            injectionHandle = g_pIPv6OutboundNetworkInjectionHandles[index];
      
            break;
         }
         case FWPS_LAYER_IPFORWARD_V4:
         {
            addressFamily = AF_INET;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_IPFORWARD_V4_DESTINATION_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_IPFORWARD_V4_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_OUTBOUND)
               injectionHandle = g_pIPv4OutboundForwardInjectionHandles[index];
            else
               injectionHandle = g_pIPv4InboundForwardInjectionHandles[index];

            /// Determine if this is a weakhost forward and adjust accordingly
            if(flags & FWP_CONDITION_FLAG_IS_INBOUND_PASS_THRU)
               injectionHandle = g_pIPv4InboundNetworkInjectionHandles[index];
            else if(flags & FWP_CONDITION_FLAG_IS_OUTBOUND_PASS_THRU)
               injectionHandle = g_pIPv4OutboundNetworkInjectionHandles[index];      

            break;
         }
         case FWPS_LAYER_IPFORWARD_V6:
         {
            addressFamily = AF_INET6;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_IPFORWARD_V6_DESTINATION_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_IPFORWARD_V6_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_OUTBOUND)
               injectionHandle = g_pIPv6OutboundForwardInjectionHandles[index];
            else
               injectionHandle = g_pIPv6InboundForwardInjectionHandles[index];

            /// Determine if this is a weakhost forward and adjust accordingly
            if(flags & FWP_CONDITION_FLAG_IS_INBOUND_PASS_THRU)
               injectionHandle = g_pIPv6InboundNetworkInjectionHandles[index];
            else if(flags & FWP_CONDITION_FLAG_IS_OUTBOUND_PASS_THRU)
               injectionHandle = g_pIPv6OutboundNetworkInjectionHandles[index];

            break;
         }
         case FWPS_LAYER_INBOUND_TRANSPORT_V4:
         {
            addressFamily = AF_INET;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_INTERFACE_INDEX].value.uint32;

            subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_FLAGS].value.uint32;

            injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];

            if(protocol == ICMPV4)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;

            break;
         }
         case FWPS_LAYER_INBOUND_TRANSPORT_V6:
         {
            addressFamily = AF_INET6;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_PROTOCOL].value.uint8;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_INTERFACE_INDEX].value.uint32;

            subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_SUB_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V6_FLAGS].value.uint32;

            injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];

            if(protocol == ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;

            break;
         }
         case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
         {
            addressFamily = AF_INET;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8;

            pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS].value.uint32);

            flags = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_FLAGS].value.uint32;

            injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];
      
            break;
         }
         case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
         {
            addressFamily = AF_INET6;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_PROTOCOL].value.uint8;

            pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V6_FLAGS].value.uint32;

            injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];
      
            break;
         }
         case FWPS_LAYER_DATAGRAM_DATA_V4:
         {
            addressFamily = AF_INET;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8;

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

            flags = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;

               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
            else
            {
               pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32);

               injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];
            }
      
            break;
         }
         case FWPS_LAYER_DATAGRAM_DATA_V6:
         {
            addressFamily = AF_INET6;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_IP_PROTOCOL].value.uint8;

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

            flags = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_INTERFACE_INDEX].value.uint32;

               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
            else
            {
               pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;

               injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];
            }

            break;
         }
         case FWPS_LAYER_INBOUND_ICMP_ERROR_V4:
         {
            addressFamily = AF_INET;

            protocol = ICMPV4;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_ICMP_ERROR_V4_INTERFACE_INDEX].value.uint32;

            subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_ICMP_ERROR_V4_SUB_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_ICMP_ERROR_V4_FLAGS].value.uint32;

            injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];

            bytesRetreated = ipHeaderSize + transportHeaderSize;

            break;
         }
         case FWPS_LAYER_INBOUND_ICMP_ERROR_V6:
         {
            addressFamily = AF_INET6;

            protocol = ICMPV6;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_ICMP_ERROR_V6_INTERFACE_INDEX].value.uint32;

            subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_ICMP_ERROR_V6_SUB_INTERFACE_INDEX].value.uint32;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_ICMP_ERROR_V6_FLAGS].value.uint32;

            injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];

            bytesRetreated = ipHeaderSize + transportHeaderSize;

            break;
         }
         case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4:
         {
            addressFamily = AF_INET;

            protocol = ICMPV4;

            pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_ICMP_ERROR_V4_IP_REMOTE_ADDRESS].value.uint32);

            flags = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_ICMP_ERROR_V4_FLAGS].value.uint32;

            injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];

            bytesRetreated = ipHeaderSize;

            break;
         }
         case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6:
         {
            addressFamily = AF_INET6;

            protocol = ICMPV6;

            pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_ICMP_ERROR_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_ICMP_ERROR_V6_FLAGS].value.uint32;

            injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];

            bytesRetreated = ipHeaderSize;

            break;
         }
         case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
         {
            addressFamily = AF_INET;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_OUTBOUND)
            {
               pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32);

               injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];
            }
            else
            {
               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_INTERFACE_INDEX].value.uint32;
               
               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];

               if(protocol == ICMPV4)
                  bytesRetreated = ipHeaderSize;
               else
                  bytesRetreated = ipHeaderSize + transportHeaderSize;
            }

            break;
         }
         case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
         {
            addressFamily = AF_INET6;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_OUTBOUND)
            {
               pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;

               injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];
            }
            else
            {
               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_INTERFACE_INDEX].value.uint32;
               
               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];

               if(protocol == ICMPV6)
                  bytesRetreated = ipHeaderSize;
               else
                  bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
      
            break;
         }
         case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
         {
            addressFamily = AF_INET;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               bytesRetreated = ipHeaderSize + transportHeaderSize;

               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_INTERFACE_INDEX].value.uint32;

               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];
            }
            else
            {
               pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32);

               injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];
            }

            break;
         }
         case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
         {
            addressFamily = AF_INET6;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V6_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               bytesRetreated = ipHeaderSize + transportHeaderSize;

               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V6_INTERFACE_INDEX].value.uint32;

               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V6_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];
            }
            else
            {
               pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;

               injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];
            }

            break;
         }
         case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4:
         {
            addressFamily = AF_INET;

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

            direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];

               if(ipHeaderSize == 0)
                  ipHeaderSize = IPV4_HEADER_MIN_SIZE;

               if(transportHeaderSize == 0)
               {
                  if(protocol == ICMPV4)
                     transportHeaderSize = ICMP_HEADER_MIN_SIZE;
                  else if(protocol == TCP)
                     transportHeaderSize = TCP_HEADER_MIN_SIZE;
                  else if(protocol == UDP)
                     transportHeaderSize = UDP_HEADER_MIN_SIZE;
               }

               if(protocol == ICMPV4)
                  bytesRetreated = ipHeaderSize;
               else
                  bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
            else
            {
               pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS].value.uint32);

               injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize;
            }
      
            break;
         }
         case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6:
         {
            addressFamily = AF_INET6;

            protocol = pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8;

            direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_DIRECTION].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];

               if(ipHeaderSize == 0)
                  ipHeaderSize = IPV6_HEADER_MIN_SIZE;

               if(transportHeaderSize == 0)
               {
                  if(protocol == ICMPV6)
                     transportHeaderSize = ICMP_HEADER_MIN_SIZE;
                  else if(protocol == TCP)
                     transportHeaderSize = TCP_HEADER_MIN_SIZE;
                  else if(protocol == UDP)
                     transportHeaderSize = UDP_HEADER_MIN_SIZE;
               }

               if(protocol == ICMPV6)
                  bytesRetreated = ipHeaderSize;
               else
                  bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
            else
            {
               pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;

               injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize;
            }

            break;
         }
         case FWPS_LAYER_STREAM_PACKET_V4:
         {
            addressFamily = AF_INET;

            protocol = TCP;

            direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_DIRECTION].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_FLAGS].value.uint32;
   
            if(direction == FWP_DIRECTION_INBOUND)
            {
               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_INTERFACE_INDEX].value.uint32;

               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv4InboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
            else
            {
               pRemoteAddress = &(pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_IP_REMOTE_ADDRESS].value.uint32);
            
               injectionHandle = g_pIPv4OutboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize;
            }

            break;
         }
         case FWPS_LAYER_STREAM_PACKET_V6:
         {
            addressFamily = AF_INET6;

            protocol = TCP;

            direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V6_DIRECTION].value.uint8;

            flags = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V6_FLAGS].value.uint32;

            if(direction == FWP_DIRECTION_INBOUND)
            {
               interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V6_INTERFACE_INDEX].value.uint32;

               subInterfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V6_SUB_INTERFACE_INDEX].value.uint32;

               injectionHandle = g_pIPv6InboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize + transportHeaderSize;
            }
            else
            {
               pRemoteAddress = pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V6_IP_REMOTE_ADDRESS].value.byteArray16->byteArray16;
            
               injectionHandle = g_pIPv6OutboundTransportInjectionHandles[index];

               bytesRetreated = ipHeaderSize;
            }

            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;

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_ETHERNET_INTERFACE_INDEX].value.uint32;

            ndisPort = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_ETHERNET_NDIS_PORT].value.uint32;

            if(etherType == 0x86DD)
            {
               addressFamily = AF_INET6;

               injectionHandle = g_pIPv6InboundMACInjectionHandles[index];
            }
            else if(etherType == 0x800)
            {
               addressFamily = AF_INET;

               injectionHandle = g_pIPv4InboundMACInjectionHandles[index];
            }
            else
               injectionHandle = g_pInboundMACInjectionHandles[index];
 
            bytesRetreated = ethernetHeaderSize;

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

            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_ETHERNET_INTERFACE_INDEX].value.uint32;

            ndisPort = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_ETHERNET_NDIS_PORT].value.uint32;

            if(etherType == 0x86DD)
            {
               addressFamily = AF_INET6;

               injectionHandle = g_pIPv6OutboundMACInjectionHandles[index];
            }
            else if(etherType == 0x800)
            {
               addressFamily = AF_INET;

               injectionHandle = g_pIPv4OutboundMACInjectionHandles[index];
            }
            else
               injectionHandle = g_pOutboundMACInjectionHandles[index];

            break;
         }
         case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE:
         {
            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;

            ndisPort = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;

            injectionHandle = g_pInboundMACInjectionHandles[index];

            break;
         }
         case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE:
         {
            interfaceIndex = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_NATIVE_INTERFACE_INDEX].value.uint32;

            ndisPort = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_NATIVE_NDIS_PORT].value.uint32;

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

            pVSwitchID = pClassifyValues->incomingValue[FWPS_FIELD_INGRESS_VSWITCH_ETHERNET_VSWITCH_ID].value.byteBlob;

            if(etherType == 0x86DD)
            {
               addressFamily   = AF_INET6;

               injectionHandle = g_pIPv6IngressVSwitchEthernetInjectionHandles[index];
            }
            else if(etherType == 0x800)
            {
               addressFamily   = AF_INET;

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

            pVSwitchID = pClassifyValues->incomingValue[FWPS_FIELD_EGRESS_VSWITCH_ETHERNET_VSWITCH_ID].value.byteBlob;

            if(etherType == 0x86DD)
            {
               addressFamily   = AF_INET6;

               injectionHandle = g_pIPv6EgressVSwitchEthernetInjectionHandles[index];
            }
            else if(etherType == 0x800)
            {
               addressFamily   = AF_INET;

               injectionHandle = g_pIPv4EgressVSwitchEthernetInjectionHandles[index];
            }
            else
               injectionHandle = g_pEgressVSwitchEthernetInjectionHandles[index];
   
            break;
         }
         
#endif // (NTDDI_VERSION >= NTDDI_WIN8)

      }

      pClassifyOut->actionType = FWP_ACTION_PERMIT;

      if(!((flags & FWP_CONDITION_FLAG_IS_LOOPBACK ||
         (flags & FWP_CONDITION_FLAG_IS_IPSEC_SECURED &&
         (flags & FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY ||
         isALEClassifyRequired)))))
      {
         injectionState = FwpsQueryPacketInjectionState(injectionHandle,
                                                        (NET_BUFFER_LIST*)pNetBufferList,
                                                        &injectionContext);
         if(injectionState != FWPS_PACKET_INJECTED_BY_SELF &&
            injectionState != FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
         {
            /// Due to TCP's locking semantics, TCP can only be injected Out of Band at any 
            /// transport layer or equivalent.
            if(protocol == TCP &&
               (injectionHandle == g_pIPv4InboundTransportInjectionHandles[index] ||
               injectionHandle == g_pIPv6InboundTransportInjectionHandles[index] ||
               injectionHandle == g_pIPv4OutboundTransportInjectionHandles[index] ||
               injectionHandle == g_pIPv6OutboundTransportInjectionHandles[index]))
               HLPR_BAIL;

            pClassifyOut->actionType  = FWP_ACTION_BLOCK;
            pClassifyOut->flags      |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            pClassifyOut->rights     ^= FWPS_RIGHT_ACTION_WRITE;

            if(bytesRetreated)
            {
               status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList),
                                                      bytesRetreated,
                                                      0,
                                                      0);
               HLPR_BAIL_ON_FAILURE(status);
            }

            status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pNetBufferList,
                                                    g_pNDISPoolData->nblPoolHandle,
                                                    g_pNDISPoolData->nbPoolHandle,
                                                    0,
                                                    &pClonedNetBufferList);

            if(bytesRetreated)
               NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList),
                                             bytesRetreated,
                                             FALSE,
                                             0);

            HLPR_BAIL_ON_FAILURE(status);

            if(injectionHandle == g_pIPv4InboundNetworkInjectionHandles[index] ||
               injectionHandle == g_pIPv6InboundNetworkInjectionHandles[index])
               status = FwpsInjectNetworkReceiveAsync(injectionHandle,
                                                      injectionContext,
                                                      0,
                                                      compartmentID,
                                                      interfaceIndex,
                                                      subInterfaceIndex,
                                                      pClonedNetBufferList,
                                                      CompleteFastPacketInjection,
                                                      0);
            else if(injectionHandle == g_pIPv4OutboundNetworkInjectionHandles[index] ||
                    injectionHandle == g_pIPv6OutboundNetworkInjectionHandles[index])
               status = FwpsInjectNetworkSendAsync(injectionHandle,
                                                   injectionContext,
                                                   0,
                                                   compartmentID,
                                                   pClonedNetBufferList,
                                                   CompleteFastPacketInjection,
                                                   0);
            else if(injectionHandle == g_pIPv4InboundForwardInjectionHandles[index] ||
                    injectionHandle == g_pIPv6InboundForwardInjectionHandles[index] ||
                    injectionHandle == g_pIPv4OutboundForwardInjectionHandles[index] ||
                    injectionHandle == g_pIPv6OutboundForwardInjectionHandles[index])
               status = FwpsInjectForwardAsync(injectionHandle,
                                               injectionContext,
                                               0,
                                               addressFamily,
                                               compartmentID,
                                               interfaceIndex,
                                               pClonedNetBufferList,
                                               CompleteFastPacketInjection,
                                               0);
            else if(injectionHandle == g_pIPv4InboundTransportInjectionHandles[index] ||
                    injectionHandle == g_pIPv6InboundTransportInjectionHandles[index])
               status = FwpsInjectTransportReceiveAsync(injectionHandle,
                                                        injectionContext,
                                                        0,
                                                        0,
                                                        addressFamily,
                                                        compartmentID,
                                                        interfaceIndex,
                                                        subInterfaceIndex,
                                                        pClonedNetBufferList,
                                                        CompleteFastPacketInjection,
                                                        0);
            else if(injectionHandle == g_pIPv4OutboundTransportInjectionHandles[index] ||
                    injectionHandle == g_pIPv6OutboundTransportInjectionHandles[index])
            {
               FWPS_TRANSPORT_SEND_PARAMS* pSendParams = 0;
               UINT32                      addressSize = addressFamily == AF_INET ? IPV4_ADDRESS_SIZE : IPV6_ADDRESS_SIZE;

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

               HLPR_NEW(pSendParams,
                        FWPS_TRANSPORT_SEND_PARAMS,
                        WFPSAMPLER_CALLOUT_DRIVER_TAG);
               HLPR_BAIL_ON_ALLOC_FAILURE_2(pSendParams,
                                            status);

               HLPR_NEW_ARRAY(pSendParams->remoteAddress,
                              BYTE,
                              addressSize,
                              WFPSAMPLER_CALLOUT_DRIVER_TAG);
               HLPR_BAIL_ON_ALLOC_FAILURE_2(pSendParams->remoteAddress,
                                            status);

#pragma warning(pop)

               if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                                 FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
               {
                  pSendParams->controlData       = pMetadata->controlData;
                  pSendParams->controlDataLength = pMetadata->controlDataLength;
               }

               if(addressFamily == AF_INET)
               {
                  UINT32 remoteAddress = *((UINT32*)pRemoteAddress);

                  remoteAddress = ntohl(remoteAddress);

                  RtlCopyMemory(pSendParams->remoteAddress,
                                &remoteAddress,
                                addressSize);
               }
               else
               {
                  RtlCopyMemory(pSendParams->remoteAddress,
                                pRemoteAddress,
                                addressSize);

                  if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                                    FWPS_METADATA_FIELD_REMOTE_SCOPE_ID))
                     pSendParams->remoteScopeId = pMetadata->remoteScopeId;
               }

               status = FwpsInjectTransportSendAsync(injectionHandle,
                                                     injectionContext,
                                                     endpointHandle,
                                                     0,
                                                     pSendParams,
                                                     addressFamily,
                                                     compartmentID,
                                                     pClonedNetBufferList,
                                                     CompleteFastPacketInjection,
                                                     pSendParams);

               HLPR_BAIL_LABEL_2:

               if(status != STATUS_SUCCESS)
               {
#pragma warning(push)
#pragma warning(disable: 28924) /// pSendParams could be NULL if the ALLOC fails

                  if(pSendParams)
                  {
                     HLPR_DELETE_ARRAY(pSendParams->remoteAddress,
                                       WFPSAMPLER_CALLOUT_DRIVER_TAG);
                  }

                  HLPR_DELETE(pSendParams,
                              WFPSAMPLER_CALLOUT_DRIVER_TAG);

#pragma warning(pop)
               }
            }

#if(NTDDI_VERSION >= NTDDI_WIN8)

            else if(injectionHandle == g_pIPv4InboundMACInjectionHandles[index] ||
                    injectionHandle == g_pIPv6InboundMACInjectionHandles[index] ||
                    injectionHandle == g_pInboundMACInjectionHandles[index])
               status = FwpsInjectMacReceiveAsync(injectionHandle,
                                                  injectionContext,
                                                  0,
                                                  pClassifyValues->layerId,
                                                  interfaceIndex,
                                                  ndisPort,
                                                  pClonedNetBufferList,
                                                  CompleteFastPacketInjection,
                                                  0);
            else if(injectionHandle == g_pIPv4OutboundMACInjectionHandles[index] ||
                    injectionHandle == g_pIPv6OutboundMACInjectionHandles[index] ||
                    injectionHandle == g_pOutboundMACInjectionHandles[index])
               status = FwpsInjectMacSendAsync(injectionHandle,
                                               injectionContext,
                                               0,
                                               pClassifyValues->layerId,
                                               interfaceIndex,
                                               ndisPort,
                                               pClonedNetBufferList,
                                               CompleteFastPacketInjection,
                                               0);
            else if(injectionHandle == g_pIPv4IngressVSwitchEthernetInjectionHandles[index] ||
                    injectionHandle == g_pIPv6IngressVSwitchEthernetInjectionHandles[index] ||
                    injectionHandle == g_pIngressVSwitchEthernetInjectionHandles[index] ||
                    injectionHandle == g_pIPv4EgressVSwitchEthernetInjectionHandles[index] ||
                    injectionHandle == g_pIPv6EgressVSwitchEthernetInjectionHandles[index] ||
                    injectionHandle == g_pEgressVSwitchEthernetInjectionHandles[index])
               status = FwpsInjectvSwitchEthernetIngressAsync(injectionHandle,
                                                              injectionContext,
                                                              0,
                                                              0,
                                                              pVSwitchID,
                                                              sourcePortID,
                                                              sourceNICIndex,
                                                              pClonedNetBufferList,
                                                              CompleteFastPacketInjection,
                                                              0);

#endif ///(NTDDI_VERSION >= NTDDI_WIN8)

            HLPR_BAIL_LABEL:
            
            if(status != STATUS_SUCCESS)
            {
               if(pClonedNetBufferList)
                  FwpsFreeCloneNetBufferList(pClonedNetBufferList,
                                             0);

               DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                          DPFLTR_ERROR_LEVEL,
                          " !!!! ClassifyFastPacketInjection : FwpsInjectAsync() [status: %#x]\n",
                          status);
            }
         }
      }
   }

   return;
}