示例#1
0
文件: protocol.c 项目: GYGit/reactos
NDIS_STATUS NTAPI
ProTransferData(
    IN  NDIS_HANDLE         MacBindingHandle,
    IN  NDIS_HANDLE         MacReceiveContext,
    IN  UINT                ByteOffset,
    IN  UINT                BytesToTransfer,
    IN  OUT PNDIS_PACKET    Packet,
    OUT PUINT               BytesTransferred)
/*
 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
 * ARGUMENTS:
 *     MacBindingHandle  = Adapter binding handle
 *     MacReceiveContext = MAC receive context
 *     ByteOffset        = Offset in packet to place data
 *     BytesToTransfer   = Number of bytes to copy into packet
 *     Packet            = Pointer to NDIS packet descriptor
 *     BytesTransferred  = Address of buffer to place number of bytes copied
 */
{
    PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
    PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
    NDIS_STATUS Status;
    KIRQL OldIrql;

    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));

    /* FIXME: Interrupts must be disabled for adapter */
    /* XXX sd - why is that true? */

    if (Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()]) {
	NDIS_DbgPrint(MAX_TRACE, ("LoopPacket\n"));
        /* NDIS is responsible for looping this packet */
        NdisCopyFromPacketToPacket(Packet,
                                   ByteOffset + Adapter->MediumHeaderSize,
                                   BytesToTransfer + Adapter->MediumHeaderSize,
                                   Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()],
                                   0,
                                   BytesTransferred);
        return NDIS_STATUS_SUCCESS;
    }

    ASSERT(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler);

    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

    Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler)(
        Packet,
        BytesTransferred,
        Adapter->NdisMiniportBlock.MiniportAdapterContext,
        MacReceiveContext,
        ByteOffset,
        BytesToTransfer);

    KeLowerIrql(OldIrql);

    return Status;
}
示例#2
0
INT
PacketReceivePacket(
	IN    NDIS_HANDLE         ProtocolBindingContext,
	IN    PNDIS_PACKET        Packet
)
{
	UINT                bytesTransfered = 0;
	POPEN_INSTANCE      open;
	PIRP                irp;
	PNDIS_PACKET        myPacket;
	PLIST_ENTRY         packetListEntry;
	ULONG               bufferLength;
	PPACKET_RESERVED    reserved;
	PIO_STACK_LOCATION  irpSp;
	PMDL                mdl;
	PVOID               startAddress;
	NTSTATUS           status;

	// DebugPrint(("PacketReceivePacket\n"));

	open = (POPEN_INSTANCE)ProtocolBindingContext;

	packetListEntry = ExInterlockedRemoveHeadList(
											&open->RcvList,
											&open->RcvQSpinLock
											);

	if (packetListEntry == NULL) {
		// DebugPrint(("No pending read, dropping packets\n"));
		return 0;
	}

	reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement);
	myPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);

	irp = RESERVED(myPacket)->Irp;
	irpSp = IoGetCurrentIrpStackLocation(irp);

	// We don't have to worry about the situation where the IRP is cancelled
	// after we remove it from the queue and before we reset the cancel
	// routine because the cancel routine has been coded to cancel an IRP
	// only if it's in the queue.

	IoSetCancelRoutine(irp, NULL);

	// Following block of code locks the destination packet
	// MDLs in a safe manner. This is a temporary workaround
	// for NdisCopyFromPacketToPacket that currently doesn't use
	// safe functions to lock pages of MDL. This is required to
	// prevent system from bugchecking under low memory resources.
	//
	{
		PVOID           virtualAddress;
		PNDIS_BUFFER    firstBuffer, nextBuffer;
		ULONG           totalLength;

		NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength);
		while( firstBuffer ) {
			NdisQueryBufferSafe( firstBuffer, &virtualAddress, &totalLength, NormalPagePriority );
			if(!virtualAddress) {
				status = STATUS_INSUFFICIENT_RESOURCES;
				goto CleanExit;
			}
			NdisGetNextBuffer(firstBuffer,  &nextBuffer);
			firstBuffer = nextBuffer;
		}
	}

	NdisChainBufferAtFront( myPacket, irp->MdlAddress );
	bufferLength=irpSp->Parameters.Read.Length;
	NdisCopyFromPacketToPacket( myPacket, 0, bufferLength, Packet, 0,  &bytesTransfered );

CleanExit:
	NdisFreePacket(myPacket);
	irp->IoStatus.Status = status;
	irp->IoStatus.Information = bytesTransfered;
	IoCompleteRequest(irp, IO_NO_INCREMENT);
	// DebugPrint(("BytesTransfered:%d\n", bytesTransfered));
	IoDecrement(open);
	return 0;
}
示例#3
0
INT
LpxProtocolReceivePacket(
	IN NDIS_HANDLE	ProtocolBindingContext,
	IN PNDIS_PACKET	Packet
){
	PDEVICE_CONTEXT	deviceContext;
	PNDIS_BUFFER	ndisFirstBuffer;
	PVOID			firstBuffer;
	UINT		    firstBufferSize;
	UINT			totalBufferSize;
	USHORT		    protocol;
	PNDIS_PACKET	packet = NULL;
	NDIS_STATUS		status;
	INT				pktReferenceCount = 0;
	UINT		    addiLlcHeaderSize = 0;
	PLPX_HEADER		lpxHeader;
	USHORT			lpxHeaderSize;
	UINT			lpxPayload;
	UINT			rawDataOffset;


	DebugPrint( 4, ("ProtocolReceivePacket: Entered\n") );
	
	deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext;

	//
	//	Check to see if the device context is initialized.
	//
	ASSERT( deviceContext->NdisBindingHandle );

	if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) ||
		FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) {

			DebugPrint( 4,("Device is not initialized. Drop packet\n") );

			return 0;
	}

	//
	//	validation
	//
	NdisGetFirstBufferFromPacket(
				Packet,
				&ndisFirstBuffer,
				&firstBuffer,
				&firstBufferSize,
				&totalBufferSize);

	if (firstBufferSize < ETHERNET_HEADER_LENGTH) {

		DebugPrint( 1, ("ProtocolReceivePacket: FirstBufferSize = %x\n", firstBufferSize) );
		return 0;
	}

	protocol = ((PETHERNET_HEADER)firstBuffer)->Type;

	//
	//	Discard 802.2 LLC SNAP field.
	//
	// if Ether Type less than 0x0600 ( 1536 )
	//

	if (NTOHS(protocol) < 0x0600  && 
	    NTOHS(protocol) != 0x0060 && // LOOP: Ethernet Loopback
		NTOHS(protocol) != 0x0200 && // PUP : Xerox PUP packet
		NTOHS(protocol) != 0x0201) { // PUPAP: Xerox PUP address trans packet 

		protocol = *(PUSHORT)((PUCHAR)firstBuffer + ETHERNET_HEADER_LENGTH + LENGTH_8022LLCSNAP - 2);
		if(firstBufferSize >= LENGTH_8022LLCSNAP)
			firstBufferSize -= LENGTH_8022LLCSNAP;
		else {
			DebugPrint( 1, ("ProtocolReceivePacket: Too small first buffer\n") );
			return 0;
		}

		if(totalBufferSize >= LENGTH_8022LLCSNAP)
			totalBufferSize -= LENGTH_8022LLCSNAP;
		else {
			DebugPrint( 1, ("ProtocolReceivePacket: Too small total buffer\n") );
			return 0;
		}
		addiLlcHeaderSize = LENGTH_8022LLCSNAP;
	}

	if (protocol != HTONS(ETH_P_LPX)) {
	
		DebugPrint( 4, ("ProtocolReceivePacket: Type = %x\n", protocol) );
		return 0;
	}
	if(totalBufferSize < ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + sizeof(LPX_HEADER)) {
		DebugPrint( 1, ("ProtocolReceivePacket: too small packet(1).\n"));
		return 0;
	}

	//
	// Extract LPX header information
	//
	//

	lpxHeader = (PLPX_HEADER)((PBYTE)firstBuffer + ETHERNET_HEADER_LENGTH + addiLlcHeaderSize);
	lpxHeaderSize = sizeof(LPX_HEADER);
	lpxPayload = NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize;

#if __LPX_OPTION_ADDRESSS__

	if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) {
		lpxHeaderSize += ETHERNET_ADDRESS_LENGTH;
	}

	if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) {
		lpxHeaderSize += ETHERNET_ADDRESS_LENGTH;
	}

#endif

	if(totalBufferSize < ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + lpxHeaderSize + lpxPayload) {
		DebugPrint( 1, ("ProtocolReceivePacket: too small packet(2).\n"));
		return 0;
	}

	//
	// DROP PACKET for DEBUGGING!!!!
	//

#if 1 //DBG // Enabled for testing

	if (PacketRxDropRate) {

		PacketRxCountForDrop++;
				
		if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) {
			PLPX_HEADER        lpxHeader = (PLPX_HEADER)((PUCHAR)firstBuffer + addiLlcHeaderSize);
#if 0
			if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) 
				DebugPrint( 1, ("[Drop(%x,%x,%x))]\n", 
								 NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) );
#endif			
			DebugPrint( 1, ("D\n") );

			return 0;
		}
	}

#endif

	ASSERT( addiLlcHeaderSize == 0 );

	DebugPrint( 4, ("ProtocolReceivePacket: TotalBuffSz = %d, FirstBuffSz = %d, LPX_HEADER size = %d\n",
					 totalBufferSize, firstBufferSize, sizeof(LPX_HEADER)) );
	//
	//  If the miniport is out of resources, we can't queue
	//  this packet - make a copy if this is so.
	//
	if (NDIS_GET_PACKET_STATUS(Packet) == NDIS_STATUS_RESOURCES) {

		UINT			bytesCopied;

		DebugPrint( 1, ("ProtocolReceivePacket: Miniport reported low packet resources.\n"));

		status = RcvPacketAlloc( deviceContext,
								 lpxPayload,
								 &packet );

		if (status == STATUS_SUCCESS) {
			ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS );
			//
			// Copy lpx payload. payload contains only data.
			//
			NdisCopyFromPacketToPacket(
						packet, 0,
						lpxPayload,
						Packet, ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + lpxHeaderSize,
						&bytesCopied);
			ASSERT(lpxPayload == bytesCopied);
		}

		rawDataOffset = 0;
		pktReferenceCount = 0;
	} else {
		PLPX_RESERVED	externalReserved;
		//
		// No need to allocate new NDIS packet and copy data to the new NDIS packet.
		// But, NDIS miniport allocates only 4 * sizeof(PVOID) for protocol reserved context.
		// We should allocate our own.
		//
		packet = Packet;

		status = NdisAllocateMemoryWithTag(&externalReserved, sizeof(LPX_RESERVED), LPX_MEM_TAG_EXTERNAL_RESERVED);
		if(status == NDIS_STATUS_SUCCESS) {

			RtlZeroMemory(externalReserved, sizeof(LPX_RESERVED));

			// By setting the external reserved field, RESERVED() uses external reserved context automatically.
			((PLPX_RESERVED)packet->ProtocolReserved)->ExternalReserved = externalReserved;

			// Initialize LPX reserved context instead of RcvPacketAlloc().
			RESERVED(packet)->Cloned = 0;
			RESERVED(packet)->Type = LPX_PACKET_TYPE_RECEIVE;
			RESERVED(packet)->RecvFlags |= LPX_RESERVED_RECVFLAG_ALLOC_MINIPORT;

			// set data offset
			// Because NDIS miniport allocated the packet, the NDIS packet contains whole raw packet data.
			rawDataOffset = ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + lpxHeaderSize;
			lpxPayload += rawDataOffset;

			// return one reference count indicating LPX will call NdisReturnPackets() once.
			pktReferenceCount = 1;

		}
	}

	if (status != NDIS_STATUS_SUCCESS) {

		return 0;
	}

	//
	// Init LPX reserved context
	//

	LpxCopyEthLpxHeadersToLpxReserved(packet, firstBuffer, protocol, lpxHeader, lpxHeaderSize);
	RESERVED(Packet)->Packet = packet;
	RESERVED(Packet)->RecvTime = CurrentTime();
	RESERVED(Packet)->PacketRawDataLength = lpxPayload;
	RESERVED(Packet)->PacketRawDataOffset = rawDataOffset;

	//
	// Queue to the device context.
	//

	ExInterlockedInsertTailList( &deviceContext->PacketInProgressList,
								 &(RESERVED(Packet)->ListEntry),
								 &deviceContext->PacketInProgressQSpinLock );


	return pktReferenceCount;
}
示例#4
0
INT
LpxProtocolReceivePacket (
	IN NDIS_HANDLE	ProtocolBindingContext,
	IN PNDIS_PACKET	Packet
	)
{
	PDEVICE_CONTEXT	deviceContext;

	PLPX_RESERVED	reserved = NULL;	

	PNDIS_BUFFER	ndisFirstBuffer;
	PVOID			firstBuffer;
	UINT		    firstBufferSize;
	UINT			totalBufferSize;
	PNDIS_PACKET	packet = NULL;
	NDIS_STATUS		status;
	INT				pktReferenceCount = 0;
	UINT		    addiLlcHeaderSize = 0;
	PLPX_HEADER		lpxHeader;
	USHORT			lpxHeaderSize;
	UINT			lpxPayload;
	UINT			rawDataOffset;
	ETHERNET_HEADER	ethernetHeader;

	DebugPrint( 4, ("ProtocolReceivePacket: Entered\n") );
	
	deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext;

	//	Check to see if the device context is initialized.

	if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) || FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) {

		DebugPrint( 1, ("Device is not initialized. Drop packet\n") );

		return NDIS_STATUS_NOT_RECOGNIZED;
	}

	NDAS_ASSERT( deviceContext->NdisBindingHandle );

	//	validation

#ifndef NTDDI_VERSION

	NdisGetFirstBufferFromPacket( Packet,
								  &ndisFirstBuffer,
								  &firstBuffer,
								  &firstBufferSize,
								  &totalBufferSize );
#else

	firstBufferSize = 0;
	
	NdisGetFirstBufferFromPacketSafe( Packet,
									  &ndisFirstBuffer,
									  &firstBuffer,
									  &firstBufferSize,
									  &totalBufferSize,
									  HighPagePriority );
#endif

	if (firstBufferSize < ETHERNET_HEADER_LENGTH) {

		NDAS_ASSERT(FALSE);

		DebugPrint( 2, ("ProtocolReceivePacket: FirstBufferSize = %x\n", firstBufferSize) );
		return 0;
	}

	RtlCopyMemory( &ethernetHeader, firstBuffer, ETHERNET_HEADER_LENGTH );

	if (ethernetHeader.DestinationAddress[5] != 0xFF) {

		DebugPrint( 3, ("LpxProtocolReceivePacket: Type = %X\n", ethernetHeader.Type) );	
	}

	//	Discard 802.2 LLC SNAP field.
	//
	// if Ether Type less than 0x0600 ( 1536 )

	if (NTOHS(ethernetHeader.Type)  < 0x0600 && 
		NTOHS(ethernetHeader.Type) != 0x0060 && // LOOP:  Ethernet Loopback
		NTOHS(ethernetHeader.Type) != 0x0200 && // PUP :  Xerox PUP packet
		NTOHS(ethernetHeader.Type) != 0x0201) { // PUPAP: Xerox PUP address trans packet 

		RtlCopyMemory( &ethernetHeader, 
					   (PUCHAR)firstBuffer + ETHERNET_HEADER_LENGTH + LENGTH_8022LLCSNAP - 2, 
					   ETHERNET_HEADER_LENGTH );

		if (firstBufferSize >= LENGTH_8022LLCSNAP) {

			firstBufferSize -= LENGTH_8022LLCSNAP;
		
		} else {

			DebugPrint( 2, ("ProtocolReceivePacket: Too small first buffer\n") );
			return 0;
		}

		if (totalBufferSize >= LENGTH_8022LLCSNAP) {

			totalBufferSize -= LENGTH_8022LLCSNAP;
		
		} else {

			DebugPrint( 2, ("ProtocolReceivePacket: Too small total buffer\n") );
			return 0;
		}

		addiLlcHeaderSize = LENGTH_8022LLCSNAP;

		NDAS_ASSERT( ethernetHeader.Type != HTONS(ETH_P_LPX) );
	}

	if (ethernetHeader.Type != HTONS(ETH_P_LPX)) {
	
		DebugPrint( 4, ("ProtocolReceivePacket: Type = %x\n", ethernetHeader.Type) );
		return 0;
	}

	if (totalBufferSize < ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + sizeof(LPX_HEADER)) {

		DebugPrint( 2, ("ProtocolReceivePacket: too small packet(1).\n"));
		return 0;
	}

	// DROP PACKET for DEBUGGING!!!!

	if (PacketRxDropRate) {

		PacketRxCountForDrop++;
				
		if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) {

			PLPX_HEADER        lpxHeader = (PLPX_HEADER)((PUCHAR)firstBuffer + addiLlcHeaderSize);

			if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) {

				DebugPrint( 6, ("[Drop(%x,%x,%x))]\n", 
								 NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) );
			}

			DebugPrint( 2, ("D\n") );

			return 0;
		}
	}

	if (!(RtlEqualMemory(ethernetHeader.DestinationAddress, deviceContext->LocalAddress.Address, ETHERNET_ADDRESS_LENGTH) ||
		  RtlEqualMemory(ethernetHeader.DestinationAddress, LpxBroadcastAddress, ETHERNET_ADDRESS_LENGTH))) {

		DebugPrint( 4, ("LpxProtocolReceivePacket, %02x%02x%02x%02x%02x%02x\n",
						 deviceContext->LocalAddress.Address[0], deviceContext->LocalAddress.Address[1], 
						 deviceContext->LocalAddress.Address[2], deviceContext->LocalAddress.Address[3], 
						 deviceContext->LocalAddress.Address[4], deviceContext->LocalAddress.Address[5]) );

		DebugPrint( 4, ("LpxProtocolReceivePacket, %02x%02x%02x%02x%02x%02x\n",
						 ethernetHeader.DestinationAddress[0], ethernetHeader.DestinationAddress[1], 
						 ethernetHeader.DestinationAddress[2], ethernetHeader.DestinationAddress[3], 
						 ethernetHeader.DestinationAddress[4], ethernetHeader.DestinationAddress[5]) );

		return 0;
	}

	// Extract LPX header information

	lpxHeader = (PLPX_HEADER)((PBYTE)firstBuffer + ETHERNET_HEADER_LENGTH + addiLlcHeaderSize);
	lpxHeaderSize = sizeof(LPX_HEADER);
	lpxPayload = NTOHS((UINT16)(lpxHeader->PacketSize & ~LPX_TYPE_MASK)) - lpxHeaderSize;

	if (lpxHeader->DestinationPort == NTOHS(LPXRP_HIX_PORT)) {

		DebugPrint( 1, ("[LPX] LpxProtocolReceivePacket: DataGram packet arrived.\n") );
	}

#if __LPX_OPTION_ADDRESSS__

	if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) {

		lpxHeaderSize += ETHERNET_ADDRESS_LENGTH;
	}

	if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) {

		lpxHeaderSize += ETHERNET_ADDRESS_LENGTH;
	}

#endif

	if (totalBufferSize < ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + lpxHeaderSize + lpxPayload) {

		DebugPrint( 2, ("ProtocolReceivePacket: too small packet(2).\n") );

		return 0;
	}

	NDAS_ASSERT( addiLlcHeaderSize == 0 );

	DebugPrint( 4, ("ProtocolReceivePacket: TotalBuffSz = %d, FirstBuffSz = %d, LPX_HEADER size = %d\n",
					 totalBufferSize, firstBufferSize, sizeof(LPX_HEADER)) );

	//  If the miniport is out of resources, we can't queue
	//  this packet - make a copy if this is so.

	NDAS_ASSERT( sizeof(ZeroProtocolReserved) == PROTOCOL_RESERVED_OFFSET );

	if (NDIS_GET_PACKET_STATUS(Packet) == NDIS_STATUS_RESOURCES ||
		!RtlEqualMemory(&Packet->ProtocolReserved[PROTOCOL_RESERVED_OFFSET], ZeroProtocolReserved, sizeof(ZeroProtocolReserved))) {

		UINT bytesCopied;
		INT  i;

		for (i=0; i<16; i++) {

			DebugPrint( 1, ("Packet->ProtocolReserved[%d] = %d\n", i, Packet->ProtocolReserved[i]) );
		}

		NDAS_ASSERT(FALSE);

		DebugPrint( 2, ("ProtocolReceivePacket: Miniport reported low packet resources.\n") );

		status = RcvPacketAlloc( deviceContext, lpxPayload, &packet );

		if (status == STATUS_SUCCESS) {

			NDAS_ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS );

			// Copy lpx payload. payload contains only data.

			NdisCopyFromPacketToPacket( packet, 
										0,
										lpxPayload,
										Packet, 
										ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + lpxHeaderSize,
										&bytesCopied
										);

			NDAS_ASSERT( lpxPayload == bytesCopied );
		}

		rawDataOffset = 0;
		pktReferenceCount = 0;
	
	} else {
	
		PLPX_RESERVED externalReserved;

		// No need to allocate new NDIS packet and copy data to the new NDIS packet.
		// But, NDIS miniport allocates only 4 * sizeof(PVOID) for protocol reserved context.
		// We should allocate our own.

		packet = Packet;

		status = NdisAllocateMemoryWithTag( &externalReserved, sizeof(LPX_RESERVED), LPX_MEM_TAG_EXTERNAL_RESERVED );

		if (status == NDIS_STATUS_SUCCESS) {

			RtlZeroMemory( externalReserved, sizeof(LPX_RESERVED) );

			// By setting the external reserved field, LpxGetReserved() uses external reserved context automatically.

			((PLPX_RESERVED)(&packet->ProtocolReserved[PROTOCOL_RESERVED_OFFSET]))->ExternalReserved = externalReserved;

			reserved = LpxGetReserved(packet);

			// Initialize LPX reserved context instead of RcvPacketAlloc().

			reserved->Cloned = 0;
			reserved->Type = LPX_PACKET_TYPE_RECEIVE;
			reserved->RecvFlags |= LPX_RESERVED_RECVFLAG_ALLOC_MINIPORT;

			// set data offset
			// Because NDIS miniport allocated the packet, the NDIS packet contains whole raw packet data.

			rawDataOffset = ETHERNET_HEADER_LENGTH + addiLlcHeaderSize + lpxHeaderSize;
			lpxPayload += rawDataOffset;

			// return one reference count indicating LPX will call NdisReturnPackets() once.

			pktReferenceCount = 1;
		}
	}

	if (status != NDIS_STATUS_SUCCESS) {

		DebugPrint( 2, ("ProtocolReceivePacket: status != NDIS_STATUS_SUCCESS\n") );
		return 0;
	}

	// Init LPX reserved context

	LpxCopyEthLpxHeadersToLpxReserved( packet, firstBuffer, ethernetHeader.Type, lpxHeader, lpxHeaderSize );

	reserved = LpxGetReserved(packet);

	reserved->Packet = packet;
	reserved->RecvTime = NdasCurrentTime();
	reserved->PacketRawDataLength = lpxPayload;
	reserved->PacketRawDataOffset = rawDataOffset;

	// Queue to the device context.

	ExInterlockedInsertTailList( &deviceContext->PacketInProgressList,
								 &(reserved->ListEntry),
								 &deviceContext->PacketInProgressQSpinLock );

	return pktReferenceCount;
}