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.
24 #include <Library/NetLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/BaseLib.h>
27 #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 DEBUG ((EFI_D_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 DEBUG ((EFI_D_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 DEBUG ((EFI_D_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 DEBUG ((EFI_D_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 DEBUG ((EFI_D_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
130 IN MNP_SERVICE_DATA
*MnpServiceData
,
131 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
136 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
140 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
142 // Media header is in FragmentTable and there is only one fragment,
143 // use fragment buffer directly.
145 *PktBuf
= TxData
->FragmentTable
[0].FragmentBuffer
;
146 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
149 // Either media header isn't in FragmentTable or there is more than
150 // one fragment, copy the data into the packet buffer. Reserve the
151 // media header space if necessary.
153 SnpMode
= MnpServiceData
->Snp
->Mode
;
154 DstPos
= MnpServiceData
->TxBuf
;
157 if (TxData
->DestinationAddress
!= NULL
) {
159 // If dest address is not NULL, move DstPos to reserve space for the
160 // media header. Add the media header length to buflen.
162 DstPos
+= SnpMode
->MediaHeaderSize
;
163 *PktLen
+= SnpMode
->MediaHeaderSize
;
166 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
172 TxData
->FragmentTable
[Index
].FragmentBuffer
,
173 TxData
->FragmentTable
[Index
].FragmentLength
175 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
179 // Set the buffer pointer and the buffer length.
181 *PktBuf
= MnpServiceData
->TxBuf
;
182 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
188 Synchronously send out the packet.
190 @param MnpServiceData Pointer to the mnp service context data.
191 @param Packet Pointer to the pakcet buffer.
192 @param Length The length of the packet.
193 @param Token Pointer to the token the packet generated from.
195 @retval EFI_SUCCESS The packet is sent out.
196 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
197 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
202 IN MNP_SERVICE_DATA
*MnpServiceData
,
205 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
209 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
210 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
214 Snp
= MnpServiceData
->Snp
;
215 TxData
= Token
->Packet
.TxData
;
217 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
220 // Start the timeout event.
222 Status
= gBS
->SetTimer (
223 MnpServiceData
->TxTimeoutEvent
,
227 if (EFI_ERROR (Status
)) {
234 // Transmit the packet through SNP.
236 Status
= Snp
->Transmit (
241 TxData
->SourceAddress
,
242 TxData
->DestinationAddress
,
243 &TxData
->ProtocolType
245 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
247 Status
= EFI_DEVICE_ERROR
;
252 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
253 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
254 // Both need to sync SNP.
259 // Get the recycled transmit buffer status.
261 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
263 if (!EFI_ERROR (gBS
->CheckEvent (MnpServiceData
->TxTimeoutEvent
))) {
265 Status
= EFI_TIMEOUT
;
268 } while (TxBuf
== NULL
);
270 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
275 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
278 MnpServiceData
->TxTimeoutEvent
,
286 // Cancel the timer event.
288 gBS
->SetTimer (MnpServiceData
->TxTimeoutEvent
, TimerCancel
, 0);
292 Token
->Status
= Status
;
293 gBS
->SignalEvent (Token
->Event
);
296 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
298 NetLibDispatchDpc ();
305 Try to deliver the received packet to the instance.
307 @param Instance Pointer to the mnp instance context data.
309 @retval EFI_SUCCESS The received packet is delivered, or there is no
310 packet to deliver, or there is no available receive
312 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
316 MnpInstanceDeliverPacket (
317 IN MNP_INSTANCE_DATA
*Instance
320 MNP_SERVICE_DATA
*MnpServiceData
;
321 MNP_RXDATA_WRAP
*RxDataWrap
;
323 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
324 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
325 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
327 MnpServiceData
= Instance
->MnpServiceData
;
328 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
330 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
332 // No pending received data or no available receive token, return.
337 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
339 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
340 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
342 // There are other instances share this Nbuf, duplicate to get a
343 // copy to allow the instance to do R/W operations.
345 DupNbuf
= MnpAllocNbuf (MnpServiceData
);
346 if (DupNbuf
== NULL
) {
347 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
349 return EFI_OUT_OF_RESOURCES
;
353 // Duplicate the net buffer.
355 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
356 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
357 RxDataWrap
->Nbuf
= DupNbuf
;
361 // All resources are OK, remove the packet from the queue.
363 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
364 Instance
->RcvdPacketQueueSize
--;
366 RxData
= &RxDataWrap
->RxData
;
367 SnpMode
= MnpServiceData
->Snp
->Mode
;
370 // Set all the buffer pointers.
372 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
373 RxData
->DestinationAddress
= RxData
->MediaHeader
;
374 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
375 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
378 // Insert this RxDataWrap into the delivered queue.
380 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
383 // Get the receive token from the RxTokenMap.
385 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
388 // Signal this token's event.
390 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
391 RxToken
->Status
= EFI_SUCCESS
;
392 gBS
->SignalEvent (RxToken
->Event
);
399 Deliver the received packet for the instances belonging to the MnpServiceData.
401 @param MnpServiceData Pointer to the mnp service context data.
408 IN MNP_SERVICE_DATA
*MnpServiceData
412 MNP_INSTANCE_DATA
*Instance
;
414 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
416 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
417 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
418 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
421 // Try to deliver packet for this instance.
423 MnpInstanceDeliverPacket (Instance
);
429 Recycle the RxData and other resources used to hold and deliver the received
432 @param Event The event this notify function registered to.
433 @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 RemoveEntryList (&RxDataWrap
->WrapEntry
);
472 gBS
->FreePool (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.
488 IN MNP_INSTANCE_DATA
*Instance
,
489 IN MNP_RXDATA_WRAP
*RxDataWrap
492 MNP_RXDATA_WRAP
*OldRxDataWrap
;
494 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
497 // Check the queue size. If it exceeds the limit, drop one packet
500 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
502 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
505 // Get the oldest packet.
507 OldRxDataWrap
= NET_LIST_HEAD (
508 &Instance
->RcvdPacketQueue
,
514 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
516 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
517 Instance
->RcvdPacketQueueSize
--;
521 // Update the timeout tick using the configured parameter.
523 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
526 // Insert this Wrap into the instance queue.
528 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
529 Instance
->RcvdPacketQueueSize
++;
534 Match the received packet with the instance receive filters.
536 @param Instance Pointer to the mnp instance context data.
537 @param RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
538 @param GroupAddress Pointer to the GroupAddress, the GroupAddress is
539 non-NULL and it contains the destination multicast
540 mac address of the received packet if the packet
541 destinated to a multicast mac address.
542 @param PktAttr The received packets attribute.
544 @return The received packet matches the instance's receive filters or not.
549 IN MNP_INSTANCE_DATA
*Instance
,
550 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
551 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
555 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
557 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
559 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
561 ConfigData
= &Instance
->ConfigData
;
564 // Check the protocol type.
566 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
570 if (ConfigData
->EnablePromiscuousReceive
) {
572 // Always match if this instance is configured to be promiscuous.
578 // The protocol type is matched, check receive filter, include unicast and broadcast.
580 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
585 // Check multicast addresses.
587 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
589 ASSERT (GroupAddress
!= NULL
);
591 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
593 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
594 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
596 // The instance is configured to receiveing packets destinated to this
597 // multicast address.
612 Analyse the received packets.
614 @param MnpServiceData Pointer to the mnp service context data.
615 @param Nbuf Pointer to the net buffer holding the received
617 @param RxData Pointer to the buffer used to save the analysed
618 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
619 @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
620 pass out the address of the multicast address the
621 received packet destinated to.
622 @param PktAttr Pointer to the buffer used to save the analysed
630 IN MNP_SERVICE_DATA
*MnpServiceData
,
632 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
633 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
637 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
641 SnpMode
= MnpServiceData
->Snp
->Mode
;
644 // Get the packet buffer.
646 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
647 ASSERT (BufPtr
!= NULL
);
650 // Set the initial values.
652 RxData
->BroadcastFlag
= FALSE
;
653 RxData
->MulticastFlag
= FALSE
;
654 RxData
->PromiscuousFlag
= FALSE
;
655 *PktAttr
= UNICAST_PACKET
;
657 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
659 // This packet isn't destinated to our current mac address, it't not unicast.
663 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
667 RxData
->BroadcastFlag
= TRUE
;
668 *PktAttr
= BROADCAST_PACKET
;
669 } else if ((*BufPtr
& 0x01) == 0x1) {
671 // It's multicast, try to match the multicast filters.
673 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->GroupAddressList
) {
675 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
676 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
677 RxData
->MulticastFlag
= TRUE
;
682 if (!RxData
->MulticastFlag
) {
684 // No match, set GroupAddress to NULL. This multicast packet must
685 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
687 *GroupAddress
= NULL
;
688 RxData
->PromiscuousFlag
= TRUE
;
690 if (MnpServiceData
->PromiscuousCount
== 0) {
692 // Skip the below code, there is no receiver of this packet.
698 RxData
->PromiscuousFlag
= TRUE
;
702 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
705 // Fill the common parts of RxData.
707 RxData
->PacketLength
= Nbuf
->TotalSize
;
708 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
709 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
710 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
711 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
718 @param Instance Pointer to the mnp instance context data.
719 @param RxData Pointer to the receive data to wrap.
721 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
726 IN MNP_INSTANCE_DATA
*Instance
,
727 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
731 MNP_RXDATA_WRAP
*RxDataWrap
;
736 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
737 if (RxDataWrap
== NULL
) {
738 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
742 RxDataWrap
->Instance
= Instance
;
745 // Fill the RxData in RxDataWrap,
747 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
750 // Create the recycle event.
752 Status
= gBS
->CreateEvent (
757 &RxDataWrap
->RxData
.RecycleEvent
759 if (EFI_ERROR (Status
)) {
761 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
762 gBS
->FreePool (RxDataWrap
);
771 Enqueue the received the packets to the instances belonging to the
774 @param MnpServiceData Pointer to the mnp service context data.
775 @param Nbuf Pointer to the net buffer representing the received
783 IN MNP_SERVICE_DATA
*MnpServiceData
,
788 MNP_INSTANCE_DATA
*Instance
;
789 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
791 MNP_GROUP_ADDRESS
*GroupAddress
;
792 MNP_RXDATA_WRAP
*RxDataWrap
;
797 // First, analyse the packet header.
799 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
801 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->PromiscuousCount
== 0)) {
803 // No receivers, no more action need.
809 // Iterate the children to find match.
811 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
813 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
814 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
816 if (!Instance
->Configured
) {
821 // Check the packet against the instance receive filters.
823 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
828 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
829 if (RxDataWrap
== NULL
) {
834 // Associate RxDataWrap with Nbuf and increase the RefCnt.
836 RxDataWrap
->Nbuf
= Nbuf
;
837 NET_GET_REF (RxDataWrap
->Nbuf
);
840 // Queue the packet into the instance queue.
842 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
849 Try to receive a packet and deliver it.
851 @param MnpServiceData Pointer to the mnp service context data.
853 @retval EFI_SUCCESS add return value to function comment
854 @retval EFI_NOT_STARTED The simple network protocol is not started.
855 @retval EFI_NOT_READY No packet received.
856 @retval EFI_DEVICE_ERROR An unexpected error occurs.
861 IN MNP_SERVICE_DATA
*MnpServiceData
865 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
872 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
874 Snp
= MnpServiceData
->Snp
;
875 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
877 // The simple network protocol is not started.
879 return EFI_NOT_STARTED
;
882 if (IsListEmpty (&MnpServiceData
->ChildrenList
)) {
884 // There is no child, no need to receive packets.
889 if (MnpServiceData
->RxNbufCache
== NULL
) {
891 // Try to get a new buffer as there may be buffers recycled.
893 MnpServiceData
->RxNbufCache
= MnpAllocNbuf (MnpServiceData
);
895 if (MnpServiceData
->RxNbufCache
== NULL
) {
897 // No availabe buffer in the buffer pool.
899 return EFI_DEVICE_ERROR
;
903 MnpServiceData
->RxNbufCache
,
904 MnpServiceData
->BufferLength
,
909 Nbuf
= MnpServiceData
->RxNbufCache
;
910 BufLen
= Nbuf
->TotalSize
;
911 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
912 ASSERT (BufPtr
!= NULL
);
915 // Receive packet through Snp.
917 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
918 if (EFI_ERROR (Status
)) {
921 if (Status
!= EFI_NOT_READY
) {
922 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
932 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
936 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
940 return EFI_DEVICE_ERROR
;
944 if (Nbuf
->TotalSize
!= BufLen
) {
946 // Trim the packet from tail.
948 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
949 ASSERT (Nbuf
->TotalSize
== BufLen
);
953 // Enqueue the packet to the matched instances.
955 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
957 if (Nbuf
->RefCnt
> 2) {
959 // RefCnt > 2 indicates there is at least one receiver of this packet.
960 // Free the current RxNbufCache and allocate a new one.
962 MnpFreeNbuf (MnpServiceData
, Nbuf
);
964 Nbuf
= MnpAllocNbuf (MnpServiceData
);
965 MnpServiceData
->RxNbufCache
= Nbuf
;
967 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
968 return EFI_DEVICE_ERROR
;
971 NetbufAllocSpace (Nbuf
, MnpServiceData
->BufferLength
, NET_BUF_TAIL
);
974 // No receiver for this packet.
977 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
983 // Deliver the queued packets.
985 MnpDeliverPacket (MnpServiceData
);
988 // Dispatch the DPC queued by the NotifyFunction of rx token's events.
990 NetLibDispatchDpc ();
994 ASSERT (Nbuf
->TotalSize
== MnpServiceData
->BufferLength
);
1001 Remove the received packets if timeout occurs.
1003 @param Event The event this notify function registered to.
1004 @param Context Pointer to the context data registered to the
1010 MnpCheckPacketTimeout (
1015 MNP_SERVICE_DATA
*MnpServiceData
;
1017 LIST_ENTRY
*RxEntry
;
1018 LIST_ENTRY
*NextEntry
;
1019 MNP_INSTANCE_DATA
*Instance
;
1020 MNP_RXDATA_WRAP
*RxDataWrap
;
1023 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1024 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1026 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1028 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1029 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1031 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1033 // This instance is not configured or there is no receive time out,
1034 // just skip to the next instance.
1039 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1041 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1043 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1046 // TimeoutTick unit is ms, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1048 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1050 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1053 // Drop the timeout packet.
1055 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1056 MnpRecycleRxData (NULL
, RxDataWrap
);
1057 Instance
->RcvdPacketQueueSize
--;
1061 gBS
->RestoreTPL (OldTpl
);
1067 Poll to receive the packets from Snp. This function is either called by upperlayer
1068 protocols/applications or the system poll timer notify mechanism.
1070 @param Event The event this notify function registered to.
1071 @param Context Pointer to the context data registered to the
1084 MNP_SERVICE_DATA
*MnpServiceData
;
1086 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1087 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1090 // Try to receive packets from Snp.
1092 MnpReceivePacket (MnpServiceData
);
1094 NetLibDispatchDpc ();