Beispiel #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);
	}
}
Beispiel #2
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;
}
Beispiel #3
0
static VOID
OvsDumpNetBuffer(PNET_BUFFER nb)
{
    OVS_LOG_INFO("NET_BUFFER: %p, ChecksumBias: %d Handle: %p, MDLChain: %p "
                 "CurrMDL: %p, CurrOffset: %d, DataLen: %d, Offset: %d",
                 nb,
                 NET_BUFFER_CHECKSUM_BIAS(nb), nb->NdisPoolHandle,
                 NET_BUFFER_FIRST_MDL(nb),
                 NET_BUFFER_CURRENT_MDL(nb),
                 NET_BUFFER_CURRENT_MDL_OFFSET(nb),
                 NET_BUFFER_DATA_LENGTH(nb),
                 NET_BUFFER_DATA_OFFSET(nb));
    OvsDumpMDLChain(NET_BUFFER_FIRST_MDL(nb));
}
Beispiel #4
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;
}
Beispiel #5
0
/*
 * --------------------------------------------------------------------------
 * FixSegmentHeader
 *
 *    Fix IP length, IP checksum, TCP sequence number and TCP checksum
 *    in the segment.
 * --------------------------------------------------------------------------
 */
static NDIS_STATUS
FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber)
{
    EthHdr *dstEth;
    IPHdr *dstIP;
    TCPHdr *dstTCP;
    PMDL mdl;
    PUINT8 bufferStart;

    mdl = NET_BUFFER_FIRST_MDL(nb);

    bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority);
    if (!bufferStart) {
        return NDIS_STATUS_RESOURCES;
    }
    dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
    ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
            >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
    dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth);
    dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
    ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
            >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));

    /* Fix IP length and checksum */
    ASSERT(dstIP->protocol == IPPROTO_TCP);
    dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
    dstIP->check = 0;
    dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);

    /* Fix TCP checksum */
    dstTCP->seq = htonl(seqNumber);
    dstTCP->check =
        IPPseudoChecksum((UINT32 *)&dstIP->saddr,
                         (UINT32 *)&dstIP->daddr,
                         IPPROTO_TCP, segmentSize + TCP_HDR_LEN(dstTCP));
    dstTCP->check = CalculateChecksumNB(nb,
            (UINT16)(NET_BUFFER_DATA_LENGTH(nb) - sizeof *dstEth - dstIP->ihl * 4),
            sizeof *dstEth + dstIP->ihl * 4);
    return STATUS_SUCCESS;
}
Beispiel #6
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;
}
Beispiel #7
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;
}
Beispiel #8
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;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
Beispiel #11
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);
    }

}
Beispiel #12
0
// NDIS packet reception notification procedure
void SlNdisReceiveNetBufferListsProc(NDIS_HANDLE protocol_binding_context, NET_BUFFER_LIST *net_buffer_lists,
									 NDIS_PORT_NUMBER port_number, ULONG NumberOfNetBufferLists,
									 ULONG receive_flags)
{
	SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
	UINT i;
	UINT return_flags = 0;
	NET_BUFFER_LIST *nbl;
	UCHAR *tmp_buffer;
	UINT tmp_size;

	if (net_buffer_lists == NULL || NumberOfNetBufferLists == 0)
	{
		return;
	}

	if (a->AdapterHandle2 == NULL)
	{
		a->AdapterHandle2 = a->AdapterHandle;
	}

	if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(receive_flags))
	{
		NDIS_SET_RETURN_FLAG(return_flags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
	}

	if (a->Halt || a->Device == NULL || a->Device->Halting || a->Ready == false || a->AdapterHandle == NULL)
	{
		goto LABEL_CLEANUP;
	}

	tmp_buffer = a->TmpBuffer;
	tmp_size = sizeof(a->TmpBuffer);

	nbl = net_buffer_lists;

	SlLockList(a->Device->FileList);
	{
		if (a->Halt == false)
		{
			for (i = 0;i < SL_LIST_NUM(a->Device->FileList);i++)
			{
				// Lock the receive queue
				SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);

				SlLock(f->RecvLock);
			}

			while (nbl != NULL)
			{
				NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);
				bool is_vlan = false;
				UCHAR vlan_tag[2];

				if (NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo) != 0)
				{
					NDIS_NET_BUFFER_LIST_8021Q_INFO qinfo;
					qinfo.Value = NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo);
					if (qinfo.TagHeader.VlanId != 0)
					{
						USHORT tag_us;
						is_vlan = true;

						tag_us = (qinfo.TagHeader.UserPriority & 0x07 << 13) |
							(qinfo.TagHeader.CanonicalFormatId & 0x01 << 12) |
							(qinfo.TagHeader.VlanId & 0x0FFF);

						vlan_tag[0] = ((UCHAR *)(&tag_us))[1];
						vlan_tag[1] = ((UCHAR *)(&tag_us))[0];
					}
				}

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

					if (size >= 14 && size <= tmp_size && size <= (UINT)((is_vlan == false) ? SL_MAX_PACKET_SIZE : (SL_MAX_PACKET_SIZE - 4)))
					{
						UCHAR *ptr = NdisGetDataBuffer(nb, size, tmp_buffer, 1, 0);

						if (ptr != NULL)
						{
							// Insert the queue to all waiting files
							for (i = 0;i < SL_LIST_NUM(a->Device->FileList);i++)
							{
								SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);

								if (f->NumRecvPackets < SL_MAX_PACKET_QUEUED)
								{
									SL_PACKET *q = SlMalloc(sizeof(SL_PACKET));

									if (is_vlan == false)
									{
										// Normal packet
										SlCopy(q->Data, ptr, size);
										q->Size = size;
									}
									else
									{
										// Insert a tag in the case of IEEE802.1Q packet
										SlCopy(q->Data, ptr, 12);
										q->Data[12] = 0x81;
										q->Data[13] = 0x00;
										SlCopy(&q->Data[14], vlan_tag, 2);
										SlCopy(&q->Data[16], &ptr[12], size - 12);

										q->Size = size + 4;
									}

									q->Next = NULL;

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

									f->RecvPacketTail = q;

									f->NumRecvPackets++;
								}
							}
						}
					}

					nb = NET_BUFFER_NEXT_NB(nb);
				}

				nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
			}

			// Hit the event
			for (i = 0;i < SL_LIST_NUM(a->Device->FileList);i++)
			{
				SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);

				// Unlock the receive queue
				SlUnlock(f->RecvLock);

				SlSet(f->Event);
			}
		}
	}
	SlUnlockList(a->Device->FileList);

LABEL_CLEANUP:

	if (NDIS_TEST_RECEIVE_CAN_PEND(receive_flags))
	{
		NdisReturnNetBufferLists(a->AdapterHandle2, net_buffer_lists, return_flags);
	}
}
Beispiel #13
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);


}
Beispiel #14
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;
}
Beispiel #15
0
VOID
FilterSendNetBufferLists(
        IN  NDIS_HANDLE         FilterModuleContext,
        IN  PNET_BUFFER_LIST    NetBufferLists,
        IN  NDIS_PORT_NUMBER    PortNumber,
        IN  ULONG               SendFlags
        )
/*++
 
Routine Description:

    Send Net Buffer List handler
    This function is an optional function for filter drivers. If provided, NDIS
    will call this function to transmit a linked list of NetBuffers, described by a 
    NetBuferList, over the network. If this handler is NULL, NDIS will skip calling
    this fitler when sending a NetBufferList and will call the next lower fitler 
    in the stack with a non_NULL FilterSendNetBufferList handleror the miniport driver.
    A filter that doesn't provide a FilerSendNetBufferList handler can not initiate a 
    send o its own.

Arguments:

    FilterModuleContext: Pointer to our filter context area.
    NetBufferLists: Pointer to a List of NetBufferLists.
    PortNumber - Port Number to which this send is targetted
    SendFlags-  Specifies if the call is at DISPATCH_LEVEL                     
  

Return Value:
 
    NDIS_STATUS_SUCCESS: 
    NDIS_STATUS_PENDING:
    NDIS_STATUS_INVALID_PACKET:
    NDIS_STATUS_RESOURCES:
    NDIS_STATUS_FAILURE:


NOTE: The filter will act like a passthru filter.       
 
--*/
{
    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;
    NDIS_STATUS         Status = NDIS_STATUS_SUCCESS;
    PNET_BUFFER_LIST    CurrNbl;
    BOOLEAN             DispatchLevel;

	// ++
	PNET_BUFFER_LIST	CurrentBufferList	= NULL;
	PNET_BUFFER			CurrentBuffer		= NULL;
	PNET_BUFFER_DATA	CurrentBufferData	= NULL;
	PMDL				PacketMdl			= NULL;
	ULONG				DataOffset			= 0;
	ULONG				PacketSize			= 0;
	PUCHAR				PacketData			= NULL;
	ARP_PACKET*			ArpPacket			= NULL;
	BOOLEAN				bWanAdapter			= FALSE;
    // --

    
    DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists));

    do
    {

       DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
#if DBG
        //
        // we should never get packets to send if we are not in running state
        //
        
        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
        //
        // If the filter is not in running state, fail the send
        // 
        if (pFilter->State != FilterRunning)
        {
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
            
            CurrNbl = NetBufferLists;
            while (CurrNbl)
            {
                NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
                CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
            }
            NdisFSendNetBufferListsComplete(pFilter->FilterHandle, 
                        NetBufferLists, 
                        DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
            break;
            
        }
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

		//  ++
		CurrentBufferList = NetBufferLists;

		while(CurrentBufferList)
		{
			// Each NET_BUFFER structure packages a packet of network data
			CurrentBuffer = NET_BUFFER_LIST_FIRST_NB(CurrentBufferList);
			while(CurrentBuffer)
			{
				// 检测其中是否有ARP协议包
				PacketMdl		= NET_BUFFER_FIRST_MDL(CurrentBuffer);
				DataOffset		= NET_BUFFER_DATA_OFFSET(CurrentBuffer);
				PacketSize	= NET_BUFFER_DATA_LENGTH(CurrentBuffer);
				
				if(PacketMdl && PacketSize)
				{
					PacketData = (UCHAR*)MmGetSystemAddressForMdlSafe(PacketMdl,NormalPagePriority);
					if(PacketData)
					{
						if(DataOffset)
						{
							PacketData = PacketData + DataOffset;
						}
						// PacketData 是网络包数据,PacketSize 是网络包数据长度

						KdPrint((" PacketData : %p , PacketSize : %d ",PacketData,PacketSize));

						ArpPacket = (ARP_PACKET*)PacketData;

						// 记录网关回应查询次数
						NdisAcquireSpinLock(&GlobalLock);
						if( ArpPacket->EthType == ETHERNET_ARP)
						{
							if( g_bRecord_ARP_Reply						&&
								ArpPacket->OperateCode == ARP_QUERY		&&
								NdisEqualMemory(ArpPacket->DestIPAddress,g_Want_ARP_Reply_IP,4)	)
							{
								g_Reply_Record->ulQueryCount ++;
								//开始记录网关查询操作
								BeginCheckGateway();
							}
						}
						NdisReleaseSpinLock(&GlobalLock);

					}
				}
				CurrentBuffer = NET_BUFFER_NEXT_NB(CurrentBuffer);
			}
			CurrentBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrentBufferList);
		}
		// --


        if (pFilter->TrackSends)
        {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
            CurrNbl = NetBufferLists;
            while (CurrNbl)
            {
                pFilter->OutstandingSends++;
                FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);
                
                CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
            }
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
        }
        //
        // If necessary, queue the NetBufferList in a local structure for later processing
        //
        NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);
        
        
    }
    while (FALSE);
    
    DEBUGP(DL_TRACE, ("<===SendNetBufferList: Status = %8x.\n", Status));
}
Beispiel #16
0
VOID
FilterReceiveNetBufferLists(
        IN  NDIS_HANDLE         FilterModuleContext,
        IN  PNET_BUFFER_LIST    NetBufferLists,
        IN  NDIS_PORT_NUMBER    PortNumber,
        IN  ULONG               NumberOfNetBufferLists,
        IN  ULONG               ReceiveFlags
         )
/*++

Routine Description:

    FilerReceiveNetBufferLists is an optional function for filter drivers. 
    If provided, this function process receive indications made by underlying 
    NIC or lower level filter drivers. This function  can also be called as a 
    result of loopback. If this handler is NULL, NDIS will skip calling this
    filter when processing a receive indication and will call the next upper 
    filter in the stack with a non-NULL FitlerReceiveNetBufferLists handler 
    or the procotol driver. A filter that doesn't provide a 
    FilterReceiveNetBufferLists handler can not provided a 
    FilterReturnNetBufferLists handler or a initiate a receive indication on 
    its own.

Arguments:

    FilterModuleContext: Pointer to our filter context area.
    NetBufferLists: A linked list of NetBufferLists allocated by underlying driver each containing
                    one NetBuffer.
    PortNumber: Port on which the Receive is indicated
    ReceiveFlags: Flags associated with the Receive such as whether the filter
                  can pend the receive
   

Return Value:

    None
 
--*/
{

    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;
    NDIS_STATUS         ReturnStatus = NDIS_STATUS_SUCCESS;
    PNET_BUFFER_LIST    NextNetBufferList;
    BOOLEAN             DispatchLevel;
    ULONG               ReturnFlags;
    ULONG               Ref;

	// ++
	PNET_BUFFER_LIST	CurrentBufferList	= NULL;
	PNET_BUFFER			CurrentBuffer		= NULL;
	PNET_BUFFER_DATA	CurrentBufferData	= NULL;
	BOOLEAN				HaveARPPacket		= FALSE;
	PMDL				PacketMdl			= NULL;
	ULONG				DataOffset			= 0;
	ULONG				PacketSize			= 0;
	PUCHAR				PacketData			= NULL;
	ARP_PACKET*			ArpPacket			= NULL;
	GATEWAY_ITEM*		Gateway				= NULL;
	LAN_ITEM*			LanItem				= NULL;
	WAN_ITEM*			WanItem				= NULL;
	ULONG				i					= 0;
	BOOLEAN				bSameRecord			= FALSE;
	enum ATTACH_TYPE	AttachType			= ATTACH_NONE;
	enum RAS_OPT		RetOpt				= OPT_PASS;
	BOOLEAN				bWanAdapter			= FALSE;
    // --

    DEBUGP(DL_TRACE, ("===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists));

    do
    {

        DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);

#if DBG
        
        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
 
        if (pFilter->State != FilterRunning)
        {
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

            if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
            {   
                ReturnFlags = 0;
                if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
                {
                    NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
                }
                
                NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
            }
            break;
        }
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

        ASSERT(NumberOfNetBufferLists >= 1);

		//  ++
		CurrentBufferList = NetBufferLists;

		while(CurrentBufferList)
		{
			// Each NET_BUFFER structure packages a packet of network data
			CurrentBuffer = NET_BUFFER_LIST_FIRST_NB(CurrentBufferList);
			while(CurrentBuffer)
			{
				// 检测其中是否有ARP协议包
				PacketMdl		= NET_BUFFER_FIRST_MDL(CurrentBuffer);
				DataOffset		= NET_BUFFER_DATA_OFFSET(CurrentBuffer);
				PacketSize	= NET_BUFFER_DATA_LENGTH(CurrentBuffer);
				
				if(PacketMdl && PacketSize)
				{
					PacketData = (UCHAR*)MmGetSystemAddressForMdlSafe(PacketMdl,NormalPagePriority);
					if(PacketData)
					{
						if(DataOffset)
						{
							PacketData = PacketData + DataOffset;
						}
						// PacketData 是网络包数据,PacketSize 是网络包数据长度

						do
						{
							ArpPacket = (ARP_PACKET*)PacketData;

							if( ArpPacket->EthType != ETHERNET_ARP || 
								PacketSize < sizeof(ARP_PACKET)		)
							{
								break;
							}
							else
							{
								KdPrint((" 收到ARP数据包"));
							}

							if( ArpPacket->OperateCode != 0x100 &&
								ArpPacket->OperateCode != 0x200 &&
								ArpPacket->OperateCode != 0x300 &&
								ArpPacket->OperateCode != 0x400 )
							{
								KdPrint((" 错误ARP/RARP协议攻击"));
								AttachType = WRONG_PROTOCOL_ATTACH;
								RetOpt = OPT_DROP;
								goto Exit;
							}

							//进行 IP - Mac 对应查询表的建立
							NdisAcquireSpinLock(&GlobalLock);
							if(g_ArpFw_ShareMem)
							{
								// 查询广播包
								if( ArpPacket->OperateCode == ARP_QUERY										&&
									NdisEqualMemory(ArpPacket->DestMacAddress,Empty_MacAddress,6)			&&
									!NdisEqualMemory(ArpPacket->SourceMacAddress,Empty_MacAddress,6)		&&
									g_ArpFw_ShareMem->ulItemCount < MAX_IP_MAC_ITEM_COUNT					)
								{
									bSameRecord = FALSE;
									for( i = 0 ; i< g_ArpFw_ShareMem->ulItemCount; i++)
									{
										if(NdisEqualMemory( g_ArpFw_ShareMem->Items[i].IPAddress,ArpPacket->SourceIPAddress,4))
										{
											bSameRecord = TRUE;
											break;
										}
									}

									//当前没有该IP地址的记录
									if(!bSameRecord)
									{
										memcpy(g_ArpFw_ShareMem->Items[g_ArpFw_ShareMem->ulItemCount].IPAddress,
												ArpPacket->SourceIPAddress,4);
										memcpy(g_ArpFw_ShareMem->Items[g_ArpFw_ShareMem->ulItemCount].MacAddress,
												ArpPacket->SourceMacAddress,6);

										g_ArpFw_ShareMem->ulItemCount ++;
										
									}	
								}
							}
							NdisReleaseSpinLock(&GlobalLock);

							// ARP Reply 报文记录
							if(	ArpPacket->OperateCode == ARP_REPLY									&& 
								g_bRecord_ARP_Reply													&&
								NdisEqualMemory(ArpPacket->SourceIPAddress,g_Want_ARP_Reply_IP,4)	)
							{
								bSameRecord = FALSE;

								NdisAcquireSpinLock(&GlobalLock);

								if(g_Reply_Record->ulItemCount < MAX_REPLY_RECORD)
								{
									do
									{
										if(g_Reply_Record->ulItemCount > 0)
										{
											for(i = 0 ; i < g_Reply_Record->ulItemCount; i ++)
											{
												if(NdisEqualMemory(ArpPacket->SourceMacAddress,
													g_Reply_Record->Items[i].MacAddress,6))
												{
													g_Reply_Record->Items[i].RecordCount ++;
													bSameRecord = TRUE;
													break;
												}
											}
										}

										if(!bSameRecord)
										{
											NdisMoveMemory(g_Reply_Record->Items[g_Reply_Record->ulItemCount].IPAddress,
																ArpPacket->SourceIPAddress,4);
											NdisMoveMemory(g_Reply_Record->Items[g_Reply_Record->ulItemCount].MacAddress,
																ArpPacket->SourceMacAddress,6);
											g_Reply_Record->Items[g_Reply_Record->ulItemCount].WanAddress	= bWanAdapter;
											g_Reply_Record->Items[g_Reply_Record->ulItemCount].Gateway		= TRUE;
											g_Reply_Record->Items[g_Reply_Record->ulItemCount].Next			= NULL;
											g_Reply_Record->Items[g_Reply_Record->ulItemCount].RecordCount	= 1;

											g_Reply_Record->ulItemCount ++;
										}
									}
									while(FALSE);
								}

								NdisReleaseSpinLock(&GlobalLock);
							}

							//检测伪造ARP/RARP Query攻击中的源Mac地址是否为正确的网关地址
							if( g_EnableGatewayCheck															&&
								(ArpPacket->OperateCode == ARP_QUERY || ArpPacket->OperateCode == RARP_QUERY )   )
							{
								// 网关地址检测,Query操作中的源地址和源MAC地址必须是正确的
								if(!bWanAdapter)		// 局域网网关检测
								{
									NdisAcquireSpinLock(&GlobalLock);
									Gateway  = g_Gateway_List;
									while(Gateway)
									{
										if( NdisEqualMemory(ArpPacket->SourceIPAddress,Gateway->IPAddress,4)	&&
											!NdisEqualMemory(ArpPacket->SourceMacAddress,Gateway->MacAddress,6)  )
										{
											// IP地址相同,Mac地址不同 (禁止该包往上通行)
											KdPrint(("伪造网关Query攻击报文"));
											AttachType = GATEWAY_ARP_QUERY_ATTACH;
											RetOpt = OPT_DROP;
											NdisReleaseSpinLock(&GlobalLock);
											goto Exit;					
										}

										Gateway = Gateway->Next;
									}
									NdisReleaseSpinLock(&GlobalLock);
								}
							}

							//伪造的ARP/RARP Reply报文检测
							if(	g_EnableGatewayCheck														  &&
								(ArpPacket->OperateCode == ARP_REPLY || ArpPacket->OperateCode == RARP_REPLY) )
							{

								if(!bWanAdapter)		// 局域网网关检测
								{
									NdisAcquireSpinLock(&GlobalLock);
									Gateway = g_Gateway_List;
									while(Gateway)
									{
										if(	NdisEqualMemory(Gateway->IPAddress,ArpPacket->SourceIPAddress,4)	&& // 是网关IP
											!NdisEqualMemory(Gateway->MacAddress,ArpPacket->SourceMacAddress,6)	)	// Mac 地址不相同,网关攻击
										{
											KdPrint(("伪造网关Reply攻击报文"));
											//禁止该包往上通行
											AttachType = GATEWAY_ARP_REPLY_ATTACH;
											RetOpt = OPT_DROP;
											NdisReleaseSpinLock(&GlobalLock);
											goto Exit;
										}
										else if(NdisEqualMemory(Gateway->IPAddress,ArpPacket->DestIPAddress,4)		&&
												!NdisEqualMemory(Gateway->MacAddress,ArpPacket->DestMacAddress,6)	)
										{
											KdPrint(("伪造网关Reply攻击报文"));
											//禁止该包往上通行
											RetOpt = OPT_DROP;
											AttachType = GATEWAY_ARP_REPLY_ATTACH;
											NdisReleaseSpinLock(&GlobalLock);
											goto Exit;
										}

										Gateway = Gateway->Next;
									}

									NdisReleaseSpinLock(&GlobalLock);
								}
							}
							
							//进行 IP 冲突攻击检测
							if(	g_EnableSameIPCheck														&&
								NdisEqualMemory(ArpPacket->SourceIPAddress,ArpPacket->DestIPAddress,4)	)
							{
								NdisAcquireSpinLock(&GlobalLock);
								if(!bWanAdapter) // 局域网检测
								{
									LanItem = g_Lan_List;
									while(LanItem)
									{
										// IP 地址相同 而 源Mac 地址不同
										if( NdisEqualMemory(ArpPacket->SourceIPAddress,LanItem->IPAddress,4) &&
											!NdisEqualMemory(ArpPacket->SourceMacAddress,LanItem->MacAddress,6) )
										{
											KdPrint(("伪造内网间IP冲突攻击报文"));
											RetOpt = OPT_DROP;
											AttachType = LAN_SAMEIP_ATTACH;
											NdisReleaseSpinLock(&GlobalLock);
											goto Exit;
										}

										LanItem = LanItem->Next;
									}
									// 局域网对外网的相同IP攻击
									WanItem = g_Wan_List;
									while(WanItem)
									{
										if(NdisEqualMemory(ArpPacket->SourceIPAddress,WanItem->IPAddress,4))
										{
											KdPrint(("伪造内外网间IP冲突攻击报文"));
											RetOpt = OPT_DROP;
											AttachType = WAN_SAMEIP_ATTACH;
											NdisReleaseSpinLock(&GlobalLock);
											goto Exit;
										}
										WanItem = WanItem->Next;
									}
								}
								NdisReleaseSpinLock(&GlobalLock);
							}
						}
						while(FALSE);
					}
				}
				CurrentBuffer = NET_BUFFER_NEXT_NB(CurrentBuffer);
			}
			CurrentBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrentBufferList);
		}
		//  --
            
        // 
        // If necessary, queue the NetBufferList in a local structure for later processing.
        // We may need to travel the list, some of them may not need post processing
        //
        if (pFilter->TrackReceives)
        {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
            pFilter->OutstandingRcvs += NumberOfNetBufferLists;
            Ref = pFilter->OutstandingRcvs;
            
            FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
        }

		KdPrint((" NdisFIndicateReceiveNetBufferLists Run "));

        NdisFIndicateReceiveNetBufferLists(
                   pFilter->FilterHandle,
                   NetBufferLists,
                   PortNumber, 
                   NumberOfNetBufferLists,
                   ReceiveFlags);


        if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) && 
            pFilter->TrackReceives)
        {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
            pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
            Ref = pFilter->OutstandingRcvs;
            FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
        }

		// ++
		break;

Exit:
		KdPrint((" Drop Received Packet "));
		if(ArpPacket)
		{
			NdisAcquireSpinLock(&GlobalLock);

			if(g_ArpFw_ShareMem && AttachType != ATTACH_NONE)	
			{
				g_ArpFw_ShareMem->NotifyPacket.AttachCount = 1;
				g_ArpFw_ShareMem->NotifyPacket.AttachType  = AttachType;
				g_ArpFw_ShareMem->NotifyPacket.SendPacket  = FALSE;
				g_ArpFw_ShareMem->NotifyPacket.WanPacket   = FALSE;

				RtlCopyMemory((PVOID)&g_ArpFw_ShareMem->NotifyPacket.ArpPacket,
								ArpPacket,sizeof(ARP_PACKET));

				SetUserShareEvent(&g_NotifyEvent);

			}
			NdisReleaseSpinLock(&GlobalLock);
		}

		// return this packet
		if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
		{
			ReturnFlags = 0;
			if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
			{
				NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
			}
			NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
		}
		// --

    } while (FALSE);
    
    DEBUGP(DL_TRACE, ("<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags));
    
}
Beispiel #17
0
/*
SdrLLSendPacket transforms NDIS packet and enqueue it in MAC send queue.

History:
    3/Nov/2009: Created by senxiang
*/
VOID SdrLLSendPacket(PSDR_CONTEXT SDRContext, PNDIS_PACKET_OR_NBL pNBSPacket)
{
    PMDL                pEthBuffer          = NULL;
    PMDL                pWlanBuffer         = NULL;
    PDLCB               pDLCB               = NULL;
    ULONG               Dot11HeaderSize     = 0;
    PUCHAR              pDot11HeaderVa      = NULL;
    PMAC                pMac                = (PMAC)SDRContext->Mac;
    PLL                 lnk                 = (PLL)SDRContext->LinkLayer;
    PSEND_QUEUE_MANAGER pSendQueueManager   = GET_SEND_QUEUE_MANAGER(pMac);
    PNET_BUFFER         pCurrentNB          = NET_BUFFER_LIST_FIRST_NB(pNBSPacket);

    ULONG               NetBufferCount      = GetNetBufferCount(pNBSPacket);
    LIST_ENTRY          DLCBList;

    BOOL                fSufficientDLCBs    = GetNFreeDLCB(&DLCBList, pSendQueueManager, NetBufferCount);
    DbgPrint("[LL_Send] %d net buffer in the NBL\n", NetBufferCount);

    if(pCurrentNB == NULL || !fSufficientDLCBs)
    {
        DbgPrint("[Error] Get NetBuffer failed, PACKET DROPPED\n");
        NicDropPacket((PMP_ADAPTER)SDRContext->Nic, pNBSPacket);
        return;
    }

    NET_BUFFER_LIST_STATUS(pNBSPacket) = NDIS_STATUS_SUCCESS; //init its status to success

    while(pCurrentNB)
    {
        //Get MDL
        ASSERT(!IsListEmpty(&DLCBList));
        pDLCB = CONTAINING_RECORD(RemoveHeadList(&DLCBList), DLCB, List);
        pDLCB->pNdisPktOrNBL = (PVOID)pNBSPacket;
        pDLCB->bLastNB = !(NET_BUFFER_NEXT_NB(pCurrentNB));

        lnk->CurSendSeqNo.SequenceNumber++;

        pEthBuffer = NET_BUFFER_CURRENT_MDL(pCurrentNB);
        if(pEthBuffer == NULL)
        {
            pDLCB->PacketBase.pMdl = NULL;
            DbgPrint("[Error] Get MDL failed, PACKET DROPPED\n");
        }
        else
        {
            EthToWlan(pEthBuffer,
                      &pWlanBuffer,
                      &Dot11HeaderSize,
                      &pDot11HeaderVa,
                      lnk->CurSendSeqNo.usValue,
                      NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNB));
            pDLCB->PacketType = PACKET_NEED_ACK;
            if(pDot11HeaderVa &&
                    (ETH_IS_BROADCAST(&((PDOT11RFC1042ENCAP)pDot11HeaderVa)->MacHeader.Address1)
                     || ETH_IS_MULTICAST(&((PDOT11RFC1042ENCAP)pDot11HeaderVa)->MacHeader.Address1)))
            {
                pDLCB->PacketType = PACKET_NOT_NEED_ACK;
            }

            //Config DLCB
            pDLCB->Dot11HeaderSize          = Dot11HeaderSize;
            pDLCB->pDot11HeaderVa           = pDot11HeaderVa;
            pDLCB->PacketBase.pMdl          = pWlanBuffer;

            pDLCB->PacketBase.PacketSize    = NET_BUFFER_DATA_LENGTH(pCurrentNB) + sizeof(DOT11RFC1042ENCAP) - sizeof(ETHERNET_HEADER);

            {   // we update the copied mdl length to packet length for baseband
                ULONG len = pDLCB->PacketBase.PacketSize;
                PMDL mdl = pDLCB->PacketBase.pMdl;
                while(mdl) {
                    if (mdl->ByteCount > len) {
                        mdl->ByteCount = len;
                        break;
                    }
                    else if (mdl->ByteCount < len) {
                        len-= mdl->ByteCount;
                        mdl = mdl->Next;
                        continue;
                    }
                    else
                        break;
                }
            }

            pDLCB->PacketBase.Reserved1     = CalcMDLChainCRC32(pWlanBuffer);
            pDLCB->RetryCount               = 0;
            pDLCB->bSendOK                  = FALSE;
        }

        SafeEnqueue(pSendQueueManager, SendSrcWaitList, pDLCB);
        InterlockedIncrement(&pSendQueueManager->nSrcPacket);

        //Notify send thread
        NIC_NOTIFY_SEND_THREAD(pMac);

        //Get next NetBuffer
        pCurrentNB = NET_BUFFER_NEXT_NB(pCurrentNB);
    }

}
Beispiel #18
0
// Packet send handler
void NeoNdisSendNetBufferLists(NDIS_HANDLE MiniportAdapterContext,
							   NET_BUFFER_LIST *NetBufferLists,
							   NDIS_PORT_NUMBER PortNumber,
							   ULONG SendFlags)
{
	if (ctx == NULL)
	{
		return;
	}

	// Update the connection state
	NeoCheckConnectState();

	if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE)
	{
		// Device is stopped
		return;
	}

	// Operation of the packet queue
	NeoLockPacketQueue();
	{
		NET_BUFFER_LIST *nbl;
		if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE)
		{
			// Device is stopped
			NeoUnlockPacketQueue();
			return;
		}

		nbl = NetBufferLists;

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

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

				if (size >= NEO_MIN_PACKET_SIZE && size <= NEO_MAX_PACKET_SIZE)
				{
					UCHAR *buf = NeoMalloc(size);
					void *ptr;

					ptr = NdisGetDataBuffer(nb, size, buf, 1, 0);

					if (ptr == NULL)
					{
						ctx->Status.NumPacketSendError++;
						ctx->Status.Int64NumSendError++;
						NeoFree(buf);
					}
					else
					{
						if (ptr != buf)
						{
							NeoCopy(buf, ptr, size);
						}

						NeoInsertQueue(buf, size);
						ctx->Status.NumPacketSend++;

						if (buf[0] & 0x40)
						{
							ctx->Status.Int64NumSendBroadcast++;
							ctx->Status.Int64BytesSendBroadcast += (UINT64)size;
						}
						else
						{
							ctx->Status.Int64NumSendUnicast++;
							ctx->Status.Int64BytesSendUnicast += (UINT64)size;
						}

						ctx->Status.Int64BytesSendTotal += (UINT64)size;
					}
				}
				else
				{
					ctx->Status.NumPacketSendError++;
					ctx->Status.Int64NumSendError++;
				}

				nb = NET_BUFFER_NEXT_NB(nb);
			}

			nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
		}
	}

	NeoUnlockPacketQueue();

	// Notify the transmission completion
	NdisMSendNetBufferListsComplete(ctx->NdisMiniport, NetBufferLists, NDIS_STATUS_SUCCESS);

	// Reception event
	NeoSet(ctx->Event);
}
Beispiel #19
0
/*
 *----------------------------------------------------------------------------
 * OvsDoEncapVxlan
 *     Encapsulates the packet.
 *----------------------------------------------------------------------------
 */
static __inline NDIS_STATUS
OvsDoEncapVxlan(PNET_BUFFER_LIST curNbl,
                OvsIPv4TunnelKey *tunKey,
                POVS_FWD_INFO fwdInfo,
                POVS_PACKET_HDR_INFO layers,
                POVS_SWITCH_CONTEXT switchContext,
                PNET_BUFFER_LIST *newNbl)
{
    NDIS_STATUS status;
    PNET_BUFFER curNb;
    PMDL curMdl;
    PUINT8 bufferStart;
    EthHdr *ethHdr;
    IPHdr *ipHdr;
    UDPHdr *udpHdr;
    VXLANHdr *vxlanHdr;
    UINT32 headRoom = OvsGetVxlanTunHdrSize();
    UINT32 packetLength;

    /*
     * XXX: the assumption currently is that the NBL is owned by OVS, and
     * headroom has already been allocated as part of allocating the NBL and
     * MDL.
     */
    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
    packetLength = NET_BUFFER_DATA_LENGTH(curNb);
    if (layers->isTcp) {
        NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo;

        tsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
                TcpLargeSendNetBufferListInfo);
        OVS_LOG_TRACE("MSS %u packet len %u", tsoInfo.LsoV1Transmit.MSS, packetLength);
        if (tsoInfo.LsoV1Transmit.MSS) {
            OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
            *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
                        tsoInfo.LsoV1Transmit.MSS, headRoom);
            if (*newNbl == NULL) {
                OVS_LOG_ERROR("Unable to segment NBL");
                return NDIS_STATUS_FAILURE;
            }
        }
    }
    /* If we didn't split the packet above, make a copy now */
    if (*newNbl == NULL) {
        *newNbl = OvsPartialCopyNBL(switchContext, curNbl, 0, headRoom,
                                    FALSE /*NBL info*/);
        if (*newNbl == NULL) {
            OVS_LOG_ERROR("Unable to copy NBL");
            return NDIS_STATUS_FAILURE;
        }
    }

    curNbl = *newNbl;
    for (curNb = NET_BUFFER_LIST_FIRST_NB(curNbl); curNb != NULL;
            curNb = curNb->Next) {
        status = NdisRetreatNetBufferDataStart(curNb, headRoom, 0, NULL);
        if (status != NDIS_STATUS_SUCCESS) {
            goto ret_error;
        }

        curMdl = NET_BUFFER_CURRENT_MDL(curNb);
        bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
        if (!bufferStart) {
            status = NDIS_STATUS_RESOURCES;
            goto ret_error;
        }

        bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
        if (NET_BUFFER_NEXT_NB(curNb)) {
            OVS_LOG_TRACE("nb length %u next %u", NET_BUFFER_DATA_LENGTH(curNb),
                          NET_BUFFER_DATA_LENGTH(curNb->Next));
        }

        /* L2 header */
        ethHdr = (EthHdr *)bufferStart;
        NdisMoveMemory(ethHdr->Destination, fwdInfo->dstMacAddr,
                       sizeof ethHdr->Destination + sizeof ethHdr->Source);
        ASSERT(((PCHAR)&fwdInfo->dstMacAddr + sizeof fwdInfo->dstMacAddr) ==
               (PCHAR)&fwdInfo->srcMacAddr);
        ethHdr->Type = htons(ETH_TYPE_IPV4);

        // XXX: question: there are fields in the OvsIPv4TunnelKey for ttl and such,
        // should we use those values instead? or will they end up being
        // uninitialized;
        /* IP header */
        ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);

        ipHdr->ihl = sizeof *ipHdr / 4;
        ipHdr->version = IPV4;
        ipHdr->tos = 0;
        ipHdr->tot_len = htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof *ethHdr);
        ipHdr->id = 0;
        ipHdr->frag_off = IP_DF_NBO;
        ipHdr->ttl = tunKey->ttl ? tunKey->ttl : VXLAN_DEFAULT_TTL;
        ipHdr->protocol = IPPROTO_UDP;
        ASSERT(tunKey->dst == fwdInfo->dstIpAddr);
        ASSERT(tunKey->src == fwdInfo->srcIpAddr || tunKey->src == 0);
        ipHdr->saddr = fwdInfo->srcIpAddr;
        ipHdr->daddr = fwdInfo->dstIpAddr;
        ipHdr->check = 0;
        ipHdr->check = IPChecksum((UINT8 *)ipHdr, sizeof *ipHdr, 0);

        /* UDP header */
        udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
        udpHdr->source = htons(tunKey->flow_hash | 32768);
        udpHdr->dest = VXLAN_UDP_PORT_NBO;
        udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom +
                            sizeof *udpHdr + sizeof *vxlanHdr);
        udpHdr->check = 0;

        /* VXLAN header */
        vxlanHdr = (VXLANHdr *)((PCHAR)udpHdr + sizeof *udpHdr);
        vxlanHdr->flags1 = 0;
        vxlanHdr->locallyReplicate = 0;
        vxlanHdr->flags2 = 0;
        vxlanHdr->reserved1 = 0;
        if (tunKey->flags | OVS_TNL_F_KEY) {
            vxlanHdr->vxlanID = VXLAN_TUNNELID_TO_VNI(tunKey->tunnelId);
            vxlanHdr->instanceID = 1;
        }
        vxlanHdr->reserved2 = 0;
    }
    return STATUS_SUCCESS;

ret_error:
    OvsCompleteNBL(switchContext, *newNbl, TRUE);
    *newNbl = NULL;
    return status;
}
Beispiel #20
0
ULONG
CopyNetBufferData (
    IN  PNET_BUFFER     NetBuffer,
    IN  ULONG           Offset,
    IN  PUCHAR          Buffer,
    IN  ULONG           Size,
    IN  BOOLEAN         FromNetBuffer
    )
{
    ULONG currLength;
    PMDL currentMdl;
    ULONG dataLength;
    PUCHAR dest;
    PUCHAR end;
    PUCHAR src;

    XM_ASSERT(NetBuffer != NULL);
    XM_ASSERT(Buffer != NULL);

    currentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer);
    dest = Buffer;
    end = dest + Size;
    Offset += NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer);
    dataLength = NET_BUFFER_DATA_LENGTH(NetBuffer);
    while ((currentMdl != NULL) && (dataLength > 0)) {
        NdisQueryMdl(currentMdl, &src, &currLength, NormalPagePriority);
        if (src == NULL) {
            break;
        }

        if (currLength > Offset) { 
            src += Offset;
            currLength -= Offset;
            if (currLength > dataLength) {
                currLength = dataLength;
            }

            if (currLength >= Size) {
                if (FromNetBuffer) {
                    NdisMoveMemory(dest, src, Size);

                } else {
                    NdisMoveMemory(src, dest, Size);
                }

                dest += Size;
                break;
            }

            if (FromNetBuffer) {
                NdisMoveMemory(dest, src, currLength);

            } else {
                NdisMoveMemory(src, dest, currLength);
            }

            Size -= currLength;
            dataLength -= currLength;
            dest += currLength;
            Offset = 0;

        } else {
            Offset -= currLength;
        }

        NdisGetNextMdl(currentMdl, &currentMdl);
    }

    return (ULONG)(dest - Buffer);
}
Beispiel #21
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;
}
Beispiel #22
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
}
Beispiel #23
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;
}
Beispiel #24
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);
		}
	}
}
Beispiel #25
0
/*
 * Convert the ndis packet chain into an lbuf .
 */
struct lbuf*
shared_txlb_convert(shared_info_t *sh, ND_PKT *p)
{
#ifndef NDIS60
	struct lbuf *lb;
	PNDIS_BUFFER b, next;
	uchar *bdata, *buf;
	uint blen, tot;
	struct lbfree *txlbfree;

	ASSERT(p);

	NdisQueryPacket(p, NULL, NULL, &b, &tot);

	ASSERT(b);
	ASSERT(tot <= LBDATASZ);

	if ((b == NULL) || (tot > LBDATASZ))
		return (NULL);

	txlbfree = &sh->txfree;
	/* txqueue free buffer count shouldn't go below threshold */
	if (txlbfree->count <= TXLB_FREEPOOL_THREHOLD(txlbfree->total))
		return (NULL);

	/* alloc lbuf */
	if ((lb = shared_lb_get(sh, txlbfree)) == NULL)
		return (NULL);

	/* Adjust for the head room requested */
	ASSERT(txlbfree->size > txlbfree->headroom);
	lb->data += txlbfree->headroom;

	/*
	 * In case of dongle, make sure the begining of the buffer is
	 * aligned at 32 bytes for DMA efficiency, after inserting
	 * header of 16 bytes later in DHD layer
	 */
	if (((uintptr)lb->data % 32) <= 16)
		lb->data += 16 - (uintptr)lb->data % 32;
	else
		lb->data -= (uintptr)lb->data % 32 - 16;

	buf = lb->data;

	while (b && tot) {
#if defined(NDIS51)
		NdisQueryBufferSafe(b, &bdata, &blen, NormalPagePriority);
#else
		NdisQueryBuffer(b, &bdata, &blen);
#endif /* defined (NDIS51) */

		blen = MIN(blen, tot);

		if (blen) {
			bcopy(bdata, buf, blen);
			lb->tail += blen;
			lb->len += blen;
			buf += blen;
			tot -= blen;
		}

		NdisGetNextBuffer(b, &next);
		b = next;
	}
	/* save a pointer to the ndis packet for later sendcomplete */
	lb->p = p;
	return (lb);

#else /* !NDIS60 */

	struct lbuf *lb;
	PNET_BUFFER nb;
	PMDL b, next;
	uint offset;
	uchar *bdata, *buf;
	uint blen, tot;
	struct lbfree *txlbfree;

	ASSERT(p);

	tot = 0;
	for (nb = NET_BUFFER_LIST_FIRST_NB(p); nb; nb = NET_BUFFER_NEXT_NB(nb))
		tot += NET_BUFFER_DATA_LENGTH(nb);

	nb = NET_BUFFER_LIST_FIRST_NB(p);
	if (nb == NULL)
		return (NULL);
	b = NET_BUFFER_CURRENT_MDL(nb);
	offset = NET_BUFFER_CURRENT_MDL_OFFSET(nb);

	ASSERT(b);
	ASSERT(tot <= LBDATASZ);

	if ((b == NULL) || (tot > LBDATASZ))
		return (NULL);

	txlbfree = &sh->txfree;
	/* txqueue free buffer count shouldn't go below threshold */
	if (txlbfree->count <= TXLB_FREEPOOL_THREHOLD(txlbfree->total))
		return (NULL);

	/* alloc lbuf */
	if ((lb = shared_lb_get(sh, txlbfree)) == NULL)
		return (NULL);

#if defined(NDIS60)
	/* Adjust for the head room requested */
	/* ASSERT(txlbfree->size > txlbfree->headroom); */
	lb->data += txlbfree->headroom;

	/*
	 * In case of dongle, make sure the begining of the buffer is
	 * aligned at 32 bytes for DMA efficiency, after inserting
	 * header of 16 bytes later in DHD layer
	 */
	if (((uintptr)lb->data % 32) <= 16)
		lb->data += 16 - (uintptr)lb->data % 32;
	else
		lb->data -= (uintptr)lb->data % 32 - 16;
#endif /* UNDER_CE && NDIS60 */

	buf = lb->data;

	while (b && tot) {
		NdisQueryMdl(b, &bdata, &blen, NormalPagePriority);

		if (bdata == NULL)
			goto next_mdl;

		if (blen > offset) {
			bdata += offset;
			blen -= offset;
		} else {
			offset -= blen;
			goto next_mdl;
		}

		blen = MIN(blen, tot);

		if (blen) {
			bcopy(bdata, buf, blen);
			lb->tail += blen;
			lb->len += blen;
			buf += blen;
			tot -= blen;
			offset = 0;
		}

	next_mdl:
		NdisGetNextMdl(b, &next);
		if (!next) {
			nb = NET_BUFFER_NEXT_NB(nb);
			if (nb) {
				next = NET_BUFFER_CURRENT_MDL(nb);
				offset = NET_BUFFER_CURRENT_MDL_OFFSET(nb);
			}
		}
		b = next;
	}

	/* save a pointer to the ndis packet for later sendcomplete */
	lb->p = p;

	return (lb);
#endif /* !NDIS60 */
}