diff options
Diffstat (limited to 'private/ntos/ndis/netflex/receive.c')
-rw-r--r-- | private/ntos/ndis/netflex/receive.c | 633 |
1 files changed, 633 insertions, 0 deletions
diff --git a/private/ntos/ndis/netflex/receive.c b/private/ntos/ndis/netflex/receive.c new file mode 100644 index 000000000..1219cb033 --- /dev/null +++ b/private/ntos/ndis/netflex/receive.c @@ -0,0 +1,633 @@ +//********************************************************************** +//********************************************************************** +// +// File Name: RECEIVE.C +// +// Program Name: NetFlex NDIS 3.0 Miniport Driver +// +// Companion Files: None +// +// Function: This module contains the NetFlex Miniport Driver +// interface routines called by the Wrapper and the +// configuration manager. +// +// (c) Compaq Computer Corporation, 1992,1993,1994 +// +// This file is licensed by Compaq Computer Corporation to Microsoft +// Corporation pursuant to the letter of August 20, 1992 from +// Gary Stimac to Mark Baber. +// +// History: +// +// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver +// +//********************************************************************** +//********************************************************************** + + +//------------------------------------- +// Include all general companion files +//------------------------------------- + +#include <ndis.h> +#include "tmsstrct.h" +#include "macstrct.h" +#include "adapter.h" +#include "protos.h" + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexProcessRcv +// +// Description: This routine looks through the receive lists +// looking for received packets. A receive +// indication is given for each packet received +// +// Input: acb - Pointer to the Adapter's acb +// +// Output: true if we should indicaterecievecomplete +// +// Calls: NdisIndicateReceive +// +// Called_By: NetflxHandleInterrupt +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +USHORT +FASTCALL +NetFlexProcessEthRcv( + PACB acb + ) +{ + PRCV rcvptr; + USHORT FrameSize; + USHORT ReceiveCount = 0; + PUCHAR Temp; + +#if (DBG || DBGPRINT) + BOOLEAN IsBroadcast; + PUCHAR SourceAddress; +#endif + + // + // While there is recieves to process... + // + rcvptr = acb->acb_rcv_head; + + // + // Ensure that our Receive Entry is on an even boundary. + // + ASSERT(!(NdisGetPhysicalAddressLow(rcvptr->RCV_Phys) & 1)); + + do + { + // + // See if the recieve is on one list... + // + if ((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) == (RCSTAT_EOF | RCSTAT_SOF)) + { + // Frame is on one list. + // + FrameSize = (USHORT)(SWAPS(rcvptr->RCV_Fsize)); + rcvptr->RCV_HeaderLen = HDR_SIZE; + + // + // Flush the receive buffer + // + NdisFlushBuffer(rcvptr->RCV_FlushBuffer, FALSE); + +#if (DBG || DBGPRINT) + SourceAddress = (PVOID)((PUCHAR)&(rcvptr->RCV_Buf) + 2); + IsBroadcast = ETH_IS_BROADCAST(SourceAddress); // works for eth & tr + if (IsBroadcast) + { + DebugPrint(3,("NF(%d): Recieved broadcast!\n",acb->anum)); + } + else if (ETH_IS_MULTICAST(SourceAddress)) + { + DebugPrint(3,("NF(%d): Recieved multicast!\n",acb->anum)); + } +#endif + // + // For speed... + // + Temp = (PUCHAR) rcvptr->RCV_Buf; + + // + // Check for Runt or Normal Packet + // + if (FrameSize >= HDR_SIZE) + { + // Normal Packet + // + ReceiveCount++; + NdisMEthIndicateReceive(acb->acb_handle, + (NDIS_HANDLE)(((PUCHAR) Temp) + HDR_SIZE), + Temp, + (UINT)HDR_SIZE, + (((PUCHAR) Temp) + HDR_SIZE), + (UINT)(FrameSize - HDR_SIZE), + (UINT)(FrameSize - HDR_SIZE)); + + } + else if (FrameSize >= NET_ADDR_SIZE) + { + ReceiveCount++; + // Runt Packet + // + DebugPrint(1,("NF(%d) - Got Runt! len = %d\n",acb->anum,FrameSize)); + NdisMEthIndicateReceive(acb->acb_handle, + (NDIS_HANDLE)(((PUCHAR) Temp) + HDR_SIZE), + Temp, + (UINT)FrameSize, + NULL, + 0, + 0); + } +#if DBG + else + { + DebugPrint(1,("NF(%d) - Rec - Packetlen = %d",acb->anum,FrameSize)); + } +#endif + + rcvptr->RCV_CSTAT = + ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO; + // + // Get next receive list + // + rcvptr = rcvptr->RCV_Next; + } + else + { + // + // Frame is too large. Release the frame. + // + acb->acb_gen_objs.frames_rcvd_err++; + + DebugPrint(0,("Netflx: Receive Not on one list.\n")); + + // + // Clean up the list making up this packet. + // + while (((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) != (RCSTAT_EOF | RCSTAT_SOF)) && + ((rcvptr->RCV_CSTAT & RCSTAT_COMPLETE) != 0) + ) + { + // + // Clean the list and set the FINT based on ratio. + // + + rcvptr->RCV_CSTAT = + ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO; + + rcvptr = rcvptr->RCV_Next; + } + } + + // + // If we're processing too many, get out + // + if (ReceiveCount >= acb->acb_maxrcvs) + break; + + } while (rcvptr->RCV_CSTAT & RCSTAT_COMPLETE); + + // + // Update head pointer + // + acb->acb_rcv_head = rcvptr; + + // + // Tell Adapter that there are more receives available + // + NdisRawWritePortUshort( acb->SifIntPort, (USHORT) SIFINT_RCVVALID); + + // + // Update number of received frames + // + acb->acb_gen_objs.frames_rcvd_ok += ReceiveCount; + + return(ReceiveCount); +} + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexProcessTrRcv +// +// Description: This routine looks through the receive lists +// looking for received packets. A receive +// indication is given for each packet received. +// +// Input: acb - Pointer to the Adapter's acb +// +// Output: true if we should indicaterecievecomplete +// +// Calls: NdisIndicateReceive +// +// Called_By: NetflxHandleInterrupt +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +USHORT +FASTCALL +NetFlexProcessTrRcv( + PACB acb + ) +{ + PRCV rcvptr; + USHORT FrameSize; + USHORT HeaderSize; + USHORT ReceiveCount = 0; + PUCHAR Temp; + +#if (DBG || DBGPRINT) + BOOLEAN IsBroadcast; + PUCHAR SourceAddress; +#endif + + // + // While there is recieves to process... + // + rcvptr = acb->acb_rcv_head; + + // + // Ensure that our Receive Entry is on an even boundary. + // + ASSERT(!(NdisGetPhysicalAddressLow(rcvptr->RCV_Phys) & 1)); + + do + { + // See if the recieve is on one list... + // + if ((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) == (RCSTAT_EOF | RCSTAT_SOF)) + { + // Frame is on one list. + // + FrameSize = (USHORT)(SWAPS(rcvptr->RCV_Fsize)); + + HeaderSize = HDR_SIZE; + + // + // Flush the receive buffer + // + NdisFlushBuffer(rcvptr->RCV_FlushBuffer, FALSE); + +#if (DBG || DBGPRINT) + SourceAddress = (PVOID)((PUCHAR)&(rcvptr->RCV_Buf) + 2); + + IsBroadcast = ETH_IS_BROADCAST(SourceAddress); // works for eth & tr + if (IsBroadcast) + { + DebugPrint(3,("NF(%d): Recieved broadcast!\n",acb->anum)); + } + else + { + TR_IS_GROUP(SourceAddress,&IsBroadcast); + if (IsBroadcast) + { + DebugPrint(3,("NF(%d): Recieved TR Group!\n",acb->anum)); + } + } + + TR_IS_FUNCTIONAL(SourceAddress,&IsBroadcast); + if (IsBroadcast) + DebugPrint(2,("NF(%d): Recieved TR Fuctional!\n",acb->anum)); +#endif + // + // For speed... + // + Temp = (PUCHAR) rcvptr->RCV_Buf; + + // + // Make sure we have at least the AC, FS, SRC & DST fields before + // looking at the source routing info. + // + if (FrameSize >= HeaderSize) + { + // Is the source routing bit is on? + // + if (Temp[8] & 0x80) + { + // Yes, figure out the size of the MAC Frame Header. + // + HeaderSize = (Temp[HDR_SIZE] & 0x1f) + HDR_SIZE; + rcvptr->RCV_HeaderLen = HeaderSize; + // + // Check for Runt or Normal Packet again... + // + if (FrameSize >= HeaderSize) + { + // Normal Packet + // + ReceiveCount++; + + NdisMTrIndicateReceive( + acb->acb_handle, + (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize), + Temp, + (UINT)HeaderSize, + (((PUCHAR) Temp) + HeaderSize), + (UINT)(FrameSize - HeaderSize), + (UINT)(FrameSize - HeaderSize)); + } + else if (FrameSize >= NET_ADDR_SIZE) + { + // Runt Packet + // + ReceiveCount++; + + DebugPrint(1,("NF(%d) - Got Runt - len = %d!\n",acb->anum,FrameSize)); + + NdisMTrIndicateReceive( + acb->acb_handle, + (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize), + Temp, + (UINT)FrameSize, + NULL, + 0, + 0); + } + } + else + { + // No Source Routing info, but has Normal Packet Length + // + rcvptr->RCV_HeaderLen = HeaderSize; + + ReceiveCount++; + + NdisMTrIndicateReceive( + acb->acb_handle, + (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize), + Temp, + (UINT)HeaderSize, + (((PUCHAR) Temp) + HeaderSize), + (UINT)(FrameSize - HeaderSize), + (UINT)(FrameSize - HeaderSize)); + } + } + else + { + // No, Frame doesn't have AC, FC, SRC & DST. + // Is it bigger than net_addr_size? + // + if (FrameSize >= NET_ADDR_SIZE) + { + // Yes, so indicate Runt Packet + // + ReceiveCount++; + + DebugPrint(1,("NF(%d) - Got Runt - len = %d!\n",acb->anum,FrameSize)); + + NdisMTrIndicateReceive( + acb->acb_handle, + (NDIS_HANDLE)(((PUCHAR) Temp) + HeaderSize), + Temp, + (UINT)FrameSize, + NULL, + 0, + 0); + } + } + + rcvptr->RCV_CSTAT = + ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO; + + // + // Get next receive list + // + rcvptr = rcvptr->RCV_Next; + + } + else + { + // Frame is too large. Release the frame. + // + acb->acb_gen_objs.frames_rcvd_err++; + DebugPrint(0,("Netflx: Receive Not on one list.\n")); + // + // Clean up the list making up this packet. + // + while (((rcvptr->RCV_CSTAT & (RCSTAT_EOF | RCSTAT_SOF)) != (RCSTAT_EOF | RCSTAT_SOF)) && + ((rcvptr->RCV_CSTAT & RCSTAT_COMPLETE) != 0)) + { + // Clean the list and set the FINT based on ratio. + // + rcvptr->RCV_CSTAT = + ((rcvptr->RCV_Number % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO; + + rcvptr = rcvptr->RCV_Next; + } + } + + // + // If we're processing too many, get out + // + if (ReceiveCount >= acb->acb_maxrcvs) + break; + + } while (rcvptr->RCV_CSTAT & RCSTAT_COMPLETE); + + // + // Update head pointer + // + acb->acb_rcv_head = rcvptr; + + // + // Tell Adapter that there are more receives available + // + NdisRawWritePortUshort( acb->SifIntPort, (USHORT) SIFINT_RCVVALID); + + // + // Update number of recieved frames + // + acb->acb_gen_objs.frames_rcvd_ok += ReceiveCount; + + return ReceiveCount; +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Routine Name: NetFlexTransferData +// +// Description: This routine copies the received data into +// a packet structure provided by the caller. +// +// Input: +// +// MiniportAdapterContext - The context value returned by the driver when the +// adapter was initialized. In reality this is a pointer to NE3200_ADAPTER. +// +// MiniportReceiveContext - The context value passed by the driver on its call +// to NdisMIndicateReceive. The driver can use this value to determine +// which packet, on which adapter, is being received. +// +// ByteOffset - An unsigned integer specifying the offset within the +// received packet at which the copy is to begin. If the entire packet +// is to be copied, ByteOffset must be zero. +// +// BytesToTransfer - An unsigned integer specifying the number of bytes +// to copy. It is legal to transfer zero bytes; this has no effect. If +// the sum of ByteOffset and BytesToTransfer is greater than the size +// of the received packet, then the remainder of the packet (starting from +// ByteOffset) is transferred, and the trailing portion of the receive +// buffer is not modified. +// +// Packet - A pointer to a descriptor for the packet storage into which +// the MAC is to copy the received packet. +// +// BytesTransfered - A pointer to an unsigned integer. The MAC writes +// the actual number of bytes transferred into this location. This value +// is not valid if the return Status is STATUS_PENDING. +// +// Output: +// Packet - Place to copy data. +// BytesTransferred - Number of bytes copied. +// Returns NDIS_STATUS_SUCCESS for a successful +// completion. Otherwise, an error code is returned. +// +// Called By: +// Miniport Wrapper +// +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +NDIS_STATUS +NetFlexTransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ) +{ + PACB acb = (PACB) MiniportAdapterContext; + PNDIS_BUFFER DestinationCurrentBuffer; + UINT DestinationBufferCount; + PUCHAR SourceCurrentAddress; + PVOID DestinationVirtualAddress; + UINT DestinationCurrentLength; + UINT LocalBytesTransferred = 0; + UINT AmountToMove; + UINT Remaining; + + // + // Display number of bytes to transfer on the debugger + // + DebugPrint(2,("NF(%d) - Copying %u bytes\n",acb->anum,BytesToTransfer)); + + // + // Initialize the number of bytes transferred to 0 + // + *BytesTransferred = 0; + + // + // If we don't have any more to transfer, we're done + // + if (BytesToTransfer == 0) + { + return NDIS_STATUS_SUCCESS; + } + + // + // Get the first buffer of the destination. + // + NdisQueryPacket( + Packet, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. If so, we are done. + // + if (DestinationBufferCount == 0) + { + return NDIS_STATUS_SUCCESS; + } + + // + // Get information on the buffer. + // + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Set up the source address. + // + SourceCurrentAddress = (PCHAR)(MiniportReceiveContext) + ByteOffset; + + // + // Do the actual transfer from source to destination + // + while (LocalBytesTransferred < BytesToTransfer) + { + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + if (DestinationCurrentLength == 0) + { + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (DestinationCurrentBuffer == NULL) + { + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + break; + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + continue; + } + + // + // Copy the data. + // + + Remaining = BytesToTransfer - LocalBytesTransferred; + + AmountToMove = DestinationCurrentLength; + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + NdisMoveMemory( + DestinationVirtualAddress, + SourceCurrentAddress, + AmountToMove + ); + + // + // Update pointers and counters + // + SourceCurrentAddress += AmountToMove; + LocalBytesTransferred += AmountToMove; + DestinationCurrentLength -= AmountToMove; + } + + // + // Indicate how many bytes were transferred + // + *BytesTransferred = LocalBytesTransferred; + + // + // Display total bytes transferred on debugger + // + DebugPrint(2,("NF(%d) - Total bytes transferred = %x\n",acb->anum,*BytesTransferred)); + + return NDIS_STATUS_SUCCESS; +} |