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; }
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; }
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; }
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( ðernetHeader, 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( ðernetHeader, (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; }