2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2013, 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
;
131 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
133 // Reserve space for vlan tag,if necessary.
135 if (MnpServiceData
->VlanId
!= 0) {
136 *PktBuf
= MnpDerviceData
->TxBuf
+ NET_VLAN_TAG_LEN
;
138 *PktBuf
= MnpDerviceData
->TxBuf
;
143 TxData
->FragmentTable
[0].FragmentBuffer
,
144 TxData
->FragmentTable
[0].FragmentLength
147 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
150 // Either media header isn't in FragmentTable or there is more than
151 // one fragment, copy the data into the packet buffer. Reserve the
152 // media header space if necessary.
154 SnpMode
= MnpDerviceData
->Snp
->Mode
;
155 DstPos
= MnpDerviceData
->TxBuf
;
158 if (TxData
->DestinationAddress
!= NULL
) {
160 // If dest address is not NULL, move DstPos to reserve space for the
161 // media header. Add the media header length to buflen.
163 DstPos
+= SnpMode
->MediaHeaderSize
;
164 *PktLen
+= SnpMode
->MediaHeaderSize
;
167 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
173 TxData
->FragmentTable
[Index
].FragmentBuffer
,
174 TxData
->FragmentTable
[Index
].FragmentLength
176 DstPos
+= TxData
->FragmentTable
[Index
].FragmentLength
;
180 // Set the buffer pointer and the buffer length.
182 *PktBuf
= MnpDerviceData
->TxBuf
;
183 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
189 Synchronously send out the packet.
191 @param[in] MnpServiceData Pointer to the mnp service context data.
192 @param[in] Packet Pointer to the pakcet buffer.
193 @param[in] Length The length of the packet.
194 @param[in, out] Token Pointer to the token the packet generated from.
196 @retval EFI_SUCCESS The packet is sent out.
197 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
198 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
203 IN MNP_SERVICE_DATA
*MnpServiceData
,
206 IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
210 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
211 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
214 MNP_DEVICE_DATA
*MnpDeviceData
;
217 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
218 Snp
= MnpDeviceData
->Snp
;
219 TxData
= Token
->Packet
.TxData
;
221 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
224 // Check media status before transmit packet.
225 // Note: media status will be updated by periodic timer MediaDetectTimer.
227 if (Snp
->Mode
->MediaPresentSupported
&& !Snp
->Mode
->MediaPresent
) {
229 // Media not present, skip packet transmit and report EFI_NO_MEDIA
231 DEBUG ((EFI_D_WARN
, "MnpSyncSendPacket: No network cable detected.\n"));
232 Status
= EFI_NO_MEDIA
;
237 // Start the timeout event.
239 Status
= gBS
->SetTimer (
240 MnpDeviceData
->TxTimeoutEvent
,
244 if (EFI_ERROR (Status
)) {
249 if (MnpServiceData
->VlanId
!= 0) {
253 MnpInsertVlanTag (MnpServiceData
, TxData
, &ProtocolType
, &Packet
, &Length
);
255 ProtocolType
= TxData
->ProtocolType
;
260 // Transmit the packet through SNP.
262 Status
= Snp
->Transmit (
267 TxData
->SourceAddress
,
268 TxData
->DestinationAddress
,
271 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
272 Status
= EFI_DEVICE_ERROR
;
277 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
278 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
279 // Both need to sync SNP.
284 // Get the recycled transmit buffer status.
286 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
288 if (!EFI_ERROR (gBS
->CheckEvent (MnpDeviceData
->TxTimeoutEvent
))) {
289 Status
= EFI_TIMEOUT
;
292 } while (TxBuf
== NULL
);
294 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
298 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
301 MnpDeviceData
->TxTimeoutEvent
,
309 // Cancel the timer event.
311 gBS
->SetTimer (MnpDeviceData
->TxTimeoutEvent
, TimerCancel
, 0);
315 Token
->Status
= Status
;
316 gBS
->SignalEvent (Token
->Event
);
319 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
328 Try to deliver the received packet to the instance.
330 @param[in, out] Instance Pointer to the mnp instance context data.
332 @retval EFI_SUCCESS The received packet is delivered, or there is no
333 packet to deliver, or there is no available receive
335 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
339 MnpInstanceDeliverPacket (
340 IN OUT MNP_INSTANCE_DATA
*Instance
343 MNP_DEVICE_DATA
*MnpDeviceData
;
344 MNP_RXDATA_WRAP
*RxDataWrap
;
346 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
347 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
348 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
350 MnpDeviceData
= Instance
->MnpServiceData
->MnpDeviceData
;
351 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
353 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
355 // No pending received data or no available receive token, return.
360 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
362 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
363 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
365 // There are other instances share this Nbuf, duplicate to get a
366 // copy to allow the instance to do R/W operations.
368 DupNbuf
= MnpAllocNbuf (MnpDeviceData
);
369 if (DupNbuf
== NULL
) {
370 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
372 return EFI_OUT_OF_RESOURCES
;
376 // Duplicate the net buffer.
378 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
379 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
380 RxDataWrap
->Nbuf
= DupNbuf
;
384 // All resources are OK, remove the packet from the queue.
386 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
387 Instance
->RcvdPacketQueueSize
--;
389 RxData
= &RxDataWrap
->RxData
;
390 SnpMode
= MnpDeviceData
->Snp
->Mode
;
393 // Set all the buffer pointers.
395 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
396 RxData
->DestinationAddress
= RxData
->MediaHeader
;
397 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
398 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
401 // Insert this RxDataWrap into the delivered queue.
403 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
406 // Get the receive token from the RxTokenMap.
408 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
411 // Signal this token's event.
413 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
414 RxToken
->Status
= EFI_SUCCESS
;
415 gBS
->SignalEvent (RxToken
->Event
);
422 Deliver the received packet for the instances belonging to the MnpServiceData.
424 @param[in] MnpServiceData Pointer to the mnp service context data.
429 IN MNP_SERVICE_DATA
*MnpServiceData
433 MNP_INSTANCE_DATA
*Instance
;
435 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
437 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
438 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
439 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
442 // Try to deliver packet for this instance.
444 MnpInstanceDeliverPacket (Instance
);
450 Recycle the RxData and other resources used to hold and deliver the received
453 @param[in] Event The event this notify function registered to.
454 @param[in] Context Pointer to the context data registerd to the Event.
464 MNP_RXDATA_WRAP
*RxDataWrap
;
465 MNP_DEVICE_DATA
*MnpDeviceData
;
467 ASSERT (Context
!= NULL
);
469 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
470 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
472 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
474 MnpDeviceData
= RxDataWrap
->Instance
->MnpServiceData
->MnpDeviceData
;
475 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
480 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
481 RxDataWrap
->Nbuf
= NULL
;
484 // Close the recycle event.
486 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
489 // Remove this Wrap entry from the list.
491 RemoveEntryList (&RxDataWrap
->WrapEntry
);
493 FreePool (RxDataWrap
);
498 Queue the received packet into instance's receive queue.
500 @param[in, out] Instance Pointer to the mnp instance context data.
501 @param[in, out] RxDataWrap Pointer to the Wrap structure containing the
502 received data and other information.
506 IN OUT MNP_INSTANCE_DATA
*Instance
,
507 IN OUT MNP_RXDATA_WRAP
*RxDataWrap
510 MNP_RXDATA_WRAP
*OldRxDataWrap
;
512 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
515 // Check the queue size. If it exceeds the limit, drop one packet
518 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
520 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
523 // Get the oldest packet.
525 OldRxDataWrap
= NET_LIST_HEAD (
526 &Instance
->RcvdPacketQueue
,
532 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
534 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
535 Instance
->RcvdPacketQueueSize
--;
539 // Update the timeout tick using the configured parameter.
541 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
544 // Insert this Wrap into the instance queue.
546 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
547 Instance
->RcvdPacketQueueSize
++;
552 Match the received packet with the instance receive filters.
554 @param[in] Instance Pointer to the mnp instance context data.
555 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
556 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
557 non-NULL and it contains the destination multicast
558 mac address of the received packet if the packet
559 destinated to a multicast mac address.
560 @param[in] PktAttr The received packets attribute.
562 @return The received packet matches the instance's receive filters or not.
567 IN MNP_INSTANCE_DATA
*Instance
,
568 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
569 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
573 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
575 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
577 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
579 ConfigData
= &Instance
->ConfigData
;
582 // Check the protocol type.
584 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
588 if (ConfigData
->EnablePromiscuousReceive
) {
590 // Always match if this instance is configured to be promiscuous.
596 // The protocol type is matched, check receive filter, include unicast and broadcast.
598 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
603 // Check multicast addresses.
605 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
607 ASSERT (GroupAddress
!= NULL
);
609 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
611 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
612 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
614 // The instance is configured to receiveing packets destinated to this
615 // multicast address.
630 Analyse the received packets.
632 @param[in] MnpServiceData Pointer to the mnp service context data.
633 @param[in] Nbuf Pointer to the net buffer holding the received
635 @param[in, out] RxData Pointer to the buffer used to save the analysed
636 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
637 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
638 pass out the address of the multicast address the
639 received packet destinated to.
640 @param[out] PktAttr Pointer to the buffer used to save the analysed
646 IN MNP_SERVICE_DATA
*MnpServiceData
,
648 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
649 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
653 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
654 MNP_DEVICE_DATA
*MnpDeviceData
;
658 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
659 SnpMode
= MnpDeviceData
->Snp
->Mode
;
662 // Get the packet buffer.
664 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
665 ASSERT (BufPtr
!= NULL
);
668 // Set the initial values.
670 RxData
->BroadcastFlag
= FALSE
;
671 RxData
->MulticastFlag
= FALSE
;
672 RxData
->PromiscuousFlag
= FALSE
;
673 *PktAttr
= UNICAST_PACKET
;
675 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
677 // This packet isn't destinated to our current mac address, it't not unicast.
681 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
685 RxData
->BroadcastFlag
= TRUE
;
686 *PktAttr
= BROADCAST_PACKET
;
687 } else if ((*BufPtr
& 0x01) == 0x1) {
689 // It's multicast, try to match the multicast filters.
691 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->GroupAddressList
) {
693 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
694 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
695 RxData
->MulticastFlag
= TRUE
;
700 if (!RxData
->MulticastFlag
) {
702 // No match, set GroupAddress to NULL. This multicast packet must
703 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
705 *GroupAddress
= NULL
;
706 RxData
->PromiscuousFlag
= TRUE
;
708 if (MnpDeviceData
->PromiscuousCount
== 0) {
710 // Skip the below code, there is no receiver of this packet.
716 RxData
->PromiscuousFlag
= TRUE
;
720 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
723 // Fill the common parts of RxData.
725 RxData
->PacketLength
= Nbuf
->TotalSize
;
726 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
727 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
728 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
729 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
736 @param[in] Instance Pointer to the mnp instance context data.
737 @param[in] RxData Pointer to the receive data to wrap.
739 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
744 IN MNP_INSTANCE_DATA
*Instance
,
745 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
749 MNP_RXDATA_WRAP
*RxDataWrap
;
754 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
755 if (RxDataWrap
== NULL
) {
756 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
760 RxDataWrap
->Instance
= Instance
;
763 // Fill the RxData in RxDataWrap,
765 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
768 // Create the recycle event.
770 Status
= gBS
->CreateEvent (
775 &RxDataWrap
->RxData
.RecycleEvent
777 if (EFI_ERROR (Status
)) {
778 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
780 FreePool (RxDataWrap
);
789 Enqueue the received the packets to the instances belonging to the
792 @param[in] MnpServiceData Pointer to the mnp service context data.
793 @param[in] Nbuf Pointer to the net buffer representing the received
799 IN MNP_SERVICE_DATA
*MnpServiceData
,
804 MNP_INSTANCE_DATA
*Instance
;
805 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
807 MNP_GROUP_ADDRESS
*GroupAddress
;
808 MNP_RXDATA_WRAP
*RxDataWrap
;
813 // First, analyse the packet header.
815 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
817 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->MnpDeviceData
->PromiscuousCount
== 0)) {
819 // No receivers, no more action need.
825 // Iterate the children to find match.
827 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
829 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
830 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
832 if (!Instance
->Configured
) {
837 // Check the packet against the instance receive filters.
839 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
843 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
844 if (RxDataWrap
== NULL
) {
849 // Associate RxDataWrap with Nbuf and increase the RefCnt.
851 RxDataWrap
->Nbuf
= Nbuf
;
852 NET_GET_REF (RxDataWrap
->Nbuf
);
855 // Queue the packet into the instance queue.
857 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
864 Try to receive a packet and deliver it.
866 @param[in, out] MnpDeviceData Pointer to the mnp device context data.
868 @retval EFI_SUCCESS add return value to function comment
869 @retval EFI_NOT_STARTED The simple network protocol is not started.
870 @retval EFI_NOT_READY No packet received.
871 @retval EFI_DEVICE_ERROR An unexpected error occurs.
876 IN OUT MNP_DEVICE_DATA
*MnpDeviceData
880 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
886 MNP_SERVICE_DATA
*MnpServiceData
;
888 BOOLEAN IsVlanPacket
;
890 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
892 Snp
= MnpDeviceData
->Snp
;
893 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
895 // The simple network protocol is not started.
897 return EFI_NOT_STARTED
;
900 if (MnpDeviceData
->RxNbufCache
== NULL
) {
902 // Try to get a new buffer as there may be buffers recycled.
904 MnpDeviceData
->RxNbufCache
= MnpAllocNbuf (MnpDeviceData
);
906 if (MnpDeviceData
->RxNbufCache
== NULL
) {
908 // No availabe buffer in the buffer pool.
910 return EFI_DEVICE_ERROR
;
914 MnpDeviceData
->RxNbufCache
,
915 MnpDeviceData
->BufferLength
,
920 Nbuf
= MnpDeviceData
->RxNbufCache
;
921 BufLen
= Nbuf
->TotalSize
;
922 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
923 ASSERT (BufPtr
!= NULL
);
926 // Receive packet through Snp.
928 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
929 if (EFI_ERROR (Status
)) {
931 if (Status
!= EFI_NOT_READY
) {
932 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
942 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
945 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
949 return EFI_DEVICE_ERROR
;
953 if (Nbuf
->TotalSize
!= BufLen
) {
955 // Trim the packet from tail.
957 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
958 ASSERT (Nbuf
->TotalSize
== BufLen
);
962 if (MnpDeviceData
->NumberOfVlan
!= 0) {
964 // VLAN is configured, remove the VLAN tag if any
966 IsVlanPacket
= MnpRemoveVlanTag (MnpDeviceData
, Nbuf
, &VlanId
);
968 IsVlanPacket
= FALSE
;
971 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
972 if (MnpServiceData
== NULL
) {
974 // VLAN is not set for this tagged frame, ignore this packet
977 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
981 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
988 // Enqueue the packet to the matched instances.
990 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
992 if (Nbuf
->RefCnt
> 2) {
994 // RefCnt > 2 indicates there is at least one receiver of this packet.
995 // Free the current RxNbufCache and allocate a new one.
997 MnpFreeNbuf (MnpDeviceData
, Nbuf
);
999 Nbuf
= MnpAllocNbuf (MnpDeviceData
);
1000 MnpDeviceData
->RxNbufCache
= Nbuf
;
1002 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
1003 return EFI_DEVICE_ERROR
;
1006 NetbufAllocSpace (Nbuf
, MnpDeviceData
->BufferLength
, NET_BUF_TAIL
);
1009 // No receiver for this packet.
1012 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
1015 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
1021 // Deliver the queued packets.
1023 MnpDeliverPacket (MnpServiceData
);
1027 ASSERT (Nbuf
->TotalSize
== MnpDeviceData
->BufferLength
);
1034 Remove the received packets if timeout occurs.
1036 @param[in] Event The event this notify function registered to.
1037 @param[in] Context Pointer to the context data registered to the event.
1042 MnpCheckPacketTimeout (
1047 MNP_DEVICE_DATA
*MnpDeviceData
;
1048 MNP_SERVICE_DATA
*MnpServiceData
;
1050 LIST_ENTRY
*ServiceEntry
;
1051 LIST_ENTRY
*RxEntry
;
1052 LIST_ENTRY
*NextEntry
;
1053 MNP_INSTANCE_DATA
*Instance
;
1054 MNP_RXDATA_WRAP
*RxDataWrap
;
1057 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1058 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1060 NET_LIST_FOR_EACH (ServiceEntry
, &MnpDeviceData
->ServiceList
) {
1061 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (ServiceEntry
);
1063 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1065 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1066 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1068 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1070 // This instance is not configured or there is no receive time out,
1071 // just skip to the next instance.
1076 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1078 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1080 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1083 // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1085 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1086 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1089 // Drop the timeout packet.
1091 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1092 MnpRecycleRxData (NULL
, RxDataWrap
);
1093 Instance
->RcvdPacketQueueSize
--;
1097 gBS
->RestoreTPL (OldTpl
);
1103 Poll to update MediaPresent field in SNP ModeData by Snp->GetStatus().
1105 @param[in] Event The event this notify function registered to.
1106 @param[in] Context Pointer to the context data registered to the event.
1111 MnpCheckMediaStatus (
1116 MNP_DEVICE_DATA
*MnpDeviceData
;
1117 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1118 UINT32 InterruptStatus
;
1120 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1121 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1123 Snp
= MnpDeviceData
->Snp
;
1124 if (Snp
->Mode
->MediaPresentSupported
) {
1126 // Upon successful return of GetStatus(), the MediaPresent field of
1127 // EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change of media status
1129 Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
1134 Poll to receive the packets from Snp. This function is either called by upperlayer
1135 protocols/applications or the system poll timer notify mechanism.
1137 @param[in] Event The event this notify function registered to.
1138 @param[in] Context Pointer to the context data registered to the event.
1148 MNP_DEVICE_DATA
*MnpDeviceData
;
1150 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1151 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1154 // Try to receive packets from Snp.
1156 MnpReceivePacket (MnpDeviceData
);
1159 // Dispatch the DPC queued by the NotifyFunction of rx token's events.