/*++ 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 */