2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution. The full
8 text of the license may be found at<BR>
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.
20 Validates the Mnp transmit token.
22 @param[in] Instance Pointer to the Mnp instance context data.
23 @param[in] Token Pointer to the transmit token to check.
25 @return The Token is valid or not.
30 IN MNP_INSTANCE_DATA
*Instance
,
31 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
34 MNP_SERVICE_DATA
*MnpServiceData
;
35 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
38 EFI_MANAGED_NETWORK_FRAGMENT_DATA
*FragmentTable
;
40 MnpServiceData
= Instance
->MnpServiceData
;
41 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
43 TxData
= Token
->Packet
.TxData
;
45 if ((Token
->Event
== NULL
) || (TxData
== NULL
) || (TxData
->FragmentCount
== 0)) {
47 // The token is invalid if the Event is NULL, or the TxData is NULL, or
48 // the fragment count is zero.
50 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid Token.\n"));
54 if ((TxData
->DestinationAddress
!= NULL
) && (TxData
->HeaderLength
!= 0)) {
56 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
57 // is NULL (The destination address is already put into the packet).
59 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
64 FragmentTable
= TxData
->FragmentTable
;
65 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
67 if ((FragmentTable
[Index
].FragmentLength
== 0) || (FragmentTable
[Index
].FragmentBuffer
== NULL
)) {
69 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
71 DEBUG ((EFI_D_WARN
, "MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
75 TotalLength
+= FragmentTable
[Index
].FragmentLength
;
78 if ((TxData
->DestinationAddress
== NULL
) && (FragmentTable
[0].FragmentLength
< TxData
->HeaderLength
)) {
80 // Media header is split between fragments.
85 if (TotalLength
!= (TxData
->DataLength
+ TxData
->HeaderLength
)) {
87 // The length calculated from the fragment information doesn't equal to the
88 // sum of the DataLength and the HeaderLength.
90 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
94 if (TxData
->DataLength
> MnpServiceData
->Mtu
) {
96 // The total length is larger than the MTU.
98 DEBUG ((EFI_D_WARN
, "MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
107 Build the packet to transmit from the TxData passed in.
109 @param[in] MnpServiceData Pointer to the mnp service context data.
110 @param[in] TxData Pointer to the transmit data containing the information
112 @param[out] PktBuf Pointer to record the address of the packet.
113 @param[out] PktLen Pointer to a UINT32 variable used to record the packet's
119 IN MNP_SERVICE_DATA
*MnpServiceData
,
120 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
125 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
128 MNP_DEVICE_DATA
*MnpDerviceData
;
130 MnpDerviceData
= MnpServiceData
->MnpDeviceData
;
133 // Reserve space for vlan tag.
135 *PktBuf
= MnpDerviceData
->TxBuf
+ NET_VLAN_TAG_LEN
;
137 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
140 TxData
->FragmentTable
[0].FragmentBuffer
,
141 TxData
->FragmentTable
[0].FragmentLength
144 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
147 // Either media header isn't in FragmentTable or there is more than
148 // one fragment, copy the data into the packet buffer. Reserve the
149 // media header space if necessary.
151 SnpMode
= MnpDerviceData
->Snp
->Mode
;
154 if (TxData
->DestinationAddress
!= NULL
) {
156 // If dest address is not NULL, move DstPos to reserve space for the
157 // media header. Add the media header length to buflen.
159 DstPos
+= SnpMode
->MediaHeaderSize
;
160 *PktLen
+= SnpMode
->MediaHeaderSize
;
163 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
169 TxData
->FragmentTable
[Index
].FragmentBuffer
,
170 TxData
->FragmentTable
[Index
].FragmentLength
172 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
176 // Set the buffer length.
178 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
184 Synchronously send out the packet.
186 @param[in] MnpServiceData Pointer to the mnp service context data.
187 @param[in] Packet Pointer to the pakcet buffer.
188 @param[in] Length The length of the packet.
189 @param[in, out] Token Pointer to the token the packet generated from.
191 @retval EFI_SUCCESS The packet is sent out.
192 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
193 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
198 IN MNP_SERVICE_DATA
*MnpServiceData
,
201 IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
205 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
206 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
209 MNP_DEVICE_DATA
*MnpDeviceData
;
212 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
213 Snp
= MnpDeviceData
->Snp
;
214 TxData
= Token
->Packet
.TxData
;
216 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
219 // Check media status before transmit packet.
220 // Note: media status will be updated by periodic timer MediaDetectTimer.
222 if (Snp
->Mode
->MediaPresentSupported
&& !Snp
->Mode
->MediaPresent
) {
224 // Media not present, skip packet transmit and report EFI_NO_MEDIA
226 DEBUG ((EFI_D_WARN
, "MnpSyncSendPacket: No network cable detected.\n"));
227 Status
= EFI_NO_MEDIA
;
232 // Start the timeout event.
234 Status
= gBS
->SetTimer (
235 MnpDeviceData
->TxTimeoutEvent
,
239 if (EFI_ERROR (Status
)) {
244 if (MnpServiceData
->VlanId
!= 0) {
248 MnpInsertVlanTag (MnpServiceData
, TxData
, &ProtocolType
, &Packet
, &Length
);
250 ProtocolType
= TxData
->ProtocolType
;
255 // Transmit the packet through SNP.
257 Status
= Snp
->Transmit (
262 TxData
->SourceAddress
,
263 TxData
->DestinationAddress
,
266 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
267 Status
= EFI_DEVICE_ERROR
;
272 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
273 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
274 // Both need to sync SNP.
279 // Get the recycled transmit buffer status.
281 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
283 if (!EFI_ERROR (gBS
->CheckEvent (MnpDeviceData
->TxTimeoutEvent
))) {
284 Status
= EFI_TIMEOUT
;
287 } while (TxBuf
== NULL
);
289 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
293 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
296 MnpDeviceData
->TxTimeoutEvent
,
304 // Cancel the timer event.
306 gBS
->SetTimer (MnpDeviceData
->TxTimeoutEvent
, TimerCancel
, 0);
310 Token
->Status
= Status
;
311 gBS
->SignalEvent (Token
->Event
);
314 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
323 Try to deliver the received packet to the instance.
325 @param[in, out] Instance Pointer to the mnp instance context data.
327 @retval EFI_SUCCESS The received packet is delivered, or there is no
328 packet to deliver, or there is no available receive
330 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
334 MnpInstanceDeliverPacket (
335 IN OUT MNP_INSTANCE_DATA
*Instance
338 MNP_DEVICE_DATA
*MnpDeviceData
;
339 MNP_RXDATA_WRAP
*RxDataWrap
;
341 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
342 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
343 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
345 MnpDeviceData
= Instance
->MnpServiceData
->MnpDeviceData
;
346 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
348 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
350 // No pending received data or no available receive token, return.
355 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
357 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
358 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
360 // There are other instances share this Nbuf, duplicate to get a
361 // copy to allow the instance to do R/W operations.
363 DupNbuf
= MnpAllocNbuf (MnpDeviceData
);
364 if (DupNbuf
== NULL
) {
365 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
367 return EFI_OUT_OF_RESOURCES
;
371 // Duplicate the net buffer.
373 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
374 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
375 RxDataWrap
->Nbuf
= DupNbuf
;
379 // All resources are OK, remove the packet from the queue.
381 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
382 Instance
->RcvdPacketQueueSize
--;
384 RxData
= &RxDataWrap
->RxData
;
385 SnpMode
= MnpDeviceData
->Snp
->Mode
;
388 // Set all the buffer pointers.
390 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
391 RxData
->DestinationAddress
= RxData
->MediaHeader
;
392 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
393 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
396 // Insert this RxDataWrap into the delivered queue.
398 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
401 // Get the receive token from the RxTokenMap.
403 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
406 // Signal this token's event.
408 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
409 RxToken
->Status
= EFI_SUCCESS
;
410 gBS
->SignalEvent (RxToken
->Event
);
417 Deliver the received packet for the instances belonging to the MnpServiceData.
419 @param[in] MnpServiceData Pointer to the mnp service context data.
424 IN MNP_SERVICE_DATA
*MnpServiceData
428 MNP_INSTANCE_DATA
*Instance
;
430 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
432 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
433 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
434 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
437 // Try to deliver packet for this instance.
439 MnpInstanceDeliverPacket (Instance
);
445 Recycle the RxData and other resources used to hold and deliver the received
448 @param[in] Event The event this notify function registered to.
449 @param[in] Context Pointer to the context data registerd to the Event.
459 MNP_RXDATA_WRAP
*RxDataWrap
;
460 MNP_DEVICE_DATA
*MnpDeviceData
;
462 ASSERT (Context
!= NULL
);
464 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
465 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
467 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
469 MnpDeviceData
= RxDataWrap
->Instance
->MnpServiceData
->MnpDeviceData
;
470 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
475 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
476 RxDataWrap
->Nbuf
= NULL
;
479 // Close the recycle event.
481 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
484 // Remove this Wrap entry from the list.
486 RemoveEntryList (&RxDataWrap
->WrapEntry
);
488 FreePool (RxDataWrap
);
493 Queue the received packet into instance's receive queue.
495 @param[in, out] Instance Pointer to the mnp instance context data.
496 @param[in, out] RxDataWrap Pointer to the Wrap structure containing the
497 received data and other information.
501 IN OUT MNP_INSTANCE_DATA
*Instance
,
502 IN OUT MNP_RXDATA_WRAP
*RxDataWrap
505 MNP_RXDATA_WRAP
*OldRxDataWrap
;
507 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
510 // Check the queue size. If it exceeds the limit, drop one packet
513 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
515 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
518 // Get the oldest packet.
520 OldRxDataWrap
= NET_LIST_HEAD (
521 &Instance
->RcvdPacketQueue
,
527 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
529 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
530 Instance
->RcvdPacketQueueSize
--;
534 // Update the timeout tick using the configured parameter.
536 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
539 // Insert this Wrap into the instance queue.
541 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
542 Instance
->RcvdPacketQueueSize
++;
547 Match the received packet with the instance receive filters.
549 @param[in] Instance Pointer to the mnp instance context data.
550 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
551 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
552 non-NULL and it contains the destination multicast
553 mac address of the received packet if the packet
554 destinated to a multicast mac address.
555 @param[in] PktAttr The received packets attribute.
557 @return The received packet matches the instance's receive filters or not.
562 IN MNP_INSTANCE_DATA
*Instance
,
563 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
564 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
568 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
570 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
572 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
574 ConfigData
= &Instance
->ConfigData
;
577 // Check the protocol type.
579 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
583 if (ConfigData
->EnablePromiscuousReceive
) {
585 // Always match if this instance is configured to be promiscuous.
591 // The protocol type is matched, check receive filter, include unicast and broadcast.
593 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
598 // Check multicast addresses.
600 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
602 ASSERT (GroupAddress
!= NULL
);
604 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
606 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
607 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
609 // The instance is configured to receiveing packets destinated to this
610 // multicast address.
625 Analyse the received packets.
627 @param[in] MnpServiceData Pointer to the mnp service context data.
628 @param[in] Nbuf Pointer to the net buffer holding the received
630 @param[in, out] RxData Pointer to the buffer used to save the analysed
631 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
632 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
633 pass out the address of the multicast address the
634 received packet destinated to.
635 @param[out] PktAttr Pointer to the buffer used to save the analysed
641 IN MNP_SERVICE_DATA
*MnpServiceData
,
643 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
644 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
648 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
649 MNP_DEVICE_DATA
*MnpDeviceData
;
653 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
654 SnpMode
= MnpDeviceData
->Snp
->Mode
;
657 // Get the packet buffer.
659 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
660 ASSERT (BufPtr
!= NULL
);
663 // Set the initial values.
665 RxData
->BroadcastFlag
= FALSE
;
666 RxData
->MulticastFlag
= FALSE
;
667 RxData
->PromiscuousFlag
= FALSE
;
668 *PktAttr
= UNICAST_PACKET
;
670 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
672 // This packet isn't destinated to our current mac address, it't not unicast.
676 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
680 RxData
->BroadcastFlag
= TRUE
;
681 *PktAttr
= BROADCAST_PACKET
;
682 } else if ((*BufPtr
& 0x01) == 0x1) {
684 // It's multicast, try to match the multicast filters.
686 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->GroupAddressList
) {
688 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
689 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
690 RxData
->MulticastFlag
= TRUE
;
695 if (!RxData
->MulticastFlag
) {
697 // No match, set GroupAddress to NULL. This multicast packet must
698 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
700 *GroupAddress
= NULL
;
701 RxData
->PromiscuousFlag
= TRUE
;
703 if (MnpDeviceData
->PromiscuousCount
== 0) {
705 // Skip the below code, there is no receiver of this packet.
711 RxData
->PromiscuousFlag
= TRUE
;
715 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
718 // Fill the common parts of RxData.
720 RxData
->PacketLength
= Nbuf
->TotalSize
;
721 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
722 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
723 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
724 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
731 @param[in] Instance Pointer to the mnp instance context data.
732 @param[in] RxData Pointer to the receive data to wrap.
734 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
739 IN MNP_INSTANCE_DATA
*Instance
,
740 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
744 MNP_RXDATA_WRAP
*RxDataWrap
;
749 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
750 if (RxDataWrap
== NULL
) {
751 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
755 RxDataWrap
->Instance
= Instance
;
758 // Fill the RxData in RxDataWrap,
760 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
763 // Create the recycle event.
765 Status
= gBS
->CreateEvent (
770 &RxDataWrap
->RxData
.RecycleEvent
772 if (EFI_ERROR (Status
)) {
773 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
775 FreePool (RxDataWrap
);
784 Enqueue the received the packets to the instances belonging to the
787 @param[in] MnpServiceData Pointer to the mnp service context data.
788 @param[in] Nbuf Pointer to the net buffer representing the received
794 IN MNP_SERVICE_DATA
*MnpServiceData
,
799 MNP_INSTANCE_DATA
*Instance
;
800 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
802 MNP_GROUP_ADDRESS
*GroupAddress
;
803 MNP_RXDATA_WRAP
*RxDataWrap
;
808 // First, analyse the packet header.
810 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
812 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->MnpDeviceData
->PromiscuousCount
== 0)) {
814 // No receivers, no more action need.
820 // Iterate the children to find match.
822 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
824 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
825 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
827 if (!Instance
->Configured
) {
832 // Check the packet against the instance receive filters.
834 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
838 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
839 if (RxDataWrap
== NULL
) {
844 // Associate RxDataWrap with Nbuf and increase the RefCnt.
846 RxDataWrap
->Nbuf
= Nbuf
;
847 NET_GET_REF (RxDataWrap
->Nbuf
);
850 // Queue the packet into the instance queue.
852 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
859 Try to receive a packet and deliver it.
861 @param[in, out] MnpDeviceData Pointer to the mnp device context data.
863 @retval EFI_SUCCESS add return value to function comment
864 @retval EFI_NOT_STARTED The simple network protocol is not started.
865 @retval EFI_NOT_READY No packet received.
866 @retval EFI_DEVICE_ERROR An unexpected error occurs.
871 IN OUT MNP_DEVICE_DATA
*MnpDeviceData
875 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
881 MNP_SERVICE_DATA
*MnpServiceData
;
883 BOOLEAN IsVlanPacket
;
885 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
887 Snp
= MnpDeviceData
->Snp
;
888 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
890 // The simple network protocol is not started.
892 return EFI_NOT_STARTED
;
895 if (MnpDeviceData
->RxNbufCache
== NULL
) {
897 // Try to get a new buffer as there may be buffers recycled.
899 MnpDeviceData
->RxNbufCache
= MnpAllocNbuf (MnpDeviceData
);
901 if (MnpDeviceData
->RxNbufCache
== NULL
) {
903 // No availabe buffer in the buffer pool.
905 return EFI_DEVICE_ERROR
;
909 MnpDeviceData
->RxNbufCache
,
910 MnpDeviceData
->BufferLength
,
915 Nbuf
= MnpDeviceData
->RxNbufCache
;
916 BufLen
= Nbuf
->TotalSize
;
917 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
918 ASSERT (BufPtr
!= NULL
);
921 // Receive packet through Snp.
923 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
924 if (EFI_ERROR (Status
)) {
926 if (Status
!= EFI_NOT_READY
) {
927 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
937 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
940 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
944 return EFI_DEVICE_ERROR
;
948 if (Nbuf
->TotalSize
!= BufLen
) {
950 // Trim the packet from tail.
952 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
953 ASSERT (Nbuf
->TotalSize
== BufLen
);
957 if (MnpDeviceData
->NumberOfVlan
!= 0) {
959 // VLAN is configured, remove the VLAN tag if any
961 IsVlanPacket
= MnpRemoveVlanTag (MnpDeviceData
, Nbuf
, &VlanId
);
963 IsVlanPacket
= FALSE
;
966 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
967 if (MnpServiceData
== NULL
) {
969 // VLAN is not set for this tagged frame, ignore this packet
972 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
976 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
983 // Enqueue the packet to the matched instances.
985 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
987 if (Nbuf
->RefCnt
> 2) {
989 // RefCnt > 2 indicates there is at least one receiver of this packet.
990 // Free the current RxNbufCache and allocate a new one.
992 MnpFreeNbuf (MnpDeviceData
, Nbuf
);
994 Nbuf
= MnpAllocNbuf (MnpDeviceData
);
995 MnpDeviceData
->RxNbufCache
= Nbuf
;
997 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
998 return EFI_DEVICE_ERROR
;
1001 NetbufAllocSpace (Nbuf
, MnpDeviceData
->BufferLength
, NET_BUF_TAIL
);
1004 // No receiver for this packet.
1007 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
1010 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
1016 // Deliver the queued packets.
1018 MnpDeliverPacket (MnpServiceData
);
1022 ASSERT (Nbuf
->TotalSize
== MnpDeviceData
->BufferLength
);
1029 Remove the received packets if timeout occurs.
1031 @param[in] Event The event this notify function registered to.
1032 @param[in] Context Pointer to the context data registered to the event.
1037 MnpCheckPacketTimeout (
1042 MNP_DEVICE_DATA
*MnpDeviceData
;
1043 MNP_SERVICE_DATA
*MnpServiceData
;
1045 LIST_ENTRY
*ServiceEntry
;
1046 LIST_ENTRY
*RxEntry
;
1047 LIST_ENTRY
*NextEntry
;
1048 MNP_INSTANCE_DATA
*Instance
;
1049 MNP_RXDATA_WRAP
*RxDataWrap
;
1052 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1053 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1055 NET_LIST_FOR_EACH (ServiceEntry
, &MnpDeviceData
->ServiceList
) {
1056 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (ServiceEntry
);
1058 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1060 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1061 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1063 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1065 // This instance is not configured or there is no receive time out,
1066 // just skip to the next instance.
1071 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1073 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1075 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1078 // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1080 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1081 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1084 // Drop the timeout packet.
1086 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1087 MnpRecycleRxData (NULL
, RxDataWrap
);
1088 Instance
->RcvdPacketQueueSize
--;
1092 gBS
->RestoreTPL (OldTpl
);
1098 Poll to update MediaPresent field in SNP ModeData by Snp->GetStatus().
1100 @param[in] Event The event this notify function registered to.
1101 @param[in] Context Pointer to the context data registered to the event.
1106 MnpCheckMediaStatus (
1111 MNP_DEVICE_DATA
*MnpDeviceData
;
1112 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1113 UINT32 InterruptStatus
;
1115 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1116 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1118 Snp
= MnpDeviceData
->Snp
;
1119 if (Snp
->Mode
->MediaPresentSupported
) {
1121 // Upon successful return of GetStatus(), the MediaPresent field of
1122 // EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change of media status
1124 Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
1129 Poll to receive the packets from Snp. This function is either called by upperlayer
1130 protocols/applications or the system poll timer notify mechanism.
1132 @param[in] Event The event this notify function registered to.
1133 @param[in] Context Pointer to the context data registered to the event.
1143 MNP_DEVICE_DATA
*MnpDeviceData
;
1145 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1146 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1149 // Try to receive packets from Snp.
1151 MnpReceivePacket (MnpDeviceData
);
1154 // Dispatch the DPC queued by the NotifyFunction of rx token's events.