2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2007, Intel Corporation.<BR>
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Library/NetLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/MemoryAllocationLib.h>
24 Validates the Mnp transmit token.
26 @param[in] Instance Pointer to the Mnp instance context data.
27 @param[in] Token Pointer to the transmit token to check.
29 @return The Token is valid or not.
34 IN MNP_INSTANCE_DATA
*Instance
,
35 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
38 MNP_SERVICE_DATA
*MnpServiceData
;
39 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
42 EFI_MANAGED_NETWORK_FRAGMENT_DATA
*FragmentTable
;
44 MnpServiceData
= Instance
->MnpServiceData
;
45 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
47 TxData
= Token
->Packet
.TxData
;
49 if ((Token
->Event
== NULL
) || (TxData
== NULL
) || (TxData
->FragmentCount
== 0)) {
51 // The token is invalid if the Event is NULL, or the TxData is NULL, or
52 // the fragment count is zero.
54 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid Token.\n"));
58 if ((TxData
->DestinationAddress
!= NULL
) && (TxData
->HeaderLength
!= 0)) {
60 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
61 // is NULL (The destination address is already put into the packet).
63 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
68 FragmentTable
= TxData
->FragmentTable
;
69 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
71 if ((FragmentTable
[Index
].FragmentLength
== 0) || (FragmentTable
[Index
].FragmentBuffer
== NULL
)) {
73 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
75 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
79 TotalLength
+= FragmentTable
[Index
].FragmentLength
;
82 if ((TxData
->DestinationAddress
== NULL
) && (FragmentTable
[0].FragmentLength
< TxData
->HeaderLength
)) {
84 // Media header is split between fragments.
89 if (TotalLength
!= (TxData
->DataLength
+ TxData
->HeaderLength
)) {
91 // The length calculated from the fragment information doesn't equal to the
92 // sum of the DataLength and the HeaderLength.
94 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
98 if (TxData
->DataLength
> MnpServiceData
->Mtu
) {
100 // The total length is larger than the MTU.
102 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
111 Build the packet to transmit from the TxData passed in.
113 @param MnpServiceData Pointer to the mnp service context data.
114 @param TxData Pointer to the transmit data containing the
115 information to build the packet.
116 @param PktBuf Pointer to record the address of the packet.
117 @param PktLen Pointer to a UINT32 variable used to record the
123 IN MNP_SERVICE_DATA
*MnpServiceData
,
124 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
129 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
133 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
135 // Media header is in FragmentTable and there is only one fragment,
136 // use fragment buffer directly.
138 *PktBuf
= TxData
->FragmentTable
[0].FragmentBuffer
;
139 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
142 // Either media header isn't in FragmentTable or there is more than
143 // one fragment, copy the data into the packet buffer. Reserve the
144 // media header space if necessary.
146 SnpMode
= MnpServiceData
->Snp
->Mode
;
147 DstPos
= MnpServiceData
->TxBuf
;
150 if (TxData
->DestinationAddress
!= NULL
) {
152 // If dest address is not NULL, move DstPos to reserve space for the
153 // media header. Add the media header length to buflen.
155 DstPos
+= SnpMode
->MediaHeaderSize
;
156 *PktLen
+= SnpMode
->MediaHeaderSize
;
159 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
165 TxData
->FragmentTable
[Index
].FragmentBuffer
,
166 TxData
->FragmentTable
[Index
].FragmentLength
168 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
172 // Set the buffer pointer and the buffer length.
174 *PktBuf
= MnpServiceData
->TxBuf
;
175 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
181 Synchronously send out the packet.
183 @param[in] MnpServiceData Pointer to the mnp service context data.
184 @param[in] Packet Pointer to the pakcet buffer.
185 @param[in] Length The length of the packet.
186 @param[in] Token Pointer to the token the packet generated from.
188 @retval EFI_SUCCESS The packet is sent out.
189 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
190 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
195 IN MNP_SERVICE_DATA
*MnpServiceData
,
198 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
202 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
203 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
207 Snp
= MnpServiceData
->Snp
;
208 TxData
= Token
->Packet
.TxData
;
210 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
213 // Start the timeout event.
215 Status
= gBS
->SetTimer (
216 MnpServiceData
->TxTimeoutEvent
,
220 if (EFI_ERROR (Status
)) {
227 // Transmit the packet through SNP.
229 Status
= Snp
->Transmit (
234 TxData
->SourceAddress
,
235 TxData
->DestinationAddress
,
236 &TxData
->ProtocolType
238 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
240 Status
= EFI_DEVICE_ERROR
;
245 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
246 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
247 // Both need to sync SNP.
252 // Get the recycled transmit buffer status.
254 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
256 if (!EFI_ERROR (gBS
->CheckEvent (MnpServiceData
->TxTimeoutEvent
))) {
258 Status
= EFI_TIMEOUT
;
261 } while (TxBuf
== NULL
);
263 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
268 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
271 MnpServiceData
->TxTimeoutEvent
,
279 // Cancel the timer event.
281 gBS
->SetTimer (MnpServiceData
->TxTimeoutEvent
, TimerCancel
, 0);
285 Token
->Status
= Status
;
286 gBS
->SignalEvent (Token
->Event
);
289 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
291 NetLibDispatchDpc ();
298 Try to deliver the received packet to the instance.
300 @param[in] Instance Pointer to the mnp instance context data.
302 @retval EFI_SUCCESS The received packet is delivered, or there is no
303 packet to deliver, or there is no available receive
305 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
309 MnpInstanceDeliverPacket (
310 IN MNP_INSTANCE_DATA
*Instance
313 MNP_SERVICE_DATA
*MnpServiceData
;
314 MNP_RXDATA_WRAP
*RxDataWrap
;
316 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
317 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
318 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
320 MnpServiceData
= Instance
->MnpServiceData
;
321 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
323 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
325 // No pending received data or no available receive token, return.
330 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
332 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
333 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
335 // There are other instances share this Nbuf, duplicate to get a
336 // copy to allow the instance to do R/W operations.
338 DupNbuf
= MnpAllocNbuf (MnpServiceData
);
339 if (DupNbuf
== NULL
) {
340 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
342 return EFI_OUT_OF_RESOURCES
;
346 // Duplicate the net buffer.
348 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
349 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
350 RxDataWrap
->Nbuf
= DupNbuf
;
354 // All resources are OK, remove the packet from the queue.
356 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
357 Instance
->RcvdPacketQueueSize
--;
359 RxData
= &RxDataWrap
->RxData
;
360 SnpMode
= MnpServiceData
->Snp
->Mode
;
363 // Set all the buffer pointers.
365 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
366 RxData
->DestinationAddress
= RxData
->MediaHeader
;
367 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
368 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
371 // Insert this RxDataWrap into the delivered queue.
373 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
376 // Get the receive token from the RxTokenMap.
378 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
381 // Signal this token's event.
383 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
384 RxToken
->Status
= EFI_SUCCESS
;
385 gBS
->SignalEvent (RxToken
->Event
);
392 Deliver the received packet for the instances belonging to the MnpServiceData.
394 @param MnpServiceData Pointer to the mnp service context data.
399 IN MNP_SERVICE_DATA
*MnpServiceData
403 MNP_INSTANCE_DATA
*Instance
;
405 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
407 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
408 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
409 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
412 // Try to deliver packet for this instance.
414 MnpInstanceDeliverPacket (Instance
);
420 Recycle the RxData and other resources used to hold and deliver the received
423 @param Event The event this notify function registered to.
424 @param Context Pointer to the context data registerd to the Event.
434 MNP_RXDATA_WRAP
*RxDataWrap
;
435 MNP_SERVICE_DATA
*MnpServiceData
;
437 ASSERT (Context
!= NULL
);
439 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
440 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
442 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
444 MnpServiceData
= RxDataWrap
->Instance
->MnpServiceData
;
445 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
450 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
451 RxDataWrap
->Nbuf
= NULL
;
454 // Close the recycle event.
456 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
459 // Remove this Wrap entry from the list.
461 RemoveEntryList (&RxDataWrap
->WrapEntry
);
463 gBS
->FreePool (RxDataWrap
);
468 Queue the received packet into instance's receive queue.
470 @param Instance Pointer to the mnp instance context data.
471 @param RxDataWrap Pointer to the Wrap structure containing the
472 received data and other information.
477 IN MNP_INSTANCE_DATA
*Instance
,
478 IN MNP_RXDATA_WRAP
*RxDataWrap
481 MNP_RXDATA_WRAP
*OldRxDataWrap
;
483 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
486 // Check the queue size. If it exceeds the limit, drop one packet
489 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
491 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
494 // Get the oldest packet.
496 OldRxDataWrap
= NET_LIST_HEAD (
497 &Instance
->RcvdPacketQueue
,
503 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
505 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
506 Instance
->RcvdPacketQueueSize
--;
510 // Update the timeout tick using the configured parameter.
512 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
515 // Insert this Wrap into the instance queue.
517 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
518 Instance
->RcvdPacketQueueSize
++;
523 Match the received packet with the instance receive filters.
525 @param[in] Instance Pointer to the mnp instance context data.
526 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
527 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
528 non-NULL and it contains the destination multicast
529 mac address of the received packet if the packet
530 destinated to a multicast mac address.
531 @param[in] PktAttr The received packets attribute.
533 @return The received packet matches the instance's receive filters or not.
538 IN MNP_INSTANCE_DATA
*Instance
,
539 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
540 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
544 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
546 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
548 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
550 ConfigData
= &Instance
->ConfigData
;
553 // Check the protocol type.
555 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
559 if (ConfigData
->EnablePromiscuousReceive
) {
561 // Always match if this instance is configured to be promiscuous.
567 // The protocol type is matched, check receive filter, include unicast and broadcast.
569 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
574 // Check multicast addresses.
576 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
578 ASSERT (GroupAddress
!= NULL
);
580 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
582 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
583 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
585 // The instance is configured to receiveing packets destinated to this
586 // multicast address.
601 Analyse the received packets.
603 @param MnpServiceData Pointer to the mnp service context data.
604 @param Nbuf Pointer to the net buffer holding the received
606 @param RxData Pointer to the buffer used to save the analysed
607 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
608 @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
609 pass out the address of the multicast address the
610 received packet destinated to.
611 @param PktAttr Pointer to the buffer used to save the analysed
617 IN MNP_SERVICE_DATA
*MnpServiceData
,
619 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
620 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
624 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
628 SnpMode
= MnpServiceData
->Snp
->Mode
;
631 // Get the packet buffer.
633 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
634 ASSERT (BufPtr
!= NULL
);
637 // Set the initial values.
639 RxData
->BroadcastFlag
= FALSE
;
640 RxData
->MulticastFlag
= FALSE
;
641 RxData
->PromiscuousFlag
= FALSE
;
642 *PktAttr
= UNICAST_PACKET
;
644 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
646 // This packet isn't destinated to our current mac address, it't not unicast.
650 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
654 RxData
->BroadcastFlag
= TRUE
;
655 *PktAttr
= BROADCAST_PACKET
;
656 } else if ((*BufPtr
& 0x01) == 0x1) {
658 // It's multicast, try to match the multicast filters.
660 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->GroupAddressList
) {
662 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
663 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
664 RxData
->MulticastFlag
= TRUE
;
669 if (!RxData
->MulticastFlag
) {
671 // No match, set GroupAddress to NULL. This multicast packet must
672 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
674 *GroupAddress
= NULL
;
675 RxData
->PromiscuousFlag
= TRUE
;
677 if (MnpServiceData
->PromiscuousCount
== 0) {
679 // Skip the below code, there is no receiver of this packet.
685 RxData
->PromiscuousFlag
= TRUE
;
689 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
692 // Fill the common parts of RxData.
694 RxData
->PacketLength
= Nbuf
->TotalSize
;
695 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
696 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
697 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
698 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
705 @param[in] Instance Pointer to the mnp instance context data.
706 @param[in] RxData Pointer to the receive data to wrap.
708 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
713 IN MNP_INSTANCE_DATA
*Instance
,
714 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
718 MNP_RXDATA_WRAP
*RxDataWrap
;
723 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
724 if (RxDataWrap
== NULL
) {
725 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
729 RxDataWrap
->Instance
= Instance
;
732 // Fill the RxData in RxDataWrap,
734 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
737 // Create the recycle event.
739 Status
= gBS
->CreateEvent (
744 &RxDataWrap
->RxData
.RecycleEvent
746 if (EFI_ERROR (Status
)) {
748 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
749 gBS
->FreePool (RxDataWrap
);
758 Enqueue the received the packets to the instances belonging to the
761 @param MnpServiceData Pointer to the mnp service context data.
762 @param Nbuf Pointer to the net buffer representing the received
768 IN MNP_SERVICE_DATA
*MnpServiceData
,
773 MNP_INSTANCE_DATA
*Instance
;
774 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
776 MNP_GROUP_ADDRESS
*GroupAddress
;
777 MNP_RXDATA_WRAP
*RxDataWrap
;
782 // First, analyse the packet header.
784 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
786 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->PromiscuousCount
== 0)) {
788 // No receivers, no more action need.
794 // Iterate the children to find match.
796 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
798 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
799 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
801 if (!Instance
->Configured
) {
806 // Check the packet against the instance receive filters.
808 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
813 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
814 if (RxDataWrap
== NULL
) {
819 // Associate RxDataWrap with Nbuf and increase the RefCnt.
821 RxDataWrap
->Nbuf
= Nbuf
;
822 NET_GET_REF (RxDataWrap
->Nbuf
);
825 // Queue the packet into the instance queue.
827 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
834 Try to receive a packet and deliver it.
836 @param[in] MnpServiceData Pointer to the mnp service context data.
838 @retval EFI_SUCCESS add return value to function comment
839 @retval EFI_NOT_STARTED The simple network protocol is not started.
840 @retval EFI_NOT_READY No packet received.
841 @retval EFI_DEVICE_ERROR An unexpected error occurs.
846 IN MNP_SERVICE_DATA
*MnpServiceData
850 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
857 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
859 Snp
= MnpServiceData
->Snp
;
860 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
862 // The simple network protocol is not started.
864 return EFI_NOT_STARTED
;
867 if (IsListEmpty (&MnpServiceData
->ChildrenList
)) {
869 // There is no child, no need to receive packets.
874 if (MnpServiceData
->RxNbufCache
== NULL
) {
876 // Try to get a new buffer as there may be buffers recycled.
878 MnpServiceData
->RxNbufCache
= MnpAllocNbuf (MnpServiceData
);
880 if (MnpServiceData
->RxNbufCache
== NULL
) {
882 // No availabe buffer in the buffer pool.
884 return EFI_DEVICE_ERROR
;
888 MnpServiceData
->RxNbufCache
,
889 MnpServiceData
->BufferLength
,
894 Nbuf
= MnpServiceData
->RxNbufCache
;
895 BufLen
= Nbuf
->TotalSize
;
896 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
897 ASSERT (BufPtr
!= NULL
);
900 // Receive packet through Snp.
902 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
903 if (EFI_ERROR (Status
)) {
906 if (Status
!= EFI_NOT_READY
) {
907 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
917 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
921 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
925 return EFI_DEVICE_ERROR
;
929 if (Nbuf
->TotalSize
!= BufLen
) {
931 // Trim the packet from tail.
933 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
934 ASSERT (Nbuf
->TotalSize
== BufLen
);
938 // Enqueue the packet to the matched instances.
940 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
942 if (Nbuf
->RefCnt
> 2) {
944 // RefCnt > 2 indicates there is at least one receiver of this packet.
945 // Free the current RxNbufCache and allocate a new one.
947 MnpFreeNbuf (MnpServiceData
, Nbuf
);
949 Nbuf
= MnpAllocNbuf (MnpServiceData
);
950 MnpServiceData
->RxNbufCache
= Nbuf
;
952 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
953 return EFI_DEVICE_ERROR
;
956 NetbufAllocSpace (Nbuf
, MnpServiceData
->BufferLength
, NET_BUF_TAIL
);
959 // No receiver for this packet.
962 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
968 // Deliver the queued packets.
970 MnpDeliverPacket (MnpServiceData
);
973 // Dispatch the DPC queued by the NotifyFunction of rx token's events.
975 NetLibDispatchDpc ();
979 ASSERT (Nbuf
->TotalSize
== MnpServiceData
->BufferLength
);
986 Remove the received packets if timeout occurs.
988 @param Event The event this notify function registered to.
989 @param Context Pointer to the context data registered to the
995 MnpCheckPacketTimeout (
1000 MNP_SERVICE_DATA
*MnpServiceData
;
1002 LIST_ENTRY
*RxEntry
;
1003 LIST_ENTRY
*NextEntry
;
1004 MNP_INSTANCE_DATA
*Instance
;
1005 MNP_RXDATA_WRAP
*RxDataWrap
;
1008 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1009 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1011 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1013 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1014 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1016 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1018 // This instance is not configured or there is no receive time out,
1019 // just skip to the next instance.
1024 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1026 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1028 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1031 // TimeoutTick unit is ms, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1033 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1035 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1038 // Drop the timeout packet.
1040 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1041 MnpRecycleRxData (NULL
, RxDataWrap
);
1042 Instance
->RcvdPacketQueueSize
--;
1046 gBS
->RestoreTPL (OldTpl
);
1052 Poll to receive the packets from Snp. This function is either called by upperlayer
1053 protocols/applications or the system poll timer notify mechanism.
1055 @param Event The event this notify function registered to.
1056 @param Context Pointer to the context data registered to the
1067 MNP_SERVICE_DATA
*MnpServiceData
;
1069 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1070 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1073 // Try to receive packets from Snp.
1075 MnpReceivePacket (MnpServiceData
);
1077 NetLibDispatchDpc ();