3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Implementation of Managed Network Protocol I/O functions.
23 #include <Library/NetLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/MemoryAllocationLib.h>
31 Validates the Mnp transmit token.
33 @param Instance Pointer to the Mnp instance context data.
34 @param Token Pointer to the transmit token to check.
36 @return The Token is valid or not.
41 IN MNP_INSTANCE_DATA
*Instance
,
42 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
45 MNP_SERVICE_DATA
*MnpServiceData
;
46 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
49 EFI_MANAGED_NETWORK_FRAGMENT_DATA
*FragmentTable
;
51 MnpServiceData
= Instance
->MnpServiceData
;
52 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
54 TxData
= Token
->Packet
.TxData
;
56 if ((Token
->Event
== NULL
) || (TxData
== NULL
) || (TxData
->FragmentCount
== 0)) {
58 // The token is invalid if the Event is NULL, or the TxData is NULL, or
59 // the fragment count is zero.
61 MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid Token.\n"));
65 if ((TxData
->DestinationAddress
!= NULL
) && (TxData
->HeaderLength
!= 0)) {
67 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
68 // is NULL (The destination address is already put into the packet).
70 MNP_DEBUG_WARN (("MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
75 FragmentTable
= TxData
->FragmentTable
;
76 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
78 if ((FragmentTable
[Index
].FragmentLength
== 0) || (FragmentTable
[Index
].FragmentBuffer
== NULL
)) {
80 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
82 MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
86 TotalLength
+= FragmentTable
[Index
].FragmentLength
;
89 if ((TxData
->DestinationAddress
== NULL
) && (FragmentTable
[0].FragmentLength
< TxData
->HeaderLength
)) {
91 // Media header is split between fragments.
96 if (TotalLength
!= (TxData
->DataLength
+ TxData
->HeaderLength
)) {
98 // The length calculated from the fragment information doesn't equal to the
99 // sum of the DataLength and the HeaderLength.
101 MNP_DEBUG_WARN (("MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
105 if (TxData
->DataLength
> MnpServiceData
->Mtu
) {
107 // The total length is larger than the MTU.
109 MNP_DEBUG_WARN (("MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
118 Build the packet to transmit from the TxData passed in.
120 @param MnpServiceData Pointer to the mnp service context data.
121 @param TxData Pointer to the transmit data containing the
122 information to build the packet.
123 @param PktBuf Pointer to record the address of the packet.
124 @param PktLen Pointer to a UINT32 variable used to record the
132 IN MNP_SERVICE_DATA
*MnpServiceData
,
133 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
138 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
142 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
144 // Media header is in FragmentTable and there is only one fragment,
145 // use fragment buffer directly.
147 *PktBuf
= TxData
->FragmentTable
[0].FragmentBuffer
;
148 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
151 // Either media header isn't in FragmentTable or there is more than
152 // one fragment, copy the data into the packet buffer. Reserve the
153 // media header space if necessary.
155 SnpMode
= MnpServiceData
->Snp
->Mode
;
156 DstPos
= MnpServiceData
->TxBuf
;
159 if (TxData
->DestinationAddress
!= NULL
) {
161 // If dest address is not NULL, move DstPos to reserve space for the
162 // media header. Add the media header length to buflen.
164 DstPos
+= SnpMode
->MediaHeaderSize
;
165 *PktLen
+= SnpMode
->MediaHeaderSize
;
168 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
174 TxData
->FragmentTable
[Index
].FragmentBuffer
,
175 TxData
->FragmentTable
[Index
].FragmentLength
177 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
181 // Set the buffer pointer and the buffer length.
183 *PktBuf
= MnpServiceData
->TxBuf
;
184 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
190 Synchronously send out the packet.
192 @param MnpServiceData Pointer to the mnp service context data.
193 @param Packet Pointer to the pakcet buffer.
194 @param Length The length of the packet.
195 @param Token Pointer to the token the packet generated from.
197 @retval EFI_SUCCESS The packet is sent out.
198 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
199 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
204 IN MNP_SERVICE_DATA
*MnpServiceData
,
207 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
211 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
212 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
216 Snp
= MnpServiceData
->Snp
;
217 TxData
= Token
->Packet
.TxData
;
219 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
222 // Start the timeout event.
224 Status
= gBS
->SetTimer (
225 MnpServiceData
->TxTimeoutEvent
,
229 if (EFI_ERROR (Status
)) {
236 // Transmit the packet through SNP.
238 Status
= Snp
->Transmit (
243 TxData
->SourceAddress
,
244 TxData
->DestinationAddress
,
245 &TxData
->ProtocolType
247 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
249 Status
= EFI_DEVICE_ERROR
;
254 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
255 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
256 // Both need to sync SNP.
261 // Get the recycled transmit buffer status.
263 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
265 if (!EFI_ERROR (gBS
->CheckEvent (MnpServiceData
->TxTimeoutEvent
))) {
267 Status
= EFI_TIMEOUT
;
270 } while (TxBuf
== NULL
);
272 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
277 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
280 MnpServiceData
->TxTimeoutEvent
,
288 // Cancel the timer event.
290 gBS
->SetTimer (MnpServiceData
->TxTimeoutEvent
, TimerCancel
, 0);
294 Token
->Status
= Status
;
295 gBS
->SignalEvent (Token
->Event
);
302 Try to deliver the received packet to the instance.
304 @param Instance Pointer to the mnp instance context data.
306 @retval EFI_SUCCESS The received packet is delivered, or there is no
307 packet to deliver, or there is no available receive
309 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
313 MnpInstanceDeliverPacket (
314 IN MNP_INSTANCE_DATA
*Instance
317 MNP_SERVICE_DATA
*MnpServiceData
;
318 MNP_RXDATA_WRAP
*RxDataWrap
;
320 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
321 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
322 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
324 MnpServiceData
= Instance
->MnpServiceData
;
325 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
327 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || NetListIsEmpty (&Instance
->RcvdPacketQueue
)) {
329 // No pending received data or no available receive token, return.
334 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
336 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
337 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
339 // There are other instances share this Nbuf, duplicate to get a
340 // copy to allow the instance to do R/W operations.
342 DupNbuf
= MnpAllocNbuf (MnpServiceData
);
343 if (DupNbuf
== NULL
) {
344 MNP_DEBUG_WARN (("MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
346 return EFI_OUT_OF_RESOURCES
;
350 // Duplicate the net buffer.
352 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
353 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
354 RxDataWrap
->Nbuf
= DupNbuf
;
358 // All resources are OK, remove the packet from the queue.
360 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
361 Instance
->RcvdPacketQueueSize
--;
363 RxData
= &RxDataWrap
->RxData
;
364 SnpMode
= MnpServiceData
->Snp
->Mode
;
367 // Set all the buffer pointers.
369 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
370 RxData
->DestinationAddress
= RxData
->MediaHeader
;
371 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
372 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
375 // Insert this RxDataWrap into the delivered queue.
377 NetListInsertTail (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
380 // Get the receive token from the RxTokenMap.
382 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
385 // Signal this token's event.
387 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
388 RxToken
->Status
= EFI_SUCCESS
;
389 gBS
->SignalEvent (RxToken
->Event
);
396 Deliver the received packet for the instances belonging to the MnpServiceData.
398 @param MnpServiceData Pointer to the mnp service context data.
406 IN MNP_SERVICE_DATA
*MnpServiceData
409 NET_LIST_ENTRY
*Entry
;
410 MNP_INSTANCE_DATA
*Instance
;
412 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
414 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
415 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
416 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
419 // Try to deliver packet for this instance.
421 MnpInstanceDeliverPacket (Instance
);
427 Recycle the RxData and other resources used to hold and deliver the received
430 @param Event The event this notify function registered to.
431 @param Context Pointer to the context data registerd to the Event.
443 MNP_RXDATA_WRAP
*RxDataWrap
;
444 MNP_SERVICE_DATA
*MnpServiceData
;
446 ASSERT (Context
!= NULL
);
448 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
449 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
451 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
453 MnpServiceData
= RxDataWrap
->Instance
->MnpServiceData
;
454 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
459 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
460 RxDataWrap
->Nbuf
= NULL
;
463 // Close the recycle event.
465 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
468 // Remove this Wrap entry from the list.
470 NetListRemoveEntry (&RxDataWrap
->WrapEntry
);
472 NetFreePool (RxDataWrap
);
477 Queue the received packet into instance's receive queue.
479 @param Instance Pointer to the mnp instance context data.
480 @param RxDataWrap Pointer to the Wrap structure containing the
481 received data and other information.
489 IN MNP_INSTANCE_DATA
*Instance
,
490 IN MNP_RXDATA_WRAP
*RxDataWrap
493 MNP_RXDATA_WRAP
*OldRxDataWrap
;
495 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
498 // Check the queue size. If it exceeds the limit, drop one packet
501 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
503 MNP_DEBUG_WARN (("MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
506 // Get the oldest packet.
508 OldRxDataWrap
= NET_LIST_HEAD (
509 &Instance
->RcvdPacketQueue
,
515 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
517 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
518 Instance
->RcvdPacketQueueSize
--;
522 // Update the timeout tick using the configured parameter.
524 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
527 // Insert this Wrap into the instance queue.
529 NetListInsertTail (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
530 Instance
->RcvdPacketQueueSize
++;
535 Match the received packet with the instance receive filters.
537 @param Instance Pointer to the mnp instance context data.
538 @param RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
539 @param GroupAddress Pointer to the GroupAddress, the GroupAddress is
540 non-NULL and it contains the destination multicast
541 mac address of the received packet if the packet
542 destinated to a multicast mac address.
543 @param PktAttr The received packets attribute.
545 @return The received packet matches the instance's receive filters or not.
551 IN MNP_INSTANCE_DATA
*Instance
,
552 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
553 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
557 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
558 NET_LIST_ENTRY
*Entry
;
559 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
561 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
563 ConfigData
= &Instance
->ConfigData
;
565 if (ConfigData
->EnablePromiscuousReceive
) {
567 // Always match if this instance is configured to be promiscuous.
572 // Check the protocol type.
574 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
579 // The protocol type is matched, check receive filter, include unicast and broadcast.
581 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
586 // Check multicast addresses.
588 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
590 ASSERT (GroupAddress
!= NULL
);
592 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
594 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
595 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
597 // The instance is configured to receiveing packets destinated to this
598 // multicast address.
613 Analyse the received packets.
615 @param MnpServiceData Pointer to the mnp service context data.
616 @param Nbuf Pointer to the net buffer holding the received
618 @param RxData Pointer to the buffer used to save the analysed
619 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
620 @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
621 pass out the address of the multicast address the
622 received packet destinated to.
623 @param PktAttr Pointer to the buffer used to save the analysed
632 IN MNP_SERVICE_DATA
*MnpServiceData
,
634 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
635 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
639 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
641 NET_LIST_ENTRY
*Entry
;
643 SnpMode
= MnpServiceData
->Snp
->Mode
;
646 // Get the packet buffer.
648 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
649 ASSERT (BufPtr
!= NULL
);
652 // Set the initial values.
654 RxData
->BroadcastFlag
= FALSE
;
655 RxData
->MulticastFlag
= FALSE
;
656 RxData
->PromiscuousFlag
= FALSE
;
657 *PktAttr
= UNICAST_PACKET
;
659 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
661 // This packet isn't destinated to our current mac address, it't not unicast.
665 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
669 RxData
->BroadcastFlag
= TRUE
;
670 *PktAttr
= BROADCAST_PACKET
;
671 } else if ((*BufPtr
& 0x01) == 0x1) {
673 // It's multicast, try to match the multicast filters.
675 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->GroupAddressList
) {
677 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
678 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
679 RxData
->MulticastFlag
= TRUE
;
684 if (!RxData
->MulticastFlag
) {
686 // No match, set GroupAddress to NULL. This multicast packet must
687 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
689 *GroupAddress
= NULL
;
690 RxData
->PromiscuousFlag
= TRUE
;
692 if (MnpServiceData
->PromiscuousCount
== 0) {
694 // Skip the below code, there is no receiver of this packet.
700 RxData
->PromiscuousFlag
= TRUE
;
704 NetZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
707 // Fill the common parts of RxData.
709 RxData
->PacketLength
= Nbuf
->TotalSize
;
710 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
711 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
712 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
713 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
720 @param Instance Pointer to the mnp instance context data.
721 @param RxData Pointer to the receive data to wrap.
723 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
729 IN MNP_INSTANCE_DATA
*Instance
,
730 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
734 MNP_RXDATA_WRAP
*RxDataWrap
;
739 RxDataWrap
= NetAllocatePool (sizeof (MNP_RXDATA_WRAP
));
740 if (RxDataWrap
== NULL
) {
741 MNP_DEBUG_ERROR (("MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
745 RxDataWrap
->Instance
= Instance
;
748 // Fill the RxData in RxDataWrap,
750 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
753 // Create the recycle event.
755 Status
= gBS
->CreateEvent (
760 &RxDataWrap
->RxData
.RecycleEvent
762 if (EFI_ERROR (Status
)) {
764 MNP_DEBUG_ERROR (("MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
765 NetFreePool (RxDataWrap
);
774 Enqueue the received the packets to the instances belonging to the
777 @param MnpServiceData Pointer to the mnp service context data.
778 @param Nbuf Pointer to the net buffer representing the received
787 IN MNP_SERVICE_DATA
*MnpServiceData
,
791 NET_LIST_ENTRY
*Entry
;
792 MNP_INSTANCE_DATA
*Instance
;
793 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
795 MNP_GROUP_ADDRESS
*GroupAddress
;
796 MNP_RXDATA_WRAP
*RxDataWrap
;
799 // First, analyse the packet header.
801 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
803 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->PromiscuousCount
== 0)) {
805 // No receivers, no more action need.
811 // Iterate the children to find match.
813 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
815 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
816 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
818 if (!Instance
->Configured
) {
823 // Check the packet against the instance receive filters.
825 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
830 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
831 if (RxDataWrap
== NULL
) {
836 // Associate RxDataWrap with Nbuf and increase the RefCnt.
838 RxDataWrap
->Nbuf
= Nbuf
;
839 NET_GET_REF (RxDataWrap
->Nbuf
);
842 // Queue the packet into the instance queue.
844 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
851 Try to receive a packet and deliver it.
853 @param MnpServiceData Pointer to the mnp service context data.
855 @retval EFI_SUCCESS add return value to function comment
856 @retval EFI_NOT_STARTED The simple network protocol is not started.
857 @retval EFI_NOT_READY No packet received.
858 @retval EFI_DEVICE_ERROR An unexpected error occurs.
863 IN MNP_SERVICE_DATA
*MnpServiceData
867 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
874 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
876 Snp
= MnpServiceData
->Snp
;
877 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
879 // The simple network protocol is not started.
881 return EFI_NOT_STARTED
;
884 if (NetListIsEmpty (&MnpServiceData
->ChildrenList
)) {
886 // There is no child, no need to receive packets.
891 if (MnpServiceData
->RxNbufCache
== NULL
) {
893 // Try to get a new buffer as there may be buffers recycled.
895 MnpServiceData
->RxNbufCache
= MnpAllocNbuf (MnpServiceData
);
897 if (MnpServiceData
->RxNbufCache
== NULL
) {
899 // No availabe buffer in the buffer pool.
901 return EFI_DEVICE_ERROR
;
905 MnpServiceData
->RxNbufCache
,
906 MnpServiceData
->BufferLength
,
911 Nbuf
= MnpServiceData
->RxNbufCache
;
912 BufLen
= Nbuf
->TotalSize
;
913 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
914 ASSERT (BufPtr
!= NULL
);
917 // Receive packet through Snp.
919 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
920 if (EFI_ERROR (Status
)) {
923 if (Status
!= EFI_NOT_READY
) {
924 MNP_DEBUG_ERROR (("MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
934 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
937 ("MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
941 return EFI_DEVICE_ERROR
;
945 if (Nbuf
->TotalSize
!= BufLen
) {
947 // Trim the packet from tail.
949 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
950 ASSERT (Nbuf
->TotalSize
== BufLen
);
954 // Enqueue the packet to the matched instances.
956 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
958 if (Nbuf
->RefCnt
> 2) {
960 // RefCnt > 2 indicates there is at least one receiver of this packet.
961 // Free the current RxNbufCache and allocate a new one.
963 MnpFreeNbuf (MnpServiceData
, Nbuf
);
965 Nbuf
= MnpAllocNbuf (MnpServiceData
);
966 MnpServiceData
->RxNbufCache
= Nbuf
;
968 MNP_DEBUG_ERROR (("MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
969 return EFI_DEVICE_ERROR
;
972 NetbufAllocSpace (Nbuf
, MnpServiceData
->BufferLength
, NET_BUF_TAIL
);
975 // No receiver for this packet.
978 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
984 // Deliver the queued packets.
986 MnpDeliverPacket (MnpServiceData
);
990 ASSERT (Nbuf
->TotalSize
== MnpServiceData
->BufferLength
);
997 Remove the received packets if timeout occurs.
999 @param Event The event this notify function registered to.
1000 @param Context Pointer to the context data registered to the
1008 MnpCheckPacketTimeout (
1013 MNP_SERVICE_DATA
*MnpServiceData
;
1014 NET_LIST_ENTRY
*Entry
;
1015 NET_LIST_ENTRY
*RxEntry
;
1016 NET_LIST_ENTRY
*NextEntry
;
1017 MNP_INSTANCE_DATA
*Instance
;
1018 MNP_RXDATA_WRAP
*RxDataWrap
;
1021 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1022 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1024 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1026 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1027 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1029 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1031 // This instance is not configured or there is no receive time out,
1032 // just skip to the next instance.
1037 OldTpl
= NET_RAISE_TPL (NET_TPL_RECYCLE
);
1039 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1041 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1043 if (RxDataWrap
->TimeoutTick
>= MNP_TIMEOUT_CHECK_INTERVAL
) {
1045 RxDataWrap
->TimeoutTick
-= MNP_TIMEOUT_CHECK_INTERVAL
;
1048 // Drop the timeout packet.
1050 MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Received packet timeout.\n"));
1051 MnpRecycleRxData (NULL
, RxDataWrap
);
1052 Instance
->RcvdPacketQueueSize
--;
1056 NET_RESTORE_TPL (OldTpl
);
1062 Poll to receive the packets from Snp. This function is either called by upperlayer
1063 protocols/applications or the system poll timer notify mechanism.
1065 @param Event The event this notify function registered to.
1066 @param Context Pointer to the context data registered to the
1079 MNP_SERVICE_DATA
*MnpServiceData
;
1081 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1082 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1085 // Try to receive packets from Snp.
1087 MnpReceivePacket (MnpServiceData
);