2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Validates the Mnp transmit token.
15 @param[in] Instance Pointer to the Mnp instance context data.
16 @param[in] Token Pointer to the transmit token to check.
18 @return The Token is valid or not.
23 IN MNP_INSTANCE_DATA
*Instance
,
24 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
27 MNP_SERVICE_DATA
*MnpServiceData
;
28 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
31 EFI_MANAGED_NETWORK_FRAGMENT_DATA
*FragmentTable
;
33 MnpServiceData
= Instance
->MnpServiceData
;
34 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
36 TxData
= Token
->Packet
.TxData
;
38 if ((Token
->Event
== NULL
) || (TxData
== NULL
) || (TxData
->FragmentCount
== 0)) {
40 // The token is invalid if the Event is NULL, or the TxData is NULL, or
41 // the fragment count is zero.
43 DEBUG ((DEBUG_WARN
, "MnpIsValidTxToken: Invalid Token.\n"));
47 if ((TxData
->DestinationAddress
!= NULL
) && (TxData
->HeaderLength
!= 0)) {
49 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
50 // is NULL (The destination address is already put into the packet).
52 DEBUG ((DEBUG_WARN
, "MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
57 FragmentTable
= TxData
->FragmentTable
;
58 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
59 if ((FragmentTable
[Index
].FragmentLength
== 0) || (FragmentTable
[Index
].FragmentBuffer
== NULL
)) {
61 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
63 DEBUG ((DEBUG_WARN
, "MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
67 TotalLength
+= FragmentTable
[Index
].FragmentLength
;
70 if ((TxData
->DestinationAddress
== NULL
) && (FragmentTable
[0].FragmentLength
< TxData
->HeaderLength
)) {
72 // Media header is split between fragments.
77 if (TotalLength
!= (TxData
->DataLength
+ TxData
->HeaderLength
)) {
79 // The length calculated from the fragment information doesn't equal to the
80 // sum of the DataLength and the HeaderLength.
82 DEBUG ((DEBUG_WARN
, "MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
86 if (TxData
->DataLength
> MnpServiceData
->Mtu
) {
88 // The total length is larger than the MTU.
90 DEBUG ((DEBUG_WARN
, "MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
98 Build the packet to transmit from the TxData passed in.
100 @param[in] MnpServiceData Pointer to the mnp service context data.
101 @param[in] TxData Pointer to the transmit data containing the information
103 @param[out] PktBuf Pointer to record the address of the packet.
104 @param[out] PktLen Pointer to a UINT32 variable used to record the packet's
107 @retval EFI_SUCCESS TxPackage is built.
108 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
113 IN MNP_SERVICE_DATA
*MnpServiceData
,
114 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
,
119 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
122 MNP_DEVICE_DATA
*MnpDeviceData
;
125 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
127 TxBuf
= MnpAllocTxBuf (MnpDeviceData
);
129 return EFI_OUT_OF_RESOURCES
;
133 // Reserve space for vlan tag if needed.
135 if (MnpServiceData
->VlanId
!= 0) {
136 *PktBuf
= TxBuf
+ NET_VLAN_TAG_LEN
;
141 if ((TxData
->DestinationAddress
== NULL
) && (TxData
->FragmentCount
== 1)) {
144 TxData
->FragmentTable
[0].FragmentBuffer
,
145 TxData
->FragmentTable
[0].FragmentLength
148 *PktLen
= TxData
->FragmentTable
[0].FragmentLength
;
151 // Either media header isn't in FragmentTable or there is more than
152 // one fragment, copy the data into the packet buffer. Reserve the
153 // media header space if necessary.
155 SnpMode
= MnpDeviceData
->Snp
->Mode
;
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 length.
182 *PktLen
+= TxData
->DataLength
+ TxData
->HeaderLength
;
189 Synchronously send out the packet.
191 This function places the packet buffer to SNP driver's tansmit queue. The packet
192 can be considered successfully sent out once SNP accept the packet, while the
193 packet buffer recycle is deferred for better performance.
195 @param[in] MnpServiceData Pointer to the mnp service context data.
196 @param[in] Packet Pointer to the packet buffer.
197 @param[in] Length The length of the packet.
198 @param[in, out] Token Pointer to the token the packet generated from.
200 @retval EFI_SUCCESS The packet is sent out.
201 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
202 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
207 IN MNP_SERVICE_DATA
*MnpServiceData
,
210 IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*Token
214 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
215 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
217 MNP_DEVICE_DATA
*MnpDeviceData
;
220 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
221 Snp
= MnpDeviceData
->Snp
;
222 TxData
= Token
->Packet
.TxData
;
223 Token
->Status
= EFI_SUCCESS
;
224 HeaderSize
= Snp
->Mode
->MediaHeaderSize
- TxData
->HeaderLength
;
227 // Check media status before transmit packet.
228 // Note: media status will be updated by periodic timer MediaDetectTimer.
230 if (Snp
->Mode
->MediaPresentSupported
&& !Snp
->Mode
->MediaPresent
) {
232 // Media not present, skip packet transmit and report EFI_NO_MEDIA
234 DEBUG ((DEBUG_WARN
, "MnpSyncSendPacket: No network cable detected.\n"));
235 Token
->Status
= EFI_NO_MEDIA
;
239 if (MnpServiceData
->VlanId
!= 0) {
243 MnpInsertVlanTag (MnpServiceData
, TxData
, &ProtocolType
, &Packet
, &Length
);
245 ProtocolType
= TxData
->ProtocolType
;
249 // Transmit the packet through SNP.
251 Status
= Snp
->Transmit (
256 TxData
->SourceAddress
,
257 TxData
->DestinationAddress
,
260 if (Status
== EFI_NOT_READY
) {
261 Status
= MnpRecycleTxBuf (MnpDeviceData
);
262 if (EFI_ERROR (Status
)) {
263 Token
->Status
= EFI_DEVICE_ERROR
;
267 Status
= Snp
->Transmit (
272 TxData
->SourceAddress
,
273 TxData
->DestinationAddress
,
278 if (EFI_ERROR (Status
)) {
279 Token
->Status
= EFI_DEVICE_ERROR
;
284 gBS
->SignalEvent (Token
->Event
);
287 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
295 Try to deliver the received packet to the instance.
297 @param[in, out] Instance Pointer to the mnp instance context data.
299 @retval EFI_SUCCESS The received packet is delivered, or there is no
300 packet to deliver, or there is no available receive
302 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
306 MnpInstanceDeliverPacket (
307 IN OUT MNP_INSTANCE_DATA
*Instance
310 MNP_DEVICE_DATA
*MnpDeviceData
;
311 MNP_RXDATA_WRAP
*RxDataWrap
;
313 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
314 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
315 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
317 MnpDeviceData
= Instance
->MnpServiceData
->MnpDeviceData
;
318 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
320 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
322 // No pending received data or no available receive token, return.
327 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
329 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
330 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
332 // There are other instances share this Nbuf, duplicate to get a
333 // copy to allow the instance to do R/W operations.
335 DupNbuf
= MnpAllocNbuf (MnpDeviceData
);
336 if (DupNbuf
== NULL
) {
337 DEBUG ((DEBUG_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
339 return EFI_OUT_OF_RESOURCES
;
343 // Duplicate the net buffer.
345 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
346 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
347 RxDataWrap
->Nbuf
= DupNbuf
;
351 // All resources are OK, remove the packet from the queue.
353 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
354 Instance
->RcvdPacketQueueSize
--;
356 RxData
= &RxDataWrap
->RxData
;
357 SnpMode
= MnpDeviceData
->Snp
->Mode
;
360 // Set all the buffer pointers.
362 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
363 RxData
->DestinationAddress
= RxData
->MediaHeader
;
364 RxData
->SourceAddress
= (UINT8
*)RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
365 RxData
->PacketData
= (UINT8
*)RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
368 // Insert this RxDataWrap into the delivered queue.
370 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
373 // Get the receive token from the RxTokenMap.
375 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
378 // Signal this token's event.
380 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
381 RxToken
->Status
= EFI_SUCCESS
;
382 gBS
->SignalEvent (RxToken
->Event
);
388 Deliver the received packet for the instances belonging to the MnpServiceData.
390 @param[in] MnpServiceData Pointer to the mnp service context data.
395 IN MNP_SERVICE_DATA
*MnpServiceData
399 MNP_INSTANCE_DATA
*Instance
;
401 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
403 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
404 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
405 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
408 // Try to deliver packet for this instance.
410 MnpInstanceDeliverPacket (Instance
);
415 Recycle the RxData and other resources used to hold and deliver the received
418 @param[in] Event The event this notify function registered to.
419 @param[in] Context Pointer to the context data registered to the Event.
429 MNP_RXDATA_WRAP
*RxDataWrap
;
430 MNP_DEVICE_DATA
*MnpDeviceData
;
432 ASSERT (Context
!= NULL
);
434 RxDataWrap
= (MNP_RXDATA_WRAP
*)Context
;
435 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
437 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
439 MnpDeviceData
= RxDataWrap
->Instance
->MnpServiceData
->MnpDeviceData
;
440 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
445 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
446 RxDataWrap
->Nbuf
= NULL
;
449 // Close the recycle event.
451 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
454 // Remove this Wrap entry from the list.
456 RemoveEntryList (&RxDataWrap
->WrapEntry
);
458 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
) {
483 DEBUG ((DEBUG_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
486 // Get the oldest packet.
488 OldRxDataWrap
= NET_LIST_HEAD (
489 &Instance
->RcvdPacketQueue
,
495 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
497 MnpRecycleRxData (NULL
, (VOID
*)OldRxDataWrap
);
498 Instance
->RcvdPacketQueueSize
--;
502 // Update the timeout tick using the configured parameter.
504 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
507 // Insert this Wrap into the instance queue.
509 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
510 Instance
->RcvdPacketQueueSize
++;
514 Match the received packet with the instance receive filters.
516 @param[in] Instance Pointer to the mnp instance context data.
517 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
518 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
519 non-NULL and it contains the destination multicast
520 mac address of the received packet if the packet
521 destinated to a multicast mac address.
522 @param[in] PktAttr The received packets attribute.
524 @return The received packet matches the instance's receive filters or not.
529 IN MNP_INSTANCE_DATA
*Instance
,
530 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
531 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
535 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
537 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
539 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
541 ConfigData
= &Instance
->ConfigData
;
544 // Check the protocol type.
546 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
550 if (ConfigData
->EnablePromiscuousReceive
) {
552 // Always match if this instance is configured to be promiscuous.
558 // The protocol type is matched, check receive filter, include unicast and broadcast.
560 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
565 // Check multicast addresses.
567 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
568 ASSERT (GroupAddress
!= NULL
);
570 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
571 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
572 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
574 // The instance is configured to receiveing packets destinated to this
575 // multicast address.
589 Analyse the received packets.
591 @param[in] MnpServiceData Pointer to the mnp service context data.
592 @param[in] Nbuf Pointer to the net buffer holding the received
594 @param[in, out] RxData Pointer to the buffer used to save the analysed
595 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
596 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
597 pass out the address of the multicast address the
598 received packet destinated to.
599 @param[out] PktAttr Pointer to the buffer used to save the analysed
605 IN MNP_SERVICE_DATA
*MnpServiceData
,
607 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
608 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
612 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
613 MNP_DEVICE_DATA
*MnpDeviceData
;
617 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
618 SnpMode
= MnpDeviceData
->Snp
->Mode
;
621 // Get the packet buffer.
623 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
624 ASSERT (BufPtr
!= NULL
);
627 // Set the initial values.
629 RxData
->BroadcastFlag
= FALSE
;
630 RxData
->MulticastFlag
= FALSE
;
631 RxData
->PromiscuousFlag
= FALSE
;
632 *PktAttr
= UNICAST_PACKET
;
634 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
636 // This packet isn't destinated to our current mac address, it't not unicast.
640 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
644 RxData
->BroadcastFlag
= TRUE
;
645 *PktAttr
= BROADCAST_PACKET
;
646 } else if ((*BufPtr
& 0x01) == 0x1) {
648 // It's multicast, try to match the multicast filters.
650 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->GroupAddressList
) {
651 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
652 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
653 RxData
->MulticastFlag
= TRUE
;
658 if (!RxData
->MulticastFlag
) {
660 // No match, set GroupAddress to NULL. This multicast packet must
661 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
663 *GroupAddress
= NULL
;
664 RxData
->PromiscuousFlag
= TRUE
;
666 if (MnpDeviceData
->PromiscuousCount
== 0) {
668 // Skip the below code, there is no receiver of this packet.
674 RxData
->PromiscuousFlag
= TRUE
;
678 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
681 // Fill the common parts of RxData.
683 RxData
->PacketLength
= Nbuf
->TotalSize
;
684 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
685 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
686 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
687 RxData
->ProtocolType
= NTOHS (*(UINT16
*)(BufPtr
+ 2 * SnpMode
->HwAddressSize
));
693 @param[in] Instance Pointer to the mnp instance context data.
694 @param[in] RxData Pointer to the receive data to wrap.
696 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
701 IN MNP_INSTANCE_DATA
*Instance
,
702 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
706 MNP_RXDATA_WRAP
*RxDataWrap
;
711 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
712 if (RxDataWrap
== NULL
) {
713 DEBUG ((DEBUG_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
717 RxDataWrap
->Instance
= Instance
;
720 // Fill the RxData in RxDataWrap,
722 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
725 // Create the recycle event.
727 Status
= gBS
->CreateEvent (
732 &RxDataWrap
->RxData
.RecycleEvent
734 if (EFI_ERROR (Status
)) {
735 DEBUG ((DEBUG_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
737 FreePool (RxDataWrap
);
745 Enqueue the received the packets to the instances belonging to the
748 @param[in] MnpServiceData Pointer to the mnp service context data.
749 @param[in] Nbuf Pointer to the net buffer representing the received
755 IN MNP_SERVICE_DATA
*MnpServiceData
,
760 MNP_INSTANCE_DATA
*Instance
;
761 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
763 MNP_GROUP_ADDRESS
*GroupAddress
;
764 MNP_RXDATA_WRAP
*RxDataWrap
;
768 // First, analyse the packet header.
770 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
772 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->MnpDeviceData
->PromiscuousCount
== 0)) {
774 // No receivers, no more action need.
780 // Iterate the children to find match.
782 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
783 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
784 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
786 if (!Instance
->Configured
) {
791 // Check the packet against the instance receive filters.
793 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
797 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
798 if (RxDataWrap
== NULL
) {
803 // Associate RxDataWrap with Nbuf and increase the RefCnt.
805 RxDataWrap
->Nbuf
= Nbuf
;
806 NET_GET_REF (RxDataWrap
->Nbuf
);
809 // Queue the packet into the instance queue.
811 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
817 Try to receive a packet and deliver it.
819 @param[in, out] MnpDeviceData Pointer to the mnp device context data.
821 @retval EFI_SUCCESS add return value to function comment
822 @retval EFI_NOT_STARTED The simple network protocol is not started.
823 @retval EFI_NOT_READY No packet received.
824 @retval EFI_DEVICE_ERROR An unexpected error occurs.
829 IN OUT MNP_DEVICE_DATA
*MnpDeviceData
833 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
839 MNP_SERVICE_DATA
*MnpServiceData
;
841 BOOLEAN IsVlanPacket
;
843 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
845 Snp
= MnpDeviceData
->Snp
;
846 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
848 // The simple network protocol is not started.
850 return EFI_NOT_STARTED
;
853 if (MnpDeviceData
->RxNbufCache
== NULL
) {
855 // Try to get a new buffer as there may be buffers recycled.
857 MnpDeviceData
->RxNbufCache
= MnpAllocNbuf (MnpDeviceData
);
859 if (MnpDeviceData
->RxNbufCache
== NULL
) {
861 // No available buffer in the buffer pool.
863 return EFI_DEVICE_ERROR
;
867 MnpDeviceData
->RxNbufCache
,
868 MnpDeviceData
->BufferLength
,
873 Nbuf
= MnpDeviceData
->RxNbufCache
;
874 BufLen
= Nbuf
->TotalSize
;
875 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
876 ASSERT (BufPtr
!= NULL
);
879 // Receive packet through Snp.
881 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
882 if (EFI_ERROR (Status
)) {
884 if (Status
!= EFI_NOT_READY
) {
885 DEBUG ((DEBUG_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
896 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
899 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
903 return EFI_DEVICE_ERROR
;
907 if (Nbuf
->TotalSize
!= BufLen
) {
909 // Trim the packet from tail.
911 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
)BufLen
, NET_BUF_TAIL
);
912 ASSERT (Nbuf
->TotalSize
== BufLen
);
916 if (MnpDeviceData
->NumberOfVlan
!= 0) {
918 // VLAN is configured, remove the VLAN tag if any
920 IsVlanPacket
= MnpRemoveVlanTag (MnpDeviceData
, Nbuf
, &VlanId
);
922 IsVlanPacket
= FALSE
;
925 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
926 if (MnpServiceData
== NULL
) {
928 // VLAN is not set for this tagged frame, ignore this packet
931 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
935 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
942 // Enqueue the packet to the matched instances.
944 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
946 if (Nbuf
->RefCnt
> 2) {
948 // RefCnt > 2 indicates there is at least one receiver of this packet.
949 // Free the current RxNbufCache and allocate a new one.
951 MnpFreeNbuf (MnpDeviceData
, Nbuf
);
953 Nbuf
= MnpAllocNbuf (MnpDeviceData
);
954 MnpDeviceData
->RxNbufCache
= Nbuf
;
956 DEBUG ((DEBUG_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
957 return EFI_DEVICE_ERROR
;
960 NetbufAllocSpace (Nbuf
, MnpDeviceData
->BufferLength
, NET_BUF_TAIL
);
963 // No receiver for this packet.
966 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
970 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
977 // Deliver the queued packets.
979 MnpDeliverPacket (MnpServiceData
);
983 ASSERT (Nbuf
->TotalSize
== MnpDeviceData
->BufferLength
);
989 Remove the received packets if timeout occurs.
991 @param[in] Event The event this notify function registered to.
992 @param[in] Context Pointer to the context data registered to the event.
997 MnpCheckPacketTimeout (
1002 MNP_DEVICE_DATA
*MnpDeviceData
;
1003 MNP_SERVICE_DATA
*MnpServiceData
;
1005 LIST_ENTRY
*ServiceEntry
;
1006 LIST_ENTRY
*RxEntry
;
1007 LIST_ENTRY
*NextEntry
;
1008 MNP_INSTANCE_DATA
*Instance
;
1009 MNP_RXDATA_WRAP
*RxDataWrap
;
1012 MnpDeviceData
= (MNP_DEVICE_DATA
*)Context
;
1013 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1015 NET_LIST_FOR_EACH (ServiceEntry
, &MnpDeviceData
->ServiceList
) {
1016 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (ServiceEntry
);
1018 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1019 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1020 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1022 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1024 // This instance is not configured or there is no receive time out,
1025 // just skip to the next instance.
1030 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1032 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1033 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1036 // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1038 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1039 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1042 // Drop the timeout packet.
1044 DEBUG ((DEBUG_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1045 MnpRecycleRxData (NULL
, RxDataWrap
);
1046 Instance
->RcvdPacketQueueSize
--;
1050 gBS
->RestoreTPL (OldTpl
);
1056 Poll to update MediaPresent field in SNP ModeData by Snp->GetStatus().
1058 @param[in] Event The event this notify function registered to.
1059 @param[in] Context Pointer to the context data registered to the event.
1064 MnpCheckMediaStatus (
1069 MNP_DEVICE_DATA
*MnpDeviceData
;
1070 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1071 UINT32 InterruptStatus
;
1073 MnpDeviceData
= (MNP_DEVICE_DATA
*)Context
;
1074 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1076 Snp
= MnpDeviceData
->Snp
;
1077 if (Snp
->Mode
->MediaPresentSupported
) {
1079 // Upon successful return of GetStatus(), the MediaPresent field of
1080 // EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change of media status
1082 Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
1087 Poll to receive the packets from Snp. This function is either called by upperlayer
1088 protocols/applications or the system poll timer notify mechanism.
1090 @param[in] Event The event this notify function registered to.
1091 @param[in] Context Pointer to the context data registered to the event.
1101 MNP_DEVICE_DATA
*MnpDeviceData
;
1103 MnpDeviceData
= (MNP_DEVICE_DATA
*)Context
;
1104 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1107 // Try to receive packets from Snp.
1109 MnpReceivePacket (MnpDeviceData
);
1112 // Dispatch the DPC queued by the NotifyFunction of rx token's events.