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.
18 Validates the Mnp transmit token.
20 @param[in] Instance Pointer to the Mnp instance context data.
21 @param[in] Token Pointer to the transmit token to check.
23 @return The Token is valid or not.
28 IN MNP_INSTANCE_DATA
*Instance
,
29 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
32 MNP_SERVICE_DATA
*MnpServiceData
;
33 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
36 EFI_MANAGED_NETWORK_FRAGMENT_DATA
*FragmentTable
;
38 MnpServiceData
= Instance
->MnpServiceData
;
39 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
41 TxData
= Token
->Packet
.TxData
;
43 if ((Token
->Event
== NULL
) || (TxData
== NULL
) || (TxData
->FragmentCount
== 0)) {
45 // The token is invalid if the Event is NULL, or the TxData is NULL, or
46 // the fragment count is zero.
48 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid Token.\n"));
52 if ((TxData
->DestinationAddress
!= NULL
) && (TxData
->HeaderLength
!= 0)) {
54 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
55 // is NULL (The destination address is already put into the packet).
57 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
62 FragmentTable
= TxData
->FragmentTable
;
63 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
65 if ((FragmentTable
[Index
].FragmentLength
== 0) || (FragmentTable
[Index
].FragmentBuffer
== NULL
)) {
67 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
69 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
73 TotalLength
+= FragmentTable
[Index
].FragmentLength
;
76 if ((TxData
->DestinationAddress
== NULL
) && (FragmentTable
[0].FragmentLength
< TxData
->HeaderLength
)) {
78 // Media header is split between fragments.
83 if (TotalLength
!= (TxData
->DataLength
+ TxData
->HeaderLength
)) {
85 // The length calculated from the fragment information doesn't equal to the
86 // sum of the DataLength and the HeaderLength.
88 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
92 if (TxData
->DataLength
> MnpServiceData
->Mtu
) {
94 // The total length is larger than the MTU.
96 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
105 Build the packet to transmit from the TxData passed in.
107 @param[in] MnpServiceData Pointer to the mnp service context data.
108 @param[in] TxData Pointer to the transmit data containing the information
110 @param[out] PktBuf Pointer to record the address of the packet.
111 @param[out] PktLen Pointer to a UINT32 variable used to record the packet's
117 IN MNP_SERVICE_DATA
*MnpServiceData
,
118 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
123 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
127 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
129 // Media header is in FragmentTable and there is only one fragment,
130 // use fragment buffer directly.
132 *PktBuf
= TxData
->FragmentTable
[0].FragmentBuffer
;
133 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
136 // Either media header isn't in FragmentTable or there is more than
137 // one fragment, copy the data into the packet buffer. Reserve the
138 // media header space if necessary.
140 SnpMode
= MnpServiceData
->Snp
->Mode
;
141 DstPos
= MnpServiceData
->TxBuf
;
144 if (TxData
->DestinationAddress
!= NULL
) {
146 // If dest address is not NULL, move DstPos to reserve space for the
147 // media header. Add the media header length to buflen.
149 DstPos
+= SnpMode
->MediaHeaderSize
;
150 *PktLen
+= SnpMode
->MediaHeaderSize
;
153 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
159 TxData
->FragmentTable
[Index
].FragmentBuffer
,
160 TxData
->FragmentTable
[Index
].FragmentLength
162 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
166 // Set the buffer pointer and the buffer length.
168 *PktBuf
= MnpServiceData
->TxBuf
;
169 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
175 Synchronously send out the packet.
177 @param[in] MnpServiceData Pointer to the mnp service context data.
178 @param[in] Packet Pointer to the pakcet buffer.
179 @param[in] Length The length of the packet.
180 @param[in, out] Token Pointer to the token the packet generated from.
182 @retval EFI_SUCCESS The packet is sent out.
183 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
184 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
189 IN MNP_SERVICE_DATA
*MnpServiceData
,
192 IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
196 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
197 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
201 Snp
= MnpServiceData
->Snp
;
202 TxData
= Token
->Packet
.TxData
;
204 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
207 // Start the timeout event.
209 Status
= gBS
->SetTimer (
210 MnpServiceData
->TxTimeoutEvent
,
214 if (EFI_ERROR (Status
)) {
221 // Transmit the packet through SNP.
223 Status
= Snp
->Transmit (
228 TxData
->SourceAddress
,
229 TxData
->DestinationAddress
,
230 &TxData
->ProtocolType
232 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
234 Status
= EFI_DEVICE_ERROR
;
239 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
240 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
241 // Both need to sync SNP.
246 // Get the recycled transmit buffer status.
248 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
250 if (!EFI_ERROR (gBS
->CheckEvent (MnpServiceData
->TxTimeoutEvent
))) {
252 Status
= EFI_TIMEOUT
;
255 } while (TxBuf
== NULL
);
257 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
262 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
265 MnpServiceData
->TxTimeoutEvent
,
273 // Cancel the timer event.
275 gBS
->SetTimer (MnpServiceData
->TxTimeoutEvent
, TimerCancel
, 0);
279 Token
->Status
= Status
;
280 gBS
->SignalEvent (Token
->Event
);
283 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
285 NetLibDispatchDpc ();
292 Try to deliver the received packet to the instance.
294 @param[in, out] Instance Pointer to the mnp instance context data.
296 @retval EFI_SUCCESS The received packet is delivered, or there is no
297 packet to deliver, or there is no available receive
299 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
303 MnpInstanceDeliverPacket (
304 IN OUT MNP_INSTANCE_DATA
*Instance
307 MNP_SERVICE_DATA
*MnpServiceData
;
308 MNP_RXDATA_WRAP
*RxDataWrap
;
310 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
311 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
312 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
314 MnpServiceData
= Instance
->MnpServiceData
;
315 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
317 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
319 // No pending received data or no available receive token, return.
324 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
326 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
327 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
329 // There are other instances share this Nbuf, duplicate to get a
330 // copy to allow the instance to do R/W operations.
332 DupNbuf
= MnpAllocNbuf (MnpServiceData
);
333 if (DupNbuf
== NULL
) {
334 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
336 return EFI_OUT_OF_RESOURCES
;
340 // Duplicate the net buffer.
342 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
343 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
344 RxDataWrap
->Nbuf
= DupNbuf
;
348 // All resources are OK, remove the packet from the queue.
350 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
351 Instance
->RcvdPacketQueueSize
--;
353 RxData
= &RxDataWrap
->RxData
;
354 SnpMode
= MnpServiceData
->Snp
->Mode
;
357 // Set all the buffer pointers.
359 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
360 RxData
->DestinationAddress
= RxData
->MediaHeader
;
361 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
362 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
365 // Insert this RxDataWrap into the delivered queue.
367 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
370 // Get the receive token from the RxTokenMap.
372 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
375 // Signal this token's event.
377 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
378 RxToken
->Status
= EFI_SUCCESS
;
379 gBS
->SignalEvent (RxToken
->Event
);
386 Deliver the received packet for the instances belonging to the MnpServiceData.
388 @param[in] MnpServiceData Pointer to the mnp service context data.
393 IN MNP_SERVICE_DATA
*MnpServiceData
397 MNP_INSTANCE_DATA
*Instance
;
399 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
401 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
402 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
403 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
406 // Try to deliver packet for this instance.
408 MnpInstanceDeliverPacket (Instance
);
414 Recycle the RxData and other resources used to hold and deliver the received
417 @param[in] Event The event this notify function registered to.
418 @param[in] Context Pointer to the context data registerd to the Event.
428 MNP_RXDATA_WRAP
*RxDataWrap
;
429 MNP_SERVICE_DATA
*MnpServiceData
;
431 ASSERT (Context
!= NULL
);
433 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
434 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
436 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
438 MnpServiceData
= RxDataWrap
->Instance
->MnpServiceData
;
439 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
444 MnpFreeNbuf (MnpServiceData
, RxDataWrap
->Nbuf
);
445 RxDataWrap
->Nbuf
= NULL
;
448 // Close the recycle event.
450 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
453 // Remove this Wrap entry from the list.
455 RemoveEntryList (&RxDataWrap
->WrapEntry
);
457 gBS
->FreePool (RxDataWrap
);
462 Queue the received packet into instance's receive queue.
464 @param[in, out] Instance Pointer to the mnp instance context data.
465 @param[in, out] RxDataWrap Pointer to the Wrap structure containing the
466 received data and other information.
470 IN OUT MNP_INSTANCE_DATA
*Instance
,
471 IN OUT MNP_RXDATA_WRAP
*RxDataWrap
474 MNP_RXDATA_WRAP
*OldRxDataWrap
;
476 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
479 // Check the queue size. If it exceeds the limit, drop one packet
482 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
484 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
487 // Get the oldest packet.
489 OldRxDataWrap
= NET_LIST_HEAD (
490 &Instance
->RcvdPacketQueue
,
496 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
498 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
499 Instance
->RcvdPacketQueueSize
--;
503 // Update the timeout tick using the configured parameter.
505 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
508 // Insert this Wrap into the instance queue.
510 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
511 Instance
->RcvdPacketQueueSize
++;
516 Match the received packet with the instance receive filters.
518 @param[in] Instance Pointer to the mnp instance context data.
519 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
520 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
521 non-NULL and it contains the destination multicast
522 mac address of the received packet if the packet
523 destinated to a multicast mac address.
524 @param[in] PktAttr The received packets attribute.
526 @return The received packet matches the instance's receive filters or not.
531 IN MNP_INSTANCE_DATA
*Instance
,
532 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
533 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
537 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
539 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
541 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
543 ConfigData
= &Instance
->ConfigData
;
546 // Check the protocol type.
548 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
552 if (ConfigData
->EnablePromiscuousReceive
) {
554 // Always match if this instance is configured to be promiscuous.
560 // The protocol type is matched, check receive filter, include unicast and broadcast.
562 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
567 // Check multicast addresses.
569 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
571 ASSERT (GroupAddress
!= NULL
);
573 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
575 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
576 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
578 // The instance is configured to receiveing packets destinated to this
579 // multicast address.
594 Analyse the received packets.
596 @param[in] MnpServiceData Pointer to the mnp service context data.
597 @param[in] Nbuf Pointer to the net buffer holding the received
599 @param[in, out] RxData Pointer to the buffer used to save the analysed
600 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
601 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
602 pass out the address of the multicast address the
603 received packet destinated to.
604 @param[out] PktAttr Pointer to the buffer used to save the analysed
610 IN MNP_SERVICE_DATA
*MnpServiceData
,
612 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
613 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
617 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
621 SnpMode
= MnpServiceData
->Snp
->Mode
;
624 // Get the packet buffer.
626 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
627 ASSERT (BufPtr
!= NULL
);
630 // Set the initial values.
632 RxData
->BroadcastFlag
= FALSE
;
633 RxData
->MulticastFlag
= FALSE
;
634 RxData
->PromiscuousFlag
= FALSE
;
635 *PktAttr
= UNICAST_PACKET
;
637 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
639 // This packet isn't destinated to our current mac address, it't not unicast.
643 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
647 RxData
->BroadcastFlag
= TRUE
;
648 *PktAttr
= BROADCAST_PACKET
;
649 } else if ((*BufPtr
& 0x01) == 0x1) {
651 // It's multicast, try to match the multicast filters.
653 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->GroupAddressList
) {
655 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
656 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
657 RxData
->MulticastFlag
= TRUE
;
662 if (!RxData
->MulticastFlag
) {
664 // No match, set GroupAddress to NULL. This multicast packet must
665 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
667 *GroupAddress
= NULL
;
668 RxData
->PromiscuousFlag
= TRUE
;
670 if (MnpServiceData
->PromiscuousCount
== 0) {
672 // Skip the below code, there is no receiver of this packet.
678 RxData
->PromiscuousFlag
= TRUE
;
682 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
685 // Fill the common parts of RxData.
687 RxData
->PacketLength
= Nbuf
->TotalSize
;
688 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
689 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
690 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
691 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
698 @param[in] Instance Pointer to the mnp instance context data.
699 @param[in] RxData Pointer to the receive data to wrap.
701 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
706 IN MNP_INSTANCE_DATA
*Instance
,
707 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
711 MNP_RXDATA_WRAP
*RxDataWrap
;
716 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
717 if (RxDataWrap
== NULL
) {
718 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
722 RxDataWrap
->Instance
= Instance
;
725 // Fill the RxData in RxDataWrap,
727 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
730 // Create the recycle event.
732 Status
= gBS
->CreateEvent (
737 &RxDataWrap
->RxData
.RecycleEvent
739 if (EFI_ERROR (Status
)) {
741 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
742 gBS
->FreePool (RxDataWrap
);
751 Enqueue the received the packets to the instances belonging to the
754 @param[in] MnpServiceData Pointer to the mnp service context data.
755 @param[in] Nbuf Pointer to the net buffer representing the received
761 IN MNP_SERVICE_DATA
*MnpServiceData
,
766 MNP_INSTANCE_DATA
*Instance
;
767 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
769 MNP_GROUP_ADDRESS
*GroupAddress
;
770 MNP_RXDATA_WRAP
*RxDataWrap
;
775 // First, analyse the packet header.
777 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
779 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->PromiscuousCount
== 0)) {
781 // No receivers, no more action need.
787 // Iterate the children to find match.
789 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
791 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
792 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
794 if (!Instance
->Configured
) {
799 // Check the packet against the instance receive filters.
801 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
806 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
807 if (RxDataWrap
== NULL
) {
812 // Associate RxDataWrap with Nbuf and increase the RefCnt.
814 RxDataWrap
->Nbuf
= Nbuf
;
815 NET_GET_REF (RxDataWrap
->Nbuf
);
818 // Queue the packet into the instance queue.
820 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
827 Try to receive a packet and deliver it.
829 @param[in, out] MnpServiceData Pointer to the mnp service context data.
831 @retval EFI_SUCCESS add return value to function comment
832 @retval EFI_NOT_STARTED The simple network protocol is not started.
833 @retval EFI_NOT_READY No packet received.
834 @retval EFI_DEVICE_ERROR An unexpected error occurs.
839 IN OUT MNP_SERVICE_DATA
*MnpServiceData
843 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
850 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
852 Snp
= MnpServiceData
->Snp
;
853 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
855 // The simple network protocol is not started.
857 return EFI_NOT_STARTED
;
860 if (IsListEmpty (&MnpServiceData
->ChildrenList
)) {
862 // There is no child, no need to receive packets.
867 if (MnpServiceData
->RxNbufCache
== NULL
) {
869 // Try to get a new buffer as there may be buffers recycled.
871 MnpServiceData
->RxNbufCache
= MnpAllocNbuf (MnpServiceData
);
873 if (MnpServiceData
->RxNbufCache
== NULL
) {
875 // No availabe buffer in the buffer pool.
877 return EFI_DEVICE_ERROR
;
881 MnpServiceData
->RxNbufCache
,
882 MnpServiceData
->BufferLength
,
887 Nbuf
= MnpServiceData
->RxNbufCache
;
888 BufLen
= Nbuf
->TotalSize
;
889 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
890 ASSERT (BufPtr
!= NULL
);
893 // Receive packet through Snp.
895 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
896 if (EFI_ERROR (Status
)) {
899 if (Status
!= EFI_NOT_READY
) {
900 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
910 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
914 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
918 return EFI_DEVICE_ERROR
;
922 if (Nbuf
->TotalSize
!= BufLen
) {
924 // Trim the packet from tail.
926 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
927 ASSERT (Nbuf
->TotalSize
== BufLen
);
931 // Enqueue the packet to the matched instances.
933 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
935 if (Nbuf
->RefCnt
> 2) {
937 // RefCnt > 2 indicates there is at least one receiver of this packet.
938 // Free the current RxNbufCache and allocate a new one.
940 MnpFreeNbuf (MnpServiceData
, Nbuf
);
942 Nbuf
= MnpAllocNbuf (MnpServiceData
);
943 MnpServiceData
->RxNbufCache
= Nbuf
;
945 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
946 return EFI_DEVICE_ERROR
;
949 NetbufAllocSpace (Nbuf
, MnpServiceData
->BufferLength
, NET_BUF_TAIL
);
952 // No receiver for this packet.
955 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
961 // Deliver the queued packets.
963 MnpDeliverPacket (MnpServiceData
);
966 // Dispatch the DPC queued by the NotifyFunction of rx token's events.
968 NetLibDispatchDpc ();
972 ASSERT (Nbuf
->TotalSize
== MnpServiceData
->BufferLength
);
979 Remove the received packets if timeout occurs.
981 @param[in] Event The event this notify function registered to.
982 @param[in] Context Pointer to the context data registered to the
988 MnpCheckPacketTimeout (
993 MNP_SERVICE_DATA
*MnpServiceData
;
996 LIST_ENTRY
*NextEntry
;
997 MNP_INSTANCE_DATA
*Instance
;
998 MNP_RXDATA_WRAP
*RxDataWrap
;
1001 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1002 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1004 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1006 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1007 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1009 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1011 // This instance is not configured or there is no receive time out,
1012 // just skip to the next instance.
1017 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1019 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1021 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1024 // TimeoutTick unit is ms, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1026 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1028 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1031 // Drop the timeout packet.
1033 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1034 MnpRecycleRxData (NULL
, RxDataWrap
);
1035 Instance
->RcvdPacketQueueSize
--;
1039 gBS
->RestoreTPL (OldTpl
);
1045 Poll to receive the packets from Snp. This function is either called by upperlayer
1046 protocols/applications or the system poll timer notify mechanism.
1048 @param[in] Event The event this notify function registered to.
1049 @param[in, out] Context Pointer to the context data registered to the event.
1056 IN OUT VOID
*Context
1059 MNP_SERVICE_DATA
*MnpServiceData
;
1061 MnpServiceData
= (MNP_SERVICE_DATA
*) Context
;
1062 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
1065 // Try to receive packets from Snp.
1067 MnpReceivePacket (MnpServiceData
);
1069 NetLibDispatchDpc ();