Esempio n. 1
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);
	}
}
Esempio n. 2
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);
		}
	}
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
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;
}
Esempio n. 7
0
/*
 * --------------------------------------------------------------------------
 * OvsTcpSegmentyNBL --
 *
 *    Segment TCP payload, and prepend each segment with ether/IP/TCP header.
 *    Leave headRoom for additional encap.
 *
 *    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.
 *       Currently this API assert there is only one NB in an NBL, it needs
 *       to be fixed if we receive multiple NBs in an NBL.
 * --------------------------------------------------------------------------
 */
PNET_BUFFER_LIST
OvsTcpSegmentNBL(PVOID ovsContext,
                 PNET_BUFFER_LIST nbl,
                 POVS_PACKET_HDR_INFO hdrInfo,
                 UINT32 mss,
                 UINT32 headRoom)
{
    POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
#ifdef DBG
    POVS_NBL_POOL ovsPool = &context->ovsPool;
#endif
    POVS_BUFFER_CONTEXT dstCtx, srcCtx;
    UINT32 size, hdrSize, seqNumber;
    PNET_BUFFER_LIST newNbl;
    PNET_BUFFER nb, newNb;
    NDIS_STATUS status;
    UINT16 segmentSize;
    ULONG copiedSize;

    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);
    ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);

    /* Figure out the segment header size */
    status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
    if (status != NDIS_STATUS_SUCCESS) {
        OVS_LOG_INFO("Cannot parse NBL header");
        return NULL;
    }

    size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;

    /* XXX add to ovsPool counters? */
    newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL,
            NULL, hdrSize, mss, hdrSize + headRoom , 0, 0);
    if (newNbl == NULL) {
        return NULL;
    }

    /* Now deal with TCP payload */
    for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
            newNb = NET_BUFFER_NEXT_NB(newNb)) {
        segmentSize = (size > mss ? mss : size) & 0xffff;
        if (headRoom) {
            NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
        }

        /* Now copy the eth/IP/TCP header and fix up */
        status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
                                                  &copiedSize);
        if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
            goto nblcopy_error;
        }

        status = FixSegmentHeader(newNb, segmentSize, seqNumber);
        if (status != NDIS_STATUS_SUCCESS) {
            goto nblcopy_error;
        }


        /* Move on to the next segment */
        size -= segmentSize;
        seqNumber += segmentSize;
    }

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

    status = OvsCopyNBLInfo(nbl, newNbl, srcCtx, hdrSize + headRoom, FALSE);
    if (status != NDIS_STATUS_SUCCESS) {
        goto nbl_context_error;
    }

    newNbl->ParentNetBufferList = nbl;

    /* Remember it's a fragment NBL so we can free it properly */
    dstCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(newNbl);
    ASSERT(dstCtx != NULL);
    dstCtx->flags = OVS_BUFFER_FRAGMENT | OVS_BUFFER_PRIVATE_CONTEXT |
        OVS_BUFFER_PRIVATE_FORWARD_CONTEXT | OVS_BUFFER_SEND_BUFFER;
    dstCtx->refCount = 1;
    dstCtx->magic = OVS_CTX_MAGIC;
    dstCtx->dataOffsetDelta = hdrSize + headRoom;

    InterlockedIncrement((LONG volatile *)&srcCtx->refCount);
#ifdef DBG
    InterlockedIncrement((LONG volatile *)&ovsPool->fragNBLCount);

    OvsDumpNetBufferList(nbl);
    OvsDumpForwardingDetails(nbl);

    OvsDumpNetBufferList(newNbl);
    OvsDumpForwardingDetails(newNbl);
#endif
    OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl);
    return newNbl;

nbl_context_error:
    OvsFreeNBLContext(context, newNbl);
nblcopy_error:
#ifdef DBG
    InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount);
#endif
    NdisFreeFragmentNetBufferList(newNbl, hdrSize + headRoom, 0);
    return NULL;
}
Esempio n. 8
0
/*
 *----------------------------------------------------------------------------
 * OvsDoDecapVxlan
 *     Decapsulates to tunnel header in 'curNbl' and puts into 'tunKey'.
 *----------------------------------------------------------------------------
 */
NDIS_STATUS
OvsDoDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
                PNET_BUFFER_LIST curNbl,
                OvsIPv4TunnelKey *tunKey,
                PNET_BUFFER_LIST *newNbl)
{
    PNET_BUFFER curNb;
    PMDL curMdl;
    EthHdr *ethHdr;
    IPHdr *ipHdr;
    UDPHdr *udpHdr;
    VXLANHdr *vxlanHdr;
    UINT32 tunnelSize = 0, packetLength = 0;
    PUINT8 bufferStart;
    NDIS_STATUS status;

    /* Check the the length of the UDP payload */
    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
    packetLength = NET_BUFFER_DATA_LENGTH(curNb);
    tunnelSize = OvsGetVxlanTunHdrSize();
    if (packetLength <= tunnelSize) {
        return NDIS_STATUS_INVALID_LENGTH;
    }

    /*
     * Create a copy of the NBL so that we have all the headers in one MDL.
     */
    *newNbl = OvsPartialCopyNBL(switchContext, curNbl,
                                tunnelSize + OVS_DEFAULT_COPY_SIZE, 0,
                                TRUE /*copy NBL info */);

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

    /* XXX: Handle VLAN header. */
    curNbl = *newNbl;
    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
    curMdl = NET_BUFFER_CURRENT_MDL(curNb);
    bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority) +
                  NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
    if (!bufferStart) {
        status = NDIS_STATUS_RESOURCES;
        goto dropNbl;
    }

    ethHdr = (EthHdr *)bufferStart;
    /* XXX: Handle IP options. */
    ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
    tunKey->src = ipHdr->saddr;
    tunKey->dst = ipHdr->daddr;
    tunKey->tos = ipHdr->tos;
    tunKey->ttl = ipHdr->ttl;
    tunKey->pad = 0;
    udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);

    /* Validate if NIC has indicated checksum failure. */
    status = OvsValidateUDPChecksum(curNbl, udpHdr->check == 0);
    if (status != NDIS_STATUS_SUCCESS) {
        goto dropNbl;
    }

    /* Calculate and verify UDP checksum if NIC didn't do it. */
    if (udpHdr->check != 0) {
        status = OvsCalculateUDPChecksum(curNbl, curNb, ipHdr, udpHdr, packetLength);
        if (status != NDIS_STATUS_SUCCESS) {
            goto dropNbl;
        }
    }

    vxlanHdr = (VXLANHdr *)((PCHAR)udpHdr + sizeof *udpHdr);
    if (vxlanHdr->instanceID) {
        tunKey->flags = OVS_TNL_F_KEY;
        tunKey->tunnelId = VXLAN_VNI_TO_TUNNELID(vxlanHdr->vxlanID);
    } else {
        tunKey->flags = 0;
        tunKey->tunnelId = 0;
    }

    /* Clear out the receive flag for the inner packet. */
    NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = 0;
    NdisAdvanceNetBufferDataStart(curNb, tunnelSize, FALSE, NULL);
    return NDIS_STATUS_SUCCESS;

dropNbl:
    OvsCompleteNBL(switchContext, *newNbl, TRUE);
    *newNbl = NULL;
    return status;
}
Esempio n. 9
-1
// Write procedure of the device
NTSTATUS SlDeviceWriteProc(DEVICE_OBJECT *device_object, IRP *irp)
{
	SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
	NTSTATUS ret = STATUS_UNSUCCESSFUL;
	IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
	UINT ret_size = 0;

	if (dev->IsBasicDevice == false)
	{
		// Adapter device
		SL_FILE *f = irp_stack->FileObject->FsContext;

		if (irp_stack->Parameters.Write.Length == SL_EXCHANGE_BUFFER_SIZE)
		{
			UCHAR *buf = irp->UserBuffer;

			if (dev->Halting || dev->Adapter->Halt || buf == NULL)
			{
				// Halting
			}
			else
			{
				// Write the packet
				MDL *mdl;
				UINT num = SL_NUM_PACKET(buf);

				mdl = IoAllocateMdl(buf, SL_EXCHANGE_BUFFER_SIZE, false, false, NULL);
				if (mdl != NULL)
				{
					MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
				}

				ret = true;
				ret_size = SL_EXCHANGE_BUFFER_SIZE;

				if (num >= 1 && num <= SL_MAX_PACKET_EXCHANGE)
				{
					UINT i, j;
					NET_BUFFER_LIST *nbl_head = NULL;
					NET_BUFFER_LIST *nbl_tail = NULL;
					UINT num_packets = 0;
					NDIS_HANDLE adapter_handle = NULL;

					SlLock(f->Adapter->Lock);

					if (f->Adapter->NumPendingSendPackets <= SL_MAX_PACKET_QUEUED)
					{
						// Admit to send only if the number of packets being transmitted does not exceed the specified limit
						adapter_handle = f->Adapter->AdapterHandle;
					}

					if (adapter_handle != NULL)
					{
						// Lock the file list which opens the same adapter
						SlLockList(dev->FileList);
						for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
						{
							SL_FILE *other = SL_LIST_DATA(dev->FileList, j);

							if (other != f)
							{
								// Lock the receive queue of other file lists
								SlLock(other->RecvLock);

								other->SetEventFlag = false;
							}
						}

						for (i = 0;i < num;i++)
						{
							UINT packet_size = SL_SIZE_OF_PACKET(buf, i);
							UCHAR *packet_buf;
							NET_BUFFER_LIST *nbl = NULL;
							bool ok = false;

							if (packet_size > SL_MAX_PACKET_SIZE)
							{
								packet_size = SL_MAX_PACKET_SIZE;
							}
							else if (packet_size < SL_PACKET_HEADER_SIZE)
							{
								packet_size = SL_PACKET_HEADER_SIZE;
							}

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

							for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
							{
								SL_FILE *other = SL_LIST_DATA(dev->FileList, j);

								if (other != f)
								{
									// Insert into the receive queue of the other file lists
									if (other->NumRecvPackets < SL_MAX_PACKET_QUEUED)
									{
										SL_PACKET *q = SlMalloc(sizeof(SL_PACKET));

										SlCopy(q->Data, packet_buf, packet_size);
										q->Size = packet_size;
										q->Next = NULL;

										if (other->RecvPacketHead == NULL)
										{
											other->RecvPacketHead = q;
										}
										else
										{
											other->RecvPacketTail->Next = q;
										}

										other->RecvPacketTail = q;

										other->NumRecvPackets++;

										other->SetEventFlag = true;
									}
								}
							}

							// Allocate a new NET_BUFFER_LIST
							if (f->NetBufferListPool != NULL)
							{
								nbl = NdisAllocateNetBufferList(f->NetBufferListPool, 16, 0);

								if (nbl != NULL)
								{
									nbl->SourceHandle = adapter_handle;
								}
							}

							if (nbl != NULL)
							{
								// Get the NET_BUFFER from the NET_BUFFER_LIST
								NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);

								NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;

								if (nb != NULL && OK(NdisRetreatNetBufferDataStart(nb, packet_size, 0, NULL)))
								{
									// Buffer copy
									UCHAR *dst = NdisGetDataBuffer(nb, packet_size, NULL, 1, 0);

									if (dst != NULL)
									{
										SlCopy(dst, packet_buf, packet_size);

										ok = true;
									}
									else
									{
										NdisAdvanceNetBufferDataStart(nb, packet_size, false, NULL);
									}
								}
							}

							if (ok == false)
							{
								if (nbl != NULL)
								{
									NdisFreeNetBufferList(nbl);
								}
							}
							else
							{
								if (nbl_head == NULL)
								{
									nbl_head = nbl;
								}

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

								nbl_tail = nbl;

								*((void **)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl)) = f;

								num_packets++;
							}
						}

						for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
						{
							SL_FILE *other = SL_LIST_DATA(dev->FileList, j);

							if (other != f)
							{
								// Release the receive queue of other file lists
								SlUnlock(other->RecvLock);

								// Set an event
								if (other->SetEventFlag)
								{
									SlSet(other->Event);
								}
							}
						}
						SlUnlockList(dev->FileList);

						if (nbl_head != NULL)
						{
							InterlockedExchangeAdd(&f->NumSendingPacketets, num_packets);
							InterlockedExchangeAdd(&f->Adapter->NumPendingSendPackets, num_packets);

							SlUnlock(f->Adapter->Lock);

							NdisSendNetBufferLists(adapter_handle, nbl_head, 0, 0);
						}
						else
						{
							SlUnlock(f->Adapter->Lock);
						}
					}
					else
					{
						SlUnlock(f->Adapter->Lock);
					}
				}

				if (mdl != NULL)
				{
					MmUnlockPages(mdl);
					IoFreeMdl(mdl);
				}
			}
		}
	}

	irp->IoStatus.Information = ret_size;
	irp->IoStatus.Status = ret;
	IoCompleteRequest(irp, IO_NO_INCREMENT);

	return ret;
}