2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2010, Intel Corporation.<BR>
5 All rights reserved. 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
;
131 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
133 // Media header is in FragmentTable and there is only one fragment,
134 // use fragment buffer directly.
136 *PktBuf
= TxData
->FragmentTable
[0].FragmentBuffer
;
137 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
140 // Either media header isn't in FragmentTable or there is more than
141 // one fragment, copy the data into the packet buffer. Reserve the
142 // media header space if necessary.
144 SnpMode
= MnpDerviceData
->Snp
->Mode
;
145 DstPos
= MnpDerviceData
->TxBuf
;
148 if (TxData
->DestinationAddress
!= NULL
) {
150 // If dest address is not NULL, move DstPos to reserve space for the
151 // media header. Add the media header length to buflen.
153 DstPos
+= SnpMode
->MediaHeaderSize
;
154 *PktLen
+= SnpMode
->MediaHeaderSize
;
157 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
163 TxData
->FragmentTable
[Index
].FragmentBuffer
,
164 TxData
->FragmentTable
[Index
].FragmentLength
166 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
170 // Set the buffer pointer and the buffer length.
172 *PktBuf
= MnpDerviceData
->TxBuf
;
173 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
179 Synchronously send out the packet.
181 @param[in] MnpServiceData Pointer to the mnp service context data.
182 @param[in] Packet Pointer to the pakcet buffer.
183 @param[in] Length The length of the packet.
184 @param[in, out] Token Pointer to the token the packet generated from.
186 @retval EFI_SUCCESS The packet is sent out.
187 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
188 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
193 IN MNP_SERVICE_DATA
*MnpServiceData
,
196 IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
200 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
201 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
204 MNP_DEVICE_DATA
*MnpDeviceData
;
207 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
208 Snp
= MnpDeviceData
->Snp
;
209 TxData
= Token
->Packet
.TxData
;
211 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
214 // Check media status before transmit packet.
215 // Note: media status will be updated by periodic timer MediaDetectTimer.
217 if (Snp
->Mode
->MediaPresentSupported
&& !Snp
->Mode
->MediaPresent
) {
219 // Media not present, skip packet transmit and report EFI_NO_MEDIA
221 DEBUG ((EFI_D_WARN
, "MnpSyncSendPacket: No network cable detected.\n"));
222 Status
= EFI_NO_MEDIA
;
227 // Start the timeout event.
229 Status
= gBS
->SetTimer (
230 MnpDeviceData
->TxTimeoutEvent
,
234 if (EFI_ERROR (Status
)) {
241 MnpInsertVlanTag (MnpServiceData
, TxData
, &ProtocolType
, &Packet
, &Length
);
245 // Transmit the packet through SNP.
247 Status
= Snp
->Transmit (
252 TxData
->SourceAddress
,
253 TxData
->DestinationAddress
,
256 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
257 Status
= EFI_DEVICE_ERROR
;
262 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
263 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
264 // Both need to sync SNP.
269 // Get the recycled transmit buffer status.
271 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
273 if (!EFI_ERROR (gBS
->CheckEvent (MnpDeviceData
->TxTimeoutEvent
))) {
274 Status
= EFI_TIMEOUT
;
277 } while (TxBuf
== NULL
);
279 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
283 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
286 MnpDeviceData
->TxTimeoutEvent
,
294 // Cancel the timer event.
296 gBS
->SetTimer (MnpDeviceData
->TxTimeoutEvent
, TimerCancel
, 0);
300 Token
->Status
= Status
;
301 gBS
->SignalEvent (Token
->Event
);
304 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
313 Try to deliver the received packet to the instance.
315 @param[in, out] Instance Pointer to the mnp instance context data.
317 @retval EFI_SUCCESS The received packet is delivered, or there is no
318 packet to deliver, or there is no available receive
320 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
324 MnpInstanceDeliverPacket (
325 IN OUT MNP_INSTANCE_DATA
*Instance
328 MNP_DEVICE_DATA
*MnpDeviceData
;
329 MNP_RXDATA_WRAP
*RxDataWrap
;
331 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
332 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
333 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
335 MnpDeviceData
= Instance
->MnpServiceData
->MnpDeviceData
;
336 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
338 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
340 // No pending received data or no available receive token, return.
345 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
347 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
348 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
350 // There are other instances share this Nbuf, duplicate to get a
351 // copy to allow the instance to do R/W operations.
353 DupNbuf
= MnpAllocNbuf (MnpDeviceData
);
354 if (DupNbuf
== NULL
) {
355 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
357 return EFI_OUT_OF_RESOURCES
;
361 // Duplicate the net buffer.
363 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
364 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
365 RxDataWrap
->Nbuf
= DupNbuf
;
369 // All resources are OK, remove the packet from the queue.
371 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
372 Instance
->RcvdPacketQueueSize
--;
374 RxData
= &RxDataWrap
->RxData
;
375 SnpMode
= MnpDeviceData
->Snp
->Mode
;
378 // Set all the buffer pointers.
380 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
381 RxData
->DestinationAddress
= RxData
->MediaHeader
;
382 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
383 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
386 // Insert this RxDataWrap into the delivered queue.
388 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
391 // Get the receive token from the RxTokenMap.
393 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
396 // Signal this token's event.
398 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
399 RxToken
->Status
= EFI_SUCCESS
;
400 gBS
->SignalEvent (RxToken
->Event
);
407 Deliver the received packet for the instances belonging to the MnpServiceData.
409 @param[in] MnpServiceData Pointer to the mnp service context data.
414 IN MNP_SERVICE_DATA
*MnpServiceData
418 MNP_INSTANCE_DATA
*Instance
;
420 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
422 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
423 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
424 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
427 // Try to deliver packet for this instance.
429 MnpInstanceDeliverPacket (Instance
);
435 Recycle the RxData and other resources used to hold and deliver the received
438 @param[in] Event The event this notify function registered to.
439 @param[in] Context Pointer to the context data registerd to the Event.
449 MNP_RXDATA_WRAP
*RxDataWrap
;
450 MNP_DEVICE_DATA
*MnpDeviceData
;
452 ASSERT (Context
!= NULL
);
454 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
455 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
457 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
459 MnpDeviceData
= RxDataWrap
->Instance
->MnpServiceData
->MnpDeviceData
;
460 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
465 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
466 RxDataWrap
->Nbuf
= NULL
;
469 // Close the recycle event.
471 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
474 // Remove this Wrap entry from the list.
476 RemoveEntryList (&RxDataWrap
->WrapEntry
);
478 FreePool (RxDataWrap
);
483 Queue the received packet into instance's receive queue.
485 @param[in, out] Instance Pointer to the mnp instance context data.
486 @param[in, out] RxDataWrap Pointer to the Wrap structure containing the
487 received data and other information.
491 IN OUT MNP_INSTANCE_DATA
*Instance
,
492 IN OUT MNP_RXDATA_WRAP
*RxDataWrap
495 MNP_RXDATA_WRAP
*OldRxDataWrap
;
497 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
500 // Check the queue size. If it exceeds the limit, drop one packet
503 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
505 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
508 // Get the oldest packet.
510 OldRxDataWrap
= NET_LIST_HEAD (
511 &Instance
->RcvdPacketQueue
,
517 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
519 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
520 Instance
->RcvdPacketQueueSize
--;
524 // Update the timeout tick using the configured parameter.
526 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
529 // Insert this Wrap into the instance queue.
531 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
532 Instance
->RcvdPacketQueueSize
++;
537 Match the received packet with the instance receive filters.
539 @param[in] Instance Pointer to the mnp instance context data.
540 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
541 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
542 non-NULL and it contains the destination multicast
543 mac address of the received packet if the packet
544 destinated to a multicast mac address.
545 @param[in] PktAttr The received packets attribute.
547 @return The received packet matches the instance's receive filters or not.
552 IN MNP_INSTANCE_DATA
*Instance
,
553 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
554 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
558 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
560 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
562 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
564 ConfigData
= &Instance
->ConfigData
;
567 // Check the protocol type.
569 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
573 if (ConfigData
->EnablePromiscuousReceive
) {
575 // Always match if this instance is configured to be promiscuous.
581 // The protocol type is matched, check receive filter, include unicast and broadcast.
583 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
588 // Check multicast addresses.
590 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
592 ASSERT (GroupAddress
!= NULL
);
594 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
596 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
597 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
599 // The instance is configured to receiveing packets destinated to this
600 // multicast address.
615 Analyse the received packets.
617 @param[in] MnpServiceData Pointer to the mnp service context data.
618 @param[in] Nbuf Pointer to the net buffer holding the received
620 @param[in, out] RxData Pointer to the buffer used to save the analysed
621 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
622 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
623 pass out the address of the multicast address the
624 received packet destinated to.
625 @param[out] PktAttr Pointer to the buffer used to save the analysed
631 IN MNP_SERVICE_DATA
*MnpServiceData
,
633 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
634 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
638 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
639 MNP_DEVICE_DATA
*MnpDeviceData
;
643 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
644 SnpMode
= MnpDeviceData
->Snp
->Mode
;
647 // Get the packet buffer.
649 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
650 ASSERT (BufPtr
!= NULL
);
653 // Set the initial values.
655 RxData
->BroadcastFlag
= FALSE
;
656 RxData
->MulticastFlag
= FALSE
;
657 RxData
->PromiscuousFlag
= FALSE
;
658 *PktAttr
= UNICAST_PACKET
;
660 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
662 // This packet isn't destinated to our current mac address, it't not unicast.
666 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
670 RxData
->BroadcastFlag
= TRUE
;
671 *PktAttr
= BROADCAST_PACKET
;
672 } else if ((*BufPtr
& 0x01) == 0x1) {
674 // It's multicast, try to match the multicast filters.
676 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->GroupAddressList
) {
678 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
679 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
680 RxData
->MulticastFlag
= TRUE
;
685 if (!RxData
->MulticastFlag
) {
687 // No match, set GroupAddress to NULL. This multicast packet must
688 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
690 *GroupAddress
= NULL
;
691 RxData
->PromiscuousFlag
= TRUE
;
693 if (MnpDeviceData
->PromiscuousCount
== 0) {
695 // Skip the below code, there is no receiver of this packet.
701 RxData
->PromiscuousFlag
= TRUE
;
705 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
708 // Fill the common parts of RxData.
710 RxData
->PacketLength
= Nbuf
->TotalSize
;
711 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
712 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
713 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
714 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
721 @param[in] Instance Pointer to the mnp instance context data.
722 @param[in] RxData Pointer to the receive data to wrap.
724 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
729 IN MNP_INSTANCE_DATA
*Instance
,
730 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
734 MNP_RXDATA_WRAP
*RxDataWrap
;
739 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
740 if (RxDataWrap
== NULL
) {
741 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
745 RxDataWrap
->Instance
= Instance
;
748 // Fill the RxData in RxDataWrap,
750 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
753 // Create the recycle event.
755 Status
= gBS
->CreateEvent (
760 &RxDataWrap
->RxData
.RecycleEvent
762 if (EFI_ERROR (Status
)) {
763 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
765 FreePool (RxDataWrap
);
774 Enqueue the received the packets to the instances belonging to the
777 @param[in] MnpServiceData Pointer to the mnp service context data.
778 @param[in] Nbuf Pointer to the net buffer representing the received
784 IN MNP_SERVICE_DATA
*MnpServiceData
,
789 MNP_INSTANCE_DATA
*Instance
;
790 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
792 MNP_GROUP_ADDRESS
*GroupAddress
;
793 MNP_RXDATA_WRAP
*RxDataWrap
;
798 // First, analyse the packet header.
800 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
802 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->MnpDeviceData
->PromiscuousCount
== 0)) {
804 // No receivers, no more action need.
810 // Iterate the children to find match.
812 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
814 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
815 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
817 if (!Instance
->Configured
) {
822 // Check the packet against the instance receive filters.
824 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[in, out] MnpDeviceData Pointer to the mnp device 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 OUT MNP_DEVICE_DATA
*MnpDeviceData
865 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
871 MNP_SERVICE_DATA
*MnpServiceData
;
873 BOOLEAN IsVlanPacket
;
875 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
877 Snp
= MnpDeviceData
->Snp
;
878 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
880 // The simple network protocol is not started.
882 return EFI_NOT_STARTED
;
885 if (MnpDeviceData
->RxNbufCache
== NULL
) {
887 // Try to get a new buffer as there may be buffers recycled.
889 MnpDeviceData
->RxNbufCache
= MnpAllocNbuf (MnpDeviceData
);
891 if (MnpDeviceData
->RxNbufCache
== NULL
) {
893 // No availabe buffer in the buffer pool.
895 return EFI_DEVICE_ERROR
;
899 MnpDeviceData
->RxNbufCache
,
900 MnpDeviceData
->BufferLength
,
905 Nbuf
= MnpDeviceData
->RxNbufCache
;
906 BufLen
= Nbuf
->TotalSize
;
907 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
908 ASSERT (BufPtr
!= NULL
);
911 // Receive packet through Snp.
913 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
914 if (EFI_ERROR (Status
)) {
916 if (Status
!= EFI_NOT_READY
) {
917 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
927 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
930 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
934 return EFI_DEVICE_ERROR
;
938 if (Nbuf
->TotalSize
!= BufLen
) {
940 // Trim the packet from tail.
942 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
943 ASSERT (Nbuf
->TotalSize
== BufLen
);
947 IsVlanPacket
= MnpRemoveVlanTag (MnpDeviceData
, Nbuf
, &VlanId
);
949 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
950 if (MnpServiceData
== NULL
) {
952 // VLAN is not set for this tagged frame, ignore this packet
955 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
959 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
966 // Enqueue the packet to the matched instances.
968 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
970 if (Nbuf
->RefCnt
> 2) {
972 // RefCnt > 2 indicates there is at least one receiver of this packet.
973 // Free the current RxNbufCache and allocate a new one.
975 MnpFreeNbuf (MnpDeviceData
, Nbuf
);
977 Nbuf
= MnpAllocNbuf (MnpDeviceData
);
978 MnpDeviceData
->RxNbufCache
= Nbuf
;
980 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
981 return EFI_DEVICE_ERROR
;
984 NetbufAllocSpace (Nbuf
, MnpDeviceData
->BufferLength
, NET_BUF_TAIL
);
987 // No receiver for this packet.
990 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
993 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
999 // Deliver the queued packets.
1001 MnpDeliverPacket (MnpServiceData
);
1005 ASSERT (Nbuf
->TotalSize
== MnpDeviceData
->BufferLength
);
1012 Remove the received packets if timeout occurs.
1014 @param[in] Event The event this notify function registered to.
1015 @param[in] Context Pointer to the context data registered to the event.
1020 MnpCheckPacketTimeout (
1025 MNP_DEVICE_DATA
*MnpDeviceData
;
1026 MNP_SERVICE_DATA
*MnpServiceData
;
1028 LIST_ENTRY
*ServiceEntry
;
1029 LIST_ENTRY
*RxEntry
;
1030 LIST_ENTRY
*NextEntry
;
1031 MNP_INSTANCE_DATA
*Instance
;
1032 MNP_RXDATA_WRAP
*RxDataWrap
;
1035 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1036 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1038 NET_LIST_FOR_EACH (ServiceEntry
, &MnpDeviceData
->ServiceList
) {
1039 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (ServiceEntry
);
1041 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1043 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1044 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1046 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1048 // This instance is not configured or there is no receive time out,
1049 // just skip to the next instance.
1054 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1056 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1058 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1061 // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1063 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1064 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1067 // Drop the timeout packet.
1069 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1070 MnpRecycleRxData (NULL
, RxDataWrap
);
1071 Instance
->RcvdPacketQueueSize
--;
1075 gBS
->RestoreTPL (OldTpl
);
1081 Poll to update MediaPresent field in SNP ModeData by Snp->GetStatus().
1083 @param[in] Event The event this notify function registered to.
1084 @param[in] Context Pointer to the context data registered to the event.
1089 MnpCheckMediaStatus (
1094 MNP_DEVICE_DATA
*MnpDeviceData
;
1095 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1096 UINT32 InterruptStatus
;
1098 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1099 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1101 Snp
= MnpDeviceData
->Snp
;
1102 if (Snp
->Mode
->MediaPresentSupported
) {
1104 // Upon successful return of GetStatus(), the MediaPresent field of
1105 // EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change of media status
1107 Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
1112 Poll to receive the packets from Snp. This function is either called by upperlayer
1113 protocols/applications or the system poll timer notify mechanism.
1115 @param[in] Event The event this notify function registered to.
1116 @param[in] Context Pointer to the context data registered to the event.
1126 MNP_DEVICE_DATA
*MnpDeviceData
;
1128 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1129 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1132 // Try to receive packets from Snp.
1134 MnpReceivePacket (MnpDeviceData
);
1137 // Dispatch the DPC queued by the NotifyFunction of rx token's events.