windows-nt/Source/XPSP1/NT/net/qos/psched/sys/recv.c
2020-09-26 16:20:57 +08:00

785 lines
22 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
recv.c
Abstract:
routines to handle receiving data
Author:
Charlie Wickham (charlwi) 08-May-1996
Rajesh Sundaram (rajeshsu) 01-Aug-1998.
Environment:
Kernel Mode
Revision History:
--*/
#include "psched.h"
#pragma hdrstop
/* External */
/* Static */
/* Forward */ /* Generated by Emacs 19.17.0 on Thu May 09 10:34:39 1996 */
INT
ClReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
);
VOID
MpReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet
);
VOID
ClReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
);
NDIS_STATUS
MpTransferData(
OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred,
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE MiniportReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer
);
VOID
ClTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pNdisPacket,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
);
/* End Forward */
VOID
PsAllocateRecvPacket(PNDIS_STATUS Status,
PPNDIS_PACKET Packet,
PADAPTER Adapter)
{
if(!Adapter->RecvPacketPool)
{
PS_LOCK_DPC(&Adapter->Lock);
if(!Adapter->RecvPacketPool)
{
NDIS_HANDLE PoolHandle = (void *) NDIS_PACKET_POOL_TAG_FOR_PSCHED;
NdisAllocatePacketPoolEx(Status,
&PoolHandle,
MIN_PACKET_POOL_SIZE,
MAX_PACKET_POOL_SIZE,
sizeof(PS_RECV_PACKET_CONTEXT));
if(*Status != NDIS_STATUS_SUCCESS)
{
Adapter->Stats.OutOfPackets ++;
PS_UNLOCK_DPC(&Adapter->Lock);
return;
}
//
// We successfully allocated a packet pool. We can now free the Fixed Size Block pool for the packet-stack API
//
Adapter->RecvPacketPool = PoolHandle;
}
PS_UNLOCK_DPC(&Adapter->Lock);
}
NdisDprAllocatePacket(Status,
Packet,
Adapter->RecvPacketPool);
}
INT
ClReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET MpPacket
)
/*++
Routine Description:
Called by the NIC to indicate a data as an NDIS_PACKET. Make a copy of the
packet struct, switch to miniport mode and continue the packet along its way
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
NDIS_STATUS Status;
PPS_RECV_PACKET_CONTEXT ContextArea;
PNDIS_PACKET OurPacket;
BOOLEAN Remaining;
PsStructAssert( Adapter );
if(!Adapter->PsNdisHandle)
{
return 0;
}
if(Adapter->MediaType == NdisMediumWan &&
Adapter->ProtocolType == ARP_ETYPE_IP)
{
//
// Munge s-mac and d-mac so that wanarp is happy.
//
PNDIS_BUFFER pNdisBuf;
UINT Len;
PETH_HEADER pAddr;
PUSHORT id;
PPS_WAN_LINK WanLink;
pNdisBuf = MpPacket->Private.Head;
NdisQueryBuffer(pNdisBuf, &pAddr, &Len);
if(Len < sizeof(ETH_HEADER))
{
return NDIS_STATUS_FAILURE;
}
id = (PUSHORT)&pAddr->DestAddr[0];
PS_LOCK(&Adapter->Lock);
if((WanLink = (PPS_WAN_LINK)g_WanLinkTable[*id]) == 0)
{
PS_UNLOCK(&Adapter->Lock);
return NDIS_STATUS_FAILURE;
}
if(WanLink->State != WanStateOpen)
{
PS_UNLOCK(&Adapter->Lock);
return NDIS_STATUS_FAILURE;
}
PS_UNLOCK(&Adapter->Lock);
NdisMoveMemory(pAddr,
&WanLink->RecvHeader,
FIELD_OFFSET(ETH_HEADER, Type));
}
NdisIMGetCurrentPacketStack(MpPacket, &Remaining);
if(Remaining != 0)
{
Status = NDIS_GET_PACKET_STATUS(MpPacket);
// TimeStamp will always be there; no need to check //
if (!TimeStmpReceivePacket( NULL, NULL, NULL, MpPacket, Adapter->MediaType ))
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_PACKET, OURS, Adapter, MpPacket, 0);
if (TimeStmpRecvPacket) {
if (!(TimeStmpRecvPacket)(
NULL,
NULL,
NULL,
MpPacket,
Adapter->MediaType
)) {
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_PACKET, OURS, Adapter, MpPacket, 0);
}
}
NdisMIndicateReceivePacket(Adapter->PsNdisHandle, &MpPacket, 1);
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
else
{
PsAllocateRecvPacket(&Status, &OurPacket, Adapter);
if(Status == NDIS_STATUS_SUCCESS)
{
PsDbgRecv(DBG_INFO, DBG_RECEIVE, CL_RECV_PACKET, ENTER, Adapter, OurPacket, MpPacket);
//
// Save Original Packet
//
ContextArea = PS_RECV_PACKET_CONTEXT_FROM_PACKET(OurPacket);
ContextArea->OriginalPacket = MpPacket;
OurPacket->Private.Head = MpPacket->Private.Head;
OurPacket->Private.Tail = MpPacket->Private.Tail;
//
// Get the original packet (it could be the same packet as one received or a different one
// based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
// correctly at the top.
//
NDIS_SET_ORIGINAL_PACKET(OurPacket, NDIS_GET_ORIGINAL_PACKET(MpPacket));
NDIS_SET_PACKET_HEADER_SIZE(OurPacket, NDIS_GET_PACKET_HEADER_SIZE(MpPacket));
//
// Set Packet Flags
//
NdisGetPacketFlags(OurPacket) = NdisGetPacketFlags(MpPacket);
Status = NDIS_GET_PACKET_STATUS(MpPacket);
NDIS_SET_PACKET_STATUS(OurPacket, Status);
if(!(TimeStmpReceivePacket)( NULL, NULL, NULL, OurPacket, Adapter->MediaType ))
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_PACKET, OURS, Adapter, OurPacket, OurPacket);
if (TimeStmpRecvPacket) {
if (!(TimeStmpRecvPacket)(
NULL,
NULL,
NULL,
OurPacket,
Adapter->MediaType
)) {
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_PACKET, OURS, Adapter, OurPacket, OurPacket);
}
}
NdisMIndicateReceivePacket(Adapter->PsNdisHandle, &OurPacket, 1);
if (Status == NDIS_STATUS_RESOURCES)
{
NdisDprFreePacket(OurPacket);
}
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
else
{
//
// out of resources. indicate that we're not hanging onto the packet
//
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_PACKET, NO_RESOURCES,
Adapter, 0, MpPacket);
Adapter->Stats.OutOfPackets ++;
return 0;
}
}
} // ClReceivePacket
VOID
MpReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
Potentially return a packet we indicated previously to the
underlying miniport. It might be one of ours from a ProtocolReceive
indication, so we disassemble it and return the packet and its
buffers to their respective S Lists
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
PPS_RECV_PACKET_CONTEXT PktContext;
PNDIS_PACKET MyPacket;
BOOLEAN Remaining;
PsStructAssert(Adapter);
NdisIMGetCurrentPacketStack(Packet, &Remaining);
if(Remaining != 0)
{
NdisReturnPackets(&Packet, 1);
}
else
{
//
// see if the OriginalPacket field indicates that this belongs
// to someone below us and return it now
//
PktContext = PS_RECV_PACKET_CONTEXT_FROM_PACKET(Packet);
MyPacket = PktContext->OriginalPacket;
PsDbgRecv(DBG_INFO, DBG_RECEIVE, MP_RETURN_PACKET, RETURNING, Adapter, Packet, MyPacket);
NdisDprFreePacket(Packet);
NdisReturnPackets(&MyPacket, 1);
}
} // MpReturnPacket
NDIS_STATUS
ClReceiveIndication(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)
/*++
Routine Description:
Called by NIC to notify protocol of incoming data. Copy the data
into a cached packet we set up during initialization and indicate
that packet to the higher layer.
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
PNDIS_PACKET MyPacket, Packet;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PsStructAssert(Adapter);
if(!Adapter->PsNdisHandle)
{
Status = NDIS_STATUS_FAILURE;
}
else
{
do
{
//
// If this was indicated by the miniport below as a packet, then get that packet
// pointer and indicate it as a packet as well (with appropriate status).
// This way the OOB stuff is accessible to the transport above us.
//
Packet = NdisGetReceivedPacket(Adapter->LowerMpHandle, MacReceiveContext);
if (Packet != NULL)
{
BOOLEAN Remaining;
//
// Check if there are any more packet stacks left. If there is need to keep per packet information,
// then the packet stack (which is returned by the api) can be used to store that
//
NdisIMGetCurrentPacketStack(Packet, &Remaining);
if (Remaining != 0)
{
NDIS_STATUS OldPacketStatus;
if(!(TimeStmpReceivePacket)( NULL, NULL, NULL, Packet, Adapter->MediaType ))
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_IND, OURS, Adapter, Packet, Packet);
if (TimeStmpRecvPacket) {
if (!(TimeStmpRecvPacket)(
NULL,
NULL,
NULL,
Packet,
Adapter->MediaType
)) {
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_IND, OURS, Adapter, Packet, Packet);
}
}
//
// Save the old status, and set packet status to NDIS_STATUS_RESOURCES
// because we can't have the protocol above us retain the packet -- it
// can go away as soon as we return from this function.
//
OldPacketStatus = NDIS_GET_PACKET_STATUS(Packet);
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
NdisMIndicateReceivePacket(Adapter->PsNdisHandle, &Packet, 1);
//
// Restore the old Status
//
NDIS_SET_PACKET_STATUS(Packet, OldPacketStatus);
// Since we had set the packet status to NDIS_STATUS_RESOURCES, our
// ReturnPacket handler won't be called for this packet.
break;
}
//
// Get a packet off the pool and indicate that up
//
PsAllocateRecvPacket(&Status,
&MyPacket,
Adapter);
if (Status == NDIS_STATUS_SUCCESS)
{
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;
//
// Get the original packet (it could be the same packet as one received or
// a different one based on # of layered MPs) and set it on the indicated
// packet so the OOB stuff is visible correctly at the top.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
//
// Make sure the status is set to NDIS_STATUS_RESOURCES.
//
NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
if(!(TimeStmpReceivePacket)( NULL, NULL, NULL, MyPacket, Adapter->MediaType ))
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_IND, OURS, Adapter, MyPacket, MyPacket);
if (TimeStmpRecvPacket) {
if (!(TimeStmpRecvPacket)(
NULL,
NULL,
NULL,
MyPacket,
Adapter->MediaType
)) {
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_IND, OURS, Adapter, MyPacket, MyPacket);
}
}
NdisMIndicateReceivePacket(Adapter->PsNdisHandle, &MyPacket, 1);
PsAssert (NDIS_GET_PACKET_STATUS(MyPacket) == NDIS_STATUS_RESOURCES);
NdisDprFreePacket(MyPacket);
break;
}
}
//
// Fall through if the miniport below us has either not indicated a packet or we
// could not allocate one
//
Adapter->IndicateRcvComplete = TRUE;
//
// If the timestamp driver is present.
//
//
if (TimeStmpRecvIndication) {
if (!(TimeStmpRecvIndication)(
NULL,
NULL,
NULL,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize,
Adapter->IPHeaderOffset
)) {
PsDbgRecv(DBG_FAILURE, DBG_RECEIVE, CL_RECV_IND, OURS, Adapter, (PNDIS_PACKET) LookAheadBuffer, NULL);
}
}
switch (Adapter->MediaType)
{
case NdisMedium802_3:
case NdisMediumWan:
NdisMEthIndicateReceive(Adapter->PsNdisHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;
case NdisMedium802_5:
NdisMTrIndicateReceive(Adapter->PsNdisHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;
case NdisMediumFddi:
NdisMFddiIndicateReceive(Adapter->PsNdisHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;
default:
PsAssert (0);
Status = NDIS_STATUS_FAILURE;
break;
}
} while (FALSE);
}
return Status;
} // ClReceiveIndication
VOID
ClReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++
Routine Description:
Called by NIC via NdisIndicateReceiveComplete. Continue this indication
up to the higher layer
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
PsStructAssert(Adapter);
PsDbgRecv(DBG_INFO, DBG_RECEIVE, CL_RECV_COMPL, ENTER, Adapter, 0, 0);
if((Adapter->PsNdisHandle != NULL) && Adapter->IndicateRcvComplete) {
switch(Adapter->MediaType){
case NdisMediumWan:
case NdisMedium802_3:
NdisMEthIndicateReceiveComplete(Adapter->PsNdisHandle);
break;
case NdisMedium802_5:
NdisMTrIndicateReceiveComplete(Adapter->PsNdisHandle);
break;
case NdisMediumFddi:
NdisMFddiIndicateReceiveComplete(Adapter->PsNdisHandle);
break;
default:
PsAssert(FALSE);
}
}
Adapter->IndicateRcvComplete = FALSE;
} // ClReceiveComplete
NDIS_STATUS
MpTransferData(
OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred,
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE MiniportReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer
)
/*++
Routine Description:
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
NDIS_STATUS Status;
PsStructAssert(Adapter);
PsDbgRecv(DBG_INFO, DBG_RECEIVE, MP_XFER_DATA, ENTER, Adapter, 0, 0);
if(IsDeviceStateOn(Adapter) == FALSE)
{
return NDIS_STATUS_FAILURE;
}
NdisTransferData(
&Status,
Adapter->LowerMpHandle,
MiniportReceiveContext,
ByteOffset,
BytesToTransfer,
Packet,
BytesTransferred);
return Status;
} // MpTransferData
VOID
ClTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)
/*++
Routine Description:
Completion routine for NdisTransferData
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
PPS_RECV_PACKET_CONTEXT PktContext;
PsStructAssert(Adapter);
PsDbgRecv(DBG_INFO, DBG_RECEIVE, CL_XFER_COMPL, ENTER, Adapter, Packet, 0);
if(Adapter->PsNdisHandle)
{
NdisMTransferDataComplete(
Adapter->PsNdisHandle,
Packet,
Status,
BytesTransferred);
}
} // ClTransferDataComplete
UINT
ClCoReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE ProtocolVcContext,
IN PNDIS_PACKET Packet
)
{
//
// We don't do anything special in the coreceive path. Just call ClReceivePacket.
//
return ClReceivePacket(ProtocolBindingContext, Packet);
} // ClCoReceivePacket
/* end recv.c */