2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2007, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/NetLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/MemoryAllocationLib.h>
23 Validates the Mnp transmit token.
25 @param Instance Pointer to the Mnp instance context data.
26 @param Token Pointer to the transmit token to check.
28 @return The Token is valid or not.
33 IN MNP_INSTANCE_DATA
*Instance
,
34 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
37 MNP_SERVICE_DATA
*MnpServiceData
;
38 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
41 EFI_MANAGED_NETWORK_FRAGMENT_DATA
*FragmentTable
;
43 MnpServiceData
= Instance
->MnpServiceData
;
44 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
46 TxData
= Token
->Packet
.TxData
;
48 if ((Token
->Event
== NULL
) || (TxData
== NULL
) || (TxData
->FragmentCount
== 0)) {
50 // The token is invalid if the Event is NULL, or the TxData is NULL, or
51 // the fragment count is zero.
53 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid Token.\n"));
57 if ((TxData
->DestinationAddress
!= NULL
) && (TxData
->HeaderLength
!= 0)) {
59 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
60 // is NULL (The destination address is already put into the packet).
62 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
67 FragmentTable
= TxData
->FragmentTable
;
68 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
70 if ((FragmentTable
[Index
].FragmentLength
== 0) || (FragmentTable
[Index
].FragmentBuffer
== NULL
)) {
72 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
74 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
78 TotalLength
+= FragmentTable
[Index
].FragmentLength
;
81 if ((TxData
->DestinationAddress
== NULL
) && (FragmentTable
[0].FragmentLength
< TxData
->HeaderLength
)) {
83 // Media header is split between fragments.
88 if (TotalLength
!= (TxData
->DataLength
+ TxData
->HeaderLength
)) {
90 // The length calculated from the fragment information doesn't equal to the
91 // sum of the DataLength and the HeaderLength.
93 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
97 if (TxData
->DataLength
> MnpServiceData
->Mtu
) {
99 // The total length is larger than the MTU.
101 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
110 Build the packet to transmit from the TxData passed in.
112 @param MnpServiceData Pointer to the mnp service context data.
113 @param TxData Pointer to the transmit data containing the
114 information to build the packet.
115 @param PktBuf Pointer to record the address of the packet.
116 @param PktLen Pointer to a UINT32 variable used to record the
122 IN MNP_SERVICE_DATA
*MnpServiceData
,
123 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
128 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
132 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
134 // Media header is in FragmentTable and there is only one fragment,
135 // use fragment buffer directly.
137 *PktBuf
= TxData
->FragmentTable
[0].FragmentBuffer
;
138 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
141 // Either media header isn't in FragmentTable or there is more than
142 // one fragment, copy the data into the packet buffer. Reserve the
143 // media header space if necessary.
145 SnpMode
= MnpServiceData
->Snp
->Mode
;
146 DstPos
= MnpServiceData
->TxBuf
;
149 if (TxData
->DestinationAddress
!= NULL
) {
151 // If dest address is not NULL, move DstPos to reserve space for the
152 // media header. Add the media header length to buflen.
154 DstPos
+= SnpMode
->MediaHeaderSize
;
155 *PktLen
+= SnpMode
->MediaHeaderSize
;
158 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
164 TxData
->FragmentTable
[Index
].FragmentBuffer
,
165 TxData
->FragmentTable
[Index
].FragmentLength
167 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
171 // Set the buffer pointer and the buffer length.
173 *PktBuf
= MnpServiceData
->TxBuf
;
174 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
180 Synchronously send out the packet.
182 @param MnpServiceData Pointer to the mnp service context data.
183 @param Packet Pointer to the pakcet buffer.
184 @param Length The length of the packet.
185 @param Token Pointer to the token the packet generated from.
187 @retval EFI_SUCCESS The packet is sent out.
188 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
189 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
194 IN MNP_SERVICE_DATA
*MnpServiceData
,
197 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
201 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
202 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
206 Snp
= MnpServiceData
->Snp
;
207 TxData
= Token
->Packet
.TxData
;
209 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
212 // Start the timeout event.
214 Status
= gBS
->SetTimer (
215 MnpServiceData
->TxTimeoutEvent
,
219 if (EFI_ERROR (Status
)) {
226 // Transmit the packet through SNP.
228 Status
= Snp
->Transmit (
233 TxData
->SourceAddress
,
234 TxData
->DestinationAddress
,
235 &TxData
->ProtocolType
237 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
239 Status
= EFI_DEVICE_ERROR
;
244 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
245 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
246 // Both need to sync SNP.
251 // Get the recycled transmit buffer status.
253 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
255 if (!EFI_ERROR (gBS
->CheckEvent (MnpServiceData
->TxTimeoutEvent
))) {
257 Status
= EFI_TIMEOUT
;
260 } while (TxBuf
== NULL
);
262 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
267 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
270 MnpServiceData
->TxTimeoutEvent
,
278 // Cancel the timer event.
280 gBS
->SetTimer (MnpServiceData
->TxTimeoutEvent
, TimerCancel
, 0);
284 Token
->Status
= Status
;
285 gBS
->SignalEvent (Token
->Event
);
288 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
290 NetLibDispatchDpc ();
297 Try to deliver the received packet to the instance.
299 @param Instance Pointer to the mnp instance context data.
301 @retval EFI_SUCCESS The received packet is delivered, or there is no
302 packet to deliver, or there is no available receive
304 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
308 MnpInstanceDeliverPacket (
309 IN MNP_INSTANCE_DATA
*Instance
312 MNP_SERVICE_DATA
*MnpServiceData
;
313 MNP_RXDATA_WRAP
*RxDataWrap
;
315 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
316 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
317 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
319 MnpServiceData
= Instance
->MnpServiceData
;
320 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
322 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
324 // No pending received data or no available receive token, return.
329 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
331 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
332 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
334 // There are other instances share this Nbuf, duplicate to get a
335 // copy to allow the instance to do R/W operations.
337 DupNbuf
= MnpAllocNbuf (MnpServiceData
);
338 if (DupNbuf
== NULL
) {
339 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
341 return EFI_OUT_OF_RESOURCES
;
345 // Duplicate the net buffer.
347 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
348 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
349 RxDataWrap
->Nbuf
= DupNbuf
;
353 // All resources are OK, remove the packet from the queue.
355 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
356 Instance
->RcvdPacketQueueSize
--;
358 RxData
= &RxDataWrap
->RxData
;
359 SnpMode
= MnpServiceData
->Snp
->Mode
;
362 // Set all the buffer pointers.
364 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
365 RxData
->DestinationAddress
= RxData
->MediaHeader
;
366 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
367 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
370 // Insert this RxDataWrap into the delivered queue.
372 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
375 // Get the receive token from the RxTokenMap.
377 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
380 // Signal this token's event.
382 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
383 RxToken
->Status
= EFI_SUCCESS
;
384 gBS
->SignalEvent (RxToken
->Event
);
391 Deliver the received packet for the instances belonging to the MnpServiceData.
393 @param MnpServiceData Pointer to the mnp service context data.
400 IN MNP_SERVICE_DATA
*MnpServiceData
404 MNP_INSTANCE_DATA
*Instance
;
406 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
408 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
409 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
410 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
413 // Try to deliver packet for this instance.
415 MnpInstanceDeliverPacket (Instance
);
421 Recycle the RxData and other resources used to hold and deliver the received
424 @param Event The event this notify function registered to.
425 @param Context Pointer to the context data registerd to the Event.
435 MNP_RXDATA_WRAP
*RxDataWrap
;
436 MNP_SERVICE_DATA
*MnpServiceData
;
438 ASSERT (Context
!= NULL
);
440 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
441 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
443 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
445 MnpServiceData
= RxDataWrap
->Instance
->MnpServiceData
;
446 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
451 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
452 RxDataWrap
->Nbuf
= NULL
;
455 // Close the recycle event.
457 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
460 // Remove this Wrap entry from the list.
462 RemoveEntryList (&RxDataWrap
->WrapEntry
);
464 gBS
->FreePool (RxDataWrap
);
469 Queue the received packet into instance's receive queue.
471 @param Instance Pointer to the mnp instance context data.
472 @param RxDataWrap Pointer to the Wrap structure containing the
473 received data and other information.
480 IN MNP_INSTANCE_DATA
*Instance
,
481 IN MNP_RXDATA_WRAP
*RxDataWrap
484 MNP_RXDATA_WRAP
*OldRxDataWrap
;
486 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
489 // Check the queue size. If it exceeds the limit, drop one packet
492 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
494 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
497 // Get the oldest packet.
499 OldRxDataWrap
= NET_LIST_HEAD (
500 &Instance
->RcvdPacketQueue
,
506 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
508 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
509 Instance
->RcvdPacketQueueSize
--;
513 // Update the timeout tick using the configured parameter.
515 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
518 // Insert this Wrap into the instance queue.
520 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
521 Instance
->RcvdPacketQueueSize
++;
526 Match the received packet with the instance receive filters.
528 @param Instance Pointer to the mnp instance context data.
529 @param RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
530 @param GroupAddress Pointer to the GroupAddress, the GroupAddress is
531 non-NULL and it contains the destination multicast
532 mac address of the received packet if the packet
533 destinated to a multicast mac address.
534 @param PktAttr The received packets attribute.
536 @return The received packet matches the instance's receive filters or not.
541 IN MNP_INSTANCE_DATA
*Instance
,
542 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
543 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
547 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
549 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
551 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
553 ConfigData
= &Instance
->ConfigData
;
556 // Check the protocol type.
558 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
562 if (ConfigData
->EnablePromiscuousReceive
) {
564 // Always match if this instance is configured to be promiscuous.
570 // The protocol type is matched, check receive filter, include unicast and broadcast.
572 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
577 // Check multicast addresses.
579 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
581 ASSERT (GroupAddress
!= NULL
);
583 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
585 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
586 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
588 // The instance is configured to receiveing packets destinated to this
589 // multicast address.
604 Analyse the received packets.
606 @param MnpServiceData Pointer to the mnp service context data.
607 @param Nbuf Pointer to the net buffer holding the received
609 @param RxData Pointer to the buffer used to save the analysed
610 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
611 @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
612 pass out the address of the multicast address the
613 received packet destinated to.
614 @param PktAttr Pointer to the buffer used to save the analysed
622 IN MNP_SERVICE_DATA
*MnpServiceData
,
624 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
625 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
629 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
633 SnpMode
= MnpServiceData
->Snp
->Mode
;
636 // Get the packet buffer.
638 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
639 ASSERT (BufPtr
!= NULL
);
642 // Set the initial values.
644 RxData
->BroadcastFlag
= FALSE
;
645 RxData
->MulticastFlag
= FALSE
;
646 RxData
->PromiscuousFlag
= FALSE
;
647 *PktAttr
= UNICAST_PACKET
;
649 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
651 // This packet isn't destinated to our current mac address, it't not unicast.
655 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
659 RxData
->BroadcastFlag
= TRUE
;
660 *PktAttr
= BROADCAST_PACKET
;
661 } else if ((*BufPtr
& 0x01) == 0x1) {
663 // It's multicast, try to match the multicast filters.
665 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->GroupAddressList
) {
667 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
668 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
669 RxData
->MulticastFlag
= TRUE
;
674 if (!RxData
->MulticastFlag
) {
676 // No match, set GroupAddress to NULL. This multicast packet must
677 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
679 *GroupAddress
= NULL
;
680 RxData
->PromiscuousFlag
= TRUE
;
682 if (MnpServiceData
->PromiscuousCount
== 0) {
684 // Skip the below code, there is no receiver of this packet.
690 RxData
->PromiscuousFlag
= TRUE
;
694 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
697 // Fill the common parts of RxData.
699 RxData
->PacketLength
= Nbuf
->TotalSize
;
700 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
701 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
702 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
703 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
710 @param Instance Pointer to the mnp instance context data.
711 @param RxData Pointer to the receive data to wrap.
713 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
718 IN MNP_INSTANCE_DATA
*Instance
,
719 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
723 MNP_RXDATA_WRAP
*RxDataWrap
;
728 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
729 if (RxDataWrap
== NULL
) {
730 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
734 RxDataWrap
->Instance
= Instance
;
737 // Fill the RxData in RxDataWrap,
739 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
742 // Create the recycle event.
744 Status
= gBS
->CreateEvent (
749 &RxDataWrap
->RxData
.RecycleEvent
751 if (EFI_ERROR (Status
)) {
753 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
754 gBS
->FreePool (RxDataWrap
);
763 Enqueue the received the packets to the instances belonging to the
766 @param MnpServiceData Pointer to the mnp service context data.
767 @param Nbuf Pointer to the net buffer representing the received
775 IN MNP_SERVICE_DATA
*MnpServiceData
,
780 MNP_INSTANCE_DATA
*Instance
;
781 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
783 MNP_GROUP_ADDRESS
*GroupAddress
;
784 MNP_RXDATA_WRAP
*RxDataWrap
;
789 // First, analyse the packet header.
791 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
793 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->PromiscuousCount
== 0)) {
795 // No receivers, no more action need.
801 // Iterate the children to find match.
803 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
805 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
806 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
808 if (!Instance
->Configured
) {
813 // Check the packet against the instance receive filters.
815 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
820 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
821 if (RxDataWrap
== NULL
) {
826 // Associate RxDataWrap with Nbuf and increase the RefCnt.
828 RxDataWrap
->Nbuf
= Nbuf
;
829 NET_GET_REF (RxDataWrap
->Nbuf
);
832 // Queue the packet into the instance queue.
834 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
841 Try to receive a packet and deliver it.
843 @param MnpServiceData Pointer to the mnp service context data.
845 @retval EFI_SUCCESS add return value to function comment
846 @retval EFI_NOT_STARTED The simple network protocol is not started.
847 @retval EFI_NOT_READY No packet received.
848 @retval EFI_DEVICE_ERROR An unexpected error occurs.
853 IN MNP_SERVICE_DATA
*MnpServiceData
857 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
864 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
866 Snp
= MnpServiceData
->Snp
;
867 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
869 // The simple network protocol is not started.
871 return EFI_NOT_STARTED
;
874 if (IsListEmpty (&MnpServiceData
->ChildrenList
)) {
876 // There is no child, no need to receive packets.
881 if (MnpServiceData
->RxNbufCache
== NULL
) {
883 // Try to get a new buffer as there may be buffers recycled.
885 MnpServiceData
->RxNbufCache
= MnpAllocNbuf (MnpServiceData
);
887 if (MnpServiceData
->RxNbufCache
== NULL
) {
889 // No availabe buffer in the buffer pool.
891 return EFI_DEVICE_ERROR
;
895 MnpServiceData
->RxNbufCache
,
896 MnpServiceData
->BufferLength
,
901 Nbuf
= MnpServiceData
->RxNbufCache
;
902 BufLen
= Nbuf
->TotalSize
;
903 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
904 ASSERT (BufPtr
!= NULL
);
907 // Receive packet through Snp.
909 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
910 if (EFI_ERROR (Status
)) {
913 if (Status
!= EFI_NOT_READY
) {
914 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
924 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
928 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
932 return EFI_DEVICE_ERROR
;
936 if (Nbuf
->TotalSize
!= BufLen
) {
938 // Trim the packet from tail.
940 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
941 ASSERT (Nbuf
->TotalSize
== BufLen
);
945 // Enqueue the packet to the matched instances.
947 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
949 if (Nbuf
->RefCnt
> 2) {
951 // RefCnt > 2 indicates there is at least one receiver of this packet.
952 // Free the current RxNbufCache and allocate a new one.
954 MnpFreeNbuf (MnpServiceData
, Nbuf
);
956 Nbuf
= MnpAllocNbuf (MnpServiceData
);
957 MnpServiceData
->RxNbufCache
= Nbuf
;
959 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
960 return EFI_DEVICE_ERROR
;
963 NetbufAllocSpace (Nbuf
, MnpServiceData
->BufferLength
, NET_BUF_TAIL
);
966 // No receiver for this packet.
969 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
975 // Deliver the queued packets.
977 MnpDeliverPacket (MnpServiceData
);
980 // Dispatch the DPC queued by the NotifyFunction of rx token's events.
982 NetLibDispatchDpc ();
986 ASSERT (Nbuf
->TotalSize
== MnpServiceData
->BufferLength
);
993 Remove the received packets if timeout occurs.
995 @param Event The event this notify function registered to.
996 @param Context Pointer to the context data registered to the
1002 MnpCheckPacketTimeout (
1007 MNP_SERVICE_DATA
*MnpServiceData
;
1009 LIST_ENTRY
*RxEntry
;
1010 LIST_ENTRY
*NextEntry
;
1011 MNP_INSTANCE_DATA
*Instance
;
1012 MNP_RXDATA_WRAP
*RxDataWrap
;
1015 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1016 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1018 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1020 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1021 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1023 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1025 // This instance is not configured or there is no receive time out,
1026 // just skip to the next instance.
1031 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1033 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1035 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1038 // TimeoutTick unit is ms, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1040 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1042 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1045 // Drop the timeout packet.
1047 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1048 MnpRecycleRxData (NULL
, RxDataWrap
);
1049 Instance
->RcvdPacketQueueSize
--;
1053 gBS
->RestoreTPL (OldTpl
);
1059 Poll to receive the packets from Snp. This function is either called by upperlayer
1060 protocols/applications or the system poll timer notify mechanism.
1062 @param Event The event this notify function registered to.
1063 @param Context Pointer to the context data registered to the
1074 MNP_SERVICE_DATA
*MnpServiceData
;
1076 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1077 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1080 // Try to receive packets from Snp.
1082 MnpReceivePacket (MnpServiceData
);
1084 NetLibDispatchDpc ();