Пример #1
0
/*
 * --------------------------------------------------------------------------
 * OvsPartialCopyToMultipleNBLs --
 *
 *     This is similar to OvsPartialCopyNBL() except that each NB will
 *     have its own NBL.
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsPartialCopyToMultipleNBLs(PVOID ovsContext,
                             PNET_BUFFER_LIST nbl,
                             UINT32 copySize,
                             UINT32 headRoom,
                             BOOLEAN copyNblInfo)
{
    PNET_BUFFER nb, nextNb = NULL, firstNb, prevNb;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    PNET_BUFFER_LIST firstNbl = NULL, newNbl, prevNbl = NULL;

    nb = NET_BUFFER_LIST_FIRST_NB(nbl);
    if (NET_BUFFER_NEXT_NB(nb) == NULL) {
        return OvsPartialCopyNBL(context, nbl, copySize, headRoom, copyNblInfo);
    }

    firstNb = nb;
    prevNb = nb;

    while (nb) {
        nextNb = NET_BUFFER_NEXT_NB(nb);
        NET_BUFFER_NEXT_NB(nb) = NULL;

        NET_BUFFER_LIST_FIRST_NB(nbl) = nb;

        newNbl = OvsPartialCopyNBL(context, nbl, copySize, headRoom,
                                   copyNblInfo);
        if (newNbl == NULL) {
            goto cleanup;
        }
        if (prevNbl == NULL) {
            firstNbl = newNbl;
        } else {
            NET_BUFFER_LIST_NEXT_NBL(prevNbl) = newNbl;
            NET_BUFFER_NEXT_NB(prevNb) = nb;
        }
        prevNbl = newNbl;
        prevNb = nb;
        nb = nextNb;
    }
    NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;
    return firstNbl;

cleanup:
    NET_BUFFER_NEXT_NB(prevNb) = nb;
    NET_BUFFER_NEXT_NB(nb) = nextNb;
    NET_BUFFER_LIST_FIRST_NB(nbl) = firstNb;

    newNbl = firstNbl;
    while (newNbl) {
        firstNbl = NET_BUFFER_LIST_NEXT_NBL(newNbl);
        NET_BUFFER_LIST_NEXT_NBL(newNbl) = NULL;
        OvsCompleteNBL(context, newNbl, TRUE);
        newNbl = firstNbl;
    }
    return NULL;
}
Пример #2
0
// NDIS packet transmission completion notification procedure
void SlNdisSendNetBufferListsCompleteProc(NDIS_HANDLE protocol_binding_context, NET_BUFFER_LIST *net_buffer_lists,
										  ULONG send_complete_flags)
{
	NET_BUFFER_LIST *nbl;

	nbl = net_buffer_lists;

	while (nbl != NULL)
	{
		NET_BUFFER_LIST *current_nbl = nbl;
		SL_FILE *f;
		NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);

		if (nb != NULL)
		{
			UINT size = NET_BUFFER_DATA_LENGTH(nb);

			NdisAdvanceNetBufferDataStart(nb, size, false, NULL);
		}

		// Get a file context
		f = *((void **)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl));

		nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
		NET_BUFFER_LIST_NEXT_NBL(current_nbl) = NULL;

		// Release the NET_BUFFER_LIST
		NdisFreeNetBufferList(current_nbl);

		// Reduce the number of packets being sent by 1
		InterlockedExchangeAdd(&f->NumSendingPacketets, (LONG)-1);
		InterlockedExchangeAdd(&f->Adapter->NumPendingSendPackets, (LONG)-1);
	}
}
Пример #3
0
// Used on PortReturn to free the RX_PACKETs 
// allocated via BasePortTranslateRxPacketsToRxNBLs 
VOID
BasePortFreeTranslatedRxNBLs(
    __in  PMP_PORT                Port,
    __out PNET_BUFFER_LIST        NetBufferLists
    )
{
    PNET_BUFFER_LIST            currentNetBufferList, nextNetBufferList;
    PMDL                        currentMdl, nextMdl;

    UNREFERENCED_PARAMETER(Port);

    currentNetBufferList = NetBufferLists;
    while (currentNetBufferList != NULL)
    {
        nextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList);
        NET_BUFFER_LIST_NEXT_NBL(currentNetBufferList) = NULL;

        currentMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(currentNetBufferList));
        while (currentMdl != NULL)
        {
            nextMdl = NDIS_MDL_LINKAGE(currentMdl);

            // Free the MDL
            NdisFreeMdl(currentMdl);

            currentMdl = nextMdl;
        }

        // Free the NET_BUFFER and NET_BUFFER_LIST
        NdisFreeNetBufferList(currentNetBufferList);
        
        currentNetBufferList = nextNetBufferList;
    }
}
Пример #4
0
BOOLEAN
NPF_IsPacketSelfSent(
	_In_ PNET_BUFFER_LIST pNetBufferList,
	_In_ BOOLEAN bIPv4
	)
{
	NTSTATUS			status = STATUS_SUCCESS;
	NET_BUFFER*			pNetBuffer = 0;
	PVOID				pContiguousData = NULL;
	UCHAR				pPacketData[IPV6_HDR_LEN];
	UCHAR				iProtocol;

	TRACE_ENTER();

	pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
	while (pNetBuffer)
	{
		pContiguousData = NdisGetDataBuffer(pNetBuffer,
			bIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN,
			pPacketData,
			1,
			0);
		if (!pContiguousData)
		{
			status = STATUS_UNSUCCESSFUL;

			TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
				"NPF_IsPacketSelfSent: NdisGetDataBuffer() [status: %#x]\n",
				status);

			TRACE_EXIT();
			return FALSE;
		}
		else
		{
			iProtocol = bIPv4 ? ((PIP_HEADER) pContiguousData)->ip_Protocol : ((PIP6_HEADER) pContiguousData)->ip6_CTL.ip6_HeaderCtl.ip6_NextHeader;
			if (iProtocol == IPPROTO_NPCAP_LOOPBACK)
			{
				TRACE_EXIT();
				return TRUE;
			}
			else
			{
				TRACE_EXIT();
				return FALSE;
			}
		}

		pNetBuffer = pNetBuffer->Next;
	}

	TRACE_EXIT();
	return FALSE;
}
Пример #5
0
ULONG GetNetBufferCount(PNDIS_PACKET_OR_NBL pNBSPacket)
{
    ULONG Count = 0;
    PNET_BUFFER pCurrentNB = NET_BUFFER_LIST_FIRST_NB(pNBSPacket);
    while (pCurrentNB)
    {
        Count++;
        pCurrentNB = NET_BUFFER_NEXT_NB(pCurrentNB);
    }
    return Count;
}
Пример #6
0
static PNET_BUFFER_LIST
OvsCopySinglePacketNBL(PVOID ovsContext,
                       PNET_BUFFER_LIST nbl,
                       PNET_BUFFER nb,
                       UINT32 headRoom,
                       BOOLEAN copyNblInfo)
{
    UINT32 size;
    ULONG copiedSize;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    PNET_BUFFER_LIST newNbl;
    PNET_BUFFER newNb;
    NDIS_STATUS status;
    POVS_BUFFER_CONTEXT srcCtx, dstCtx;

    size = NET_BUFFER_DATA_LENGTH(nb);
    if ((size + headRoom) <= OVS_FIX_NBL_DATA_SIZE) {
        newNbl = OvsAllocateFixSizeNBL(context, size, headRoom);
    } else {
        newNbl = OvsAllocateVariableSizeNBL(context, size, headRoom);
    }
    if (newNbl == NULL) {
        return NULL;
    }
    newNb = NET_BUFFER_LIST_FIRST_NB(newNbl);
    status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
                                              &copiedSize);

    srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    if (status == NDIS_STATUS_SUCCESS) {
        status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copiedSize, copyNblInfo);
    }

    if (status != NDIS_STATUS_SUCCESS || copiedSize != size) {
        OvsCompleteNBL(context, newNbl, TRUE);
        return NULL;
    }

    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
    ASSERT(dstCtx && srcCtx);
    ASSERT(srcCtx->magic == OVS_CTX_MAGIC && dstCtx->magic == OVS_CTX_MAGIC);

    dstCtx->flags |= srcCtx->flags & (OVS_BUFFER_RECV_BUFFER |
                                      OVS_BUFFER_SEND_BUFFER);
#ifdef DBG
    OvsDumpNetBufferList(newNbl);
    OvsDumpForwardingDetails(newNbl);
#endif
    OVS_LOG_LOUD("Copy single nb to new NBL: %p", newNbl);
    return newNbl;
}
Пример #7
0
/*
 * --------------------------------------------------------------------------
 * OvsFullCopyToMultipleNBLs --
 *
 *    Copy NBL to multiple NBLs, each NB will have its own NBL
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsFullCopyToMultipleNBLs(PVOID ovsContext,
                          PNET_BUFFER_LIST nbl,
                          UINT32 headRoom,
                          BOOLEAN copyNblInfo)
{

    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    PNET_BUFFER_LIST firstNbl, currNbl, newNbl;
    PNET_BUFFER nb;
    POVS_BUFFER_CONTEXT srcCtx;

    srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
        OVS_LOG_INFO("src nbl must have ctx initialized");
        ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
        return NULL;
    }

    nb =  NET_BUFFER_LIST_FIRST_NB(nbl);
    newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);

    if (newNbl == NULL || NET_BUFFER_NEXT_NB(nb) == NULL) {
        return newNbl;
    } else {
        firstNbl = newNbl;
        currNbl = newNbl;
    }

    while (nb) {
        newNbl = OvsCopySinglePacketNBL(context, nbl, nb, headRoom,
                                        copyNblInfo);
        if (newNbl == NULL) {
            goto copymultiple_error;
        }
        NET_BUFFER_LIST_NEXT_NBL(currNbl) = newNbl;
        currNbl = newNbl;
        nb = NET_BUFFER_NEXT_NB(nb);
    }
    return firstNbl;

copymultiple_error:
    while (firstNbl) {
        currNbl = firstNbl;
        firstNbl = NET_BUFFER_LIST_NEXT_NBL(firstNbl);
        NET_BUFFER_LIST_NEXT_NBL(currNbl) = NULL;
        OvsCompleteNBL(context, currNbl, TRUE);
    }
    return NULL;

}
Пример #8
0
static __inline uint32_t
OvsGetTcpPayloadLength(PNET_BUFFER_LIST nbl)
{
    IPHdr *ipHdr;
    char *ipBuf[sizeof(IPHdr)];
    PNET_BUFFER curNb;
    curNb = NET_BUFFER_LIST_FIRST_NB(nbl);
    ipHdr = NdisGetDataBuffer(curNb, sizeof *ipHdr, (PVOID) &ipBuf,
                                                    1 /*no align*/, 0);
    TCPHdr *tcp = (TCPHdr *)((PCHAR)ipHdr + ipHdr->ihl * 4);
    return (UINT16)ntohs(ipHdr->tot_len)
                        - (ipHdr->ihl * 4)
                        - (sizeof * tcp);
}
Пример #9
0
static VOID
OvsDumpNetBufferList(PNET_BUFFER_LIST nbl)
{
    PNET_BUFFER nb;
    OVS_LOG_INFO("NBL: %p, parent: %p, SrcHandle: %p, ChildCount:%d "
                 "poolHandle: %p",
                 nbl, nbl->ParentNetBufferList,
                 nbl->SourceHandle, nbl->ChildRefCount,
                 nbl->NdisPoolHandle);
    OvsDumpNBLContext(nbl);
    nb = NET_BUFFER_LIST_FIRST_NB(nbl);
    while (nb) {
        OvsDumpNetBuffer(nb);
        nb = NET_BUFFER_NEXT_NB(nb);
    }
}
Пример #10
0
ULONG
tapGetNetBufferCountsFromNetBufferList(__in PNET_BUFFER_LIST NetBufferList,
                                       __inout_opt PULONG TotalByteCount  // Of all linked NBs
                                       )
/*++

Routine Description:

    Returns the number of net buffers linked to the net buffer list.

    Optionally retuens the total byte count of all net buffers linked
    to the net buffer list

    Runs at IRQL <= DISPATCH_LEVEL.

Arguments:

    NetBufferList                 The NBL to examine

Return Value:

    The number of net buffers linked to the net buffer list.

--*/
{
  ULONG netBufferCount = 0;
  PNET_BUFFER currentNb;

  if (TotalByteCount) {
    *TotalByteCount = 0;
  }

  currentNb = NET_BUFFER_LIST_FIRST_NB(NetBufferList);

  while (currentNb) {
    ++netBufferCount;

    if (TotalByteCount) {
      *TotalByteCount += NET_BUFFER_DATA_LENGTH(currentNb);
    }

    // Move to next NB
    currentNb = NET_BUFFER_NEXT_NB(currentNb);
  }

  return netBufferCount;
}
Пример #11
0
NTSTATUS
StreamOobCopyDataToFlatBuffer(
   _Inout_ STREAM_EDITOR* streamEditor,
   _Inout_ NET_BUFFER_LIST* netBufferListChain,
   size_t totalDataLength,
   DWORD streamFlags
   )
/* ++

   This function copies the data described by NBL(s) into a flat buffer. 
   
   It reuses the FwpsCopyStreamDataToBuffer API (via StreamCopyDataForInspection)
   by creating a FWPS_STREAM_DATA struct.

-- */
{
   NTSTATUS status = STATUS_SUCCESS;

   FWPS_STREAM_DATA streamData = {0};

   if (totalDataLength > 0)
   {
      streamData.netBufferListChain = netBufferListChain;
      streamData.dataLength =  totalDataLength;
      streamData.flags = streamFlags;

      streamData.dataOffset.netBufferList = netBufferListChain;
      streamData.dataOffset.netBuffer = 
         NET_BUFFER_LIST_FIRST_NB(streamData.dataOffset.netBufferList);
      streamData.dataOffset.mdl = 
         NET_BUFFER_CURRENT_MDL(streamData.dataOffset.netBuffer);
      streamData.dataOffset.mdlOffset = 
         NET_BUFFER_CURRENT_MDL_OFFSET(streamData.dataOffset.netBuffer);

      if (StreamCopyDataForInspection(
            streamEditor,
            &streamData
            ) == FALSE)
      {
         status = STATUS_NO_MEMORY;
      }
   }

   return status;
}
Пример #12
0
static void
shared_free_pkt(ND_PKT* p)
{
#ifndef NDIS60
	PNDIS_BUFFER b;

	NdisQueryPacket(p, NULL, NULL, &b, NULL);
	ASSERT(b);
	NdisFreeBuffer(b);
	NdisFreePacket(p);
#else /* NDIS60 */
	PNET_BUFFER nb;
	PMDL b;

	nb = NET_BUFFER_LIST_FIRST_NB(p);
	b = NET_BUFFER_FIRST_MDL(nb);
	ASSERT(b);
	NdisFreeMdl(b);
	NdisFreeNetBufferList(p);
#endif /* NDIS60 */
}
Пример #13
0
/*
 * --------------------------------------------------------------------------
 * OvsInitExternalNBLContext --
 *
 *     For NBL not allocated by OVS, it will allocate and initialize
 *     the NBL context.
 * --------------------------------------------------------------------------
 */
POVS_BUFFER_CONTEXT
OvsInitExternalNBLContext(PVOID ovsContext,
                          PNET_BUFFER_LIST nbl,
                          BOOLEAN isRecv)
{
    NDIS_HANDLE poolHandle;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    POVS_BUFFER_CONTEXT ctx;
    PNET_BUFFER nb;
    NDIS_STATUS status;
    UINT16 flags;

    poolHandle = NdisGetPoolFromNetBufferList(nbl);

    if (poolHandle == context->ovsPool.ndisHandle) {
        return (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    }
    status = NdisAllocateNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT),
                                              OVS_DEFAULT_NBL_CONTEXT_FILL,
                                              OVS_OTHER_POOL_TAG);
    if (status != NDIS_STATUS_SUCCESS) {
        return NULL;
    }
#ifdef DBG
    OvsDumpNBLContext(nbl);
    InterlockedIncrement((LONG volatile *)&context->ovsPool.sysNBLCount);
#endif
    flags = isRecv ? OVS_BUFFER_RECV_BUFFER : OVS_BUFFER_SEND_BUFFER;
    flags |= OVS_BUFFER_NEED_COMPLETE | OVS_BUFFER_PRIVATE_CONTEXT;
    ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);

    nb = NET_BUFFER_LIST_FIRST_NB(nbl);
    /*
     * we use first nb to decide whether we need advance or retreat during
     * complete.
     */
    OvsInitNBLContext(ctx, flags, NET_BUFFER_DATA_LENGTH(nb), OVS_DEFAULT_PORT_NO);
    return ctx;
}
bool CNBL::ParseBuffers()
{
    m_MaxDataLength = 0;

    for (auto NB = NET_BUFFER_LIST_FIRST_NB(m_NBL); NB != nullptr; NB = NET_BUFFER_NEXT_NB(NB))
    {
        CNB *NBHolder = new (m_Context->MiniportHandle) CNB(NB, this, m_Context);
        if(!NBHolder || !NBHolder->IsValid())
        {
            return false;
        }
        RegisterNB(NBHolder);
        m_MaxDataLength = max(m_MaxDataLength, NBHolder->GetDataLength());
    }

    if(m_MaxDataLength == 0)
    {
        DPrintf(0, ("Empty NBL (%p) dropped\n", __FUNCTION__, m_NBL));
        return false;
    }

    return true;
}
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;
}
Пример #16
0
// Process the received packet
void NeoWrite(void *buf)
{
	UINT num, i, size;
	UCHAR *packet_buf;
	NET_BUFFER_LIST *nbl_chain = NULL;
	NET_BUFFER_LIST *nbl_tail = NULL;
	UINT num_nbl_chain = 0;
	// Validate arguments
	if (buf == NULL)
	{
		return;
	}

	// Number of packets
	num = NEO_NUM_PACKET(buf);
	if (num > NEO_MAX_PACKET_EXCHANGE)
	{
		// Number of packets is too many
		return;
	}
	if (num == 0)
	{
		// No packet
		return;
	}

	if (ctx->Halting != FALSE)
	{
		// Stopping
		return;
	}

	if (ctx->Paused)
	{
		// Paused
		return;
	}

	if (ctx->Opened == FALSE)
	{
		// Not connected
		return;
	}

	for (i = 0;i < num;i++)
	{
		PACKET_BUFFER *p = ctx->PacketBuffer[i];
		void *dst;
		NET_BUFFER_LIST *nbl = ctx->PacketBuffer[i]->NetBufferList;
		NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);

		nbl->SourceHandle = ctx->NdisMiniport;

		NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;

		size = NEO_SIZE_OF_PACKET(buf, i);
		if (size > NEO_MAX_PACKET_SIZE)
		{
			size = NEO_MAX_PACKET_SIZE;
		}
		if (size < NEO_PACKET_HEADER_SIZE)
		{
			size = NEO_PACKET_HEADER_SIZE;
		}

		packet_buf = (UCHAR *)(NEO_ADDR_OF_PACKET(buf, i));

		if (OK(NdisRetreatNetBufferDataStart(nb, size, 0, NULL)))
		{
			// Buffer copy
			dst = NdisGetDataBuffer(nb,
				size,
				NULL,
				1,
				0);

			if (dst != NULL)
			{
				NeoCopy(dst, packet_buf, size);

				if (nbl_chain == NULL)
				{
					nbl_chain = nbl;
				}

				if (nbl_tail != NULL)
				{
					NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl;
				}

				nbl_tail = nbl;

				num_nbl_chain++;
			}
		}

		nbl->Status = NDIS_STATUS_RESOURCES;

		ctx->Status.Int64BytesRecvTotal += (UINT64)size;

		if (packet_buf[0] & 0x40)
		{
			ctx->Status.Int64NumRecvBroadcast++;
			ctx->Status.Int64BytesRecvBroadcast += (UINT64)size;
		}
		else
		{
			ctx->Status.Int64NumRecvUnicast++;
			ctx->Status.Int64BytesRecvUnicast += (UINT64)size;
		}
	}

	if (nbl_chain == NULL)
	{
		return;
	}

	// Notify that it has received
	ctx->Status.NumPacketRecv += num_nbl_chain;

	NdisMIndicateReceiveNetBufferLists(ctx->NdisMiniport,
		nbl_chain, 0, num_nbl_chain, NDIS_RECEIVE_FLAGS_RESOURCES);

	if (true)
	{
		// Restore the packet buffer
		NET_BUFFER_LIST *nbl = nbl_chain;

		while (nbl != NULL)
		{
			NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);

			if (nb != NULL)
			{
				UINT size = NET_BUFFER_DATA_LENGTH(nb);

				NdisAdvanceNetBufferDataStart(nb, size, false, NULL);
			}

			nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
		}
	}
}
Пример #17
0
NTSTATUS
TLInspectCloneReinjectInbound(
   IN OUT 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;

   //
   // 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)
   {
      ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize);
      packet->transportHeaderSize = 0;
   }

   //
   // Adjust the net buffer list offset to the start of the IP header.
   //
   NdisRetreatNetBufferDataStart(
      netBuffer,
      packet->ipHeaderSize + packet->transportHeaderSize,
      0,
      NULL
      );

   //
   // Note that the clone will inherit the original net buffer list's offset.
   //

   status = FwpsAllocateCloneNetBufferList0(
               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.
      // 
#if (NTDDI_VERSION >= NTDDI_WIN6SP1)

      status = FwpsConstructIpHeaderForTransportPacket0(
                  clonedNetBufferList,
                  packet->ipHeaderSize,
                  packet->addressFamily,
                  (UINT8*)&packet->remoteAddr, 
                  (UINT8*)&packet->localAddr,  
                  packet->protocol,
                  0,
                  NULL,
                  0,
                  0,
                  NULL,
                  0,
                  0
                  );
#else
      ASSERT(FALSE); // Prior to Vista SP1, IP address needs to be updated 
                     // manually (including updating IP checksum).

      status = STATUS_NOT_IMPLEMENTED;
#endif

      if (!NT_SUCCESS(status))
      {
         goto Exit;
      }
   }

   if (packet->completionContext != NULL)
   {
      ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET);

      FwpsCompleteOperation0(
         packet->completionContext,
         clonedNetBufferList
         );

      packet->completionContext = NULL;
   }

   status = FwpsInjectTransportReceiveAsync0(
               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)
   {
      FwpsFreeCloneNetBufferList0(clonedNetBufferList, 0);
   }

   return status;
}
Пример #18
0
VOID
NdisprotReceiveNetBufferLists(
    IN NDIS_HANDLE                  ProtocolBindingContext,
    IN PNET_BUFFER_LIST             pNetBufferLists,
    IN NDIS_PORT_NUMBER             PortNumber,
    IN ULONG                        NumberOfNetBufferLists,
    IN ULONG                        ReceiveFlags
    )
/*++

Routine Description:

    Protocol entry point called by NDIS if the driver below
    uses NDIS 6 net buffer list indications.

    If the miniport allows us to hold on to this net buffer list, we
    use it as is, otherwise we make a copy.

Arguments:

    ProtocolBindingContext - pointer to open context
    pNetBufferLists - a list of the Net Buffer lists being indicated up.
    PortNumber - Port on which the Net Bufer list was received
    NumberOfNetBufferLists - the number of NetBufferLists in this indication
    ReceiveFlags - indicates whether the NetBufferLists can be pended in
                   the protocol driver.

Return Value:

--*/
{
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    PMDL                    pMdl = NULL;
    UINT                    BufferLength;
    PNDISPROT_ETH_HEADER    pEthHeader = NULL;
    PNET_BUFFER_LIST        pCopyNetBufList;
    PUCHAR                  pCopyBuf;
    ULONG                   TotalLength;
    ULONG                   BytesCopied;
    PNET_BUFFER_LIST        pNetBufList;
    PNET_BUFFER_LIST        pNetBufListOrig = NULL;
    PNET_BUFFER_LIST        pNextNetBufList;
    PNET_BUFFER_LIST        pReturnNetBufList = NULL;
    PNET_BUFFER_LIST        pLastReturnNetBufList = NULL;
    NTSTATUS                NtStatus;
    BOOLEAN                 bAcceptedReceive;
    ULONG                   Offset;
    ULONG                   ReturnFlags = 0;
    BOOLEAN                 DispatchLevel;
    BOOLEAN 			NoReadIRP = FALSE;

    UNREFERENCED_PARAMETER(PortNumber);
    UNREFERENCED_PARAMETER(NumberOfNetBufferLists);

    pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;

    if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
    {
        NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
    }

    NPROT_STRUCT_ASSERT(pOpenContext, oc);
    if ((pOpenContext->State == NdisprotPausing)
        || (pOpenContext->State == NdisprotPaused))
    {
        if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags) == TRUE)
        {

            NdisReturnNetBufferLists(pOpenContext->BindingHandle,
                                    pNetBufferLists,
                                    ReturnFlags);
        }
        return;
    }

    pNetBufList = pNetBufferLists;

    while (pNetBufList != NULL)
    {
        pNextNetBufList = NET_BUFFER_LIST_NEXT_NBL (pNetBufList);

        NBL_CLEAR_PROT_RSVD_FLAG(pNetBufList, NBL_PROT_RSVD_FLAGS);
        bAcceptedReceive = FALSE;

        //
        // Get first MDL and data length in the list
        //
        pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
        TotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
        Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pNetBufList));
        BufferLength = 0;

        do
        {
            ASSERT(pMdl != NULL);
            if (pMdl)
            {
                NdisQueryMdl(
                    pMdl,
                    &pEthHeader,
                    &BufferLength,
                    NormalPagePriority);
            }

            if (pEthHeader == NULL)
            {
                //
                //  The system is low on resources. Set up to handle failure
                //  below.
                //
                BufferLength = 0;
                break;
            }

            if (BufferLength == 0)
            {
                break;
            }

            ASSERT(BufferLength > Offset);

            BufferLength -= Offset;
            pEthHeader = (PNDISPROT_ETH_HEADER)((PUCHAR)pEthHeader + Offset);

            if (BufferLength < sizeof(NDISPROT_ETH_HEADER))
            {
                DEBUGP(DL_WARN,
                    ("ReceiveNetBufferList: Open %p, runt nbl %p, first buffer length %d\n",
                        pOpenContext, pNetBufList, BufferLength));

                break;
            }

            //
            //  Check the EtherType. If the Ether type indicates presence of
            //  a tag, then the "real" Ether type is 4 bytes further down.
            //
            if (pEthHeader->EthType == NPROT_8021P_TAG_TYPE)
            {
                USHORT UNALIGNED *pEthType;

                if (BufferLength < (sizeof(NDISPROT_ETH_HEADER) + 4))
                {
                    break;
                }

                pEthType = (USHORT UNALIGNED *)((PUCHAR)&pEthHeader->EthType + 4);

                if (*pEthType != Globals.EthType)
                {
                    break;
                }
            }
            else if (pEthHeader->EthType != Globals.EthType)
            {
                break;
            }

            bAcceptedReceive = TRUE;
            DEBUGP(DL_LOUD, ("ReceiveNetBufferList: Open %p, interesting nbl %p\n",
                        pOpenContext, pNetBufList));

            //
            //  If the miniport is out of resources, we can't queue
            //  this list of net buffer list - make a copy if this is so.
            //
            DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);

            NoReadIRP = NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads);

            if (NoReadIRP || NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags))
            {
            	bAcceptedReceive = FALSE;
                pCopyNetBufList = ndisprotAllocateReceiveNetBufferList(
                                pOpenContext,
                                TotalLength,
                                &pCopyBuf);

                if (pCopyNetBufList == NULL)
                {
                    DEBUGP(DL_FATAL, ("ReceiveNetBufferList: Open %p, failed to"
                        " alloc copy, %d bytes\n", pOpenContext, TotalLength));
                    break;
                }
                NBL_SET_PROT_RSVD_FLAG(pCopyNetBufList, NPROT_ALLOCATED_NBL);
                //
                // Copy the data to the new allocated NetBufferList
                //
                NtStatus = NdisCopyFromNetBufferToNetBuffer(NET_BUFFER_LIST_FIRST_NB(pCopyNetBufList),
                                                            0,
                                                            TotalLength,
                                                            NET_BUFFER_LIST_FIRST_NB(pNetBufList),
                                                            0,
                                                            &BytesCopied);


                if (NtStatus != STATUS_SUCCESS)
                {
                    DEBUGP(DL_FATAL, ("ReceiveNetBufferList: Open %p, failed to"
                        " copy the data, %d bytes\n", pOpenContext, TotalLength));
                    //
                    // Free the NetBufferList and memory allocate before
                    //
                    ndisprotFreeReceiveNetBufferList(pOpenContext,
                                                    pCopyNetBufList,
                                                    DispatchLevel);
                    break;
                }

                NPROT_ASSERT(BytesCopied == TotalLength);


                //
                // The other members of NET_BUFFER_DATA structure are already initialized properly during allocation.
                //
                NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pCopyNetBufList)) = BytesCopied;

                //
                //save a copy for no Read IRP case
                //
                if(NoReadIRP)
                {
                	pNetBufListOrig  = pNetBufList;
                }
                pNetBufList = pCopyNetBufList;

            }
            //
            //  Queue this up and service any pending Read IRPs.
            //
            ndisprotQueueReceiveNetBufferList(pOpenContext, pNetBufList, DispatchLevel);

        }
        while (FALSE);

        //
        // Ndisprot is not interested this NetBufferList, return the
        // NetBufferList back to the miniport if the miniport gave us
        // ownership of it
        //
        if ((bAcceptedReceive == FALSE) &&
            (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags) == TRUE))
        {
            // Restore pNetBufList if it was overwritten earlier
            if (pNetBufListOrig != NULL)
            {
                pNetBufList = pNetBufListOrig;

                pNetBufListOrig = NULL;
            }
            if (pReturnNetBufList == NULL)
            {
                pReturnNetBufList = pNetBufList;
            }
            else
            {
                NET_BUFFER_LIST_NEXT_NBL(pLastReturnNetBufList) = pNetBufList;
            }
            pLastReturnNetBufList = pNetBufList;
            NET_BUFFER_LIST_NEXT_NBL(pNetBufList) = NULL;

        }

        pNetBufList = pNextNetBufList;
    } // end of the for loop

    if (pReturnNetBufList != NULL)
    {
        NdisReturnNetBufferLists(pOpenContext->BindingHandle,
                                    pReturnNetBufList,
                                    ReturnFlags);
    }

}
Пример #19
0
VOID
ndisprotServiceReads(
    IN PNDISPROT_OPEN_CONTEXT        pOpenContext
    )
/*++

Routine Description:

    Utility routine to copy received data into user buffers and
    complete READ IRPs.

Arguments:

    pOpenContext - pointer to open context

Return Value:

    None

--*/
{
    PIRP                pIrp = NULL;
    PLIST_ENTRY         pIrpEntry;
    PNET_BUFFER_LIST    pRcvNetBufList;
    PLIST_ENTRY         pRcvNetBufListEntry;
    PUCHAR              pSrc, pDst;
    ULONG               BytesRemaining; // at pDst
    PMDL                pMdl;
    ULONG               BytesAvailable;
    BOOLEAN             FoundPendingIrp = FALSE;
    ULONG               SrcTotalLength = 0; // Source NetBuffer DataLenght
    ULONG               Offset = 0;         // CurrentMdlOffset
    ULONG               BytesToCopy = 0;

    DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
            pOpenContext, pOpenContext->Flags));

    NPROT_REF_OPEN(pOpenContext);  // temp ref - service reads

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

    while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
           !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue))
    {
        FoundPendingIrp = FALSE;

        //
        //  Get the first pended Read IRP
        //
        pIrpEntry = pOpenContext->PendedReads.Flink;
        while (pIrpEntry != &pOpenContext->PendedReads)
        {
            pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);

            //
            //  Check to see if it is being cancelled.
            //
            if (IoSetCancelRoutine(pIrp, NULL))
            {
                //
                //  It isn't being cancelled, and can't be cancelled henceforth.
                //
                NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
                FoundPendingIrp = TRUE;
                break;

                //
                //  NOTE: we decrement PendedReadCount way below in the
                //  while loop, to avoid letting through a thread trying
                //  to unbind.
                //
            }
            else
            {
                //
                //  The IRP is being cancelled; let the cancel routine handle it.
                //
                DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
                        pOpenContext, pIrp));

                pIrpEntry = pIrpEntry->Flink;
            }
        }

        if (FoundPendingIrp == FALSE)
        {
            break;
        }
        //
        //  Get the first queued receive packet
        //
        pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink;
        NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry);

        pOpenContext->RecvNetBufListCount --;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        NPROT_DEREF_OPEN(pOpenContext);  // Service: dequeue rcv packet

        pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry);
        NPROT_ASSERT(pRcvNetBufList != NULL);
        _Analysis_assume_(pRcvNetBufList != NULL);
        NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL;

        //
        //  Copy as much data as possible from the receive packet to
        //  the IRP MDL.
        //
        
        pDst = NULL;
        NdisQueryMdl(pIrp->MdlAddress, &pDst, &BytesRemaining, NormalPagePriority);
        NPROT_ASSERT(pDst != NULL);  // since it was already mapped
        _Analysis_assume_(pDst != NULL);

        pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        //
        // Copy the data in the received packet into the buffer provided by the client.
        // If the length of the receive packet is greater than length of the given buffer,
        // we just copy as many bytes as we can. Once the buffer is full, we just discard
        // the rest of the data, and complete the IRP sucessfully even we only did a partial copy.
        //

        SrcTotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
        Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        while (BytesRemaining && (pMdl != NULL) && SrcTotalLength)
        {
            pSrc = NULL;
            NdisQueryMdl(pMdl, &pSrc, &BytesAvailable, NormalPagePriority);

            if (pSrc == NULL)
            {
                DEBUGP(DL_FATAL,
                    ("ServiceReads: Open %p, NdisQueryMdl failed for MDL %p\n",
                            pOpenContext, pMdl));
                break;
            }

            NPROT_ASSERT(BytesAvailable > Offset);

            BytesToCopy = MIN(BytesAvailable - Offset, BytesRemaining);
            BytesToCopy = MIN(BytesToCopy, SrcTotalLength);

            NPROT_COPY_MEM(pDst, pSrc + Offset, BytesToCopy);
            BytesRemaining -= BytesToCopy;
            pDst += BytesToCopy;
            SrcTotalLength -= BytesToCopy;

            //
            // CurrentMdlOffset is used only for the first Mdl processed. For the remaining Mdls, it is 0.
            //
            Offset = 0;

            NdisGetNextMdl(pMdl, &pMdl);
        }

        //
        //  Complete the IRP.
        //
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;

        DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
            pOpenContext, pIrp, (ULONG)pIrp->IoStatus.Information));

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList,FALSE);


        NPROT_DEREF_OPEN(pOpenContext);    // took out pended Read

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
        pOpenContext->PendedReadCount--;

    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

    NPROT_DEREF_OPEN(pOpenContext);    // temp ref - service reads
}
Пример #20
0
static NTSTATUS
OvsTunnelAnalyzePacket(OVS_TUNNEL_PENDED_PACKET *packet)
{
    NTSTATUS status = STATUS_SUCCESS;
    UINT32 packetLength = 0;
    ULONG bytesCopied = 0;
    NET_BUFFER_LIST *copiedNBL = NULL;
    NET_BUFFER *netBuffer;
    NDIS_STATUS ndisStatus;

    /*
     * For inbound net buffer list, we can assume it contains only one
     * net buffer (unless it was an re-assembeled fragments). in both cases
     * the first net buffer should include all headers, we assert if the retreat fails
     */
    netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);

    /* Drop the packet from the host stack */
    packet->classifyOut->actionType = FWP_ACTION_BLOCK;
    packet->classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;

    /* Adjust the net buffer list offset to the start of the IP header */
    ndisStatus = NdisRetreatNetBufferDataStart(netBuffer,
                                               packet->ipHeaderSize +
                                               packet->transportHeaderSize,
                                               0, NULL);
    ASSERT(ndisStatus == NDIS_STATUS_SUCCESS);

    /* Single NBL element for WFP */
    ASSERT(packet->netBufferList->Next == NULL);

    /* Note that the copy will inherit the original net buffer list's offset */
    packetLength = NET_BUFFER_DATA_LENGTH(netBuffer);
    copiedNBL = OvsAllocateVariableSizeNBL(gOvsSwitchContext, packetLength,
                                           OVS_DEFAULT_HEADROOM_SIZE);

    if (copiedNBL == NULL) {
        goto analyzeDone;
    }

    status = NdisCopyFromNetBufferToNetBuffer(NET_BUFFER_LIST_FIRST_NB(copiedNBL),
                                              0, packetLength,
                                              netBuffer, 0, &bytesCopied);
    if (status != NDIS_STATUS_SUCCESS || packetLength != bytesCopied) {
        goto analyzeFreeNBL;
    }

    status = OvsInjectPacketThroughActions(copiedNBL,
                                           packet);
    goto analyzeDone;

    /* Undo the adjustment on the original net buffer list */
analyzeFreeNBL:
    OvsCompleteNBL(gOvsSwitchContext, copiedNBL, TRUE);
analyzeDone:
    NdisAdvanceNetBufferDataStart(netBuffer,
                                  packet->transportHeaderSize + packet->ipHeaderSize,
                                  FALSE,
                                  NULL);
    return status;
}
Пример #21
0
/*
 * --------------------------------------------------------------------------
 * OvsCompleteNBL --
 *
 *     This function tries to free the NBL allocated by OVS buffer
 *     management module. If it trigger the completion of the parent
 *     NBL, it will recursively call itself. If it trigger the completion
 *     of external NBL, it will be returned to the caller. The caller
 *     is responsible to call API to return to upper layer.
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsCompleteNBL(POVS_SWITCH_CONTEXT context,
               PNET_BUFFER_LIST nbl,
               BOOLEAN updateRef)
{
    POVS_BUFFER_CONTEXT ctx;
    UINT16 flags;
    PNET_BUFFER_LIST parent;
    NDIS_STATUS status;
    NDIS_HANDLE poolHandle;
    LONG value;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    PNET_BUFFER nb;


    ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);

    ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);

    OVS_LOG_TRACE("Enter: nbl: %p, ctx: %p, refCount: %d, updateRef:%d",
                 nbl, ctx, ctx->refCount, updateRef);

    if (updateRef) {
        value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
        if (value != 0) {
            return NULL;
        }
    } else {
        /*
         * This is a special case, the refCount must be zero
         */
        ASSERT(ctx->refCount == 0);
    }

    nb = NET_BUFFER_LIST_FIRST_NB(nbl);

    flags = ctx->flags;
    if (!(flags & OVS_BUFFER_FRAGMENT) &&
        NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) {
        UINT32 diff;
        if (NET_BUFFER_DATA_LENGTH(nb) < ctx->origDataLength) {
            diff = ctx->origDataLength -NET_BUFFER_DATA_LENGTH(nb);
            status = NdisRetreatNetBufferListDataStart(nbl, diff, 0,
                                                       NULL, NULL);
            ASSERT(status == NDIS_STATUS_SUCCESS);
        } else {
            diff = NET_BUFFER_DATA_LENGTH(nb) - ctx->origDataLength;
            NdisAdvanceNetBufferListDataStart(nbl, diff, TRUE, NULL);
        }
    }

    if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) {
        NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT));
    }

    if (flags & OVS_BUFFER_NEED_COMPLETE) {
        /*
         * return to caller for completion
         */
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->sysNBLCount);
#endif
        return nbl;
    }

    if (flags & OVS_BUFFER_PRIVATE_FORWARD_CONTEXT) {
        context->NdisSwitchHandlers.
              FreeNetBufferListForwardingContext(ovsPool->ndisContext, nbl);
    }

    if (flags & (OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA)) {
        PNET_BUFFER nb = NET_BUFFER_LIST_FIRST_NB(nbl);
        while (nb) {
            PMDL mdl = NET_BUFFER_FIRST_MDL(nb);
            NET_BUFFER_FIRST_MDL(nb) = NULL;
            ASSERT(mdl->Next == NULL);
            OvsFreeMDLAndData(mdl);
            nb = NET_BUFFER_NEXT_NB(nb);
        }
    }

    if (flags & OVS_BUFFER_PRIVATE_NET_BUFFER) {
        PNET_BUFFER nb, nextNb;

        nb = NET_BUFFER_LIST_FIRST_NB(nbl);
        while (nb) {
            nextNb = NET_BUFFER_NEXT_NB(nb);
            NdisFreeNetBuffer(nb);
#ifdef DBG
            InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
#endif
            nb = nextNb;
        }
        NET_BUFFER_LIST_FIRST_NB(nbl) = NULL;
    }

    parent = nbl->ParentNetBufferList;

    poolHandle = NdisGetPoolFromNetBufferList(nbl);
    if (flags & OVS_BUFFER_FROM_FIX_SIZE_POOL) {
        ASSERT(poolHandle == ovsPool->fixSizePool);
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->fixNBLCount);
#endif
        NdisFreeNetBufferList(nbl);
    } else if (flags & OVS_BUFFER_FROM_ZERO_SIZE_POOL) {
        ASSERT(poolHandle == ovsPool->zeroSizePool);
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->zeroNBLCount);
#endif
        NdisFreeNetBufferList(nbl);
    } else if (flags & OVS_BUFFER_FROM_NBL_ONLY_POOL) {
        ASSERT(poolHandle == ovsPool->nblOnlyPool);
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->nblOnlyCount);
#endif
        NdisFreeCloneNetBufferList(nbl, 0);
    } else if (flags & OVS_BUFFER_FRAGMENT) {
        OVS_LOG_TRACE("Free fragment %p parent %p", nbl, parent);
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
#endif
        NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0);
    }

    if (parent != NULL) {
        ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(parent);
        ASSERT(ctx && ctx->magic == OVS_CTX_MAGIC);
        value = InterlockedDecrement((LONG volatile *)&ctx->refCount);
        if (value == 0) {
            return OvsCompleteNBL(context, parent, FALSE);
        }
    }
    return NULL;
}
Пример #22
0
VOID
tapCompleteIrpAndFreeReceiveNetBufferList(
    __in  PTAP_ADAPTER_CONTEXT  Adapter,
    __in  PNET_BUFFER_LIST      NetBufferList,  // Only one NB here...
    __in  NTSTATUS              IoCompletionStatus
    )
{
    PIRP    irp;
    ULONG   frameType, netBufferCount, byteCount;
    LONG    nblCount;

    // Fetch NB frame type.
    frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList));

    // Fetch statistics for all NBs linked to the NB.
    netBufferCount = tapGetNetBufferCountsFromNetBufferList(
                        NetBufferList,
                        &byteCount
                        );

    // Update statistics by frame type
    if(IoCompletionStatus == STATUS_SUCCESS)
    {
        switch(frameType)
        {
        case NDIS_PACKET_TYPE_DIRECTED:
            Adapter->FramesRxDirected += netBufferCount;
            Adapter->BytesRxDirected += byteCount;
            break;

        case NDIS_PACKET_TYPE_BROADCAST:
            Adapter->FramesRxBroadcast += netBufferCount;
            Adapter->BytesRxBroadcast += byteCount;
            break;

        case NDIS_PACKET_TYPE_MULTICAST:
            Adapter->FramesRxMulticast += netBufferCount;
            Adapter->BytesRxMulticast += byteCount;
            break;

        default:
            ASSERT(FALSE);
            break;
        }
    }

    //
    // Handle P2P Packet
    // -----------------
    // Free MDL allocated for P2P Ethernet header.
    //
    if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P))
    {
        PNET_BUFFER     netBuffer;
        PMDL            mdl;

        netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
        mdl = NET_BUFFER_FIRST_MDL(netBuffer);
        mdl->Next = NULL;

        NdisFreeMdl(mdl);
    }

    //
    // Handle Injected Packet
    // -----------------------
    // Free MDL and data buffer allocated for injected packet.
    //
    if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED))
    {
        PNET_BUFFER     netBuffer;
        PMDL            mdl;
        PUCHAR          injectBuffer;

        netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
        mdl = NET_BUFFER_FIRST_MDL(netBuffer);

        injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority);

        if(injectBuffer)
        {
            NdisFreeMemory(injectBuffer,0,0);
        }

        NdisFreeMdl(mdl);
    }

    //
    // Complete the IRP
    //
    irp = (PIRP )NetBufferList->MiniportReserved[0];

    if(irp)
    {
        irp->IoStatus.Status = IoCompletionStatus;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
    }

    // Decrement in-flight receive NBL count.
    nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
    ASSERT(nblCount >= 0 );
    if (0 == nblCount)
    {
        NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
    }

    // Free the NBL
    NdisFreeNetBufferList(NetBufferList);
}
Пример #23
0
VOID FreeNetBufferList(PNET_BUFFER_LIST_KK pNetBufferList)
{
	PMDL                pMdl;
	UINT                TotalLength;
	UINT                BufferLength;
	PUCHAR              pCopyData = NULL;
	ULONG               ReturnFlags = 0;

	if (pNetBufferList==NULL)
	{
		return ;
	}
	do
	{
		pMdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufferList));
		TotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pNetBufferList));

		if (pMdl==NULL)
		{
			kprintf("FreeNetBufferList()pMdl==Null\n");
			break;
		}

		NdisQueryMdl(
			pMdl,
			(PVOID *)&pCopyData,
			&BufferLength,
			NormalPagePriority);

		if (BufferLength!=TotalLength)
		{
			kprintf("FreeNetBufferList() NPROT_ASSERT(BufferLength == TotalLength)\n");
			break;
		}

		if (pCopyData==NULL)
		{
			kprintf("FreeNetBufferList() pCopyData==Null\n");
			break;
		}

		if (1)
		{

			if (g_pfnNdisFreeNetBufferList==0)
			{
				break;
			}
			_asm 
			{
				push pNetBufferList
				call g_pfnNdisFreeNetBufferList
			}
		}

		//NdisFreeNetBufferList(pNetBufferList);

		IoFreeMdl(pMdl);

		kfree(pCopyData);
		break;


	}
	while (FALSE);


}
Пример #24
0
// checks if the NBL chain contains any ICMP Echo Replies
BOOLEAN ProcessNblChain ( PNET_BUFFER_LIST  NetBufferLists )
{
    PNET_BUFFER_LIST  NetBufferList = NetBufferLists;
    PNET_BUFFER_LIST  NextNetBufferList;

    // Step #1 : Iterate through all the NET_BUFFER_LISTs in the NET_BUFFER_LIST chain
    for (NetBufferList = NetBufferLists; NetBufferList; NetBufferList = NET_BUFFER_LIST_NEXT_NBL(NetBufferList) ) {

        PNET_BUFFER NetBuffer;

        //  Step #2 : Iterate through all the NET_BUFFERs in the NET_BUFFER_LISTs passed to the function 
        for (NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); NetBuffer; NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer)) {

            // Declare a storage buffer big enough to hold the MAC header (ETH_HEADER), 
            // IP Header (IP_HEADER) and ICMP Header (ICMP_HEADER)
            UCHAR LocalBuffer[sizeof(ETH_HEADER) + sizeof(IP_HEADER) + sizeof(ICMP_HEADER)];
            ULONG LocalBufferLength = sizeof(ETH_HEADER) + sizeof(IP_HEADER) + sizeof(ICMP_HEADER);
            PUCHAR HeaderBuffer = NULL;
            PETH_HEADER EthHeader;
            PIP_HEADER IpHeader;
            PICMP_HEADER IcmpHeader;

            // Step #4 : Attempt to retrieve the pointer (NdisGetDataBuffer()) to the data area in HeaderBuffer
            // from the NB that contains the ETH, IP and ICMP headers. Pass in the storage buffer (LocalBuffer) 
            // where the data would be copied in case the ETH, IP and ICMP headers are not contiguous. 
            if (NULL == (HeaderBuffer = NdisGetDataBuffer(NetBuffer, LocalBufferLength, LocalBuffer, 1, 1)))
            {
                //  Step #3 : If the current NB is not large enough (NET_BUFFER_DATA_LENGTH()) to hold the required headers then skip this NB.
                continue;
            }

            // Step #5 : Initialize EthHeader to the point to the start of HeaderBuffer 
            EthHeader = (PETH_HEADER)HeaderBuffer;

            // Step #6 : If the layer 3 protocol (h_proto) in the ETH_HEADER is not IPv4 (ETH_TYPE_IP) then skip this NB.
            // Note h_proto is in network byte format and must be converted to host byte format (ntohs())
            if (ETH_TYPE_IP != ntohs(EthHeader->h_proto))
            {
                continue;
            }

            // Step #7 : Initialize IpHeader to point to HeaderBuffer after ETH_HEADER 
            IpHeader = (PIP_HEADER)((ULONG_PTR)EthHeader + sizeof(*EthHeader));

            // Step #8 : If the layer 4 protocol (ip_p) in the PIP_HEADER is not ICMP (IPPROTO_ICMP) then skip this NB
            if (IPPROTO_ICMP != IpHeader->ip_p)
            {
                continue;
            }

            // Step #9 : Initialize IcmpHeader to point to HeaderBuffer after ETH_HEADER and IP_HEADER
            IcmpHeader = (PICMP_HEADER)((ULONG_PTR)IpHeader + sizeof(*IpHeader));

            DPF (( "%s ICMP (%u) %u.%u.%u.%u < %u.%u.%u.%u\n", __FUNCTION__, 
                IcmpHeader->type,
                ((PUCHAR)(&IpHeader->ip_dst))[0], ((PUCHAR)(&IpHeader->ip_dst))[1],  ((PUCHAR)(&IpHeader->ip_dst))[2],  ((PUCHAR)(&IpHeader->ip_dst))[3],
                ((PUCHAR)(&IpHeader->ip_src))[0], ((PUCHAR)(&IpHeader->ip_src))[1],  ((PUCHAR)(&IpHeader->ip_src))[2],  ((PUCHAR)(&IpHeader->ip_src))[3] ));

            // Step #10 : If the IMCP type (type) in the ICMP_HEADER is echo reply (ICMP_ECHOREPLY) 
            // then return TRUE which will cause the caller to drop the packet
            if (ICMP_ECHOREPLY == IcmpHeader->type)
            {
                return TRUE;
            }
        }
    }

    return FALSE;
} // ProcessNblChain()
Пример #25
0
/*
 * --------------------------------------------------------------------------
 * OvsAllocateFixSizeNBL --
 *
 *    Allocate fix size NBL which include
 *       NBL + NB + MBL + Data + Context
 *    Please note:
 *       * Forwarding Context is allocated, but forwarding detail information
 *       is not initailized.
 *       * The headroom can not be larger than OVS_DEFAULT_HEADROOM_SIZE(128
 *       byte).
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsAllocateFixSizeNBL(PVOID ovsContext,
                      UINT32 size,
                      UINT32 headRoom)
{
    PNET_BUFFER_LIST nbl = NULL;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    POVS_BUFFER_CONTEXT ctx;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    NDIS_STATUS status;
    UINT32 line;
    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;

    if ((headRoom + size) > OVS_FIX_NBL_DATA_SIZE || size == 0) {
        line = __LINE__;
        goto allocate_done;
    }

    nbl = NdisAllocateNetBufferList(ovsPool->fixSizePool,
                                    (UINT16)sizeof (OVS_BUFFER_CONTEXT),
                                    (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);

    if (nbl == NULL) {
        line = __LINE__;
        goto allocate_done;
    }

    nbl->SourceHandle = ovsPool->ndisHandle;
    status = context->NdisSwitchHandlers.
             AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);

    if (status != NDIS_STATUS_SUCCESS) {
        NdisFreeNetBufferList(nbl);
        nbl = NULL;
        line = __LINE__;
        goto allocate_done;
    }
    info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
    ASSERT(info);
    info->IsPacketDataSafe = TRUE;
    info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;

    status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
                                           size, 0, NULL);
    ASSERT(status == NDIS_STATUS_SUCCESS);

#ifdef DBG
    InterlockedIncrement((LONG volatile *)&ovsPool->fixNBLCount);
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);
#endif

    ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    ASSERT(ctx);

    OvsInitNBLContext(ctx, OVS_BUFFER_FROM_FIX_SIZE_POOL |
                      OVS_BUFFER_PRIVATE_FORWARD_CONTEXT, size,
                      OVS_DEFAULT_PORT_NO);
    line = __LINE__;
allocate_done:
    OVS_LOG_LOUD("Allocate Fix NBL: %p, line: %d", nbl, line);
    return nbl;
}
Пример #26
0
NTSTATUS
InsertNBs(
	_Inout_ KKDRV_QUEUE_DATA *queueData,
	_In_ NET_BUFFER_LIST *head
	)
{
	NTSTATUS status = STATUS_SUCCESS;
	KLOCK_QUEUE_HANDLE lockHandle;

	NET_BUFFER_LIST *nbl = head;
	NET_BUFFER *nb;

	while (nbl)
	{
		nb = NET_BUFFER_LIST_FIRST_NB(nbl);

		while (nb)
		{
			PVOID data;
			ULONG dataLength = NET_BUFFER_DATA_LENGTH(nb);
			PKKDRV_PACKET packet = (PKKDRV_PACKET)ExAllocatePoolWithTag(
				NonPagedPool,
				KKDRV_PACKET_SIZE + dataLength,
				KKDRV_TAG
				);
			if (packet == NULL)
			{
				return STATUS_INSUFFICIENT_RESOURCES;
			};

			packet->dataLength = dataLength;
			data = NdisGetDataBuffer(nb, dataLength, NULL, 1, 0);
			if (data == NULL)
			{
				NdisGetDataBuffer(nb, dataLength, &packet->data, 1, 0);
			}
			else
			{
				RtlCopyMemory(&(packet->data), data, dataLength);
			}

			KeAcquireInStackQueuedSpinLockAtDpcLevel(
				&queueData->queueLock,
				&lockHandle
				);

			InsertTailList(&queueData->queue, &packet->entry);
			queueData->queueLength++;

			if (queueData->queueLength > queueData->queueLengthMax)
			{
				PLIST_ENTRY entry = RemoveHeadList(&queueData->queue);
				ExFreePoolWithTag(entry, KKDRV_TAG);
				queueData->queueLength--;
			}

			KeReleaseInStackQueuedSpinLockFromDpcLevel(
				&lockHandle
				);

			nb = nb->Next;
		}

		nbl = nbl->Next;
	}

	return status;
}
Пример #27
0
/*
 * --------------------------------------------------------------------------
 * OvsFullCopyNBL --
 *
 *    Copy the NBL to a new NBL including data.
 *
 * Notes:
 *     The NBL can have multiple NBs, but the final result is one NBL.
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsFullCopyNBL(PVOID ovsContext,
               PNET_BUFFER_LIST nbl,
               UINT32 headRoom,
               BOOLEAN copyNblInfo)
{
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    PNET_BUFFER_LIST newNbl;
    PNET_BUFFER nb, newNb, firstNb = NULL, prevNb = NULL;
    POVS_BUFFER_CONTEXT dstCtx, srcCtx;
    PMDL mdl;
    NDIS_STATUS status;
    UINT32 size, totalSize;
    ULONG copiedSize;
    UINT16 flags;
    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO dstInfo;

    srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
        OVS_LOG_INFO("src nbl must have ctx initialized");
        ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
        return NULL;
    }

    nb = NET_BUFFER_LIST_FIRST_NB(nbl);

    if (NET_BUFFER_NEXT_NB(nb) == NULL) {
        return OvsCopySinglePacketNBL(context, nbl, nb, headRoom, copyNblInfo);
    }

    newNbl = NdisAllocateNetBufferList(ovsPool->nblOnlyPool,
                                       (UINT16)sizeof (OVS_BUFFER_CONTEXT),
                                       (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL);
    if (newNbl == NULL) {
        return NULL;
    }

    while (nb) {
        size = NET_BUFFER_DATA_LENGTH(nb);
        totalSize = MEM_ALIGN_SIZE(size + headRoom);
        mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, totalSize);

        if (mdl == NULL) {
            goto nblcopy_error;
        }
        newNb = NdisAllocateNetBuffer(ovsPool->nbPool, mdl, totalSize, 0);
        if (newNb == NULL) {
            OvsFreeMDLAndData(mdl);
            goto nblcopy_error;
        }
        if (firstNb == NULL) {
            firstNb = newNb;
        } else {
            NET_BUFFER_NEXT_NB(prevNb) = newNb;
        }
        prevNb = newNb;
#ifdef DBG
        InterlockedIncrement((LONG volatile *)&ovsPool->nbCount);
#endif
        status = NdisRetreatNetBufferDataStart(newNb, size, 0, NULL);
        ASSERT(status == NDIS_STATUS_SUCCESS);

        status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, size, nb, 0,
                                                  &copiedSize);
        if (status != NDIS_STATUS_SUCCESS || size != copiedSize) {
            goto nblcopy_error;
        }

        nb = NET_BUFFER_NEXT_NB(nb);
    }

    NET_BUFFER_LIST_FIRST_NB(newNbl) = firstNb;

    newNbl->SourceHandle = ovsPool->ndisHandle;
    status = context->NdisSwitchHandlers.
         AllocateNetBufferListForwardingContext(ovsPool->ndisContext, newNbl);

    if (status != NDIS_STATUS_SUCCESS) {
        goto nblcopy_error;
    }

    status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, 0, copyNblInfo);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nblcopy_error;
    }

    dstInfo = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(newNbl);
    dstInfo->IsPacketDataSafe = TRUE;

    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);

    flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);

    flags |= OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
             OVS_BUFFER_PRIVATE_NET_BUFFER | OVS_BUFFER_FROM_NBL_ONLY_POOL |
             OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;

    OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(firstNb),
                      OVS_DEFAULT_PORT_NO);

#ifdef DBG
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);
    InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
#endif
    OVS_LOG_LOUD("newNbl: %p", newNbl);
    return newNbl;

nblcopy_error:
    while (firstNb) {
#ifdef DBG
        InterlockedDecrement((LONG volatile *)&ovsPool->nbCount);
#endif
        prevNb = firstNb;
        firstNb = NET_BUFFER_NEXT_NB(prevNb);
        mdl = NET_BUFFER_FIRST_MDL(prevNb);
        NET_BUFFER_FIRST_MDL(prevNb) = NULL;
        NdisFreeNetBuffer(prevNb);
        OvsFreeMDLAndData(mdl);
    }
    NdisFreeNetBufferList(newNbl);
    OVS_LOG_ERROR("OvsFullCopyNBL failed");
    return NULL;
}
Пример #28
0
/*
 * --------------------------------------------------------------------------
 * OvsAllocateVariableSizeNBL --
 *
 *    Allocate variable size NBL, the NBL looks like
 *      NBL + NB + Context
 *      MDL + Data
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsAllocateVariableSizeNBL(PVOID ovsContext,
                           UINT32 size,
                           UINT32 headRoom)
{
    PNET_BUFFER_LIST nbl = NULL;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    POVS_BUFFER_CONTEXT ctx;
    UINT32 realSize;
    PMDL mdl;
    NDIS_STATUS status;
    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
    if (size == 0) {
        return NULL;
    }
    realSize = MEM_ALIGN_SIZE(size + headRoom);

    mdl = OvsAllocateMDLAndData(ovsPool->ndisHandle, realSize);
    if (mdl == NULL) {
        return NULL;
    }

    nbl = NdisAllocateNetBufferAndNetBufferList(ovsPool->zeroSizePool,
                                         (UINT16)sizeof (OVS_BUFFER_CONTEXT),
                                         (UINT16)OVS_DEFAULT_NBL_CONTEXT_FILL,
                                                mdl, realSize, 0);
    if (nbl == NULL) {
        OvsFreeMDLAndData(mdl);
        return NULL;
    }

    nbl->SourceHandle = ovsPool->ndisHandle;
    status = context->NdisSwitchHandlers.
             AllocateNetBufferListForwardingContext(ovsPool->ndisContext, nbl);

    if (status != NDIS_STATUS_SUCCESS) {
       /*
        * do we need to remove mdl from nbl XXX
        */
        OvsFreeMDLAndData(mdl);
        NdisFreeNetBufferList(nbl);
        return NULL;
    }

    info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(nbl);
    ASSERT(info);
    info->IsPacketDataSafe = TRUE;
    info->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
    status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(nbl),
                                           size, 0, NULL);
    ASSERT(status == NDIS_STATUS_SUCCESS);

#ifdef DBG
    InterlockedIncrement((LONG volatile *)&ovsPool->zeroNBLCount);
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);
#endif

    ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);

    OvsInitNBLContext(ctx, OVS_BUFFER_PRIVATE_MDL | OVS_BUFFER_PRIVATE_DATA |
                           OVS_BUFFER_PRIVATE_FORWARD_CONTEXT |
                           OVS_BUFFER_FROM_ZERO_SIZE_POOL,
                      size, OVS_DEFAULT_PORT_NO);

    OVS_LOG_LOUD("Allocate variable size NBL: %p", nbl);
    return nbl;
}
Пример #29
0
static NTSTATUS
OvsInjectPacketThroughActions(PNET_BUFFER_LIST pNbl,
                              OVS_TUNNEL_PENDED_PACKET *packet)
{
    NTSTATUS status = STATUS_SUCCESS;
    OvsIPv4TunnelKey tunnelKey;
    NET_BUFFER *pNb;
    ULONG sendCompleteFlags = 0;
    BOOLEAN dispatch;
    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
    LOCK_STATE_EX lockState, dpLockState;
    LIST_ENTRY missedPackets;
    OvsCompletionList completionList;
    KIRQL irql;
    ULONG SendFlags = NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP;
    OVS_DATAPATH *datapath = NULL;

    ASSERT(gOvsSwitchContext);
    datapath = &gOvsSwitchContext->datapath;

    /* Fill the tunnel key */
    status = OvsSlowPathDecapVxlan(pNbl, &tunnelKey);

    if(!NT_SUCCESS(status)) {
        goto dropit;
    }

    pNb = NET_BUFFER_LIST_FIRST_NB(pNbl);

    NdisAdvanceNetBufferDataStart(pNb,
                                  packet->transportHeaderSize + packet->ipHeaderSize +
                                  sizeof(VXLANHdr),
                                  FALSE,
                                  NULL);

    /* Most likely (always) dispatch irql */
    irql = KeGetCurrentIrql();

    /* dispatch is used for datapath lock as well */
    dispatch = (irql == DISPATCH_LEVEL) ?  NDIS_RWL_AT_DISPATCH_LEVEL : 0;
    if (dispatch) {
        sendCompleteFlags |=  NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL;
    }

    InitializeListHead(&missedPackets);
    OvsInitCompletionList(&completionList, gOvsSwitchContext,
                          sendCompleteFlags);

    {
        POVS_VPORT_ENTRY vport;
        UINT32 portNo;
        OVS_PACKET_HDR_INFO layers;
        OvsFlowKey key;
        UINT64 hash;
        PNET_BUFFER curNb;
        OvsFlow *flow;

        fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);

        /*
         * XXX WFP packets contain a single NBL structure.
         * Reassembeled packet "may" have multiple NBs, however, a simple test shows
         * that the packet still has a single NB (after reassemble)
         * We still need to check if the Ethernet header of the innet packet is in a single MD
         */

        curNb = NET_BUFFER_LIST_FIRST_NB(pNbl);
        ASSERT(curNb->Next == NULL);

        NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, dispatch);

        /* Lock the flowtable for the duration of accessing the flow */
        OvsAcquireDatapathRead(datapath, &dpLockState, NDIS_RWL_AT_DISPATCH_LEVEL);

        SendFlags |= NDIS_SEND_FLAGS_DISPATCH_LEVEL;

        vport = OvsFindTunnelVportByDstPort(gOvsSwitchContext,
                                            htons(tunnelKey.dst_port),
                                            OVS_VPORT_TYPE_VXLAN);

        if (vport == NULL){
            status = STATUS_UNSUCCESSFUL;
            goto unlockAndDrop;
        }

        ASSERT(vport->ovsType == OVS_VPORT_TYPE_VXLAN);

        portNo = vport->portNo;

        status = OvsExtractFlow(pNbl, portNo, &key, &layers, &tunnelKey);
        if (status != NDIS_STATUS_SUCCESS) {
            goto unlockAndDrop;
        }

        flow = OvsLookupFlow(datapath, &key, &hash, FALSE);
        if (flow) {
            OvsFlowUsed(flow, pNbl, &layers);
            datapath->hits++;

            OvsActionsExecute(gOvsSwitchContext, &completionList, pNbl,
                              portNo, SendFlags, &key, &hash, &layers,
                              flow->actions, flow->actionsLen);

            OvsReleaseDatapath(datapath, &dpLockState);
        } else {
            POVS_PACKET_QUEUE_ELEM elem;

            datapath->misses++;
            elem = OvsCreateQueueNlPacket(NULL, 0, OVS_PACKET_CMD_MISS,
                                          vport, &key, pNbl, curNb,
                                          TRUE, &layers);
            if (elem) {
                /* Complete the packet since it was copied to user buffer. */
                InsertTailList(&missedPackets, &elem->link);
                OvsQueuePackets(&missedPackets, 1);
            } else {
                status = STATUS_INSUFFICIENT_RESOURCES;
            }
            goto unlockAndDrop;
        }

        NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);

    }

    return status;

unlockAndDrop:
    OvsReleaseDatapath(datapath, &dpLockState);
    NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
dropit:
    pNbl = OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE);
    ASSERT(pNbl == NULL);
    return status;
}
Пример #30
0
/*
 * --------------------------------------------------------------------------
 * OvsPartialCopyNBL --
 *
 *    Partial copy NBL, if there is multiple NB in NBL, each one will be
 *    copied. We also reserve headroom for the new NBL.
 *
 *    Please note,
 *       NBL should have OVS_BUFFER_CONTEXT setup before calling
 *       this function.
 *       The NBL should already have ref to itself so that during copy
 *       it will not be freed.
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsPartialCopyNBL(PVOID ovsContext,
                  PNET_BUFFER_LIST nbl,
                  UINT32 copySize,
                  UINT32 headRoom,
                  BOOLEAN copyNblInfo)
{
    PNET_BUFFER_LIST newNbl;
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
    NDIS_STATUS status;
    PNET_BUFFER srcNb, dstNb;
    ULONG byteCopied;
    POVS_NBL_POOL ovsPool = &context->ovsPool;
    POVS_BUFFER_CONTEXT srcCtx, dstCtx;
    UINT16 flags;

    srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
    if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
        OVS_LOG_INFO("src nbl must have ctx initialized");
        ASSERT(srcCtx && srcCtx->magic == OVS_CTX_MAGIC);
        return NULL;
    }

    if (copySize) {
        NdisAdvanceNetBufferListDataStart(nbl, copySize, FALSE, NULL);
    }
    newNbl = NdisAllocateCloneNetBufferList(nbl, ovsPool->nblOnlyPool,
                                            NULL, 0);
    if (copySize) {
        status = NdisRetreatNetBufferListDataStart(nbl, copySize, 0,
                                                   NULL, NULL);
        ASSERT(status == NDIS_STATUS_SUCCESS);
    }

    if (newNbl == NULL) {
        return NULL;
    }

    /*
     * Allocate private memory for copy
     */
    if (copySize + headRoom) {
        status = NdisRetreatNetBufferListDataStart(newNbl, copySize + headRoom,
                                                   0, NULL, NULL);
        if (status != NDIS_STATUS_SUCCESS) {
            goto retreat_error;
        }

        if (headRoom) {
            NdisAdvanceNetBufferListDataStart(newNbl, headRoom, FALSE, NULL);
        }
        if (copySize) {
            srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
            dstNb = NET_BUFFER_LIST_FIRST_NB(newNbl);

            while (srcNb) {
                status = NdisCopyFromNetBufferToNetBuffer(dstNb, 0, copySize,
                                                          srcNb, 0,
                                                          &byteCopied);
                if (status != NDIS_STATUS_SUCCESS || copySize != byteCopied) {
                    goto nbl_context_error;
                }
                srcNb = NET_BUFFER_NEXT_NB(srcNb);
                dstNb = NET_BUFFER_NEXT_NB(dstNb);
            }
        }
    }

    status = OvsAllocateNBLContext(context, newNbl);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nbl_context_error;
    }

    status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, copySize, copyNblInfo);
    if (status != NDIS_STATUS_SUCCESS) {
        goto copy_list_info_error;
    }

#ifdef DBG
    InterlockedIncrement((LONG volatile *)&ovsPool->nblOnlyCount);
#endif

    newNbl->ParentNetBufferList = nbl;

    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
    ASSERT(dstCtx != NULL);

    flags = srcCtx->flags & (OVS_BUFFER_RECV_BUFFER | OVS_BUFFER_SEND_BUFFER);

    flags |= OVS_BUFFER_FROM_NBL_ONLY_POOL | OVS_BUFFER_PRIVATE_CONTEXT |
             OVS_BUFFER_PRIVATE_FORWARD_CONTEXT;

    srcNb = NET_BUFFER_LIST_FIRST_NB(nbl);
    OvsInitNBLContext(dstCtx, flags, NET_BUFFER_DATA_LENGTH(srcNb) - copySize,
                      OVS_DEFAULT_PORT_NO);

    InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
#ifdef DBG
    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);

    OvsDumpNetBufferList(newNbl);
    OvsDumpForwardingDetails(newNbl);
#endif
    OVS_LOG_LOUD("Partial Copy new NBL: %p", newNbl);
    return newNbl;

copy_list_info_error:
    OvsFreeNBLContext(context, newNbl);
nbl_context_error:
    if (copySize) {
        NdisAdvanceNetBufferListDataStart(newNbl, copySize, TRUE, NULL);
    }
retreat_error:
    NdisFreeCloneNetBufferList(newNbl, 0);
    return NULL;
}