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; }
NDIS_STATUS NTAPI MiniportSend ( IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET Packet, IN UINT Flags ) { PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; NDIS_STATUS status; PSCATTER_GATHER_LIST sgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo); ULONG transmitLength; ULONG transmitBuffer; PNDIS_BUFFER firstBuffer; PVOID firstBufferVa; UINT firstBufferLength, totalBufferLength; PUCHAR runtBuffer; ASSERT(sgList != NULL); ASSERT(sgList->NumberOfElements == 1); ASSERT(sgList->Elements[0].Address.HighPart == 0); ASSERT((sgList->Elements[0].Address.LowPart & 3) == 0); ASSERT(sgList->Elements[0].Length <= MAXIMUM_FRAME_SIZE); NDIS_DbgPrint(MAX_TRACE, ("Sending %d byte packet\n", sgList->Elements[0].Length)); NdisAcquireSpinLock(&adapter->Lock); if (adapter->TxFull) { NDIS_DbgPrint(MIN_TRACE, ("All TX descriptors are full\n")); NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_RESOURCES; } NDIS_DbgPrint(MAX_TRACE, ("Sending packet on TX desc %d\n", adapter->CurrentTxDesc)); // // If this is a runt, we need to pad it manually for the RTL8139 // if (sgList->Elements[0].Length < MINIMUM_FRAME_SIZE) { transmitLength = MINIMUM_FRAME_SIZE; transmitBuffer = adapter->RuntTxBuffersPa.LowPart + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); NdisGetFirstBufferFromPacketSafe(Packet, &firstBuffer, &firstBufferVa, &firstBufferLength, &totalBufferLength, NormalPagePriority); if (firstBufferVa == NULL) { NDIS_DbgPrint(MIN_TRACE, ("Unable to get buffer from packet\n")); NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_RESOURCES; } ASSERT(firstBufferLength == totalBufferLength); runtBuffer = adapter->RuntTxBuffers + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); RtlCopyMemory(runtBuffer, firstBufferVa, firstBufferLength); RtlFillMemory(runtBuffer + firstBufferLength, MINIMUM_FRAME_SIZE - firstBufferLength, 0x00); } else { transmitLength = sgList->Elements[0].Length; transmitBuffer = sgList->Elements[0].Address.LowPart; } status = NICTransmitPacket(adapter, adapter->CurrentTxDesc, transmitBuffer, transmitLength); if (status != NDIS_STATUS_SUCCESS) { NDIS_DbgPrint(MIN_TRACE, ("Transmit packet failed\n")); NdisReleaseSpinLock(&adapter->Lock); return status; } adapter->CurrentTxDesc++; adapter->CurrentTxDesc %= TX_DESC_COUNT; if (adapter->CurrentTxDesc == adapter->DirtyTxDesc) { NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n")); adapter->TxFull = TRUE; } NdisReleaseSpinLock(&adapter->Lock); return NDIS_STATUS_SUCCESS; }
VOID SecLabFreeReceivePacket( PADAPT pAdapt, IN PNDIS_PACKET pNdisPacket ) /*++ Routine Description: 释放所有与接收包相关的资源。如果这是一个本地拷贝,将此包释放到接收包池 。否则释放到miniport. Arguments: pNdisPacket - 指向要释放的包的指针 Return Value: None --*/ { PNDIS_BUFFER pNdisBuffer; UINT TotalLength; UINT BufferLength; PUCHAR pCopyData; if (NdisGetPoolFromPacket(pNdisPacket) ==pAdapt->RecvPacketPoolHandle) { // // This is a local copy. // #ifdef NDIS51 NdisGetFirstBufferFromPacketSafe( pNdisPacket, &pNdisBuffer, (PVOID *)&pCopyData, &BufferLength, &TotalLength, NormalPagePriority); #else NdisGetFirstBufferFromPacket( pNdisPacket, &pNdisBuffer, (PVOID *)&pCopyData, &BufferLength, &TotalLength); #endif if(BufferLength != TotalLength || pNdisBuffer==NULL || pCopyData==NULL) { DbgPrint("Error! Failed in Free a Packet"); DbgBreakPoint(); } NdisFreePacket(pNdisPacket); NdisFreeBuffer(pNdisBuffer); NdisFreeMemory(pCopyData,0,0); } else { NdisReturnPackets(&pNdisPacket, 1); } }