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);
}
Example #2
0
u_int32 xword(PMDL p, u_int32 k, int *err)
{
	size_t len, len0;
	u_char *CurBuf, *NextBuf;
	PMDL p0;

	*err = 1;
	MDLIDX(len, p, k, CurBuf);
	CurBuf += k;
	if (len - k >= 4) {
		*err = 0;
		return EXTRACT_LONG(CurBuf);
	}
	p0 = p->Next;
	if (p0 == NULL)
		return 0;
	NdisQueryMdl(p0, &NextBuf, &len0, NormalPagePriority);
	if (NextBuf == NULL || (len - k) + len0 < 4)
		return 0;
	*err = 0;

	switch (len - k) {
	case 1:
		return (CurBuf[0] << 24) | (NextBuf[0] << 16) | (NextBuf[1] << 8) | NextBuf[2];
	case 2:
		return (CurBuf[0] << 24) | (CurBuf[1] << 16) | (NextBuf[0] << 8) | NextBuf[1];
	default:
		return (CurBuf[0] << 24) | (CurBuf[1] << 16) | (CurBuf[2] << 8) | NextBuf[0];
	}
}
Example #3
0
u_int32 xhalf(PMDL p, u_int32 k, int *err)
{
	size_t len, len0;
	u_char *CurBuf, *NextBuf;
	PMDL p0;

	*err = 1;
	MDLIDX(len, p, k, CurBuf);
	CurBuf += k;
	if (len - k >= 2) {
		*err = 0;
		return EXTRACT_SHORT(CurBuf);
	}
	p0 = p->Next;
	if (p0 == NULL)
		return 0;
	NdisQueryMdl(p0, &NextBuf, &len0, NormalPagePriority);
	if (NextBuf == NULL || len0 < 1)
		return 0;
	*err = 0;

	return (CurBuf[0] << 8) | NextBuf[0];
}
Example #4
0
File: Lo_send.c Project: nmap/npcap
NTSTATUS
NTAPI
NPF_WSKSendPacket_NBL(
	IN PNET_BUFFER_LIST NetBufferList
	)
{
	PMDL				pMdl = NULL;
	ULONG				BuffSize;
	PETHER_HEADER		pEthernetHdr;
	PDLT_NULL_HEADER	pDltNullHdr;
	NTSTATUS			status = STATUS_UNSUCCESSFUL;

	TRACE_ENTER();

	pMdl = NetBufferList->FirstNetBuffer->CurrentMdl;
	if (pMdl)
	{
		NdisQueryMdl(
			pMdl,
			&pEthernetHdr,
			&BuffSize,
			NormalPagePriority);
		pDltNullHdr = (PDLT_NULL_HEADER) pEthernetHdr;
	}
	else
	{
		TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL()::NetBufferList->FirstNetBuffer->CurrentMdl failed with pMdl 0x%p\n", pMdl);

		TRACE_EXIT();
		return status;
	}

	if (pEthernetHdr == NULL)
	{
		//
		//  The system is low on resources. Set up to handle failure
		//  below.
		//
		TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL()::NdisQueryMdl() failed with pEthernetHdr 0x%p\n", pEthernetHdr);

		TRACE_EXIT();
		return status;
	}

	if (g_DltNullMode)
	{
		if (pDltNullHdr->null_type == DLTNULLTYPE_IP)
		{
			status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV4, NetBufferList, DLT_NULL_HDR_LEN);
		}
		else if (pDltNullHdr->null_type == DLTNULLTYPE_IPV6)
		{
			status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV6, NetBufferList, DLT_NULL_HDR_LEN);
		}
		else
		{
			TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL() failed with status 0x%08X, not valid loopback IPv4 or IPv6 packet (DLT_NULL)\n", status);
		}
	}
	else
	{
		if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IP))
		{
			status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV4, NetBufferList, ETHER_HDR_LEN);
		}
		else if (pEthernetHdr->ether_type == RtlUshortByteSwap(ETHERTYPE_IPV6))
		{
			status = WSKSendPacketInternal_NBL(NPF_LOOPBACK_SEND_TYPE_IPV6, NetBufferList, ETHER_HDR_LEN);
		}
		else
		{
			TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "NPF_WSKSendPacket_NBL() failed with status 0x%08X, not valid loopback IPv4 or IPv6 packet\n", status);
		}
	}

	TRACE_EXIT();
	return status;
}
Example #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);
    }

}
Example #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
}
Example #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);
}
Example #8
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);


}
Example #9
0
// IRP_MJ_WRITE callback.
NTSTATUS
TapDeviceWrite(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
{
    NTSTATUS                ntStatus = STATUS_SUCCESS;// Assume success
    PIO_STACK_LOCATION      irpSp;// Pointer to current stack location
    PTAP_ADAPTER_CONTEXT    adapter = NULL;
    ULONG                   dataLength;

    PAGED_CODE();

    irpSp = IoGetCurrentIrpStackLocation( Irp );

    //
    // Fetch adapter context for this device.
    // --------------------------------------
    // Adapter pointer was stashed in FsContext when handle was opened.
    //
    adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;

    ASSERT(adapter);

    //
    // Sanity checks on state variables
    //
    if (!tapAdapterReadAndWriteReady(adapter))
    {
        //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
        //    MINIPORT_INSTANCE_ID (adapter)));
        //NOTE_ERROR();

        Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);

        return ntStatus;
    }

    // Save IRP-accessible copy of buffer length
    Irp->IoStatus.Information = irpSp->Parameters.Write.Length;

    if (Irp->MdlAddress == NULL)
    {
        DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
            MINIPORT_INSTANCE_ID (adapter)));

        NOTE_ERROR();
        Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);

        return ntStatus;
    }

    //
    // Try to get a virtual address for the MDL.
    //
    NdisQueryMdl(
        Irp->MdlAddress,
        &Irp->AssociatedIrp.SystemBuffer,
        &dataLength,
        NormalPagePriority
        );

    if (Irp->AssociatedIrp.SystemBuffer == NULL)
    {
        DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
            MINIPORT_INSTANCE_ID (adapter)));

        NOTE_ERROR();
        Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);

        return ntStatus;
    }

    ASSERT(dataLength == irpSp->Parameters.Write.Length);

    Irp->IoStatus.Information = irpSp->Parameters.Write.Length;

    //
    // Handle miniport Pause
    // ---------------------
    // NDIS 6 miniports implement a temporary "Pause" state normally followed
    // by the Restart. While in the Pause state it is forbidden for the miniport
    // to indicate receive NBLs.
    //
    // That is: The device interface may be "up", but the NDIS miniport send/receive
    // interface may be temporarily "down".
    //
    // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path
    // the code below will perform a "lying send" for write IRPs passed to the
    // driver while the miniport is in the Paused state.
    //
    // The correct implementation is to go ahead and build the NBLs corresponding
    // to the user-mode write - but queue them. When Restart is entered the
    // queued NBLs would be dequeued and indicated to the host.
    //
    if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
    {
        if (!adapter->m_tun && ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
        {
            PNET_BUFFER_LIST    netBufferList;

            DUMP_PACKET ("IRP_MJ_WRITE ETH",
                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
                irpSp->Parameters.Write.Length);

            //=====================================================
            // If IPv4 packet, check whether or not packet
            // was truncated.
            //=====================================================
#if PACKET_TRUNCATION_CHECK
            IPv4PacketSizeVerify (
                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
                irpSp->Parameters.Write.Length,
                FALSE,
                "RX",
                &adapter->m_RxTrunc
                );
#endif
            (Irp->MdlAddress)->Next = NULL; // No next MDL

            // Allocate the NBL and NB. Link MDL chain to NB.
            netBufferList = NdisAllocateNetBufferAndNetBufferList(
                adapter->ReceiveNblPool,
                0,                  // ContextSize
                0,                  // ContextBackFill
                Irp->MdlAddress,    // MDL chain
                0,
                dataLength
                );

            if(netBufferList != NULL)
            {
                LONG    nblCount;

                NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL

                // Stash IRP pointer in NBL MiniportReserved[0] field.
                netBufferList->MiniportReserved[0] = Irp;
                netBufferList->MiniportReserved[1] = NULL;

                // BUGBUG!!! Setup for IRP cancel!!!

                TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);

                // Increment in-flight receive NBL count.
                nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
                ASSERT(nblCount > 0 );

                //
                // Indicate the packet
                // -------------------
                // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
                // contains the complete packet including Ethernet header and payload.
                //
                NdisMIndicateReceiveNetBufferLists(
                    adapter->MiniportAdapterHandle,
                    netBufferList,
                    NDIS_DEFAULT_PORT_NUMBER,
                    1,      // NumberOfNetBufferLists
                    0       // ReceiveFlags
                    );

                ntStatus = STATUS_PENDING;
            }
            else
            {
                DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
                    MINIPORT_INSTANCE_ID (adapter)));
                NOTE_ERROR ();

                // Fail the IRP
                Irp->IoStatus.Information = 0;
                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            }
        }
        else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
        {
            PETH_HEADER         p_UserToTap = &adapter->m_UserToTap;
            PMDL                mdl;    // Head of MDL chain.

            // For IPv6, need to use Ethernet header with IPv6 proto
            if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 )
            {
                p_UserToTap = &adapter->m_UserToTap_IPv6;
            }

            DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
                p_UserToTap,
                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
                irpSp->Parameters.Write.Length);

            //=====================================================
            // If IPv4 packet, check whether or not packet
            // was truncated.
            //=====================================================
#if PACKET_TRUNCATION_CHECK
            IPv4PacketSizeVerify (
                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
                irpSp->Parameters.Write.Length,
                TRUE,
                "RX",
                &adapter->m_RxTrunc
                );
#endif

            //
            // Allocate MDL for Ethernet header
            // --------------------------------
            // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
            // contains the only the Ethernet payload. Prepend the user-mode provided
            // payload with the Ethernet header pointed to by p_UserToTap.
            //
            mdl = NdisAllocateMdl(
                adapter->MiniportAdapterHandle,
                p_UserToTap,
                sizeof(ETH_HEADER)
                );

            if(mdl != NULL)
            {
                PNET_BUFFER_LIST    netBufferList;

                // Chain user's Ethernet payload behind Ethernet header.
                mdl->Next = Irp->MdlAddress;
                (Irp->MdlAddress)->Next = NULL; // No next MDL

                // Allocate the NBL and NB. Link MDL chain to NB.
                netBufferList = NdisAllocateNetBufferAndNetBufferList(
                    adapter->ReceiveNblPool,
                    0,          // ContextSize
                    0,          // ContextBackFill
                    mdl,        // MDL chain
                    0,
                    sizeof(ETH_HEADER) + dataLength
                    );

                if(netBufferList != NULL)
                {
                    LONG        nblCount;

                    NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL

                    // This IRP is pended.
                    IoMarkIrpPending(Irp);

                    // This IRP cannot be cancelled while in-flight.
                    IoSetCancelRoutine(Irp,NULL);

                    // Stash IRP pointer in NBL MiniportReserved[0] field.
                    netBufferList->MiniportReserved[0] = Irp;
                    netBufferList->MiniportReserved[1] = NULL;

                    // Set flag indicating that this is P2P packet
                    TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
                    TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P);

                    // Increment in-flight receive NBL count.
                    nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
                    ASSERT(nblCount > 0 );

                    //
                    // Indicate the packet
                    //
                    NdisMIndicateReceiveNetBufferLists(
                        adapter->MiniportAdapterHandle,
                        netBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        1,      // NumberOfNetBufferLists
                        0       // ReceiveFlags
                        );

                    ntStatus = STATUS_PENDING;
                }
                else
                {
                    mdl->Next = NULL;
                    NdisFreeMdl(mdl);

                    DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
                        MINIPORT_INSTANCE_ID (adapter)));
                    NOTE_ERROR ();

                    // Fail the IRP
                    Irp->IoStatus.Information = 0;
                    ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                }
            }
            else
            {
                DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n",
                    MINIPORT_INSTANCE_ID (adapter)));
                NOTE_ERROR ();

                // Fail the IRP
                Irp->IoStatus.Information = 0;
                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            }
        }
        else
        {
            DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
                MINIPORT_INSTANCE_ID (adapter),
                irpSp->Parameters.Write.Length));
            NOTE_ERROR ();

            Irp->IoStatus.Information = 0;	// ETHERNET_HEADER_SIZE;
            Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
        }
    }
    else
    {
        DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n",
            MINIPORT_INSTANCE_ID (adapter)));

        ntStatus = STATUS_SUCCESS;
    }

    if (ntStatus != STATUS_PENDING)
    {
        Irp->IoStatus.Status = ntStatus;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
    }

    return ntStatus;
}
Example #10
0
NTSTATUS
NdisprotWrite(
    IN PDEVICE_OBJECT       pDeviceObject,
    IN PIRP                 pIrp
    )
/*++

Routine Description:

    Dispatch routine to handle IRP_MJ_WRITE. 

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - Pointer to request packet

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION      pIrpSp;
    ULONG                   DataLength;
    NTSTATUS                NtStatus;
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    PNET_BUFFER_LIST        pNetBufferList;
    PMDL                    pMdl;
    NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
    PVOID                   CancelId;
    ULONG                   SendFlags = 0;

    UNREFERENCED_PARAMETER(pDeviceObject);

    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;


    do
    {
        if (pOpenContext == NULL)
        {
            DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
                pIrpSp->FileObject));
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }
               
        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        if (pIrp->MdlAddress == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        // Try to get a virtual address for the MDL.
        //
        
        pEthHeader = NULL;
        NdisQueryMdl(pIrp->MdlAddress, &pEthHeader, &DataLength, NormalPagePriority);

        if (pEthHeader == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
                    " IRP %p, MDL %p\n",
                    pIrp, pIrp->MdlAddress));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Sanity-check the length.
        //
        if (DataLength < sizeof(NDISPROT_ETH_HEADER))
        {
            DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
                DataLength));
            NtStatus = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER)))
        {
            DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
                    " larger than max frame size (%d)\n",
                    pOpenContext, DataLength, pOpenContext->MaxFrameSize));

            NtStatus = STATUS_INVALID_BUFFER_SIZE;
            break;
        }

        if (pEthHeader->EthType != Globals.EthType)
        {
            DEBUGP(DL_WARN, ("Write: Failing send with EthType %x\n",
                pEthHeader->EthType));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }
       
        if (!NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
        {
            DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }
        

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
            " or in low power state\n", pOpenContext));

            NtStatus = STATUS_INVALID_HANDLE;
            break;
        } 

        if (pOpenContext->State != NdisprotRunning  ||
            pOpenContext->PowerState != NetDeviceStateD0)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
            
            DEBUGP(DL_INFO, ("Device is not ready.\n"));
            NtStatus = STATUS_UNSUCCESSFUL;
            break;
        }


        pMdl = pIrp->MdlAddress;
        NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL);
        pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
                                pOpenContext->SendNetBufferListPool,
                                sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta
                                0,           // back fill size
                                pMdl,
                                0,          // Data offset
                                DataLength);
        
        if (pNetBufferList == NULL)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
            
            DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n",
                    pOpenContext));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        pOpenContext->PendedSendCount++;

        NPROT_REF_OPEN(pOpenContext);  // pended send

        IoMarkIrpPending(pIrp);

        //
        //  Initialize the NetBufferList ref count. This NetBufferList will be freed
        //  when this count goes to zero.
        //
        NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1;

        //
        //  We set up a cancel ID on each send NetBufferList (which maps to a Write IRP), 
        //  and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use
        //  NdisCancelSendNetBufferLists() to cancel the NetBufferList.
        //
       
        CancelId = NPROT_GET_NEXT_CANCEL_ID();
        NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId);
        pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
        pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNetBufferList;
        pIrp->Tail.Overlay.DriverContext[2] = CancelId;

        NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);

        IoSetCancelRoutine(pIrp, NdisprotCancelWrite);


        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        //
        //  Set a back pointer from the packet to the IRP.
        //
        NPROT_IRP_FROM_SEND_NBL(pNetBufferList) = pIrp;

        NtStatus = STATUS_PENDING;


#if SEND_DBG
        {
            PUCHAR      pData;

            pData = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
            NPROT_ASSERT(pEthHeader == pData);

            DEBUGP(DL_VERY_LOUD, 
                ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
                    pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));

            DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
        }
#endif // SEND_DBG

        pNetBufferList->SourceHandle = pOpenContext->BindingHandle;
        ASSERT (NDIS_MDL_LINKAGE(pMdl) == NULL);
        
        SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;

        NdisSendNetBufferLists(        
                        pOpenContext->BindingHandle,
                        pNetBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        SendFlags);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        pIrp->IoStatus.Status = NtStatus;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    }

    return (NtStatus);
}
Example #11
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 */
}