2 Implementation of Managed Network Protocol I/O functions.
4 Copyright (c) 2005 - 2009, 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 // Start the timeout event.
216 Status
= gBS
->SetTimer (
217 MnpDeviceData
->TxTimeoutEvent
,
221 if (EFI_ERROR (Status
)) {
228 MnpInsertVlanTag (MnpServiceData
, TxData
, &ProtocolType
, &Packet
, &Length
);
232 // Transmit the packet through SNP.
234 Status
= Snp
->Transmit (
239 TxData
->SourceAddress
,
240 TxData
->DestinationAddress
,
243 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
244 Status
= EFI_DEVICE_ERROR
;
249 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
250 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
251 // Both need to sync SNP.
256 // Get the recycled transmit buffer status.
258 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
260 if (!EFI_ERROR (gBS
->CheckEvent (MnpDeviceData
->TxTimeoutEvent
))) {
261 Status
= EFI_TIMEOUT
;
264 } while (TxBuf
== NULL
);
266 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
270 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
273 MnpDeviceData
->TxTimeoutEvent
,
281 // Cancel the timer event.
283 gBS
->SetTimer (MnpDeviceData
->TxTimeoutEvent
, TimerCancel
, 0);
287 Token
->Status
= Status
;
288 gBS
->SignalEvent (Token
->Event
);
291 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
300 Try to deliver the received packet to the instance.
302 @param[in, out] Instance Pointer to the mnp instance context data.
304 @retval EFI_SUCCESS The received packet is delivered, or there is no
305 packet to deliver, or there is no available receive
307 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
311 MnpInstanceDeliverPacket (
312 IN OUT MNP_INSTANCE_DATA
*Instance
315 MNP_DEVICE_DATA
*MnpDeviceData
;
316 MNP_RXDATA_WRAP
*RxDataWrap
;
318 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
319 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
320 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
322 MnpDeviceData
= Instance
->MnpServiceData
->MnpDeviceData
;
323 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
325 if (NetMapIsEmpty (&Instance
->RxTokenMap
) || IsListEmpty (&Instance
->RcvdPacketQueue
)) {
327 // No pending received data or no available receive token, return.
332 ASSERT (Instance
->RcvdPacketQueueSize
!= 0);
334 RxDataWrap
= NET_LIST_HEAD (&Instance
->RcvdPacketQueue
, MNP_RXDATA_WRAP
, WrapEntry
);
335 if (RxDataWrap
->Nbuf
->RefCnt
> 2) {
337 // There are other instances share this Nbuf, duplicate to get a
338 // copy to allow the instance to do R/W operations.
340 DupNbuf
= MnpAllocNbuf (MnpDeviceData
);
341 if (DupNbuf
== NULL
) {
342 DEBUG ((EFI_D_WARN
, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
344 return EFI_OUT_OF_RESOURCES
;
348 // Duplicate the net buffer.
350 NetbufDuplicate (RxDataWrap
->Nbuf
, DupNbuf
, 0);
351 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
352 RxDataWrap
->Nbuf
= DupNbuf
;
356 // All resources are OK, remove the packet from the queue.
358 NetListRemoveHead (&Instance
->RcvdPacketQueue
);
359 Instance
->RcvdPacketQueueSize
--;
361 RxData
= &RxDataWrap
->RxData
;
362 SnpMode
= MnpDeviceData
->Snp
->Mode
;
365 // Set all the buffer pointers.
367 RxData
->MediaHeader
= NetbufGetByte (RxDataWrap
->Nbuf
, 0, NULL
);
368 RxData
->DestinationAddress
= RxData
->MediaHeader
;
369 RxData
->SourceAddress
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->HwAddressSize
;
370 RxData
->PacketData
= (UINT8
*) RxData
->MediaHeader
+ SnpMode
->MediaHeaderSize
;
373 // Insert this RxDataWrap into the delivered queue.
375 InsertTailList (&Instance
->RxDeliveredPacketQueue
, &RxDataWrap
->WrapEntry
);
378 // Get the receive token from the RxTokenMap.
380 RxToken
= NetMapRemoveHead (&Instance
->RxTokenMap
, NULL
);
383 // Signal this token's event.
385 RxToken
->Packet
.RxData
= &RxDataWrap
->RxData
;
386 RxToken
->Status
= EFI_SUCCESS
;
387 gBS
->SignalEvent (RxToken
->Event
);
394 Deliver the received packet for the instances belonging to the MnpServiceData.
396 @param[in] MnpServiceData Pointer to the mnp service context data.
401 IN MNP_SERVICE_DATA
*MnpServiceData
405 MNP_INSTANCE_DATA
*Instance
;
407 NET_CHECK_SIGNATURE (MnpServiceData
, MNP_SERVICE_DATA_SIGNATURE
);
409 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
410 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
411 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
414 // Try to deliver packet for this instance.
416 MnpInstanceDeliverPacket (Instance
);
422 Recycle the RxData and other resources used to hold and deliver the received
425 @param[in] Event The event this notify function registered to.
426 @param[in] Context Pointer to the context data registerd to the Event.
436 MNP_RXDATA_WRAP
*RxDataWrap
;
437 MNP_DEVICE_DATA
*MnpDeviceData
;
439 ASSERT (Context
!= NULL
);
441 RxDataWrap
= (MNP_RXDATA_WRAP
*) Context
;
442 NET_CHECK_SIGNATURE (RxDataWrap
->Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
444 ASSERT (RxDataWrap
->Nbuf
!= NULL
);
446 MnpDeviceData
= RxDataWrap
->Instance
->MnpServiceData
->MnpDeviceData
;
447 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
452 MnpFreeNbuf (MnpDeviceData
, RxDataWrap
->Nbuf
);
453 RxDataWrap
->Nbuf
= NULL
;
456 // Close the recycle event.
458 gBS
->CloseEvent (RxDataWrap
->RxData
.RecycleEvent
);
461 // Remove this Wrap entry from the list.
463 RemoveEntryList (&RxDataWrap
->WrapEntry
);
465 FreePool (RxDataWrap
);
470 Queue the received packet into instance's receive queue.
472 @param[in, out] Instance Pointer to the mnp instance context data.
473 @param[in, out] RxDataWrap Pointer to the Wrap structure containing the
474 received data and other information.
478 IN OUT MNP_INSTANCE_DATA
*Instance
,
479 IN OUT MNP_RXDATA_WRAP
*RxDataWrap
482 MNP_RXDATA_WRAP
*OldRxDataWrap
;
484 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
487 // Check the queue size. If it exceeds the limit, drop one packet
490 if (Instance
->RcvdPacketQueueSize
== MNP_MAX_RCVD_PACKET_QUE_SIZE
) {
492 DEBUG ((EFI_D_WARN
, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
495 // Get the oldest packet.
497 OldRxDataWrap
= NET_LIST_HEAD (
498 &Instance
->RcvdPacketQueue
,
504 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
506 MnpRecycleRxData (NULL
, (VOID
*) OldRxDataWrap
);
507 Instance
->RcvdPacketQueueSize
--;
511 // Update the timeout tick using the configured parameter.
513 RxDataWrap
->TimeoutTick
= Instance
->ConfigData
.ReceivedQueueTimeoutValue
;
516 // Insert this Wrap into the instance queue.
518 InsertTailList (&Instance
->RcvdPacketQueue
, &RxDataWrap
->WrapEntry
);
519 Instance
->RcvdPacketQueueSize
++;
524 Match the received packet with the instance receive filters.
526 @param[in] Instance Pointer to the mnp instance context data.
527 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
528 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
529 non-NULL and it contains the destination multicast
530 mac address of the received packet if the packet
531 destinated to a multicast mac address.
532 @param[in] PktAttr The received packets attribute.
534 @return The received packet matches the instance's receive filters or not.
539 IN MNP_INSTANCE_DATA
*Instance
,
540 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
541 IN MNP_GROUP_ADDRESS
*GroupAddress OPTIONAL
,
545 EFI_MANAGED_NETWORK_CONFIG_DATA
*ConfigData
;
547 MNP_GROUP_CONTROL_BLOCK
*GroupCtrlBlk
;
549 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
551 ConfigData
= &Instance
->ConfigData
;
554 // Check the protocol type.
556 if ((ConfigData
->ProtocolTypeFilter
!= 0) && (ConfigData
->ProtocolTypeFilter
!= RxData
->ProtocolType
)) {
560 if (ConfigData
->EnablePromiscuousReceive
) {
562 // Always match if this instance is configured to be promiscuous.
568 // The protocol type is matched, check receive filter, include unicast and broadcast.
570 if ((Instance
->ReceiveFilter
& PktAttr
) != 0) {
575 // Check multicast addresses.
577 if (ConfigData
->EnableMulticastReceive
&& RxData
->MulticastFlag
) {
579 ASSERT (GroupAddress
!= NULL
);
581 NET_LIST_FOR_EACH (Entry
, &Instance
->GroupCtrlBlkList
) {
583 GroupCtrlBlk
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_CONTROL_BLOCK
, CtrlBlkEntry
);
584 if (GroupCtrlBlk
->GroupAddress
== GroupAddress
) {
586 // The instance is configured to receiveing packets destinated to this
587 // multicast address.
602 Analyse the received packets.
604 @param[in] MnpServiceData Pointer to the mnp service context data.
605 @param[in] Nbuf Pointer to the net buffer holding the received
607 @param[in, out] RxData Pointer to the buffer used to save the analysed
608 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
609 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
610 pass out the address of the multicast address the
611 received packet destinated to.
612 @param[out] PktAttr Pointer to the buffer used to save the analysed
618 IN MNP_SERVICE_DATA
*MnpServiceData
,
620 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
,
621 OUT MNP_GROUP_ADDRESS
**GroupAddress
,
625 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
626 MNP_DEVICE_DATA
*MnpDeviceData
;
630 MnpDeviceData
= MnpServiceData
->MnpDeviceData
;
631 SnpMode
= MnpDeviceData
->Snp
->Mode
;
634 // Get the packet buffer.
636 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
637 ASSERT (BufPtr
!= NULL
);
640 // Set the initial values.
642 RxData
->BroadcastFlag
= FALSE
;
643 RxData
->MulticastFlag
= FALSE
;
644 RxData
->PromiscuousFlag
= FALSE
;
645 *PktAttr
= UNICAST_PACKET
;
647 if (!NET_MAC_EQUAL (&SnpMode
->CurrentAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
649 // This packet isn't destinated to our current mac address, it't not unicast.
653 if (NET_MAC_EQUAL (&SnpMode
->BroadcastAddress
, BufPtr
, SnpMode
->HwAddressSize
)) {
657 RxData
->BroadcastFlag
= TRUE
;
658 *PktAttr
= BROADCAST_PACKET
;
659 } else if ((*BufPtr
& 0x01) == 0x1) {
661 // It's multicast, try to match the multicast filters.
663 NET_LIST_FOR_EACH (Entry
, &MnpDeviceData
->GroupAddressList
) {
665 *GroupAddress
= NET_LIST_USER_STRUCT (Entry
, MNP_GROUP_ADDRESS
, AddrEntry
);
666 if (NET_MAC_EQUAL (BufPtr
, &((*GroupAddress
)->Address
), SnpMode
->HwAddressSize
)) {
667 RxData
->MulticastFlag
= TRUE
;
672 if (!RxData
->MulticastFlag
) {
674 // No match, set GroupAddress to NULL. This multicast packet must
675 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
677 *GroupAddress
= NULL
;
678 RxData
->PromiscuousFlag
= TRUE
;
680 if (MnpDeviceData
->PromiscuousCount
== 0) {
682 // Skip the below code, there is no receiver of this packet.
688 RxData
->PromiscuousFlag
= TRUE
;
692 ZeroMem (&RxData
->Timestamp
, sizeof (EFI_TIME
));
695 // Fill the common parts of RxData.
697 RxData
->PacketLength
= Nbuf
->TotalSize
;
698 RxData
->HeaderLength
= SnpMode
->MediaHeaderSize
;
699 RxData
->AddressLength
= SnpMode
->HwAddressSize
;
700 RxData
->DataLength
= RxData
->PacketLength
- RxData
->HeaderLength
;
701 RxData
->ProtocolType
= NTOHS (*(UINT16
*) (BufPtr
+ 2 * SnpMode
->HwAddressSize
));
708 @param[in] Instance Pointer to the mnp instance context data.
709 @param[in] RxData Pointer to the receive data to wrap.
711 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
716 IN MNP_INSTANCE_DATA
*Instance
,
717 IN EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
721 MNP_RXDATA_WRAP
*RxDataWrap
;
726 RxDataWrap
= AllocatePool (sizeof (MNP_RXDATA_WRAP
));
727 if (RxDataWrap
== NULL
) {
728 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
732 RxDataWrap
->Instance
= Instance
;
735 // Fill the RxData in RxDataWrap,
737 CopyMem (&RxDataWrap
->RxData
, RxData
, sizeof (RxDataWrap
->RxData
));
740 // Create the recycle event.
742 Status
= gBS
->CreateEvent (
747 &RxDataWrap
->RxData
.RecycleEvent
749 if (EFI_ERROR (Status
)) {
750 DEBUG ((EFI_D_ERROR
, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status
));
752 FreePool (RxDataWrap
);
761 Enqueue the received the packets to the instances belonging to the
764 @param[in] MnpServiceData Pointer to the mnp service context data.
765 @param[in] Nbuf Pointer to the net buffer representing the received
771 IN MNP_SERVICE_DATA
*MnpServiceData
,
776 MNP_INSTANCE_DATA
*Instance
;
777 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData
;
779 MNP_GROUP_ADDRESS
*GroupAddress
;
780 MNP_RXDATA_WRAP
*RxDataWrap
;
785 // First, analyse the packet header.
787 MnpAnalysePacket (MnpServiceData
, Nbuf
, &RxData
, &GroupAddress
, &PktAttr
);
789 if (RxData
.PromiscuousFlag
&& (MnpServiceData
->MnpDeviceData
->PromiscuousCount
== 0)) {
791 // No receivers, no more action need.
797 // Iterate the children to find match.
799 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
801 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
802 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
804 if (!Instance
->Configured
) {
809 // Check the packet against the instance receive filters.
811 if (MnpMatchPacket (Instance
, &RxData
, GroupAddress
, PktAttr
)) {
815 RxDataWrap
= MnpWrapRxData (Instance
, &RxData
);
816 if (RxDataWrap
== NULL
) {
821 // Associate RxDataWrap with Nbuf and increase the RefCnt.
823 RxDataWrap
->Nbuf
= Nbuf
;
824 NET_GET_REF (RxDataWrap
->Nbuf
);
827 // Queue the packet into the instance queue.
829 MnpQueueRcvdPacket (Instance
, RxDataWrap
);
836 Try to receive a packet and deliver it.
838 @param[in, out] MnpDeviceData Pointer to the mnp device context data.
840 @retval EFI_SUCCESS add return value to function comment
841 @retval EFI_NOT_STARTED The simple network protocol is not started.
842 @retval EFI_NOT_READY No packet received.
843 @retval EFI_DEVICE_ERROR An unexpected error occurs.
848 IN OUT MNP_DEVICE_DATA
*MnpDeviceData
852 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
858 MNP_SERVICE_DATA
*MnpServiceData
;
860 BOOLEAN IsVlanPacket
;
862 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
864 Snp
= MnpDeviceData
->Snp
;
865 if (Snp
->Mode
->State
!= EfiSimpleNetworkInitialized
) {
867 // The simple network protocol is not started.
869 return EFI_NOT_STARTED
;
872 if (MnpDeviceData
->RxNbufCache
== NULL
) {
874 // Try to get a new buffer as there may be buffers recycled.
876 MnpDeviceData
->RxNbufCache
= MnpAllocNbuf (MnpDeviceData
);
878 if (MnpDeviceData
->RxNbufCache
== NULL
) {
880 // No availabe buffer in the buffer pool.
882 return EFI_DEVICE_ERROR
;
886 MnpDeviceData
->RxNbufCache
,
887 MnpDeviceData
->BufferLength
,
892 Nbuf
= MnpDeviceData
->RxNbufCache
;
893 BufLen
= Nbuf
->TotalSize
;
894 BufPtr
= NetbufGetByte (Nbuf
, 0, NULL
);
895 ASSERT (BufPtr
!= NULL
);
898 // Receive packet through Snp.
900 Status
= Snp
->Receive (Snp
, &HeaderSize
, &BufLen
, BufPtr
, NULL
, NULL
, NULL
);
901 if (EFI_ERROR (Status
)) {
903 if (Status
!= EFI_NOT_READY
) {
904 DEBUG ((EFI_D_WARN
, "MnpReceivePacket: Snp->Receive() = %r.\n", Status
));
914 if ((HeaderSize
!= Snp
->Mode
->MediaHeaderSize
) || (BufLen
< HeaderSize
)) {
917 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
921 return EFI_DEVICE_ERROR
;
925 if (Nbuf
->TotalSize
!= BufLen
) {
927 // Trim the packet from tail.
929 Trimmed
= NetbufTrim (Nbuf
, Nbuf
->TotalSize
- (UINT32
) BufLen
, NET_BUF_TAIL
);
930 ASSERT (Nbuf
->TotalSize
== BufLen
);
934 IsVlanPacket
= MnpRemoveVlanTag (MnpDeviceData
, Nbuf
, &VlanId
);
936 MnpServiceData
= MnpFindServiceData (MnpDeviceData
, VlanId
);
937 if (MnpServiceData
== NULL
) {
939 // VLAN is not set for this tagged frame, ignore this packet
942 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
946 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
953 // Enqueue the packet to the matched instances.
955 MnpEnqueuePacket (MnpServiceData
, Nbuf
);
957 if (Nbuf
->RefCnt
> 2) {
959 // RefCnt > 2 indicates there is at least one receiver of this packet.
960 // Free the current RxNbufCache and allocate a new one.
962 MnpFreeNbuf (MnpDeviceData
, Nbuf
);
964 Nbuf
= MnpAllocNbuf (MnpDeviceData
);
965 MnpDeviceData
->RxNbufCache
= Nbuf
;
967 DEBUG ((EFI_D_ERROR
, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
968 return EFI_DEVICE_ERROR
;
971 NetbufAllocSpace (Nbuf
, MnpDeviceData
->BufferLength
, NET_BUF_TAIL
);
974 // No receiver for this packet.
977 NetbufAllocSpace (Nbuf
, Trimmed
, NET_BUF_TAIL
);
980 NetbufAllocSpace (Nbuf
, NET_VLAN_TAG_LEN
, NET_BUF_HEAD
);
986 // Deliver the queued packets.
988 MnpDeliverPacket (MnpServiceData
);
992 ASSERT (Nbuf
->TotalSize
== MnpDeviceData
->BufferLength
);
999 Remove the received packets if timeout occurs.
1001 @param[in] Event The event this notify function registered to.
1002 @param[in] Context Pointer to the context data registered to the
1008 MnpCheckPacketTimeout (
1013 MNP_DEVICE_DATA
*MnpDeviceData
;
1014 MNP_SERVICE_DATA
*MnpServiceData
;
1016 LIST_ENTRY
*ServiceEntry
;
1017 LIST_ENTRY
*RxEntry
;
1018 LIST_ENTRY
*NextEntry
;
1019 MNP_INSTANCE_DATA
*Instance
;
1020 MNP_RXDATA_WRAP
*RxDataWrap
;
1023 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1024 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1026 NET_LIST_FOR_EACH (ServiceEntry
, &MnpDeviceData
->ServiceList
) {
1027 MnpServiceData
= MNP_SERVICE_DATA_FROM_LINK (ServiceEntry
);
1029 NET_LIST_FOR_EACH (Entry
, &MnpServiceData
->ChildrenList
) {
1031 Instance
= NET_LIST_USER_STRUCT (Entry
, MNP_INSTANCE_DATA
, InstEntry
);
1032 NET_CHECK_SIGNATURE (Instance
, MNP_INSTANCE_DATA_SIGNATURE
);
1034 if (!Instance
->Configured
|| (Instance
->ConfigData
.ReceivedQueueTimeoutValue
== 0)) {
1036 // This instance is not configured or there is no receive time out,
1037 // just skip to the next instance.
1042 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1044 NET_LIST_FOR_EACH_SAFE (RxEntry
, NextEntry
, &Instance
->RcvdPacketQueue
) {
1046 RxDataWrap
= NET_LIST_USER_STRUCT (RxEntry
, MNP_RXDATA_WRAP
, WrapEntry
);
1049 // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1051 if (RxDataWrap
->TimeoutTick
>= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10)) {
1052 RxDataWrap
->TimeoutTick
-= (MNP_TIMEOUT_CHECK_INTERVAL
/ 10);
1055 // Drop the timeout packet.
1057 DEBUG ((EFI_D_WARN
, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1058 MnpRecycleRxData (NULL
, RxDataWrap
);
1059 Instance
->RcvdPacketQueueSize
--;
1063 gBS
->RestoreTPL (OldTpl
);
1069 Poll to receive the packets from Snp. This function is either called by upperlayer
1070 protocols/applications or the system poll timer notify mechanism.
1072 @param[in] Event The event this notify function registered to.
1073 @param[in, out] Context Pointer to the context data registered to the event.
1080 IN OUT VOID
*Context
1083 MNP_DEVICE_DATA
*MnpDeviceData
;
1085 MnpDeviceData
= (MNP_DEVICE_DATA
*) Context
;
1086 NET_CHECK_SIGNATURE (MnpDeviceData
, MNP_DEVICE_DATA_SIGNATURE
);
1089 // Try to receive packets from Snp.
1091 MnpReceivePacket (MnpDeviceData
);
1094 // Dispatch the DPC queued by the NotifyFunction of rx token's events.