bool CNB::Copy(PVOID Dst, ULONG Length) const
{
    ULONG CurrOffset = NET_BUFFER_CURRENT_MDL_OFFSET(m_NB);
    ULONG Copied = 0;

    for (PMDL CurrMDL = NET_BUFFER_CURRENT_MDL(m_NB);
         CurrMDL != nullptr && Copied < Length;
         CurrMDL = CurrMDL->Next)
    {
        ULONG CurrLen;
        PVOID CurrAddr;

#if NDIS_SUPPORT_NDIS620
        NdisQueryMdl(CurrMDL, &CurrAddr, &CurrLen, LowPagePriority | MdlMappingNoExecute);
#else
        NdisQueryMdl(CurrMDL, &CurrAddr, &CurrLen, LowPagePriority);
#endif

        if (CurrAddr == nullptr)
        {
            break;
        }

        CurrLen = min(CurrLen - CurrOffset, Length - Copied);

        NdisMoveMemory(RtlOffsetToPointer(Dst, Copied),
                       RtlOffsetToPointer(CurrAddr, CurrOffset),
                       CurrLen);

        Copied += CurrLen;
        CurrOffset = 0;
    }

    return (Copied == Length);
}
Пример #2
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;
}
Пример #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));
}
Пример #4
0
NTSTATUS
StreamOobCopyDataToFlatBuffer(
   _Inout_ STREAM_EDITOR* streamEditor,
   _Inout_ NET_BUFFER_LIST* netBufferListChain,
   size_t totalDataLength,
   DWORD streamFlags
   )
/* ++

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

-- */
{
   NTSTATUS status = STATUS_SUCCESS;

   FWPS_STREAM_DATA streamData = {0};

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

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

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

   return status;
}
Пример #5
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);
    }

}
Пример #6
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
}
Пример #7
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);
}
Пример #8
0
NDIS_STATUS
CopyBytesFromNetBuffer(  PNET_BUFFER_KK        NetBuffer,  PULONG             cbDest, PVOID Dest)
/*++

Routine Description:

    Copies the first cbDest bytes from a NET_BUFFER. In order to show how the various data structures fit together, this 
    implementation copies the data by iterating through the MDLs for the NET_BUFFER. The NdisGetDataBuffer API also allows you
    to copy a contiguous block of data from a NET_BUFFER. 

    Runs at IRQL <= DISPATCH_LEVEL.

Arguments:

    NetBuffer                   The NB to read
    cbDest                      On input, the number of bytes in the buffer Dest
                                On return, the number of bytes actually copied
    Dest                        On return, receives the first cbDest bytes of
                                the network frame in NetBuffer

Return Value:

    None.

Notes:

    If the output buffer is larger than the NB's frame size, *cbDest will
    contain the number of bytes in the frame size.

    If the output buffer is smaller than the NB's frame size, only the first
    *cbDest bytes will be copied (the buffer will receive a truncated copy of
    the frame).

--*/
{
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
    //
    // Start copy from current MDL
    //
    PMDL CurrentMdl = NET_BUFFER_CURRENT_MDL(NetBuffer);
    //
    // Data on current MDL may be offset from start of MDL
    //
    ULONG DestOffset = 0;
    while (DestOffset < *cbDest && CurrentMdl)
    {
        //
        // Map MDL memory to System Address Space. LowPagePriority means mapping may fail if 
        // system is low on memory resources. 
        //
        PUCHAR SrcMemory = MmGetSystemAddressForMdlSafe(CurrentMdl, LowPagePriority);
        ULONG Length = MmGetMdlByteCount(CurrentMdl);
        if (!SrcMemory)
        {
            Status = NDIS_STATUS_RESOURCES;
            break;
        }

        if(DestOffset==0)
        {
            //
            // The first MDL segment should be accessed from the current MDL offset
            //
            ULONG MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer);
            SrcMemory += MdlOffset;
            Length -= MdlOffset;
        }

        Length = min(Length, *cbDest-DestOffset);

        //
        // Copy Memory
        //
        NdisMoveMemory((PUCHAR)Dest+DestOffset, SrcMemory, Length);
        DestOffset += Length;

        //
        // Get next MDL (if any available) 
        //
        CurrentMdl = NDIS_MDL_LINKAGE(CurrentMdl);
    }

    if(Status == NDIS_STATUS_SUCCESS)
    {
        *cbDest = DestOffset;
    }

    return Status;
}
Пример #9
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);
    }

}
Пример #10
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;
}
Пример #11
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;
}
Пример #12
0
    ULONG                   dataSize;
    ULONG                   data;
    PUCHAR                  SA;
    PUCHAR                  DA;
    ULONG                   headerSize;
    PDOT11_DATA_LONG_HEADER dataHeader;

    // 
    // Note: only the first MDL is guaranteed to be mapped to system virtual space.
    //

    //
    // Find data header.
    //
    mdl = NET_BUFFER_CURRENT_MDL(NetBuffer);
    dataHeader = Add2Ptr(mdl->MappedSystemVa, NET_BUFFER_CURRENT_MDL_OFFSET(NetBuffer));

    //
    // Find SA, DA and header size.
    //
    if (dataHeader->FrameControl.ToDS)
    {
        DA = dataHeader->Address3;
        if (dataHeader->FrameControl.FromDS) 
        {
            headerSize = sizeof(DOT11_DATA_LONG_HEADER);
            SA = dataHeader->Address4;
        } 
        else 
        {
            headerSize = sizeof(DOT11_DATA_SHORT_HEADER);
Пример #13
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 */
}