NTSTATUS TLInspectCloneReinjectOutbound( _Inout_ TL_INSPECT_PENDED_PACKET* packet ) /* ++ This function clones the outbound net buffer list and reinject it back. -- */ { NTSTATUS status = STATUS_SUCCESS; NET_BUFFER_LIST* clonedNetBufferList = NULL; FWPS_TRANSPORT_SEND_PARAMS sendArgs = {0}; status = FwpsAllocateCloneNetBufferList( packet->netBufferList, NULL, NULL, 0, &clonedNetBufferList ); if (!NT_SUCCESS(status)) { goto Exit; } sendArgs.remoteAddress = (UINT8*)(&packet->remoteAddr); sendArgs.remoteScopeId = packet->remoteScopeId; sendArgs.controlData = packet->controlData; sendArgs.controlDataLength = packet->controlDataLength; // // Send-inject the cloned net buffer list. // status = FwpsInjectTransportSendAsync( gInjectionHandle, NULL, packet->endpointHandle, 0, &sendArgs, packet->addressFamily, packet->compartmentId, clonedNetBufferList, TLInspectInjectComplete, packet ); if (!NT_SUCCESS(status)) { goto Exit; } clonedNetBufferList = NULL; // ownership transferred to the // completion function. Exit: if (clonedNetBufferList != NULL) { FwpsFreeCloneNetBufferList(clonedNetBufferList, 0); } return status; }
NTSTATUS PrvCloneAuthorizedNBLAndInject(_Inout_ CLASSIFY_DATA** ppClassifyData, _Inout_ INJECTION_DATA** ppInjectionData) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PrvCloneAuthorizedNBLAndInject()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); 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; UINT32 bytesRetreated = 0; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; BOOLEAN isInbound = FALSE; NET_BUFFER_LIST* pNetBufferList = 0; PEND_AUTHORIZATION_COMPLETION_DATA* pCompletionData = 0; FWPS_TRANSPORT_SEND_PARAMS* pSendParams = 0; BYTE* pRemoteAddress = 0; #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using PendAuthorizationCompletionDataDestroy HLPR_NEW(pCompletionData, PEND_AUTHORIZATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); HLPR_NEW(pSendParams, FWPS_TRANSPORT_SEND_PARAMS, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pSendParams, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = FALSE; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; pCompletionData->pSendParams = pSendParams; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; pSendParams = 0; if(pCompletionData->pInjectionData->direction == FWP_DIRECTION_INBOUND) isInbound = TRUE; 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_IP_HEADER_SIZE)) bytesRetreated = pMetadata->ipHeaderSize; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) bytesRetreated += pMetadata->transportHeaderSize; if(pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6) { if(isInbound) /// NBL offset is at the start of the transport header ... { if(bytesRetreated) { /// so retreat (size of IP Header) to clone the whole NBL 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, " !!!! PrvCloneAuthorizedNBLAndInject: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } } } else if(pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6) { /// NBL offset is at the Transport Header, and no IP Header is present yet bytesRetreated = 0; isInbound = FALSE; } else { status = STATUS_FWP_INCOMPATIBLE_LAYER; HLPR_BAIL; } status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)(pCompletionData->pClassifyData->pPacket), g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(bytesRetreated) { /// Advance the NBL offset so we are back at the expected position in the NET_BUFFER_LIST NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, FALSE, 0); } if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PrvCloneAuthorizedNBLAndInject : FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } if(isInbound) { FWP_VALUE* pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_INTERFACE_INDEX); FWP_VALUE* pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_SUB_INTERFACE_INDEX); IF_INDEX interfaceIndex = 0; IF_INDEX subInterfaceIndex = 0; if(pInterfaceIndex && pInterfaceIndex->type == FWP_UINT32) interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; if(pSubInterfaceIndex && pSubInterfaceIndex->type == FWP_UINT32) subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32; status = FwpsInjectTransportReceiveAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, 0, pCompletionData->pInjectionData->addressFamily, compartmentID, interfaceIndex, subInterfaceIndex, pNetBufferList, CompletePendAuthorization, pCompletionData); } else { UINT64 endpointHandle = 0; FWP_VALUE* pAddressValue = 0; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)) endpointHandle = pMetadata->transportEndpointHandle; pAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); if(pAddressValue) { if(pCompletionData->pInjectionData->addressFamily == AF_INET) { UINT32 tempAddress = htonl(pAddressValue->uint32); #pragma warning(push) #pragma warning(disable: 6014) /// pRemoteAddress will be freed in completionFn using PendAuthorizationCompletionDataDestroy HLPR_NEW_ARRAY(pRemoteAddress, BYTE, IPV4_ADDRESS_SIZE, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress, status); #pragma warning(pop) RtlCopyMemory(pRemoteAddress, &tempAddress, IPV4_ADDRESS_SIZE); } else { #pragma warning(push) #pragma warning(disable: 6014) /// pRemoteAddress will be freed in completionFn using PendAuthorizationCompletionDataDestroy HLPR_NEW_ARRAY(pRemoteAddress, BYTE, IPV6_ADDRESS_SIZE, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress, status); #pragma warning(pop) RtlCopyMemory(pRemoteAddress, pAddressValue->byteArray16->byteArray16, IPV6_ADDRESS_SIZE); if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_REMOTE_SCOPE_ID)) pCompletionData->pSendParams->remoteScopeId = pMetadata->remoteScopeId; } pCompletionData->pSendParams->remoteAddress = pRemoteAddress; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); status = FwpsInjectTransportSendAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, endpointHandle, 0, pCompletionData->pSendParams, pCompletionData->pInjectionData->addressFamily, compartmentID, pNetBufferList, CompletePendAuthorization, pCompletionData); } HLPR_BAIL_LABEL: if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) PendAuthorizationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PrvCloneAuthorizedNBLAndInject() [status: %#x]\n", status); #endif /// DBG return status; }
NTSTATUS TLInspectCloneReinjectInbound( _Inout_ TL_INSPECT_PENDED_PACKET* packet ) /* ++ This function clones the inbound net buffer list and, if needed, rebuild the IP header to remove the IpSec headers and receive-injects the clone back to the tcpip stack. -- */ { NTSTATUS status = STATUS_SUCCESS; NET_BUFFER_LIST* clonedNetBufferList = NULL; NET_BUFFER* netBuffer; ULONG nblOffset; NDIS_STATUS ndisStatus; // // For inbound net buffer list, we can assume it contains only one // net buffer. // netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList); nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer); // // The TCP/IP stack could have retreated the net buffer list by the // transportHeaderSize amount; detect the condition here to avoid // retreating twice. // if (nblOffset != packet->nblOffset) { NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize); packet->transportHeaderSize = 0; } // // Adjust the net buffer list offset to the start of the IP header. // ndisStatus = NdisRetreatNetBufferDataStart( netBuffer, packet->ipHeaderSize + packet->transportHeaderSize, 0, NULL ); _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS); // // Note that the clone will inherit the original net buffer list's offset. // status = FwpsAllocateCloneNetBufferList( packet->netBufferList, NULL, NULL, 0, &clonedNetBufferList ); // // Undo the adjustment on the original net buffer list. // NdisAdvanceNetBufferDataStart( netBuffer, packet->ipHeaderSize + packet->transportHeaderSize, FALSE, NULL ); if (!NT_SUCCESS(status)) { goto Exit; } if (packet->ipSecProtected) { // // When an IpSec protected packet is indicated to AUTH_RECV_ACCEPT or // INBOUND_TRANSPORT layers, for performance reasons the tcpip stack // does not remove the AH/ESP header from the packet. And such // packets cannot be recv-injected back to the stack w/o removing the // AH/ESP header. Therefore before re-injection we need to "re-build" // the cloned packet. // status = FwpsConstructIpHeaderForTransportPacket( clonedNetBufferList, packet->ipHeaderSize, packet->addressFamily, (UINT8*)&packet->remoteAddr, (UINT8*)&packet->localAddr, packet->protocol, 0, NULL, 0, 0, NULL, 0, 0 ); if (!NT_SUCCESS(status)) { goto Exit; } } if (packet->completionContext != NULL) { NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET); FwpsCompleteOperation( packet->completionContext, clonedNetBufferList ); packet->completionContext = NULL; } status = FwpsInjectTransportReceiveAsync( gInjectionHandle, NULL, NULL, 0, packet->addressFamily, packet->compartmentId, packet->interfaceIndex, packet->subInterfaceIndex, clonedNetBufferList, TLInspectInjectComplete, packet ); if (!NT_SUCCESS(status)) { goto Exit; } clonedNetBufferList = NULL; // ownership transferred to the // completion function. Exit: if (clonedNetBufferList != NULL) { FwpsFreeCloneNetBufferList(clonedNetBufferList, 0); } return status; }
void NPF_NetworkClassify( _In_ const FWPS_INCOMING_VALUES* inFixedValues, _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues, _Inout_opt_ void* layerData, _In_ const FWPS_FILTER* filter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT* classifyOut ) #endif { POPEN_INSTANCE GroupOpen; POPEN_INSTANCE TempOpen; NTSTATUS status = STATUS_SUCCESS; UINT32 ipHeaderSize = 0; UINT32 bytesRetreated = 0; UINT32 bytesRetreatedEthernet = 0; INT32 iIPv4 = -1; INT32 iDrection = -1; BOOLEAN bSelfSent = FALSE; PVOID pContiguousData = NULL; NET_BUFFER* pNetBuffer = 0; UCHAR pPacketData[ETHER_HDR_LEN]; PNET_BUFFER_LIST pNetBufferList = (NET_BUFFER_LIST*) layerData; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; FWPS_PACKET_INJECTION_STATE injectionState = FWPS_PACKET_INJECTION_STATE_MAX; #if(NTDDI_VERSION >= NTDDI_WIN7) UNREFERENCED_PARAMETER(classifyContext); #endif UNREFERENCED_PARAMETER(filter); UNREFERENCED_PARAMETER(flowContext); // Make the default action. if (classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) classifyOut->actionType = FWP_ACTION_CONTINUE; #if(NTDDI_VERSION >= NTDDI_WIN7) // Filter out fragment packets and reassembled packets. if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FRAGMENT_DATA) { return; } if (inMetaValues->currentMetadataValues & FWP_CONDITION_FLAG_IS_REASSEMBLED) { return; } #endif TRACE_ENTER(); // Get the packet protocol (IPv4 or IPv6) and the direction (Inbound or Outbound). if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4) { iIPv4 = 1; } else // if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) { iIPv4 = 0; } if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) { iDrection = 0; } else // if (inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) { iDrection = 1; } if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_IP_HEADER_SIZE) { ipHeaderSize = inMetaValues->ipHeaderSize; } injectionState = FwpsQueryPacketInjectionState(iIPv4 ? g_InjectionHandle_IPv4 : g_InjectionHandle_IPv6, pNetBufferList, NULL); if (injectionState == FWPS_PACKET_INJECTED_BY_SELF || injectionState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) { TRACE_MESSAGE(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: this packet is injected by ourself, let it go\n"); TRACE_EXIT(); return; } // Inbound: Initial offset is at the Transport Header, so retreat the size of the Ethernet Header and IP Header. // Outbound: Initial offset is at the IP Header, so just retreat the size of the Ethernet Header. // We retreated the packet in two phases: 1) retreat the IP Header (if has), 2) clone the packet and retreat the Ethernet Header. // We must NOT retreat the Ethernet Header on the original packet, or this will lead to BAD_POOL_CALLER Bluescreen. bytesRetreated = iDrection ? ipHeaderSize : 0; status = NdisRetreatNetBufferListDataStart(pNetBufferList, bytesRetreated, 0, NULL, NULL); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(bytesRetreated) [status: %#x]\n", status); TRACE_EXIT(); return; } //bSelfSent = NPF_IsPacketSelfSent(pNetBufferList, (BOOLEAN)iIPv4); bSelfSent = (iDrection == 0) ? FALSE : NPF_IsPacketSelfSent(pNetBufferList, (BOOLEAN) iIPv4); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: %#x]\n", bSelfSent); if (bSelfSent) { NdisAdvanceNetBufferListDataStart(pNetBufferList, iIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN, FALSE, 0); } // Here if this NBL is sent by ourself, we will clone it starting from IP header and inject it into Network Layer send path. if (bSelfSent) { PNET_BUFFER_LIST pClonedNetBufferList_Injection; status = FwpsAllocateCloneNetBufferList(pNetBufferList, NULL, NULL, 0, &pClonedNetBufferList_Injection); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: FwpsAllocateCloneNetBufferList(pClonedNetBufferList_Injection) [status: %#x]\n", status); goto Exit_WSK_IP_Retreated; } if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)inMetaValues->compartmentId; // This cloned NBL will be freed in NPF_NetworkInjectionComplete function. status = FwpsInjectNetworkSendAsync(iIPv4 ? g_InjectionHandle_IPv4 : g_InjectionHandle_IPv6, NULL, 0, compartmentID, pClonedNetBufferList_Injection, NPF_NetworkInjectionComplete, NULL); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: FwpsInjectNetworkSendAsync() [status: %#x]\n", status); FwpsFreeCloneNetBufferList(pClonedNetBufferList_Injection, 0); goto Exit_WSK_IP_Retreated; } // We have successfully re-inject the cloned NBL, so remove this one. classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; classifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; } // We clone this NBL again, for packet reading operation. PNET_BUFFER_LIST pClonedNetBufferList; status = FwpsAllocateCloneNetBufferList(pNetBufferList, NULL, NULL, 0, &pClonedNetBufferList); if (status != STATUS_SUCCESS) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); goto Exit_WSK_IP_Retreated; } bytesRetreatedEthernet = g_DltNullMode ? DLT_NULL_HDR_LEN : ETHER_HDR_LEN; status = NdisRetreatNetBufferListDataStart(pClonedNetBufferList, bytesRetreatedEthernet, 0, 0, 0); if (status != STATUS_SUCCESS) { bytesRetreatedEthernet = 0; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(bytesRetreatedEthernet) [status: %#x]\n", status); goto Exit_Packet_Cloned; } pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pClonedNetBufferList); while (pNetBuffer) { pContiguousData = NdisGetDataBuffer(pNetBuffer, bytesRetreatedEthernet, pPacketData, 1, 0); if (!pContiguousData) { status = STATUS_UNSUCCESSFUL; TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_NetworkClassify: NdisGetDataBuffer() [status: %#x]\n", status); goto Exit_Ethernet_Retreated; } else { if (g_DltNullMode) { ((PDLT_NULL_HEADER) pContiguousData)->null_type = iIPv4 ? DLTNULLTYPE_IP : DLTNULLTYPE_IPV6; } else { RtlZeroMemory(pContiguousData, ETHER_ADDR_LEN * 2); ((PETHER_HEADER) pContiguousData)->ether_type = iIPv4 ? RtlUshortByteSwap(ETHERTYPE_IP) : RtlUshortByteSwap(ETHERTYPE_IPV6); } } pNetBuffer = pNetBuffer->Next; } // Send the loopback packets data to the user-mode code. if (g_LoopbackOpenGroupHead) { //get the 1st group adapter child GroupOpen = g_LoopbackOpenGroupHead->GroupNext; } else { // Should not come here GroupOpen = NULL; } while (GroupOpen != NULL) { TempOpen = GroupOpen; if (TempOpen->AdapterBindingStatus == ADAPTER_BOUND) { //let every group adapter receive the packets NPF_TapExForEachOpen(TempOpen, pClonedNetBufferList); } GroupOpen = TempOpen->GroupNext; } Exit_Ethernet_Retreated: // Advance the offset back to the original position. NdisAdvanceNetBufferListDataStart(pClonedNetBufferList, bytesRetreatedEthernet, FALSE, 0); Exit_Packet_Cloned: FwpsFreeCloneNetBufferList(pClonedNetBufferList, 0); Exit_WSK_IP_Retreated: if (bSelfSent) { status = NdisRetreatNetBufferListDataStart(pNetBufferList, iIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN, 0, NULL, NULL); // if (status != STATUS_SUCCESS) // { // TRACE_MESSAGE1(PACKET_DEBUG_LOUD, // "NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(IP_HDR_LEN) [status: %#x]\n", // status); // // goto Exit_IP_Retreated; // } } /*Exit_IP_Retreated:*/ NdisAdvanceNetBufferListDataStart(pNetBufferList, bytesRetreated, FALSE, 0); // // print "protocol, direction, fragment, reassembled" info for the current packet. // // int iFragment = -1; // if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FRAGMENT_DATA) // { // iFragment = 1; // } // else // { // iFragment = 0; // } // // int iReassembled = -1; // if (inMetaValues->currentMetadataValues & FWP_CONDITION_FLAG_IS_REASSEMBLED) // { // iReassembled = 1; // } // else // { // iReassembled = 0; // } // IF_LOUD(DbgPrint("\n\nNPF_NetworkClassify: Loopback packet found !!! protocol=[%d] (ipv4=0, ipv6=1), direction=[%d] (out=0, in=1), fragment=[%d], reassembled=[%d]\n", iProtocol, iDrection, iFragment, iReassembled);) TRACE_EXIT(); return; }